added disk cache for block headers
authorForrest Voight <forrest@forre.st>
Wed, 10 Aug 2011 04:52:20 +0000 (00:52 -0400)
committerForrest Voight <forrest@forre.st>
Wed, 10 Aug 2011 04:52:20 +0000 (00:52 -0400)
p2pool/bitcoin/p2p.py
p2pool/data.py
p2pool/main.py

index 59df45c..e264ce3 100644 (file)
@@ -311,19 +311,23 @@ class ClientFactory(protocol.ReconnectingClientFactory):
         return self.conn.get_not_none()
 
 class HeaderWrapper(object):
-    target = 0
+    target = 2**256 - 1
     __slots__ = 'hash previous_hash'.split(' ')
     
-    def __init__(self, header):
-        self.hash = bitcoin_data.block_header_type.hash256(header)
-        self.previous_hash = header['previous_block']
+    @classmethod
+    def from_header(cls, header):
+        return cls(bitcoin_data.block_header_type.hash256(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, factory):
+    def __init__(self, factory, backing):
         self.factory = factory
         self.tracker = bitcoin_data.Tracker()
+        self.backing = backing
         self.most_recent = None
         
         self._watch1 = self.factory.new_headers.watch(self.heard_headers)
@@ -337,8 +341,29 @@ class HeightTracker(object):
         
         self.updated = variable.Event()
         
+        self._load_backing()
+        
         self.think()
     
+    def _load_backing(self):
+        open(self.backing, 'ab').close()
+        with open(self.backing, 'rb') as f:
+          count = 0
+          for line in f:
+            try:
+                hash, previous_hash, checksum = (int(x, 16) for x in line.strip().split(' '))
+            except Exception:
+                print "skipping over bad data in headers.dat"
+            else:
+                if (hash - previous_hash) % 2**256 != checksum:
+                   print "checksum failed"
+                   continue
+                if previous_hash == 0: previous_hash = None
+                count += 1
+                if count % 10000 == 0 and count: print count
+                if hash not in self.tracker.shares:
+                    self.tracker.add(HeaderWrapper(hash, previous_hash))
+    
     def think(self):
         highest_head = max(self.tracker.heads, key=lambda h: self.tracker.get_height_and_last(h)[0]) if self.tracker.heads else None
         height, last = self.tracker.get_height_and_last(highest_head)
@@ -371,12 +396,16 @@ class HeightTracker(object):
     
     def heard_headers(self, headers):
         changed = False
+        b = open(self.backing, 'ab')
         for header in headers:
-            hw = HeaderWrapper(header)
+            hw = HeaderWrapper.from_header(header)
             if hw.hash in self.tracker.shares:
                 continue
             changed = True
             self.tracker.add(hw)
+            hash, prev = hw.hash, 0 if hw.previous_hash is None else hw.previous_hash
+            b.write('%x %x %x\n' % (hash, prev, (hash - prev) % 2**256))
+        b.close()
         if changed:
             self.updated.happened()
         self.think()
index cfa2973..2827649 100644 (file)
@@ -432,6 +432,7 @@ class Mainnet(bitcoin_data.Mainnet):
     P2P_PORT = 9333
     MAX_TARGET = 2**256//2**32 - 1
     PERSIST = True
+    HEADERSTORE_FILENAME = 'headers.dat'
 
 class Testnet(bitcoin_data.Testnet):
     SHARE_PERIOD = 1 # seconds
@@ -445,3 +446,4 @@ class Testnet(bitcoin_data.Testnet):
     P2P_PORT = 19333
     MAX_TARGET = 2**256//2**20 - 1
     PERSIST = False
+    HEADERSTORE_FILENAME = 'testnet_headers.dat'
index 8538616..a480e61 100644 (file)
@@ -87,7 +87,10 @@ def main(args):
         print '    Payout script:', my_script.encode('hex')
         print
         
-        ht = bitcoin.p2p.HeightTracker(factory)
+        print 'Loading cached block headers...'
+        ht = bitcoin.p2p.HeightTracker(factory, args.net.HEADERSTORE_FILENAME)
+        print '   ...done loading %i cached block headers.' % (len(ht.tracker.shares),)
+        print
         
         tracker = p2pool.OkayTracker(args.net)
         chains = expiring_dict.ExpiringDict(300)