optimization
authorforrest <forrest@470744a7-cac9-478e-843e-5ec1b25c69e8>
Sat, 16 Jul 2011 08:06:21 +0000 (08:06 +0000)
committerforrest <forrest@470744a7-cac9-478e-843e-5ec1b25c69e8>
Sat, 16 Jul 2011 08:06:21 +0000 (08:06 +0000)
git-svn-id: svn://forre.st/p2pool@1397 470744a7-cac9-478e-843e-5ec1b25c69e8

p2pool/bitcoin/data.py
p2pool/data.py
p2pool/main.py
p2pool/util/skiplist.py [new file with mode: 0644]

index 187928a..e8559b3 100644 (file)
@@ -2,6 +2,7 @@ from __future__ import division
 
 import struct
 import hashlib
+import itertools
 import warnings
 
 from . import base58
@@ -404,6 +405,7 @@ def pubkey_hash_to_script2(pubkey_hash):
 class Tracker(object):
     def __init__(self):
         self.shares = {} # hash -> share
+        self.ids = {} # hash -> (id, height)
         self.reverse_shares = {} # previous_hash -> set of share_hashes
         
         self.heads = {} # head hash -> tail_hash
@@ -419,6 +421,19 @@ class Tracker(object):
         if share.hash in self.shares:
             return # XXX raise exception?
         
+        '''
+        parent_id = self.ids.get(share.previous_hash, None)
+        children_ids = set(self.ids.get(share2_hash) for share2_hash in self.reverse_shares.get(share.hash, set()))
+        infos = set()
+        if parent_id is not None:
+            infos.add((parent_id[0], parent_id[1] + 1))
+        for child_id in children_ids:
+            infos.add((child_id[0], child_id[1] - 1))
+        if not infos:
+            infos.add((self.id_generator.next(), 0))
+        chosen = min(infos)
+        '''
+        
         self.shares[share.hash] = share
         self.reverse_shares.setdefault(share.previous_hash, set()).add(share.hash)
         
@@ -544,7 +559,7 @@ class Tracker(object):
             height += height_inc
         for update_hash, height_then in updates:
             self.heights[update_hash] = height - height_then, share_hash
-        assert (height, share_hash) == self.get_height_and_last2(orig), ((height, share_hash), self.get_height_and_last2(orig))
+        #assert (height, share_hash) == self.get_height_and_last2(orig), ((height, share_hash), self.get_height_and_last2(orig))
         return height, share_hash
     
     def get_height_and_last2(self, share_hash):
@@ -631,6 +646,11 @@ class Tracker(object):
         for i in xrange(n):
             x = self.shares[item_hash].previous_hash
         return x
+    
+    def distance_up_to_branch(self, item_hash, max_dist=None):
+        while True:
+            if a:
+                pass
 
 if __name__ == '__main__':
     class FakeShare(object):
index 217e74d..ef636a8 100644 (file)
@@ -2,6 +2,7 @@ from __future__ import division
 
 import itertools
 import random
+import time
 
 from twisted.python import log
 
@@ -170,6 +171,7 @@ class Share(object):
             raise ValueError('not enough work!')
         
         
+        self.time_seen = time.time()
         self.shared = False
     
     def as_block(self):
@@ -352,11 +354,24 @@ class OkayTracker(bitcoin_data.Tracker):
                 desired.add((self.verified.shares[random.choice(list(self.verified.reverse_shares[last_hash]))].peer, last_last_hash))
         
         # decide best verified head
-        best = max(self.verified.heads, key=lambda h: self.score(h, ht)) if self.verified.heads else None
+        scores = sorted(self.verified.heads, key=lambda h: self.score(h, ht))
+        
+        print "---"
+        for a in scores:
+            print time.time()
+            print '%x'%a, self.score(a, ht)
+        print "---"
+        
+        for share_hash in scores[:-5]:
+            if tracker.shares[share_hash].time_seen > time.time() - 30:
+                continue
+            tracker.remove(share_hash)
+        
+        best = scores[-1] if scores else None
         
         return best, desired
     
-    @memoize.memoize_with_backing(expiring_dict.ExpiringDict(15, get_touches=False))
+    @memoize.memoize_with_backing(expiring_dict.ExpiringDict(5, get_touches=False))
     def score(self, share_hash, ht):
         head_height, last = self.verified.get_height_and_last(share_hash)
         score2 = 0
@@ -372,8 +387,8 @@ class OkayTracker(bitcoin_data.Tracker):
             #this_score = -(ht.get_highest_height() - max_height + 1)//attempts
             if this_score > score2:
                 score2 = this_score
-        res = (min(head_height, self.net.CHAIN_LENGTH), score2)
-        print res
+        res = (min(head_height, self.net.CHAIN_LENGTH), score2, -self.verified.shares[share_hash].time_seen)
+        #print res
         return res
 
 
index 22d1aa6..a813335 100644 (file)
@@ -25,7 +25,7 @@ try:
 except:
     __version__ = 'unknown'
 
-@deferral.retry('Error getting work from bitcoind:', 1)
+@deferral.retry('Error getting work from bitcoind:', 3)
 @defer.inlineCallbacks
 def getwork(bitcoind):
     # a block could arrive in between these two queries
diff --git a/p2pool/util/skiplist.py b/p2pool/util/skiplist.py
new file mode 100644 (file)
index 0000000..8729ecd
--- /dev/null
@@ -0,0 +1,54 @@
+class SkipList(object):
+    def query(self, start, *args, **kwargs):
+        updates = {}
+        pos = start
+        while True:
+            if pos not in self.skips:
+                self.skips[pos] = math.geometric(.5), [self.base(pos)]
+            skip_length, skip = self.skips[pos]
+            
+            for i in xrange(skip_length):
+                if i in updates:
+                    n_then, that_hash = updates.pop(i)
+                    x, y = self.skips[that_hash]
+                    assert len(y) == i
+                    y.append((n_then - n, pos))
+            
+            for i in xrange(len(skip), skip_length):
+                updates[i] = n, item_hash
+            
+            if skip_length + 1 in updates:
+                updates[skip_length + 1] = self.combine(updates[skip_length + 1], updates[skip_length])
+            
+            for delta, jump in reversed(skip):
+                sol_if = self.combine(sol, delta)
+                decision = self.judge(sol_if)
+                if decision == 0:
+                    return sol_if
+                elif decision < 0:
+                    break
+            else:
+                raise AssertionError()
+        
+        return item_hash
+
+class DistanceSkipList(SkipList):
+    def combine(self, a, b):
+        return a + b
+    
+    def base(self, element):
+        return 1, self.tracker.shares[element].previous_hash
+
+class WeightsList(SkipList):
+    # share_count, weights, total_weight
+    def combine(self, (ac, a, at), (bc, b, bt)):
+        return ac + bc, dict((k, a.get(k, 0) + b.get(k, 0)) for k in set(a.keys() + b.keys())), at + bt
+    
+    def base(self, element):
+        share = self.tracker.shares[element]
+        att = target_to_average_attempts(share.target2)
+        return (1, {share.new_script: att}, att), self.tracker.shares[element].previous_hash
+    
+    def judge(self, (share_count, weights, total_weight), max_shares, desired_weight):
+        if share_count > max_shares:
+            return 1