From 4251bb65352e45d12c21b23dc2a77841b6a02df5 Mon Sep 17 00:00:00 2001 From: Forrest Voight Date: Fri, 2 Nov 2012 01:00:05 -0400 Subject: [PATCH] rewrote switchover logic to be more general --- p2pool/data.py | 45 +++++++++++++++++++++++++++++++++------------ p2pool/work.py | 28 ++++++++++++++++------------ 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/p2pool/data.py b/p2pool/data.py index 94f8149..3395e64 100644 --- a/p2pool/data.py +++ b/p2pool/data.py @@ -56,6 +56,9 @@ def load_share(share, net, peer): DONATION_SCRIPT = '4104ffd03de44a6e11b9917f3a29f9443283d9871c9d743ef30d5eddcd37094b64d1b3d8090496b53256786bf5c82932ec23c3b74d9f05a6f95a8b5529352656664bac'.decode('hex') class Share(object): + VERSION = 7 + SUCCESSOR = None + small_block_header_type = pack.ComposedType([ ('version', pack.VarIntType()), # XXX must be constrained to 32 bits ('previous_block', pack.PossiblyNoneType(0, pack.IntType(256))), @@ -259,11 +262,24 @@ class Share(object): return self.as_share1b() def check(self, tracker): + from p2pool import p2p if self.share_data['previous_share_hash'] is not None: previous_share = tracker.items[self.share_data['previous_share_hash']] - if isinstance(previous_share, NewShare): - from p2pool import p2p - raise p2p.PeerMisbehavingError('''Share can't follow NewShare''') + if type(self) is type(previous_share): + pass + elif type(self) is type(previous_share).SUCCESSOR: + if tracker.get_height(previous_share.hash) < self.net.CHAIN_LENGTH: + from p2pool import p2p + raise p2p.PeerMisbehavingError('switch without enough history') + + # switch only valid if 85% of hashes in [self.net.CHAIN_LENGTH*9//10, self.net.CHAIN_LENGTH] for new version + counts = get_desired_version_counts(tracker, + tracker.get_nth_parent_hash(previous_share.hash, self.net.CHAIN_LENGTH*9//10), self.net.CHAIN_LENGTH//10) + if counts.get(self.VERSION, 0) < sum(counts.itervalues())*85//100: + raise p2p.PeerMisbehavingError('switch without enough hash power upgraded') + else: + raise p2p.PeerMisbehavingError('''%s can't follow %s''' % (type(self).__name__, type(previous_share).__name__)) + share_info, gentx, other_transaction_hashes, get_share = self.generate_transaction(tracker, self.share_info['share_data'], self.header['bits'].target, self.share_info['timestamp'], self.share_info['bits'].target, self.common['ref_merkle_link'], [], self.net) # ok because desired_other_transaction_hashes is only used in get_share if share_info != self.share_info: raise ValueError('share_info invalid') @@ -290,6 +306,7 @@ class Share(object): class NewShare(object): VERSION = 8 + SUCCESSOR = None other_txs = None @@ -506,19 +523,23 @@ class NewShare(object): return dict(type=self.VERSION, contents=self.share_type.pack(self.contents)) def check(self, tracker): + from p2pool import p2p if self.share_data['previous_share_hash'] is not None: previous_share = tracker.items[self.share_data['previous_share_hash']] - if isinstance(previous_share, Share): + if type(self) is type(previous_share): + pass + elif type(self) is type(previous_share).SUCCESSOR: if tracker.get_height(previous_share.hash) < self.net.CHAIN_LENGTH: from p2pool import p2p - raise p2p.PeerMisbehavingError('NewShare without enough history') - else: - # Share -> NewShare only valid if 85% of hashes in [self.net.CHAIN_LENGTH*9//10, self.net.CHAIN_LENGTH] for new version - counts = get_desired_version_counts(tracker, - tracker.get_nth_parent_hash(previous_share.hash, self.net.CHAIN_LENGTH*9//10), self.net.CHAIN_LENGTH//10) - if counts.get(self.VERSION, 0) < sum(counts.itervalues())*85//100: - from p2pool import p2p - raise p2p.PeerMisbehavingError('NewShare without enough hash power upgraded') + raise p2p.PeerMisbehavingError('switch without enough history') + + # switch only valid if 85% of hashes in [self.net.CHAIN_LENGTH*9//10, self.net.CHAIN_LENGTH] for new version + counts = get_desired_version_counts(tracker, + tracker.get_nth_parent_hash(previous_share.hash, self.net.CHAIN_LENGTH*9//10), self.net.CHAIN_LENGTH//10) + if counts.get(self.VERSION, 0) < sum(counts.itervalues())*85//100: + raise p2p.PeerMisbehavingError('switch without enough hash power upgraded') + else: + raise p2p.PeerMisbehavingError('''%s can't follow %s''' % (type(self).__name__, type(previous_share).__name__)) other_tx_hashes = [tracker.items[tracker.get_nth_parent_hash(self.hash, x['share_count'])].share_info['new_transaction_hashes'][x['tx_count']] for x in self.share_info['transaction_hash_refs']] diff --git a/p2pool/work.py b/p2pool/work.py index 21b77ac..40fcfce 100644 --- a/p2pool/work.py +++ b/p2pool/work.py @@ -183,20 +183,24 @@ class WorkerBridge(worker_interface.WorkerBridge): tx_hashes = [bitcoin_data.hash256(bitcoin_data.tx_type.pack(tx)) for tx in self.current_work.value['transactions']] tx_map = dict(zip(tx_hashes, self.current_work.value['transactions'])) - share_type = p2pool_data.NewShare - if self.node.best_share_var.value is not None: + if self.node.best_share_var.value is None: + share_type = p2pool_data.Share + else: previous_share = self.node.tracker.items[self.node.best_share_var.value] - if isinstance(previous_share, p2pool_data.Share): + previous_share_type = type(previous_share) + + if previous_share_type.SUCCESSOR is None or self.node.tracker.get_height(previous_share.hash) < self.node.net.CHAIN_LENGTH: + share_type = previous_share_type + else: + successor_type = previous_share_type.SUCCESSOR + + counts = p2pool_data.get_desired_version_counts(self.node.tracker, + self.node.tracker.get_nth_parent_hash(previous_share.hash, self.node.net.CHAIN_LENGTH*9//10), self.node.net.CHAIN_LENGTH//10) # Share -> NewShare only valid if 85% of hashes in [net.CHAIN_LENGTH*9//10, net.CHAIN_LENGTH] for new version - if self.node.tracker.get_height(previous_share.hash) < self.node.net.CHAIN_LENGTH: - share_type = p2pool_data.Share - elif time.time() < 1351383661 and self.node.net.NAME == 'bitcoin': - share_type = p2pool_data.Share + if counts.get(successor_type.VERSION, 0) > sum(counts.itervalues())*95//100: + share_type = successor_type else: - counts = p2pool_data.get_desired_version_counts(self.node.tracker, - self.node.tracker.get_nth_parent_hash(previous_share.hash, self.node.net.CHAIN_LENGTH*9//10), self.node.net.CHAIN_LENGTH//10) - if counts.get(p2pool_data.NewShare.VERSION, 0) < sum(counts.itervalues())*95//100: - share_type = p2pool_data.Share + share_type = previous_share_type if True: share_info, gentx, other_transaction_hashes, get_share = share_type.generate_transaction( @@ -216,7 +220,7 @@ class WorkerBridge(worker_interface.WorkerBridge): 'doa' if doas > doas_recorded_in_chain else None )(*self.get_stale_counts()), - desired_version=7, + desired_version=share_type.SUCCESSOR.VERSION if share_type.SUCCESSOR is not None else share_type.VERSION, ), block_target=self.current_work.value['bits'].target, desired_timestamp=int(time.time() + 0.5), -- 1.7.1