fixed SkipList.finalize's arguments causing pylint warnings
[p2pool.git] / p2pool / util / skiplist.py
index e57eeda..e9e36c2 100644 (file)
@@ -1,22 +1,24 @@
-from p2pool.util import math, expiring_dict
+from p2pool.util import math, memoize
 
-class Base(object):
-    def finalize(self, sol):
-        return sol
-
-class SkipList(Base):
-    def __init__(self):
-        self.skips = expiring_dict.ExpiringDict(3600)
+class SkipList(object):
+    def __init__(self, p=0.5):
+        self.p = p
+        
+        self.skips = {}
     
-    def __call__(self, start, *args, **kwargs):
+    def forget_item(self, item):
+        self.skips.pop(item, None)
+    
+    @memoize.memoize_with_backing(memoize.LRUDict(5))
+    def __call__(self, start, *args):
         updates = {}
         pos = start
         sol = self.initial_solution(start, args)
         if self.judge(sol, args) == 0:
-            return self.finalize(sol)
+            return self.finalize(sol, args)
         while True:
             if pos not in self.skips:
-                self.skips[pos] = math.geometric(.5), [(self.previous(pos), self.get_delta(pos))]
+                self.skips[pos] = math.geometric(self.p), [(self.previous(pos), self.get_delta(pos))]
             skip_length, skip = self.skips[pos]
             
             # fill previous updates
@@ -39,7 +41,7 @@ class SkipList(Base):
                 decision = self.judge(sol_if, args)
                 #print pos, sol, jump, delta, sol_if, decision
                 if decision == 0:
-                    return self.finalize(sol_if)
+                    return self.finalize(sol_if, args)
                 elif decision < 0:
                     sol = sol_if
                     break
@@ -52,129 +54,6 @@ class SkipList(Base):
             # XXX could be better by combining updates
             for x in updates:
                 updates[x] = updates[x][0], self.combine_deltas(updates[x][1], delta) if updates[x][1] is not None else delta
-            
-        
-        return item_hash
-
-class DumbSkipList(Base):
-    def __call__(self, start, *args):
-        pos = start
-        sol = self.initial_solution(start, args)
-        while True:
-            decision = self.judge(sol, args)
-            if decision > 0:
-                raise AssertionError()
-            elif decision == 0:
-                return self.finalize(sol)
-            
-            delta = self.get_delta(pos)
-            sol = self.apply_delta(sol, delta, args)
-            
-            pos = self.previous(pos)
-
-class DistanceSkipList(SkipList):
-    def __init__(self, tracker):
-        SkipList.__init__(self)
-        self.tracker = tracker
-    
-    def previous(self, element):
-        return self.tracker.shares[element].previous_hash
-    
-    def get_delta(self, element):
-        return element, 1, self.tracker.shares[element].previous_hash
     
-    def combine_deltas(self, (from_hash1, dist1, to_hash1), (from_hash2, dist2, to_hash2)):
-        if to_hash1 != from_hash2:
-            raise AssertionError()
-        return from_hash1, dist1 + dist2, to_hash2
-    
-    def initial_solution(self, start, (n,)):
-        return 0, start
-    
-    def apply_delta(self, (dist1, to_hash1), (from_hash2, dist2, to_hash2), (n,)):
-        if to_hash1 != from_hash2:
-            raise AssertionError()
-        return dist1 + dist2, to_hash2
-    
-    def judge(self, (dist, hash), (n,)):
-        if dist > n:
-            return 1
-        elif dist == n:
-            return 0
-        else:
-            return -1
-    
-    def finalize(self, (dist, hash)):
-        return hash
-
-if __name__ == '__main__':
-    import random
-    from p2pool.bitcoin import data
-    t = data.Tracker()
-    d = DistanceSkipList(t)
-    for i in xrange(2000):
-        t.add(data.FakeShare(hash=i, previous_hash=i - 1 if i > 0 else None))
-    for i in xrange(2000):
-        a = random.randrange(2000)
-        b = random.randrange(a + 1)
-        res = d(a, b)
-        assert res == a - b, (a, b, res)
-
-class WeightsSkipList(SkipList):
-    # share_count, weights, total_weight
-    
-    def __init__(self, tracker):
-        SkipList.__init__(self)
-        self.tracker = tracker
-    
-    def previous(self, element):
-        return self.tracker.shares[element].previous_hash
-    
-    def get_delta(self, element):
-        from p2pool.bitcoin import data as bitcoin_data
-        if element is None:
-            return (2**256, {}, 0) # XXX
-        share = self.tracker.shares[element]
-        att = bitcoin_data.target_to_average_attempts(share.target)
-        return 1, {share.new_script: att}, att
-    
-    def combine_deltas(self, (share_count1, weights1, total_weight1), (share_count2, weights2, total_weight2)):
-        return share_count1 + share_count2, dict((k, weights1.get(k, 0) + weights2.get(k, 0)) for k in set(weights1.keys() + weights2.keys())), total_weight1 + total_weight2
-    
-    def initial_solution(self, start, (max_shares, desired_weight)):
-        return 0, {}, 0 
-    
-    def combine_deltas(self, (share_count1, weights1, total_weight1), (share_count2, weights2, total_weight2)):
-        return share_count1 + share_count2, dict((k, weights1.get(k, 0) + weights2.get(k, 0)) for k in set(weights1.keys() + weights2.keys())), total_weight1 + total_weight2
-    
-    
-    def apply_delta(self, (share_count1, weights1, total_weight1), (share_count2, weights2, total_weight2), (max_shares, desired_weight)):
-        if total_weight1 + total_weight2 > desired_weight and len(weights2) == 1:
-            script, = weights2.iterkeys()
-            new_weights = dict(weights1)
-            new_weights[script] = new_weights.get(script, 0) + desired_weight - total_weight1
-            return share_count1 + share_count2, new_weights, desired_weight
-        return share_count1 + share_count2, dict((k, weights1.get(k, 0) + weights2.get(k, 0)) for k in set(weights1.keys() + weights2.keys())), total_weight1 + total_weight2
-    
-    def judge(self, (share_count, weights, total_weight), (max_shares, desired_weight)):
-        if share_count > max_shares or total_weight > desired_weight:
-            return 1
-        elif share_count == max_shares or total_weight == desired_weight:
-            return 0
-        else:
-            return -1
-    
-    def finalize(self, (share_count, weights, total_weight)):
-        return weights, total_weight
-
-if __name__ == '__main__':
-    import random
-    from p2pool.bitcoin import data
-    t = data.Tracker()
-    d = WeightsSkipList(t)
-    for i in xrange(2000):
-        t.add(data.FakeShare(hash=i, previous_hash=i - 1 if i > 0 else None, new_script=i, target=random.randrange(2**249, 2**250)))
-    for i in xrange(2000):
-        #a = random.randrange(2000)
-        a = 1999
-        print d(a, a, 1000000)[1]
+    def finalize(self, sol, args):
+        return sol