def validate_block(self, block: BlockAPI) -> None: if not isinstance(block, self.get_block_class()): raise ValidationError( f"This vm ({self!r}) is not equipped to validate a block of type {block!r}" ) if block.is_genesis: validate_length_lte(block.header.extra_data, self.extra_data_max_bytes, title="BlockHeader.extra_data") else: parent_header = get_parent_header(block.header, self.chaindb) self.validate_header(block.header, parent_header) tx_root_hash, _ = make_trie_root_and_nodes(block.transactions) if tx_root_hash != block.header.transaction_root: raise ValidationError( f"Block's transaction_root ({block.header.transaction_root}) " f"does not match expected value: {tx_root_hash}") if len(block.uncles) > MAX_UNCLES: raise ValidationError( f"Blocks may have a maximum of {MAX_UNCLES} uncles. " f"Found {len(block.uncles)}.") if not self.chaindb.exists(block.header.state_root): raise ValidationError("`state_root` was not found in the db.\n" f"- state_root: {block.header.state_root}") local_uncle_hash = keccak(rlp.encode(block.uncles)) if local_uncle_hash != block.header.uncles_hash: raise ValidationError( "`uncles_hash` and block `uncles` do not match.\n" f" - num_uncles : {len(block.uncles)}\n" f" - block uncle_hash : {local_uncle_hash}\n" f" - header uncle_hash: {block.header.uncles_hash}")
def configure_homestead_header(vm: "HomesteadVM", **header_params: Any) -> BlockHeader: validate_header_params_for_configuration(header_params) with vm.header.build_changeset(**header_params) as changeset: if 'timestamp' in header_params and changeset.block_number > 0: parent_header = get_parent_header(changeset.build_rlp(), vm.chaindb) changeset.difficulty = compute_homestead_difficulty( parent_header, header_params['timestamp'], ) # In geth the modification of the state in the DAO fork block is performed # before any transactions are applied, so doing it here is the closest we # get to that. Another alternative would be to do it in Block.mine(), but # there we'd need to manually instantiate the State and update # header.state_root after we're done. if vm.support_dao_fork and changeset.block_number == vm.get_dao_fork_block_number(): state = vm.state for account in dao_drain_list: address = Address(decode_hex(account)) balance = state.get_balance(address) state.delta_balance(dao_refund_contract, balance) state.set_balance(address, 0) # Persist the changes to the database state.persist() # Update state_root manually changeset.state_root = state.state_root header = changeset.commit() return header
def get_prev_hashes(cls, last_block_hash: Hash32, chaindb: BaseChainDB) -> Optional[Iterable[Hash32]]: if last_block_hash == GENESIS_PARENT_HASH: return block_header = get_block_header_by_hash(last_block_hash, chaindb) for _ in range(MAX_PREV_HEADER_DEPTH): yield block_header.hash try: block_header = get_parent_header(block_header, chaindb) except (IndexError, HeaderNotFound): break
def configure_frontier_header(vm: "FrontierVM", **header_params: Any) -> BlockHeader: validate_header_params_for_configuration(header_params) with vm.get_header().build_changeset(**header_params) as changeset: if 'timestamp' in header_params and vm.get_header().block_number > 0: parent_header = get_parent_header(changeset.build_rlp(), vm.chaindb) changeset.difficulty = compute_frontier_difficulty( parent_header, header_params['timestamp'], ) header = changeset.commit() return header
def validate_block(self, block: BaseBlock) -> None: """ Validate the the given block. """ if not isinstance(block, self.get_block_class()): raise ValidationError( "This vm ({0!r}) is not equipped to validate a block of type {1!r}".format( self, block, ) ) if block.is_genesis: validate_length_lte(block.header.extra_data, 32, title="BlockHeader.extra_data") else: parent_header = get_parent_header(block.header, self.chaindb) self.validate_header(block.header, parent_header) tx_root_hash, _ = make_trie_root_and_nodes(block.transactions) if tx_root_hash != block.header.transaction_root: raise ValidationError( "Block's transaction_root ({0}) does not match expected value: {1}".format( block.header.transaction_root, tx_root_hash)) if len(block.uncles) > MAX_UNCLES: raise ValidationError( "Blocks may have a maximum of {0} uncles. Found " "{1}.".format(MAX_UNCLES, len(block.uncles)) ) if not self.chaindb.exists(block.header.state_root): raise ValidationError( "`state_root` was not found in the db.\n" "- state_root: {0}".format( block.header.state_root, ) ) local_uncle_hash = keccak(rlp.encode(block.uncles)) if local_uncle_hash != block.header.uncles_hash: raise ValidationError( "`uncles_hash` and block `uncles` do not match.\n" " - num_uncles : {0}\n" " - block uncle_hash : {1}\n" " - header uncle_hash: {2}".format( len(block.uncles), local_uncle_hash, block.header.uncles_hash, ) )
def configure_header(difficulty_fn: Callable[[BlockHeader, int], int], vm: BaseVM, **header_params: Any) -> BlockHeader: validate_header_params_for_configuration(header_params) with vm.header.build_changeset(**header_params) as changeset: if 'timestamp' in header_params and changeset.block_number > 0: parent_header = get_parent_header(changeset.build_rlp(), vm.chaindb) changeset.difficulty = difficulty_fn( parent_header, header_params['timestamp'], ) header = changeset.commit() return header