def check(self, tracker, other_txs=None): from p2pool import p2p counts = None if self.share_data['previous_share_hash'] is not None: previous_share = tracker.items[self.share_data['previous_share_hash']] if tracker.get_height(self.share_data['previous_share_hash']) >= self.net.CHAIN_LENGTH: 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 type(self) is type(previous_share): pass elif type(self) is type(previous_share).SUCCESSOR: # switch only valid if 60% of hashes in [self.net.CHAIN_LENGTH*9//10, self.net.CHAIN_LENGTH] for new version if counts.get(self.VERSION, 0) < sum(counts.itervalues())*60//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__)) elif type(self) is type(previous_share).SUCCESSOR: raise p2p.PeerMisbehavingError('switch without enough history') other_tx_hashes = [tracker.items[tracker.get_nth_parent_hash(self.hash, share_count)].share_info['new_transaction_hashes'][tx_count] for share_count, tx_count in self.iter_transaction_hash_refs()] if other_txs is not None and not isinstance(other_txs, dict): other_txs = dict((bitcoin_data.hash256(bitcoin_data.tx_type.pack(tx)), tx) for tx in other_txs) share_info, gentx, other_tx_hashes2, 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.contents['ref_merkle_link'], [(h, None) for h in other_tx_hashes], self.net, known_txs=other_txs, last_txout_nonce=self.contents['last_txout_nonce'], segwit_data=self.share_info.get('segwit_data', None)) assert other_tx_hashes2 == other_tx_hashes if share_info != self.share_info: raise ValueError('share_info invalid') if bitcoin_data.get_txid(gentx) != self.gentx_hash: raise ValueError('''gentx doesn't match hash_link''') if bitcoin_data.calculate_merkle_link([None] + other_tx_hashes, 0) != self.merkle_link: # the other hash commitments are checked in the share_info assertion raise ValueError('merkle_link and other_tx_hashes do not match') update_min_protocol_version(counts, self) return gentx # only used by as_block
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 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__)) other_tx_hashes = [tracker.items[tracker.get_nth_parent_hash(self.hash, share_count)].share_info['new_transaction_hashes'][tx_count] for share_count, tx_count in self.iter_transaction_hash_refs()] share_info, gentx, other_tx_hashes2, 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.contents['ref_merkle_link'], [(h, None) for h in other_tx_hashes], self.net, last_txout_nonce=self.contents['last_txout_nonce']) assert other_tx_hashes2 == other_tx_hashes if share_info != self.share_info: raise ValueError('share_info invalid') if bitcoin_data.hash256(bitcoin_data.tx_type.pack(gentx)) != self.gentx_hash: raise ValueError('''gentx doesn't match hash_link''') if bitcoin_data.calculate_merkle_link([None] + other_tx_hashes, 0) != self.merkle_link: raise ValueError('merkle_link and other_tx_hashes do not match') return gentx # only used by as_block
def __init__(self, net, peer_addr, contents): self.net = net self.peer_addr = peer_addr self.contents = contents self.min_header = contents['min_header'] self.share_info = contents['share_info'] self.hash_link = contents['hash_link'] self.merkle_link = contents['merkle_link'] if not (2 <= len(self.share_info['share_data']['coinbase']) <= 100): raise ValueError('''bad coinbase size! %i bytes''' % (len(self.share_info['share_data']['coinbase']),)) if len(self.merkle_link['branch']) > 16: raise ValueError('merkle branch too long!') assert not self.hash_link['extra_data'], repr(self.hash_link['extra_data']) self.share_data = self.share_info['share_data'] self.max_target = self.share_info['max_bits'].target self.target = self.share_info['bits'].target self.timestamp = self.share_info['timestamp'] self.previous_hash = self.share_data['previous_share_hash'] self.new_script = bitcoin_data.pubkey_hash_to_script2(self.share_data['pubkey_hash']) self.desired_version = self.share_data['desired_version'] self.absheight = self.share_info['absheight'] self.abswork = self.share_info['abswork'] n = set() for share_count, tx_count in self.iter_transaction_hash_refs(): assert share_count < 110 if share_count == 0: n.add(tx_count) assert n == set(range(len(self.share_info['new_transaction_hashes']))) self.gentx_hash = check_hash_link( self.hash_link, self.get_ref_hash(net, self.share_info, contents['ref_merkle_link']) + pack.IntType(64).pack(self.contents['last_txout_nonce']) + pack.IntType(32).pack(0), self.gentx_before_refhash, ) merkle_root = bitcoin_data.check_merkle_link(self.gentx_hash, self.merkle_link) self.header = dict(self.min_header, merkle_root=merkle_root) self.pow_hash = net.PARENT.POW_FUNC(bitcoin_data.block_header_type.pack(self.header)) #self.hash = self.header_hash = bitcoin_data.hash256(bitcoin_data.block_header_type.pack(self.header)) self.hash = self.header_hash = net.PARENT.BLOCKHASH_FUNC(bitcoin_data.block_header_type.pack(self.header)) if self.target > net.MAX_TARGET: from p2pool import p2p raise p2p.PeerMisbehavingError('share target invalid') if self.pow_hash > self.target: from p2pool import p2p raise p2p.PeerMisbehavingError('share PoW invalid') self.new_transaction_hashes = self.share_info['new_transaction_hashes'] # XXX eww self.time_seen = time.time()
def handle_bestblock(self, header, peer): if self.node.net.PARENT.POW_FUNC( dash_data.block_header_type.pack( header)) > header['bits'].target: raise p2p.PeerMisbehavingError( 'received block header fails PoW test') self.node.handle_header(header)
def load_share(share, net, peer): if share['type'] in [0, 1, 2, 3, 4, 5, 6, 7, 8]: from p2pool import p2p raise p2p.PeerMisbehavingError('sent an obsolete share') elif share['type'] == Share.VERSION: return Share(net, peer, Share.share_type.unpack(share['contents'])) else: raise ValueError('unknown share type: %r' % (share['type'],))
def load_share(share, net, peer_addr): assert peer_addr is None or isinstance(peer_addr, tuple) if share['type'] < Share.VERSION: from p2pool import p2p raise p2p.PeerMisbehavingError('sent an obsolete share') elif share['type'] == Share.VERSION: return Share(net, peer_addr, Share.share_type.unpack(share['contents'])) else: raise ValueError('unknown share type: %r' % (share['type'],))
def load_share(share, net, peer_addr): assert peer_addr is None or isinstance(peer_addr, tuple) if share['type'] in share_versions: return share_versions[share['type']](net, peer_addr, share_versions[share['type']].get_dynamic_types(net)['share_type'].unpack(share['contents'])) elif share['type'] < Share.VERSION: from p2pool import p2p raise p2p.PeerMisbehavingError('sent an obsolete share') else: raise ValueError('unknown share type: %r' % (share['type'],))
def load_share(share, net, peer): if share['type'] in [0, 1, 2, 3]: from p2pool import p2p raise p2p.PeerMisbehavingError('sent an obsolete share') elif share['type'] == 4: return Share(net, peer, other_txs=None, **Share.share1a_type.unpack(share['contents'])) elif share['type'] == 5: share1b = Share.share1b_type.unpack(share['contents']) return Share(net, peer, merkle_link=bitcoin_data.calculate_merkle_link([0] + [ bitcoin_data.hash256(bitcoin_data.tx_type.pack(x)) for x in share1b['other_txs'] ], 0), **share1b) else: raise ValueError('unknown share type: %r' % (share['type'], ))
def handle_bestblock(self, header, peer): if bitcoin_data.scrypt(bitcoin_data.block_header_type.pack( header)) > header['bits'].target: raise p2p.PeerMisbehavingError( 'received block header fails PoW test') self.node.handle_header(header)
def check(self, tracker, known_txs=None, block_abs_height_func=None, feecache=None): from p2pool import p2p if self.timestamp > int(time.time()) + 600: raise ValueError("Share timestamp is %i seconds in the future! Check your system clock." % self.timestamp - int(time.time())) counts = None if self.share_data['previous_share_hash'] is not None and block_abs_height_func is not None: previous_share = tracker.items[self.share_data['previous_share_hash']] if tracker.get_height(self.share_data['previous_share_hash']) >= self.net.CHAIN_LENGTH: 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 type(self) is type(previous_share): pass elif type(self) is type(previous_share).SUCCESSOR: # switch only valid if 60% of hashes in [self.net.CHAIN_LENGTH*9//10, self.net.CHAIN_LENGTH] for new version if counts.get(self.VERSION, 0) < sum(counts.itervalues())*60//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__)) elif type(self) is type(previous_share).SUCCESSOR: raise p2p.PeerMisbehavingError('switch without enough history') if self.VERSION < 34: other_tx_hashes = [tracker.items[tracker.get_nth_parent_hash( self.hash, share_count)].share_info['new_transaction_hashes'][tx_count] for share_count, tx_count in self.iter_transaction_hash_refs()] else: other_tx_hashes = [] if known_txs is not None and not isinstance(known_txs, dict): print "Performing maybe-unnecessary packing and hashing" known_txs = dict((bitcoin_data.hash256( bitcoin_data.tx_type.pack(tx)), tx) for tx in known_txs) share_info, gentx, other_tx_hashes2, 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.contents['ref_merkle_link'], [(h, None) for h in other_tx_hashes], self.net, known_txs=None, last_txout_nonce=self.contents['last_txout_nonce'], segwit_data=self.share_info.get('segwit_data', None)) if self.VERSION < 34: # check for excessive fees if self.share_data['previous_share_hash'] is not None and block_abs_height_func is not None: height = (block_abs_height_func( self.header['previous_block'])+1) base_subsidy = self.net.PARENT.SUBSIDY_FUNC(height) fees = [feecache[x] for x in other_tx_hashes if x in feecache] missing = sum( [1 for x in other_tx_hashes if not x in feecache]) if missing == 0: max_subsidy = sum(fees) + base_subsidy details = "Max allowed = %i, requested subsidy = %i, share hash = %064x, miner = %s" % ( max_subsidy, self.share_data['subsidy'], self.hash, self.address) if self.share_data['subsidy'] > max_subsidy: self.naughty = 1 print "Excessive block reward in share! Naughty. " + details elif self.share_data['subsidy'] < max_subsidy: print "Strange, we received a share that did not include as many coins in the block reward as was allowed. " print "While permitted by the protocol, this causes coins to be lost forever if mined as a block, and costs us money." print details if self.share_data['previous_share_hash'] and tracker.items[self.share_data['previous_share_hash']].naughty: print "naughty ancestor found %i generations ago" % tracker.items[ self.share_data['previous_share_hash']].naughty # I am not easily angered ... print "I will not fail to punish children and grandchildren to the third and fourth generation for the sins of their parents." self.naughty = 1 + \ tracker.items[self.share_data['previous_share_hash']].naughty if self.naughty > 6: self.naughty = 0 assert other_tx_hashes2 == other_tx_hashes if share_info != self.share_info: raise ValueError('share_info invalid') if bitcoin_data.get_txid(gentx) != self.gentx_hash: raise ValueError('''gentx doesn't match hash_link''') if self.VERSION < 34: # the other hash commitments are checked in the share_info assertion if bitcoin_data.calculate_merkle_link([None] + other_tx_hashes, 0) != self.merkle_link: raise ValueError( 'merkle_link and other_tx_hashes do not match') update_min_protocol_version(counts, self) self.gentx_size = len(bitcoin_data.tx_id_type.pack(gentx)) self.gentx_weight = len( bitcoin_data.tx_type.pack(gentx)) + 3*self.gentx_size # saving this share's gentx size as a class variable is an ugly hack, and you're welcome to hate me for doing it. But it works. type(self).gentx_size = self.gentx_size type(self).gentx_weight = self.gentx_weight _diff = self.net.PARENT.DUMB_SCRYPT_DIFF*float( bitcoin_data.target_to_difficulty(self.target)) if not self.naughty: print("Received good share: diff=%.2e hash=%064x miner=%s" % (_diff, self.hash, self.address)) else: print("Received naughty=%i share: diff=%.2e hash=%064x miner=%s" % (self.naughty, _diff, self.hash, self.address)) return gentx # only used by as_block
def __init__(self, net, peer_addr, contents): dynamic_types = self.get_dynamic_types(net) self.share_info_type = dynamic_types['share_info_type'] self.share_type = dynamic_types['share_type'] self.ref_type = dynamic_types['ref_type'] self.net = net self.peer_addr = peer_addr self.contents = contents self.min_header = contents['min_header'] self.share_info = contents['share_info'] self.hash_link = contents['hash_link'] self.merkle_link = contents['merkle_link'] self.naughty = 0 # save some memory if we can if self.VERSION < 34: txrefs = self.share_info['transaction_hash_refs'] if txrefs and max(txrefs) < 2**16: self.share_info['transaction_hash_refs'] = array.array( 'H', txrefs) # in case we see blocks with more than 65536 tx in the future elif txrefs and max(txrefs) < 2**32: self.share_info['transaction_hash_refs'] = array.array( 'L', txrefs) segwit_activated = is_segwit_activated(self.VERSION, net) if not (2 <= len(self.share_info['share_data']['coinbase']) <= 100): raise ValueError('''bad coinbase size! %i bytes''' % ( len(self.share_info['share_data']['coinbase']),)) assert not self.hash_link['extra_data'], repr( self.hash_link['extra_data']) self.share_data = self.share_info['share_data'] self.max_target = self.share_info['max_bits'].target self.target = self.share_info['bits'].target self.timestamp = self.share_info['timestamp'] self.previous_hash = self.share_data['previous_share_hash'] if self.VERSION >= 34: self.new_script = bitcoin_data.address_to_script2( self.share_data['address'], net.PARENT) self.address = self.share_data['address'] else: self.new_script = bitcoin_data.pubkey_hash_to_script2( self.share_data['pubkey_hash'], net.PARENT.ADDRESS_VERSION, -1, net.PARENT) self.address = bitcoin_data.pubkey_hash_to_address( self.share_data['pubkey_hash'], net.PARENT.ADDRESS_VERSION, -1, net.PARENT) self.desired_version = self.share_data['desired_version'] self.absheight = self.share_info['absheight'] self.abswork = self.share_info['abswork'] if net.NAME == 'bitcoin' and self.absheight > 3927800 and self.desired_version == 16: raise ValueError("This is not a hardfork-supporting share!") if self.VERSION < 34: n = set() for share_count, tx_count in self.iter_transaction_hash_refs(): assert share_count < 110 if share_count == 0: n.add(tx_count) assert n == set( range(len(self.share_info['new_transaction_hashes']))) self.gentx_hash = check_hash_link( self.hash_link, self.get_ref_hash(net, self.share_info, contents['ref_merkle_link']) + pack.IntType( 64).pack(self.contents['last_txout_nonce']) + pack.IntType(32).pack(0), self.gentx_before_refhash, ) merkle_root = bitcoin_data.check_merkle_link( self.gentx_hash, self.share_info['segwit_data']['txid_merkle_link'] if segwit_activated else self.merkle_link) self.header = dict(self.min_header, merkle_root=merkle_root) self.pow_hash = net.PARENT.POW_FUNC( bitcoin_data.block_header_type.pack(self.header)) self.hash = self.header_hash = bitcoin_data.hash256( bitcoin_data.block_header_type.pack(self.header)) if self.target > net.MAX_TARGET: from p2pool import p2p raise p2p.PeerMisbehavingError('share target invalid') if self.pow_hash > self.target: from p2pool import p2p raise p2p.PeerMisbehavingError('share PoW invalid') if self.VERSION < 34: self.new_transaction_hashes = self.share_info['new_transaction_hashes'] # XXX eww self.time_seen = time.time()
def __init__(self, net, peer, common, merkle_link, other_txs): self.net = net self.peer = peer self.common = common self.min_header = common['min_header'] self.share_info = common['share_info'] self.hash_link = common['hash_link'] self.merkle_link = merkle_link self.other_txs = other_txs if len(self.share_info['share_data']['coinbase']) > 100: raise ValueError( '''coinbase too large! %i bytes''' % (len(self.share_info['share_data']['coinbase']), )) if len(merkle_link['branch']) > 16: raise ValueError('merkle branch too long!') if p2pool.DEBUG and other_txs is not None and bitcoin_data.calculate_merkle_link( [0] + [ bitcoin_data.hash256(bitcoin_data.tx_type.pack(x)) for x in other_txs ], 0) != merkle_link: raise ValueError('merkle_link and other_txs do not match') assert not self.hash_link['extra_data'], repr( self.hash_link['extra_data']) self.share_data = self.share_info['share_data'] self.max_target = self.share_info['max_bits'].target self.target = self.share_info['bits'].target self.timestamp = self.share_info['timestamp'] self.previous_hash = self.share_data['previous_share_hash'] self.new_script = bitcoin_data.pubkey_hash_to_script2( self.share_data['pubkey_hash']) self.desired_version = self.share_data['desired_version'] self.gentx_hash = check_hash_link( self.hash_link, self.get_ref_hash(net, self.share_info, common['ref_merkle_link']) + pack.IntType(32).pack(0), self.gentx_before_refhash, ) merkle_root = bitcoin_data.check_merkle_link(self.gentx_hash, merkle_link) self.header = dict(self.min_header, merkle_root=merkle_root) self.pow_hash = net.PARENT.POW_FUNC( bitcoin_data.block_header_type.pack(self.header)) self.hash = self.header_hash = bitcoin_data.hash256( bitcoin_data.block_header_type.pack(self.header)) if self.pow_hash > self.target: from p2pool import p2p raise p2p.PeerMisbehavingError('share PoW invalid') if other_txs is not None and not self.pow_hash <= self.header[ 'bits'].target: raise ValueError('other_txs provided when not a block solution') if other_txs is None and self.pow_hash <= self.header['bits'].target: raise ValueError('other_txs not provided when a block solution') # XXX eww self.time_seen = time.time()