b7491194695e51f3c3184e394df94738793ff6b0
[p2pool.git] / p2pool / skiplists.py
1 from p2pool.util import math, skiplist
2
3 class WeightsSkipList(skiplist.SkipList):
4     # share_count, weights, total_weight
5     
6     def __init__(self, tracker):
7         skiplist.SkipList.__init__(self)
8         self.tracker = tracker
9     
10     def previous(self, element):
11         return self.tracker.shares[element].previous_hash
12     
13     def get_delta(self, element):
14         from p2pool.bitcoin import data as bitcoin_data
15         if element is None:
16             return (2**256, {}, 0, 0) # XXX
17         share = self.tracker.shares[element]
18         att = bitcoin_data.target_to_average_attempts(share.target)
19         return 1, {share.new_script: att*(65535-share.donation)}, att*65535, att*share.donation
20     
21     def combine_deltas(self, (share_count1, weights1, total_weight1, total_donation_weight1), (share_count2, weights2, total_weight2, total_donation_weight2)):
22         return share_count1 + share_count2, math.add_dicts([weights1, weights2]), total_weight1 + total_weight2, total_donation_weight1 + total_donation_weight2
23     
24     def initial_solution(self, start, (max_shares, desired_weight)):
25         assert desired_weight % 65535 == 0, divmod(desired_weight, 65535)
26         return 0, {}, 0, 0
27     
28     def apply_delta(self, (share_count1, weights1, total_weight1, total_donation_weight1), (share_count2, weights2, total_weight2, total_donation_weight2), (max_shares, desired_weight)):
29         if total_weight1 + total_weight2 > desired_weight and share_count2 == 1:
30             script, = weights2.iterkeys()
31             new_weights = dict(weights1)
32             assert (desired_weight - total_weight1) % 65535 == 0
33             new_weights[script] = new_weights.get(script, 0) + (desired_weight - total_weight1)//65535*weights2[script]//(total_weight2//65535)
34             return share_count1 + share_count2, new_weights, desired_weight, total_donation_weight1 + (desired_weight - total_weight1)//65535*total_donation_weight2//(total_weight2//65535)
35         return share_count1 + share_count2, math.add_dicts([weights1, weights2]), total_weight1 + total_weight2, total_donation_weight1 + total_donation_weight2
36     
37     def judge(self, (share_count, weights, total_weight, total_donation_weight), (max_shares, desired_weight)):
38         if share_count > max_shares or total_weight > desired_weight:
39             return 1
40         elif share_count == max_shares or total_weight == desired_weight:
41             return 0
42         else:
43             return -1
44     
45     def finalize(self, (share_count, weights, total_weight, total_donation_weight)):
46         return weights, total_weight, total_donation_weight
47
48 class CountsSkipList(skiplist.SkipList):
49     # share_count, counts, total_count
50     
51     def __init__(self, tracker, run_identifier):
52         skiplist.SkipList.__init__(self)
53         self.tracker = tracker
54         self.run_identifier = run_identifier
55     
56     def previous(self, element):
57         return self.tracker.shares[element].previous_hash
58     
59     def get_delta(self, element):
60         if element is None:
61             raise AssertionError()
62         share = self.tracker.shares[element]
63         return 1, set([share.hash]) if share.nonce.startswith(self.run_identifier) else set()
64     
65     def combine_deltas(self, (share_count1, share_hashes1), (share_count2, share_hashes2)):
66         if share_hashes1 & share_hashes2:
67             raise AssertionError()
68         return share_count1 + share_count2, share_hashes1 | share_hashes2
69     
70     def initial_solution(self, start, (desired_shares,)):
71         return 0, set()
72     
73     def apply_delta(self, (share_count1, share_hashes1), (share_count2, share_hashes2), (desired_shares,)):
74         if share_hashes1 & share_hashes2:
75             raise AssertionError()
76         return share_count1 + share_count2, share_hashes1 | share_hashes2
77     
78     def judge(self, (share_count, share_hashes), (desired_shares,)):
79         if share_count > desired_shares:
80             return 1
81         elif share_count == desired_shares:
82             return 0
83         else:
84             return -1
85     
86     def finalize(self, (share_count, share_hashes)):
87         return share_hashes
88
89 if __name__ == '__main__':
90     import random
91     from p2pool.bitcoin import data
92     t = data.Tracker()
93     d = WeightsSkipList(t)
94     for i in xrange(2000):
95         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)))
96     for i in xrange(2000):
97         #a = random.randrange(2000)
98         a = 1999
99         print d(a, a, 1000000)[1]