def pos_block_pool(self, n=1.5): """ create a snapshot of the transaction pool to account for network traversal time (probably less than 300ms, but let's give a window of 1.5 seconds). :param n: :return: list of merkle root hashes of the tx pool over last 1.5 seconds """ timestamp = time() start_time = timestamp - n x = self.sorted_tx_pool(start_time) y = self.sorted_tx_pool(timestamp) if not y: # if pool is empty -> return sha256 null return [sha256('')], [[]] elif x == y: # if the pool isnt empty but there is no difference then return the only merkle hash possible.. return [merkle_tx_hash(y)], [y] else: # there is a difference in contents of pool over last 1.5 seconds.. merkle_hashes = [] txhashes = [] if not x: merkle_hashes.append(sha256('')) x = [] txhashes.append(x) else: merkle_hashes.append(merkle_tx_hash(x)) txhashes.append(x) tmp_txhashes = x for tx in reversed(self.transaction_pool): if tx.txhash in y and tx.txhash not in x: tmp_txhashes.append(tx.txhash) tmp_txhashes.sort() merkle_hashes.append(merkle_tx_hash(tmp_txhashes)) txhashes.append(tmp_txhashes) return merkle_hashes, txhashes
def closest_hash(list_hash): """ returns the closest hash in numerical terms to merkle root hash of all the supplied hashes.. :param list_hash: :return: """ if isinstance(list_hash, list): if len(list_hash) == 1: return False, False if isinstance(list_hash, str): if len(list_hash) == 64: return False, False list_hash.sort() root = merkle_tx_hash(list_hash) p = [] for l in list_hash: p.append(int(l, 16)) closest = closest_number(int(root, 16), p) return ''.join(list_hash[p.index(closest)]), root
def test_update_mining_address(self): self.block.update_mining_address(dev_config=config.dev, mining_address=bob.address) coinbase_tx = Transaction.from_pbdata(self.block.transactions[0]) self.assertTrue(isinstance(coinbase_tx, CoinBase)) self.assertEqual(coinbase_tx.addr_to, bob.address) hashedtransactions = [] for tx in self.block.transactions: hashedtransactions.append(tx.transaction_hash) self.assertEqual(self.block.blockheader.tx_merkle_root, merkle_tx_hash(hashedtransactions))
def create(self, chain, reveal_hash, vote_hash, last_block_number=-1): # FIXME: probably this should turn into a constructor reveal_hash = reveal_hash vote_hash = vote_hash data = None if last_block_number == -1: data = chain.block_chain_buffer.get_last_block( ) # m_get_last_block() else: data = chain.block_chain_buffer.get_block_n(last_block_number) last_block_number = data.blockheader.blocknumber prev_blockheaderhash = data.blockheader.headerhash hashedtransactions = [] self.transactions = [None] fee_reward = 0 for tx in chain.transaction_pool: if tx.subtype == TX_SUBTYPE_TX: fee_reward += tx.fee hashedtransactions.append(tx.txhash) self.transactions.append(tx) # copy memory rather than sym link self.duplicate_transactions = [] for tx in chain.duplicate_tx_pool: self.duplicate_transactions.append(chain.duplicate_tx_pool[tx]) if not hashedtransactions: hashedtransactions = [sha256('')] hashedtransactions = merkle_tx_hash(hashedtransactions) self.blockheader = BlockHeader() self.blockheader.create(chain=chain, blocknumber=last_block_number + 1, reveal_hash=reveal_hash, vote_hash=vote_hash, prev_blockheaderhash=prev_blockheaderhash, hashedtransactions=hashedtransactions, fee_reward=fee_reward) coinbase_tx = CoinBase().create( self.blockheader, chain.block_chain_buffer.get_slave_xmss(last_block_number + 1)) # coinbase_tx = CoinBase().create(self.blockheader.block_reward + self.blockheader.fee_reward, # self.blockheader.headerhash, # chain.wallet.address_bundle[0].xmss.get_address(), # chain.block_chain_buffer.get_slave_xmss(last_block_number + 1)) self.transactions[0] = coinbase_tx sv_list = chain.block_chain_buffer.get_stake_validators_list( last_block_number + 1).sv_list coinbase_tx.nonce = sv_list[chain.mining_address].nonce + 1
def validate(self, chain_manager, future_blocks: OrderedDict) -> bool: if chain_manager.get_block_is_duplicate(self): logger.warning('Duplicate Block #%s %s', self.block_number, bin2hstr(self.headerhash)) return False parent_block = chain_manager.get_block(self.prev_headerhash) # If parent block not found in state, then check if its in the future block list if not parent_block: try: parent_block = future_blocks[self.prev_headerhash] except KeyError: logger.warning('Parent block not found') logger.warning('Parent block headerhash %s', bin2hstr(self.prev_headerhash)) return False if not self._validate_parent_child_relation(parent_block): logger.warning('Failed to validate blocks parent child relation') return False if not chain_manager.validate_mining_nonce(self.blockheader): logger.warning('Failed PoW Validation') return False fee_reward = 0 for index in range(1, len(self.transactions)): fee_reward += self.transactions[index].fee if len(self.transactions) == 0: return False try: coinbase_txn = Transaction.from_pbdata(self.transactions[0]) coinbase_amount = coinbase_txn.amount if not coinbase_txn.validate_extended(self.block_number): return False except Exception as e: logger.warning('Exception %s', e) return False hashedtransactions = [] for tx in self.transactions: tx = Transaction.from_pbdata(tx) hashedtransactions.append(tx.txhash) if not self.blockheader.validate(fee_reward, coinbase_amount, merkle_tx_hash(hashedtransactions)): return False return True
def update_mining_address(self, mining_address: bytes): coinbase_tx = Transaction.from_pbdata(self.transactions[0]) coinbase_tx.update_mining_address(mining_address) hashedtransactions = [coinbase_tx.txhash] for tx in self.transactions: hashedtransactions.append(tx.transaction_hash) self.blockheader.update_merkle_root(merkle_tx_hash(hashedtransactions)) self._data.header.MergeFrom(self.blockheader.pbdata)
def create(staking_address: bytes, block_number: int, reveal_hash: bytes, prevblock_headerhash: bytes, transactions: list, duplicate_transactions: OrderedDict, vote: VoteMetadata, signing_xmss: XMSS, nonce: int): block = Block() block._data.transactions.extend([qrl_pb2.Transaction() ]) # FIXME: Empty for coinbase? # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: if tx.subtype == qrl_pb2.Transaction.TRANSFER: fee_reward += tx.fee hashedtransactions.append(tx.txhash) block._data.transactions.extend( [tx.pbdata]) # copy memory rather than sym link if not hashedtransactions: hashedtransactions = [sha256(b'')] txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes for tx in duplicate_transactions.values( ): # TODO: Add merkle hash for dup txn block._data.duplicate_transactions.extend([tx.pbdata]) for staker in vote.stake_validator_vote: # TODO: Add merkle hash for vote block._data.vote.extend([vote.stake_validator_vote[staker].pbdata]) tmp_blockheader = BlockHeader.create( staking_address=staking_address, blocknumber=block_number, reveal_hash=reveal_hash, prev_blockheaderhash=prevblock_headerhash, hashedtransactions=txs_hash, fee_reward=fee_reward) block._data.header.MergeFrom(tmp_blockheader.pbdata) # Prepare coinbase tx coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss) coinbase_tx.pbdata.nonce = nonce coinbase_tx.sign(signing_xmss) # Sign after nonce has been set # Replace first tx block._data.transactions[0].CopyFrom(coinbase_tx.pbdata) return block
def update_mining_address(self, mining_address: bytes): self.transactions[0].update_mining_address(mining_address) hashedtransactions = [] for tx in self.transactions: hashedtransactions.append(tx.transaction_hash) tmp_blockheader = BlockHeader.create( blocknumber=self.block_number, prev_blockheaderhash=self.prev_headerhash, hashedtransactions=merkle_tx_hash(hashedtransactions), fee_reward=self.fee_reward) self._data.header.MergeFrom(tmp_blockheader.pbdata)
def create(dev_config: DevConfig, block_number: int, prev_headerhash: bytes, prev_timestamp: int, transactions: list, miner_address: bytes, seed_height: Optional[int], seed_hash: Optional[bytes]): block = Block() # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee # Prepare coinbase tx total_reward_amount = BlockHeader.block_reward_calc( block_number, dev_config) + fee_reward coinbase_tx = CoinBase.create(dev_config, total_reward_amount, miner_address, block_number) hashedtransactions.append(coinbase_tx.txhash) Block._copy_tx_pbdata_into_block( block, coinbase_tx) # copy memory rather than sym link for tx in transactions: hashedtransactions.append(tx.txhash) Block._copy_tx_pbdata_into_block( block, tx) # copy memory rather than sym link txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create(dev_config=dev_config, blocknumber=block_number, prev_headerhash=prev_headerhash, prev_timestamp=prev_timestamp, hashedtransactions=txs_hash, fee_reward=fee_reward, seed_height=seed_height, seed_hash=seed_hash) block.blockheader = tmp_blockheader block._data.header.MergeFrom(tmp_blockheader.pbdata) block.set_nonces(dev_config, 0, 0) return block
def test_update_mining_address(self): alice_xmss = get_alice_xmss() bob_xmss = get_bob_xmss() block = Block.create(block_number=5, prev_headerhash=bytes(sha2_256(b'test')), prev_timestamp=10, transactions=[], miner_address=alice_xmss.address) block.update_mining_address(mining_address=bob_xmss.address) coinbase_tx = Transaction.from_pbdata(block.transactions[0]) self.assertTrue(isinstance(coinbase_tx, CoinBase)) self.assertEqual(coinbase_tx.addr_to, bob_xmss.address) hashedtransactions = [] for tx in block.transactions: hashedtransactions.append(tx.transaction_hash) self.assertEqual(block.blockheader.tx_merkle_root, merkle_tx_hash(hashedtransactions))
def create(block_number: int, prev_block_headerhash: bytes, prev_block_timestamp: int, transactions: list, miner_address: bytes): block = Block() # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee # Prepare coinbase tx total_reward_amount = BlockHeader.block_reward_calc( block_number) + fee_reward coinbase_tx = CoinBase.create(total_reward_amount, miner_address, block_number) hashedtransactions.append(coinbase_tx.txhash) block._data.transactions.extend([coinbase_tx.pbdata ]) # copy memory rather than sym link for tx in transactions: hashedtransactions.append(tx.txhash) block._data.transactions.extend( [tx.pbdata]) # copy memory rather than sym link txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create( blocknumber=block_number, prev_block_headerhash=prev_block_headerhash, prev_block_timestamp=prev_block_timestamp, hashedtransactions=txs_hash, fee_reward=fee_reward) block.blockheader = tmp_blockheader block._data.header.MergeFrom(tmp_blockheader.pbdata) block.set_nonces(0, 0) return block
def create(mining_nonce: int, block_number: int, prevblock_headerhash: bytes, transactions: list, signing_xmss: XMSS, master_address: bytes, nonce: int): block = Block() block._data.transactions.extend([qrl_pb2.Transaction()]) # FIXME: Empty for coinbase? # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee hashedtransactions.append(tx.txhash) block._data.transactions.extend([tx.pbdata]) # copy memory rather than sym link if not hashedtransactions: hashedtransactions = [sha256(b'')] txs_hash = merkle_tx_hash(hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create(blocknumber=block_number, mining_nonce=mining_nonce, PK=signing_xmss.pk(), prev_blockheaderhash=prevblock_headerhash, hashedtransactions=txs_hash, fee_reward=fee_reward) block._data.header.MergeFrom(tmp_blockheader.pbdata) # Prepare coinbase tx coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss, master_address) coinbase_tx.pbdata.nonce = nonce coinbase_tx.sign(signing_xmss) # Sign after nonce has been set # Replace first tx block._data.transactions[0].CopyFrom(coinbase_tx.pbdata) return block
def create(block_number: int, prevblock_headerhash: bytes, transactions: list, signing_xmss: XMSS, master_address: bytes, nonce: int): block = Block() block._data.transactions.extend([qrl_pb2.Transaction() ]) # FIXME: Empty for coinbase? # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee hashedtransactions.append(tx.txhash) block._data.transactions.extend( [tx.pbdata]) # copy memory rather than sym link if not hashedtransactions: hashedtransactions = [sha256(b'')] txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create( blocknumber=block_number, PK=signing_xmss.pk, prev_blockheaderhash=prevblock_headerhash, hashedtransactions=txs_hash, fee_reward=fee_reward) block._data.header.MergeFrom(tmp_blockheader.pbdata) # Prepare coinbase tx coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss, master_address) coinbase_tx.pbdata.nonce = nonce coinbase_tx.sign(signing_xmss) # Sign after nonce has been set # Replace first tx block._data.transactions[0].CopyFrom(coinbase_tx.pbdata) return block
def create(self, chain, hashchain_link, reveal_list=None, vote_hashes=None, last_block_number=-1): # FIXME: probably this should turn into a constructor if not reveal_list: reveal_list = [] if not vote_hashes: vote_hashes = [] data = None if last_block_number == -1: data = chain.block_chain_buffer.get_last_block() # m_get_last_block() else: data = chain.block_chain_buffer.get_block_n(last_block_number) last_block_number = data.blockheader.blocknumber prev_blockheaderhash = data.blockheader.headerhash hashedtransactions = [] self.transactions = [None] for tx in chain.transaction_pool: hashedtransactions.append(tx.txhash) self.transactions.append(tx) # copy memory rather than sym link if not hashedtransactions: hashedtransactions = sha256('') hashedtransactions = merkle_tx_hash(hashedtransactions) self.blockheader = BlockHeader() self.blockheader.create(chain=chain, blocknumber=last_block_number + 1, reveal_list=reveal_list, vote_hashes=vote_hashes, hashchain_link=hashchain_link, prev_blockheaderhash=prev_blockheaderhash, hashedtransactions=hashedtransactions) coinbase_tx = transaction.CoinBase().create(self.blockheader.block_reward, self.blockheader.headerhash, chain.my[0][1]) self.transactions[0] = coinbase_tx coinbase_tx.nonce = chain.block_chain_buffer.get_stxn_state(last_block_number + 1, chain.mining_address)[0] + 1
def validate_block(self, chain, verify_block_reveal_list=True): # check validity of new block.. """ block validation :param chain: :param verify_block_reveal_list: :return: """ b = self.blockheader last_blocknum = b.blocknumber - 1 if len(self.transactions) == 0: logger.warning('BLOCK : There must be atleast 1 txn') return False coinbase_tx = self.transactions[0] try: if coinbase_tx.subtype != transaction.TX_SUBTYPE_COINBASE: logger.warning('BLOCK : First txn must be a COINBASE txn') return False except Exception as e: logger.exception(e) return False if coinbase_tx.txfrom != self.blockheader.stake_selector: logger.info('Non matching txto and stake_selector') logger.info('txto: %s stake_selector %s', coinbase_tx.txfrom, self.blockheader.stake_selector) return False if coinbase_tx.amount != self.blockheader.block_reward: logger.info('Block_reward doesnt match') logger.info('Found: %d Expected: %d', coinbase_tx.amount, self.blockheader.block_reward) return False if b.timestamp == 0 and b.blocknumber > 0: logger.warning('Invalid block timestamp ') return False if b.block_reward != b.block_reward_calc(): logger.warning('Block reward incorrect for block: failed validation') return False if b.epoch != b.blocknumber / config.dev.blocks_per_epoch: logger.warning('Epoch incorrect for block: failed validation') return False if b.blocknumber == 1: x = 0 for tx in self.transactions: if tx.subtype == transaction.TX_SUBTYPE_STAKE: if tx.txfrom == b.stake_selector: x = 1 hash, _ = chain.select_hashchain(chain.m_blockchain[-1].blockheader.headerhash, b.stake_selector, tx.hash, blocknumber=1) if sha256(b.hash) != hash or hash not in tx.hash: logger.warning('Hashchain_link does not hash correctly to terminator: failed validation') return False if x != 1: logger.warning('Stake selector not in block.stake: failed validation') return False else: # we look in stake_list for the hash terminator and hash to it.. found = False terminator = sha256(b.hash) for _ in range(b.blocknumber - (b.epoch * config.dev.blocks_per_epoch) + 1): terminator = sha256(terminator) tmp_stake_list = chain.state.stake_list_get() for st in tmp_stake_list: if st[0] == b.stake_selector: found = True if terminator != st[1][-1]: logger.warning('Supplied hash does not iterate to terminator: failed validation') return False if not found: logger.warning('Stake selector not in stake_list for this epoch..') return False if len(b.reveal_list) != len(set(b.reveal_list)): logger.warning('Repetition in reveal_list') return False if verify_block_reveal_list: i = 0 for r in b.reveal_list: t = sha256(r) for _ in range(b.blocknumber - ( b.epoch * config.dev.blocks_per_epoch) + 1): # +1 as reveal has 1 extra hash t = sha256(t) for s in tmp_stake_list: if t == s[1][-1]: i += 1 if i != len(b.reveal_list): logger.warning('Not all the reveal_hashes are valid..') return False i = 0 target_chain = select_target_hashchain(b.prev_blockheaderhash) for r in b.vote_hashes: t = sha256(r) for x in range(b.blocknumber - (b.epoch * config.dev.blocks_per_epoch)): t = sha256(t) for s in tmp_stake_list: if t == s[1][target_chain]: i += 1 if i != len(b.vote_hashes): logger.warning('Not all the reveal_hashes are valid..') return False if b.generate_headerhash() != b.headerhash: logger.warning('Headerhash false for block: failed validation') return False tmp_last_block = chain.block_chain_buffer.get_block_n(last_blocknum) if tmp_last_block.blockheader.headerhash != b.prev_blockheaderhash: logger.warning('Headerhash not in sequence: failed validation') return False if tmp_last_block.blockheader.blocknumber != b.blocknumber - 1: logger.warning('Block numbers out of sequence: failed validation') return False if not self.validate_tx_in_block(): logger.warning('Block validate_tx_in_block error: failed validation') return False if len(self.transactions) == 1: txhashes = sha256('') else: txhashes = [] for tx_num in range(1, len(self.transactions)): tx = self.transactions[tx_num] txhashes.append(tx.txhash) if merkle_tx_hash(txhashes) != b.tx_merkle_root: logger.warning('Block hashedtransactions error: failed validation') return False return True
def audit_chain(qrl_client, dbg_addr): """ Request and store each blockself. Iterate thru each block, replaying each transaction to recreate address balances. Query each address comparing the reported vs calculated balances. """ total_blocks = 0 block_store = dict() balances_store = dict() transaction_store = dict() if dbg_addr is not None: dbg_addr = bytes.fromhex(dbg_addr[1:]).hex() # load the blocks while True: request = qrl_pb2.GetObjectReq(query=str(total_blocks).encode( encoding='ascii')) response = qrl_client.GetObject(request) if not response.HasField('block_extended'): # we reached the end of the chain break # get and store block block = response.block_extended block_store[total_blocks] = block total_blocks += 1 logging.info('loaded up to block number {}'.format(total_blocks)) # re-create balances by replaying each block for block_num in range(0, total_blocks): block = block_store[block_num] # store transactions in each block for txn in range(0, len(block.extended_transactions)): txhash = block.extended_transactions[txn].tx.transaction_hash.hex() transaction_store[txhash] = block.extended_transactions[txn] # handle coinbase address = block.extended_transactions[0].tx.coinbase.addr_to.hex() amount = block.extended_transactions[0].tx.coinbase.amount if not address in balances_store: balances_store[address] = 0 balances_store[address] += amount if dbg_addr in [address]: print('coinbase amnt {} -> Q{} via blk {}'.format( amount, address, block_num)) # handle all other transactions outside of coinbase for txn in range(1, len(block.extended_transactions)): tx = block.extended_transactions[txn].tx addr_from = block.extended_transactions[txn].addr_from.hex() tx_hash = tx.transaction_hash.hex() if tx.fee > 0: balances_store[addr_from] -= tx.fee if dbg_addr in [addr_from]: print('fee amnt {} Q{} -> Q{} via tx {}'.format( tx.fee, addr_from, address, tx_hash)) if tx.HasField('transfer'): update_balances(balances_store, addr_from, tx.transfer, dbg_addr, tx_hash) if tx.HasField('multi_sig_spend'): if has_multi_sig_spend_executed(qrl_client, tx.transaction_hash): addr_from = tx.multi_sig_spend.multi_sig_address.hex() update_balances(balances_store, addr_from, tx.multi_sig_spend, dbg_addr, tx_hash) logging.info('loaded {} addresses and {} transactions'.format( len(balances_store), len(transaction_store))) # audit each block, checking the block header and building a list for block_num in range(0, total_blocks): block = block_store[block_num] if block_num > 0: blockPrev = block_store[block_num - 1] if block.header.hash_header_prev != blockPrev.header.hash_header: logging.error('prev block error at {}'.format(block_num)) if block.header.timestamp_seconds < blockPrev.header.timestamp_seconds: logging.error('timestamp error at {}'.format(block_num)) if block.header.block_number != block_num: logging.error('block num error at {}'.format(block_num)) hashedtransactions = [ block.extended_transactions[0].tx.transaction_hash ] reward = block.header.reward_block for txn in range(1, len(block.extended_transactions)): reward += block.extended_transactions[txn].tx.fee hashedtransactions.append( block.extended_transactions[txn].tx.transaction_hash) if block.extended_transactions[0].tx.coinbase.amount != reward: logging.error('coinbase error at {}'.format(block_num)) if block.header.reward_fee + block.header.reward_block != reward: logging.error('reward error at {}'.format(block_num)) merkle_root = merkle_tx_hash(hashedtransactions) if block.header.merkle_root != merkle_root: logging.error('merkle_root error at {}'.format(block_num)) for addr in balances_store: try: balance = audit_address(qrl_client, 'Q' + addr, False) if balance != balances_store[addr]: logging.error('balance for {} does not match'.format('Q' + addr)) logging.error('node-reported balance: {}'.format(balance)) logging.error('calculated balance: {}'.format( balances_store[addr])) except: logging.error('could not query addr {}'.format('Q' + addr)) raise
def validate(self, chain_manager, future_blocks: OrderedDict) -> bool: if chain_manager.get_block_is_duplicate(self): logger.warning('Duplicate Block #%s %s', self.block_number, bin2hstr(self.headerhash)) return False parent_block = chain_manager.get_block(self.prev_headerhash) dev_config = chain_manager.get_config_by_block_number(self.block_number) # If parent block not found in state, then check if its in the future block list if not parent_block: try: parent_block = future_blocks[self.prev_headerhash] except KeyError: logger.warning('Parent block not found') logger.warning('Parent block headerhash %s', bin2hstr(self.prev_headerhash)) return False if not self._validate_parent_child_relation(parent_block): logger.warning('Failed to validate blocks parent child relation') return False if not chain_manager.validate_mining_nonce(self.blockheader, dev_config): logger.warning('Failed PoW Validation') return False if len(self.transactions) == 0: return False try: state_container = chain_manager.new_state_container(set(), self.block_number, False, None) coinbase_txn = Transaction.from_pbdata(self.transactions[0]) coinbase_amount = coinbase_txn.amount if not coinbase_txn.validate_all(state_container): return False if self.block_number != 2078158: for proto_tx in self.transactions[1:]: if proto_tx.WhichOneof('transactionType') == 'coinbase': logger.warning("Multiple coinbase transaction found") return False except Exception as e: logger.warning('Exception %s', e) return False # Build transaction merkle tree, calculate fee reward, and then see if BlockHeader also agrees. hashedtransactions = [] for tx in self.transactions: tx = Transaction.from_pbdata(tx) hashedtransactions.append(tx.txhash) fee_reward = 0 for index in range(1, len(self.transactions)): fee_reward += self.transactions[index].fee qn = Qryptonight() seed_block = chain_manager.get_block_by_number(qn.get_seed_height(self.block_number)) self.blockheader._seed_height = seed_block.block_number self.blockheader._seed_hash = seed_block.headerhash if not self.blockheader.validate(fee_reward, coinbase_amount, merkle_tx_hash(hashedtransactions), dev_config): return False return True