moved heighttracker to bitcoin.height_tracker
authorForrest Voight <forrest.voight@gmail.com>
Sun, 11 Mar 2012 21:00:15 +0000 (17:00 -0400)
committerForrest Voight <forrest@forre.st>
Mon, 12 Mar 2012 05:44:29 +0000 (01:44 -0400)
p2pool/bitcoin/height_tracker.py [new file with mode: 0644]
p2pool/bitcoin/p2p.py
p2pool/main.py

diff --git a/p2pool/bitcoin/height_tracker.py b/p2pool/bitcoin/height_tracker.py
new file mode 100644 (file)
index 0000000..53d7e84
--- /dev/null
@@ -0,0 +1,119 @@
+from twisted.internet import defer, task
+from twisted.python import log
+
+from p2pool.bitcoin import data as bitcoin_data, getwork
+from p2pool.util import deferral, forest, variable
+
+class HeaderWrapper(object):
+    target = 2**256 - 1
+    __slots__ = 'hash previous_hash'.split(' ')
+    
+    @classmethod
+    def from_header(cls, header):
+        return cls(bitcoin_data.hash256(bitcoin_data.block_header_type.pack(header)), header['previous_block'])
+    
+    def __init__(self, hash, previous_hash):
+        self.hash, self.previous_hash = hash, previous_hash
+
+class HeightTracker(object):
+    '''Point this at a factory and let it take care of getting block heights'''
+    
+    def __init__(self, rpc_proxy, factory, backlog_needed):
+        self._rpc_proxy = rpc_proxy
+        self._factory = factory
+        self._backlog_needed = backlog_needed
+        
+        self._tracker = forest.Tracker()
+        
+        self._watch1 = self._factory.new_headers.watch(self._heard_headers)
+        self._watch2 = self._factory.new_block.watch(self._request)
+        
+        self._requested = set()
+        self._clear_task = task.LoopingCall(self._requested.clear)
+        self._clear_task.start(60)
+        
+        self._last_notified_size = 0
+        
+        self.updated = variable.Event()
+        
+        self._think_task = task.LoopingCall(self._think)
+        self._think_task.start(15)
+        self._think2_task = task.LoopingCall(self._think2)
+        self._think2_task.start(15)
+        self.best_hash = None
+    
+    def _think(self):
+        try:
+            highest_head = max(self._tracker.heads, key=lambda h: self._tracker.get_height_and_last(h)[0]) if self._tracker.heads else None
+            if highest_head is None:
+                return # wait for think2
+            height, last = self._tracker.get_height_and_last(highest_head)
+            if height < self._backlog_needed:
+                self._request(last)
+        except:
+            log.err(None, 'Error in HeightTracker._think:')
+    
+    @defer.inlineCallbacks
+    def _think2(self):
+        try:
+            ba = getwork.BlockAttempt.from_getwork((yield self._rpc_proxy.rpc_getwork()))
+            self._request(ba.previous_block)
+            self.best_hash = ba.previous_block
+        except:
+            log.err(None, 'Error in HeightTracker._think2:')
+    
+    def _heard_headers(self, headers):
+        changed = False
+        for header in headers:
+            hw = HeaderWrapper.from_header(header)
+            if hw.hash in self._tracker.shares:
+                continue
+            changed = True
+            self._tracker.add(hw)
+        if changed:
+            self.updated.happened()
+        self._think()
+        
+        if len(self._tracker.shares) >= self._last_notified_size + 100:
+            print 'Have %i/%i block headers' % (len(self._tracker.shares), self._backlog_needed)
+            self._last_notified_size = len(self._tracker.shares)
+    
+    @defer.inlineCallbacks
+    def _request(self, last):
+        if last in self._tracker.shares:
+            return
+        if last in self._requested:
+            return
+        self._requested.add(last)
+        (yield self._factory.getProtocol()).send_getheaders(version=1, have=[], last=last)
+    
+    def get_height_rel_highest(self, block_hash):
+        # callers: highest height can change during yields!
+        best_height, best_last = self._tracker.get_height_and_last(self.best_hash)
+        height, last = self._tracker.get_height_and_last(block_hash)
+        if last != best_last:
+            return -1000000000 # XXX hack
+        return height - best_height
+
+@defer.inlineCallbacks
+def get_height_rel_highest_func(bitcoind, factory, current_work, net):
+    if '\ngetblock ' in (yield deferral.retry()(bitcoind.rpc_help)()):
+        @deferral.DeferredCacher
+        @defer.inlineCallbacks
+        def height_cacher(block_hash):
+            try:
+                x = yield bitcoind.rpc_getblock('%x' % (block_hash,))
+            except jsonrpc.Error, e:
+                if e.code == -5 and not p2pool.DEBUG:
+                    raise deferral.RetrySilentlyException()
+                raise
+            defer.returnValue(x['blockcount'] if 'blockcount' in x else x['height'])
+        best_height_cached = variable.Variable((yield deferral.retry()(height_cacher)(current_work.value['previous_block'])))
+        def get_height_rel_highest(block_hash):
+            this_height = height_cacher.call_now(block_hash, 0)
+            best_height = height_cacher.call_now(current_work.value['previous_block'], 0)
+            best_height_cached.set(max(best_height_cached.value, this_height, best_height))
+            return this_height - best_height_cached.value
+    else:
+        get_height_rel_highest = HeightTracker(bitcoind, factory, 5*net.SHARE_PERIOD*net.CHAIN_LENGTH/net.PARENT.BLOCK_PERIOD).get_height_rel_highest
+    defer.returnValue(get_height_rel_highest)
index a8310bf..46c104f 100644 (file)
@@ -13,8 +13,8 @@ from twisted.internet import defer, protocol, reactor, task
 from twisted.python import log
 
 import p2pool
