import struct
import hashlib
+import itertools
import warnings
from . import base58
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
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)
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):
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):
import itertools
import random
+import time
from twisted.python import log
raise ValueError('not enough work!')
+ self.time_seen = time.time()
self.shared = False
def as_block(self):
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
#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
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
--- /dev/null
+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