28520e3da4c54a5c86d0f184d799f0d75b974569
[p2pool.git] / p2pool / skiplists.py
1 import operator
2
3 from p2pool.util import forest, math
4
5 class WeightsSkipList(forest.TrackerSkipList):
6     # share_count, weights, total_weight
7     
8     def get_delta(self, element):
9         from p2pool.bitcoin import data as bitcoin_data
10         if element is None:
11             return (2**256, {}, 0, 0) # XXX
12         share = self.tracker.shares[element]
13         att = bitcoin_data.target_to_average_attempts(share.target)
14         return 1, {share.new_script: att*(65535-share.donation)}, att*65535, att*share.donation
15     
16     def combine_deltas(self, (share_count1, weights1, total_weight1, total_donation_weight1), (share_count2, weights2, total_weight2, total_donation_weight2)):
17         return share_count1 + share_count2, math.add_dicts(weights1, weights2), total_weight1 + total_weight2, total_donation_weight1 + total_donation_weight2
18     
19     def initial_solution(self, start, (max_shares, desired_weight)):
20         assert desired_weight % 65535 == 0, divmod(desired_weight, 65535)
21         return 0, {}, 0, 0
22     
23     def apply_delta(self, (share_count1, weights1, total_weight1, total_donation_weight1), (share_count2, weights2, total_weight2, total_donation_weight2), (max_shares, desired_weight)):
24         if total_weight1 + total_weight2 > desired_weight and share_count2 == 1:
25             script, = weights2.iterkeys()
26             new_weights = dict(weights1)
27             assert (desired_weight - total_weight1) % 65535 == 0
28             new_weights[script] = new_weights.get(script, 0) + (desired_weight - total_weight1)//65535*weights2[script]//(total_weight2//65535)
29             return share_count1 + share_count2, new_weights, desired_weight, total_donation_weight1 + (desired_weight - total_weight1)//65535*total_donation_weight2//(total_weight2//65535)
30         return share_count1 + share_count2, math.add_dicts(weights1, weights2), total_weight1 + total_weight2, total_donation_weight1 + total_donation_weight2
31     
32     def judge(self, (share_count, weights, total_weight, total_donation_weight), (max_shares, desired_weight)):
33         if share_count > max_shares or total_weight > desired_weight:
34             return 1
35         elif share_count == max_shares or total_weight == desired_weight:
36             return 0
37         else:
38             return -1
39     
40     def finalize(self, (share_count, weights, total_weight, total_donation_weight), (max_shares, desired_weight)):
41         assert share_count <= max_shares and total_weight <= desired_weight
42         assert share_count == max_shares or total_weight == desired_weight
43         return weights, total_weight, total_donation_weight
44
45 class SumSkipList(forest.TrackerSkipList):
46     def __init__(self, tracker, value_func, identity_value=0, add_func=operator.add):
47         forest.TrackerSkipList.__init__(self, tracker)
48         self.value_func = value_func
49         self.identity_value = identity_value
50         self.add_func = add_func
51     
52     
53     def get_delta(self, element):
54         return self.value_func(self.tracker.shares[element]), 1
55     
56     def combine_deltas(self, (result1, count1), (result2, count2)):
57         return self.add_func(result1, result2), count1 + count2
58     
59     
60     def initial_solution(self, start_hash, (desired_count,)):
61         return self.identity_value, 0
62     
63     def apply_delta(self, (result, count), (d_result, d_count), (desired_count,)):
64         return self.add_func(result, d_result), count + d_count
65     
66     def judge(self, (result, count), (desired_count,)):
67         return cmp(count, desired_count)
68     
69     def finalize(self, (result, count), (desired_count,)):
70         assert count == desired_count
71         return result