-from . import data as bitcoin_data, getwork
-from p2pool.util import variable, datachunker, deferral, forest, pack
+from . import data as bitcoin_data
+from p2pool.util import datachunker, deferral, pack, variable
 
 class TooLong(Exception):
     pass
@@ -247,97 +247,6 @@ class ClientFactory(protocol.ReconnectingClientFactory):
     def getProtocol(self):
         return self.conn.get_not_none()
 
-class HeaderWrapper(object):
-    target = 2**256 - 1
-    __slots__ = 'hash previous_hash'.split(' ')
-    
-    @classmethod
-    def from_header(cls, header):
-        return cls(bitcoin_data.hash256(bitcoin_data.block_header_type.pack(header)), header['previous_block'])
-    
-    def __init__(self, hash, previous_hash):
-        self.hash, self.previous_hash = hash, previous_hash
-
-class HeightTracker(object):
-    '''Point this at a factory and let it take care of getting block heights'''
-    
-    def __init__(self, rpc_proxy, factory, backlog_needed):
-        self._rpc_proxy = rpc_proxy
-        self._factory = factory
-        self._backlog_needed = backlog_needed
-        
-        self._tracker = forest.Tracker()
-        
-        self._watch1 = self._factory.new_headers.watch(self._heard_headers)
-        self._watch2 = self._factory.new_block.watch(self._request)
-        
-        self._requested = set()
-        self._clear_task = task.LoopingCall(self._requested.clear)
-        self._clear_task.start(60)
-        
-        self._last_notified_size = 0
-        
-        self.updated = variable.Event()
-        
-        self._think_task = task.LoopingCall(self._think)
-        self._think_task.start(15)
-        self._think2_task = task.LoopingCall(self._think2)
-        self._think2_task.start(15)
-        self.best_hash = None
-    
-    def _think(self):
-        try:
-            highest_head = max(self._tracker.heads, key=lambda h: self._tracker.get_height_and_last(h)[0]) if self._tracker.heads else None
-            if highest_head is None:
-                return # wait for think2
-            height, last = self._tracker.get_height_and_last(highest_head)
-            if height < self._backlog_needed:
-                self._request(last)
-        except:
-            log.err(None, 'Error in HeightTracker._think:')
-    
-    @defer.inlineCallbacks
-    def _think2(self):
-        try:
-            ba = getwork.BlockAttempt.from_getwork((yield self._rpc_proxy.rpc_getwork()))
-            self._request(ba.previous_block)
-            self.best_hash = ba.previous_block
-        except:
-            log.err(None, 'Error in HeightTracker._think2:')
-    
-    def _heard_headers(self, headers):
-        changed = False
-        for header in headers:
-            hw = HeaderWrapper.from_header(header)
-            if hw.hash in self._tracker.shares:
-                continue
-            changed = True
-            self._tracker.add(hw)
-        if changed:
-            self.updated.happened()
-        self._think()
-        
-        if len(self._tracker.shares) >= self._last_notified_size + 100:
-            print 'Have %i/%i block headers' % (len(self._tracker.shares), self._backlog_needed)
-            self._last_notified_size = len(self._tracker.shares)
-    
-    @defer.inlineCallbacks
-    def _request(self, last):
-        if last in self._tracker.shares:
-            return
-        if last in self._requested:
-            return
-        self._requested.add(last)
-        (yield self._factory.getProtocol()).send_getheaders(version=1, have=[], last=last)
-    
-    def get_height_rel_highest(self, block_hash):
-        # callers: highest height can change during yields!
-        best_height, best_last = self._tracker.get_height_and_last(self.best_hash)
-        height, last = self._tracker.get_height_and_last(block_hash)
-        if last != best_last:
-            return -1000000000 # XXX hack
-        return height - best_height
-
 if __name__ == '__main__':
     from . import networks
     factory = ClientFactory(networks.BitcoinMainnet)
