1 from p2pool.util import math, expiring_dict
4 def finalize(self, sol):
9 self.skips = expiring_dict.ExpiringDict(600)
11 def __call__(self, start, *args, **kwargs):
14 sol = self.initial_solution(start, args)
15 if self.judge(sol, args) == 0:
16 return self.finalize(sol)
18 if pos not in self.skips:
19 self.skips[pos] = math.geometric(.5), [(self.previous(pos), self.get_delta(pos))]
20 skip_length, skip = self.skips[pos]
22 # fill previous updates
23 for i in xrange(skip_length):
25 that_hash, delta = updates.pop(i)
26 x, y = self.skips[that_hash]
28 y.append((pos, delta))
30 # put desired skip nodes in updates
31 for i in xrange(len(skip), skip_length):
32 updates[i] = pos, None
34 #if skip_length + 1 in updates:
35 # updates[skip_length + 1] = self.combine(updates[skip_length + 1], updates[skip_length])
37 for jump, delta in reversed(skip):
38 sol_if = self.apply_delta(sol, delta, args)
39 decision = self.judge(sol_if, args)
40 #print pos, sol, jump, delta, sol_if, decision
42 return self.finalize(sol_if)
47 raise AssertionError()
52 # XXX could be better by combining updates
54 updates[x] = updates[x][0], self.combine_deltas(updates[x][1], delta) if updates[x][1] is not None else delta
59 class DumbSkipList(Base):
60 def __call__(self, start, *args):
62 sol = self.initial_solution(start, args)
64 decision = self.judge(sol, args)
66 raise AssertionError()
68 return self.finalize(sol)
70 delta = self.get_delta(pos)
71 sol = self.apply_delta(sol, delta, args)
73 pos = self.previous(pos)
75 class DistanceSkipList(SkipList):
76 def __init__(self, tracker):
77 SkipList.__init__(self)
78 self.tracker = tracker
80 def previous(self, element):
81 return self.tracker.shares[element].previous_hash
83 def get_delta(self, element):
84 return element, 1, self.tracker.shares[element].previous_hash
86 def combine_deltas(self, (from_hash1, dist1, to_hash1), (from_hash2, dist2, to_hash2)):
87 if to_hash1 != from_hash2:
88 raise AssertionError()
89 return from_hash1, dist1 + dist2, to_hash2
91 def initial_solution(self, start, (n,)):
94 def apply_delta(self, (dist1, to_hash1), (from_hash2, dist2, to_hash2), (n,)):
95 if to_hash1 != from_hash2:
96 raise AssertionError()
97 return dist1 + dist2, to_hash2
99 def judge(self, (dist, hash), (n,)):
107 def finalize(self, (dist, hash)):
110 if __name__ == '__main__':
112 from p2pool.bitcoin import data
114 d = DistanceSkipList(t)
115 for i in xrange(2000):
116 t.add(data.FakeShare(hash=i, previous_hash=i - 1 if i > 0 else None))
117 for i in xrange(2000):
118 a = random.randrange(2000)
119 b = random.randrange(a + 1)
121 assert res == a - b, (a, b, res)
123 class WeightsSkipList(SkipList):
124 # share_count, weights, total_weight
126 def __init__(self, tracker):
127 SkipList.__init__(self)
128 self.tracker = tracker
130 def previous(self, element):
131 return self.tracker.shares[element].previous_hash
133 def get_delta(self, element):
134 from p2pool.bitcoin import data as bitcoin_data
136 return (2**256, {}, 0) # XXX
137 share = self.tracker.shares[element]
138 att = bitcoin_data.target_to_average_attempts(share.target)
139 return 1, {share.new_script: att}, att
141 def combine_deltas(self, (share_count1, weights1, total_weight1), (share_count2, weights2, total_weight2)):
142 return share_count1 + share_count2, math.add_dicts([weights1, weights2]), total_weight1 + total_weight2
144 def initial_solution(self, start, (max_shares, desired_weight)):
147 def apply_delta(self, (share_count1, weights1, total_weight1), (share_count2, weights2, total_weight2), (max_shares, desired_weight)):
148 if total_weight1 + total_weight2 > desired_weight and len(weights2) == 1:
149 script, = weights2.iterkeys()
150 new_weights = dict(weights1)
151 new_weights[script] = new_weights.get(script, 0) + desired_weight - total_weight1
152 return share_count1 + share_count2, new_weights, desired_weight
153 return share_count1 + share_count2, math.add_dicts([weights1, weights2]), total_weight1 + total_weight2
155 def judge(self, (share_count, weights, total_weight), (max_shares, desired_weight)):
156 if share_count > max_shares or total_weight > desired_weight:
158 elif share_count == max_shares or total_weight == desired_weight:
163 def finalize(self, (share_count, weights, total_weight)):
164 return weights, total_weight
166 class CountsSkipList(SkipList):
167 # share_count, counts, total_count
169 def __init__(self, tracker, run_identifier):
170 SkipList.__init__(self)
171 self.tracker = tracker
172 self.run_identifier = run_identifier
174 def previous(self, element):
175 return self.tracker.shares[element].previous_hash
177 def get_delta(self, element):
178 from p2pool.bitcoin import data as bitcoin_data
181 share = self.tracker.shares[element]
182 weight = 1 if share.nonce[:8] == self.run_identifier else 0
185 def combine_deltas(self, (share_count1, weights1, total_weight1), (share_count2, weights2, total_weight2)):
186 return share_count1 + share_count2, weights1 + weights2, total_weight1 + total_weight2
188 def initial_solution(self, start, (max_shares, desired_weight)):
192 def apply_delta(self, (share_count1, weights1, total_weight1), (share_count2, weights2, total_weight2), (max_shares, desired_weight)):
193 return share_count1 + share_count2, weights1 + weights2, total_weight1 + total_weight2
195 def judge(self, (share_count, weights, total_weight), (max_shares, desired_weight)):
196 if share_count > max_shares or total_weight > desired_weight:
198 elif share_count == max_shares or total_weight == desired_weight:
203 def finalize(self, (share_count, weights, total_weight)):
204 if share_count != total_weight:
205 raise AssertionError()
208 if __name__ == '__main__':
210 from p2pool.bitcoin import data
212 d = WeightsSkipList(t)
213 for i in xrange(2000):
214 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)))
215 for i in xrange(2000):
216 #a = random.randrange(2000)
218 print d(a, a, 1000000)[1]