index a7cefb8..379522f 100644 (file)
@@ -17,7 +17,7 @@ from twisted.python import log
 from nattraverso import portmapper, ipdiscover
 
 import bitcoin.p2p as bitcoin_p2p, bitcoin.getwork as bitcoin_getwork, bitcoin.data as bitcoin_data
-from bitcoin import worker_interface
+from bitcoin import worker_interface, height_tracker
 from util import expiring_dict, jsonrpc, variable, deferral, math, logging, pack
 from . import p2p, networks, web
 import p2pool, p2pool.data as p2pool_data
@@ -166,25 +166,7 @@ def main(args, net, datadir_path, merged_urls, worker_endpoint):
             ))
         yield set_real_work1()
         
-        if '\ngetblock ' in (yield deferral.retry()(bitcoind.rpc_help)()):
-            @deferral.DeferredCacher
-            @defer.inlineCallbacks
-            def height_cacher(block_hash):
-                try:
-                    x = yield bitcoind.rpc_getblock('%x' % (block_hash,))
-                except jsonrpc.Error, e:
-                    if e.code == -5 and not p2pool.DEBUG:
-                        raise deferral.RetrySilentlyException()
-                    raise
-                defer.returnValue(x['blockcount'] if 'blockcount' in x else x['height'])
-            best_height_cached = variable.Variable((yield deferral.retry()(height_cacher)(pre_current_work.value['previous_block'])))
-            def get_height_rel_highest(block_hash):
-                this_height = height_cacher.call_now(block_hash, 0)
-                best_height = height_cacher.call_now(pre_current_work.value['previous_block'], 0)
-                best_height_cached.set(max(best_height_cached.value, this_height, best_height))
-                return this_height - best_height_cached.value
-        else:
-            get_height_rel_highest = bitcoin_p2p.HeightTracker(bitcoind, factory, 5*net.SHARE_PERIOD*net.CHAIN_LENGTH/net.PARENT.BLOCK_PERIOD).get_height_rel_highest
+        get_height_rel_highest = yield height_tracker.get_height_rel_highest_func(bitcoind, factory, pre_current_work, net)
         
         def set_real_work2():
             best, desired = tracker.think(get_height_rel_highest, pre_current_work.value['previous_block'], pre_current_work.value['bits'])