def apply_create_message(self) -> BaseComputation: computation = self.apply_message() if computation.is_error: return computation else: contract_code = computation.output if contract_code: contract_code_gas_fee = len(contract_code) * GAS_CODEDEPOSIT try: computation.consume_gas( contract_code_gas_fee, reason="Write contract code for CREATE", ) except OutOfGas: computation.output = b'' else: self.logger.trace( "SETTING CODE: %s -> length: %s | hash: %s", encode_hex(self.msg.storage_address), len(contract_code), encode_hex(keccak(contract_code))) self.state.account_db.set_code(self.msg.storage_address, contract_code) return computation
def build_computation(self, message: Message, transaction: BaseTransaction) -> BaseComputation: """Apply the message to the VM.""" transaction_context = self.vm_state.get_transaction_context( transaction) if message.is_create: is_collision = self.vm_state.account_db.account_has_code_or_nonce( message.storage_address) if is_collision: # The address of the newly created contract has *somehow* collided # with an existing contract address. computation = self.vm_state.get_computation( message, transaction_context) computation._error = ContractCreationCollision( "Address collision while creating contract: {0}".format( encode_hex(message.storage_address), )) self.vm_state.logger.trace( "Address collision while creating contract: %s", encode_hex(message.storage_address), ) else: computation = self.vm_state.get_computation( message, transaction_context, ).apply_create_message() else: computation = self.vm_state.get_computation( message, transaction_context).apply_message() return computation
def get_canonical_transaction(self, transaction_hash: Hash32) -> BaseTransaction: """ Returns the requested transaction as specified by the transaction hash from the canonical chain. Raises TransactionNotFound if no transaction with the specified hash is found in the main chain. """ (block_num, index) = self.chaindb.get_transaction_index(transaction_hash) VM = self.get_vm_class_for_block_number(block_num) transaction = self.chaindb.get_transaction_by_index( block_num, index, VM.get_transaction_class(), ) if transaction.hash == transaction_hash: return transaction else: raise TransactionNotFound("Found transaction {} instead of {} in block {} at {}".format( encode_hex(transaction.hash), encode_hex(transaction_hash), block_num, index, ))
def validate_uncles(self, block: BaseBlock) -> None: """ Validate the uncles for the given block. """ # Check for duplicates uncle_groups = groupby(operator.attrgetter('hash'), block.uncles) duplicate_uncles = tuple(sorted( hash for hash, twins in uncle_groups.items() if len(twins) > 1 )) if duplicate_uncles: raise ValidationError( "Block contains duplicate uncles:\n" " - {0}".format(' - '.join(duplicate_uncles)) ) recent_ancestors = tuple( ancestor for ancestor in self.get_ancestors(MAX_UNCLE_DEPTH + 1, header=block.header) ) recent_ancestor_hashes = {ancestor.hash for ancestor in recent_ancestors} recent_uncle_hashes = _extract_uncle_hashes(recent_ancestors) for uncle in block.uncles: if uncle.hash == block.hash: raise ValidationError("Uncle has same hash as block") # ensure the uncle has not already been included. if uncle.hash in recent_uncle_hashes: raise ValidationError( "Duplicate uncle: {0}".format(encode_hex(uncle.hash)) ) # ensure that the uncle is not one of the canonical chain blocks. if uncle.hash in recent_ancestor_hashes: raise ValidationError( "Uncle {0} cannot be an ancestor of {1}".format( encode_hex(uncle.hash), encode_hex(block.hash))) # ensure that the uncle was built off of one of the canonical chain # blocks. if uncle.parent_hash not in recent_ancestor_hashes or ( uncle.parent_hash == block.header.parent_hash): raise ValidationError( "Uncle's parent {0} is not an ancestor of {1}".format( encode_hex(uncle.parent_hash), encode_hex(block.hash))) # Now perform VM level validation of the uncle self.validate_seal(uncle) try: uncle_parent = self.get_block_header_by_hash(uncle.parent_hash) except HeaderNotFound: raise ValidationError( "Uncle ancestor not found: {0}".format(uncle.parent_hash) ) uncle_vm_class = self.get_vm_class_for_block_number(uncle.block_number) uncle_vm_class.validate_uncle(block, uncle, uncle_parent)
def __enter__(self) -> 'BaseComputation': self.logger.trace( ("COMPUTATION STARTING: gas: %s | from: %s | to: %s | value: %s " "| depth %s | static: %s"), self.msg.gas, encode_hex(self.msg.sender), encode_hex(self.msg.to), self.msg.value, self.msg.depth, "y" if self.msg.is_static else "n", ) return self
def check_pow(block_number: int, mining_hash: Hash32, mix_hash: Hash32, nonce: bytes, difficulty: int) -> None: validate_length(mix_hash, 32, title="Mix Hash") validate_length(mining_hash, 32, title="Mining Hash") validate_length(nonce, 8, title="POW Nonce") cache = get_cache(block_number) mining_output = hashimoto_light(block_number, cache, mining_hash, big_endian_to_int(nonce)) if mining_output[b'mix digest'] != mix_hash: raise ValidationError("mix hash mismatch; {0} != {1}".format( encode_hex(mining_output[b'mix digest']), encode_hex(mix_hash))) result = big_endian_to_int(mining_output[b'result']) validate_lte(result, 2**256 // difficulty, title="POW Difficulty")
def build_evm_message(self, transaction): transaction_context = self.get_transaction_context(transaction) gas_fee = transaction.gas * transaction_context.gas_price # Buy Gas self.vm_state.account_db.delta_balance(transaction.sender, -1 * gas_fee) # Increment Nonce self.vm_state.account_db.increment_nonce(transaction.sender) # Setup VM Message message_gas = transaction.gas - transaction.intrinsic_gas if transaction.to == CREATE_CONTRACT_ADDRESS: contract_address = generate_contract_address( transaction.sender, self.vm_state.account_db.get_nonce(transaction.sender) - 1, ) data = b'' code = transaction.data else: contract_address = None data = transaction.data code = self.vm_state.account_db.get_code(transaction.to) self.vm_state.logger.trace( ("TRANSACTION: sender: %s | to: %s | value: %s | gas: %s | " "gas-price: %s | s: %s | r: %s | v: %s | data-hash: %s"), encode_hex(transaction.sender), encode_hex(transaction.to), transaction.value, transaction.gas, transaction.gas_price, transaction.s, transaction.r, transaction.v, encode_hex(keccak(transaction.data)), ) message = Message( gas=message_gas, to=transaction.to, sender=transaction.sender, value=transaction.value, data=data, code=code, create_address=contract_address, ) return message
def validate_gaslimit(self, header: BlockHeader) -> None: """ Validate the gas limit on the given header. """ parent_header = self.get_block_header_by_hash(header.parent_hash) low_bound, high_bound = compute_gas_limit_bounds(parent_header) if header.gas_limit < low_bound: raise ValidationError( "The gas limit on block {0} is too low: {1}. It must be at least {2}".format( encode_hex(header.hash), header.gas_limit, low_bound)) elif header.gas_limit > high_bound: raise ValidationError( "The gas limit on block {0} is too high: {1}. It must be at most {2}".format( encode_hex(header.hash), header.gas_limit, high_bound))
def apply_create_message(self): snapshot = self.state.snapshot() # EIP161 nonce incrementation self.state.account_db.increment_nonce(self.msg.storage_address) computation = self.apply_message() if computation.is_error: self.state.revert(snapshot) return computation else: contract_code = computation.output if contract_code and len(contract_code) >= EIP170_CODE_SIZE_LIMIT: computation._error = OutOfGas( "Contract code size exceeds EIP170 limit of {0}. Got code of " "size: {1}".format( EIP170_CODE_SIZE_LIMIT, len(contract_code), )) self.state.revert(snapshot) elif contract_code: contract_code_gas_cost = len( contract_code) * constants.GAS_CODEDEPOSIT try: computation.consume_gas( contract_code_gas_cost, reason="Write contract code for CREATE", ) except OutOfGas as err: # Different from Frontier: reverts state on gas failure while # writing contract code. computation._error = err self.state.revert(snapshot) else: if self.logger: self.logger.trace( "SETTING CODE: %s -> length: %s | hash: %s", encode_hex(self.msg.storage_address), len(contract_code), encode_hex(keccak(contract_code))) self.state.account_db.set_code(self.msg.storage_address, contract_code) self.state.commit(snapshot) else: self.state.commit(snapshot) return computation
def finalize_computation(self, transaction: BaseTransaction, computation: BaseComputation) -> BaseComputation: # Self Destruct Refunds num_deletions = len(computation.get_accounts_for_deletion()) if num_deletions: computation.refund_gas(REFUND_SELFDESTRUCT * num_deletions) # Gas Refunds gas_remaining = computation.get_gas_remaining() gas_refunded = computation.get_gas_refund() gas_used = transaction.gas - gas_remaining gas_refund = min(gas_refunded, gas_used // 2) gas_refund_amount = (gas_refund + gas_remaining) * transaction.gas_price if gas_refund_amount: self.vm_state.logger.trace( 'TRANSACTION REFUND: %s -> %s', gas_refund_amount, encode_hex(computation.msg.sender), ) self.vm_state.account_db.delta_balance(computation.msg.sender, gas_refund_amount) # Miner Fees transaction_fee = \ (transaction.gas - gas_remaining - gas_refund) * transaction.gas_price self.vm_state.logger.trace( 'TRANSACTION FEE: %s -> %s', transaction_fee, encode_hex(self.vm_state.coinbase), ) self.vm_state.account_db.delta_balance(self.vm_state.coinbase, transaction_fee) # Process Self Destructs for account, beneficiary in computation.get_accounts_for_deletion(): # TODO: need to figure out how we prevent multiple selfdestructs from # the same account and if this is the right place to put this. self.vm_state.logger.trace('DELETING ACCOUNT: %s', encode_hex(account)) # TODO: this balance setting is likely superflous and can be # removed since `delete_account` does this. self.vm_state.account_db.set_balance(account, 0) self.vm_state.account_db.delete_account(account) return computation
def __exit__(self, exc_type: None, exc_value: None, traceback: None) -> None: if exc_value and isinstance(exc_value, VMError): self.logger.trace( ("COMPUTATION ERROR: gas: %s | from: %s | to: %s | value: %s | " "depth: %s | static: %s | error: %s"), self.msg.gas, encode_hex(self.msg.sender), encode_hex(self.msg.to), self.msg.value, self.msg.depth, "y" if self.msg.is_static else "n", exc_value, ) # print("COMPUTATION ERROR:\"{}\", gasUsed:\"{}\"".format(exc_value, ('%x' % (self.msg.gas - self._gas_meter.gas_remaining)))) import binascii print("{{\"output\": \"{}\", \"gasUsed\": \"0x{}\"}}".format( str(binascii.hexlify(self.output), encoding="utf8"), '%x' % (self.msg.gas - self._gas_meter.gas_remaining))) self._error = exc_value if self.should_burn_gas: self.consume_gas( self._gas_meter.gas_remaining, reason=" ".join(( "Zeroing gas due to VM Exception:", str(exc_value), )), ) # suppress VM exceptions return True elif exc_type is None: self.logger.trace( ("COMPUTATION SUCCESS: from: %s | to: %s | value: %s | " "depth: %s | static: %s | gas-used: %s | gas-remaining: %s"), encode_hex(self.msg.sender), encode_hex(self.msg.to), self.msg.value, self.msg.depth, "y" if self.msg.is_static else "n", self.msg.gas - self._gas_meter.gas_remaining, self._gas_meter.gas_remaining, ) import binascii print("{{\"output\": \"{}\", \"gasUsed\": \"0x{}\"}}".format( str(binascii.hexlify(self.output), encoding="utf8"), '%x' % (self.msg.gas - self._gas_meter.gas_remaining)))
def format_block(block: BaseBlock) -> str: return ( "\n\n" "------------------------Block------------------------------------\n" "Number #{b.number:>12} Hash {hash}\n" "-----------------------------------------------------------------\n" ).format(b=block, hash=encode_hex(block.hash))
def _decode_header_to_dict( cls, encoded_header: bytes) -> Iterator[Tuple[str, Any]]: if len(encoded_header) != cls.smc_encoded_size: raise ValidationError( "Expected encoded header to be of size: {0}. Got size {1} instead.\n- {2}" .format( cls.smc_encoded_size, len(encoded_header), encode_hex(encoded_header), )) start_indices = accumulate(lambda i, field: i + field[2], cls.fields_with_sizes, 0) field_bounds = sliding_window(2, start_indices) for byte_range, field in zip(field_bounds, cls._meta.fields): start_index, end_index = byte_range field_name, field_type = field field_bytes = encoded_header[start_index:end_index] if field_type == rlp.sedes.big_endian_int: # remove the leading zeros, to avoid `not minimal length` error in deserialization formatted_field_bytes = field_bytes.lstrip(b'\x00') elif field_type == address: formatted_field_bytes = field_bytes[-20:] else: formatted_field_bytes = field_bytes yield field_name, field_type.deserialize(formatted_field_bytes)
def import_block(self, block: BaseBlock, perform_validation: bool = True) -> BaseBlock: """ Imports a complete block. """ try: parent_header = self.get_block_header_by_hash( block.header.parent_hash) except HeaderNotFound: raise ValidationError( "Attempt to import block #{}. Cannot import block {} before importing " "its parent block at {}".format( block.number, block.hash, block.header.parent_hash, )) base_header_for_import = self.create_header_from_parent(parent_header) imported_block = self.get_vm(base_header_for_import).import_block( block) # Validate the imported block. if perform_validation: ensure_imported_block_unchanged(imported_block, block) self.validate_block(imported_block) self.chaindb.persist_block(imported_block) self.logger.debug( 'IMPORTED_BLOCK: number %s | hash %s', imported_block.number, encode_hex(imported_block.hash), ) return imported_block
def sstore_eip1283(computation): slot, value = computation.stack_pop(num_items=2, type_hint=UINT256) current_value = computation.state.account_db.get_storage( address=computation.msg.storage_address, slot=slot, ) original_value = computation.state.account_db.get_storage( address=computation.msg.storage_address, slot=slot, from_journal=False) gas_refund = 0 if current_value == value: gas_cost = constants.GAS_SSTORE_EIP1283_NOOP else: if original_value == current_value: if original_value == 0: gas_cost = constants.GAS_SSTORE_EIP1283_INIT else: gas_cost = constants.GAS_SSTORE_EIP1283_CLEAN if value == 0: gas_refund += constants.GAS_SSTORE_EIP1283_CLEAR_REFUND else: gas_cost = constants.GAS_SSTORE_EIP1283_NOOP if original_value != 0: if current_value == 0: gas_refund -= constants.GAS_SSTORE_EIP1283_CLEAR_REFUND if value == 0: gas_refund += constants.GAS_SSTORE_EIP1283_CLEAR_REFUND if original_value == value: if original_value == 0: gas_refund += constants.GAS_SSTORE_EIP1283_RESET_CLEAR_REFUND else: gas_refund += constants.GAS_SSTORE_EIP1283_RESET_REFUND computation.consume_gas( gas_cost, reason="SSTORE: {0}[{1}] -> {2} (current: {3} / original: {4})".format( encode_hex(computation.msg.storage_address), slot, value, current_value, original_value, )) if gas_refund: computation.refund_gas(gas_refund) computation.state.account_db.set_storage( address=computation.msg.storage_address, slot=slot, value=value, )
def __call__(self, computation: BaseComputation) -> None: stack_data = self.get_stack_data(computation) gas_cost = self.get_gas_cost(stack_data) computation.consume_gas(gas_cost, reason=self.mnemonic) computation.extend_memory(stack_data.memory_start, stack_data.memory_length) insufficient_funds = computation.state.account_db.get_balance( computation.msg.storage_address) < stack_data.endowment stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT if insufficient_funds or stack_too_deep: computation.stack_push(0) return call_data = computation.memory_read(stack_data.memory_start, stack_data.memory_length) create_msg_gas = self.max_child_gas_modifier( computation.get_gas_remaining()) computation.consume_gas(create_msg_gas, reason=self.mnemonic) contract_address = self.generate_contract_address( stack_data, call_data, computation) is_collision = computation.state.account_db.account_has_code_or_nonce( contract_address) if is_collision: self.logger.trace( "Address collision while creating contract: %s", encode_hex(contract_address), ) computation.stack_push(0) return child_msg = computation.prepare_child_message( gas=create_msg_gas, to=constants.CREATE_CONTRACT_ADDRESS, value=stack_data.endowment, data=b'', code=call_data, create_address=contract_address, ) child_computation = computation.apply_child_computation(child_msg) if child_computation.is_error: computation.stack_push(0) else: computation.stack_push(contract_address) computation.return_gas(child_computation.get_gas_remaining())
def import_block(self, block: BaseBlock, perform_validation: bool=True ) -> Tuple[BaseBlock, Tuple[BaseBlock, ...], Tuple[BaseBlock, ...]]: """ Imports a complete block and returns a 3-tuple - the imported block - a tuple of blocks which are now part of the canonical chain. - a tuple of blocks which are were canonical and now are no longer canonical. """ try: parent_header = self.get_block_header_by_hash(block.header.parent_hash) except HeaderNotFound: raise ValidationError( "Attempt to import block #{}. Cannot import block {} before importing " "its parent block at {}".format( block.number, block.hash, block.header.parent_hash, ) ) base_header_for_import = self.create_header_from_parent(parent_header) imported_block = self.get_vm(base_header_for_import).import_block(block) # Validate the imported block. if perform_validation: validate_imported_block_unchanged(imported_block, block) self.validate_block(imported_block) ( new_canonical_hashes, old_canonical_hashes, ) = self.chaindb.persist_block(imported_block) self.logger.debug( 'IMPORTED_BLOCK: number %s | hash %s', imported_block.number, encode_hex(imported_block.hash), ) new_canonical_blocks = tuple( self.get_block_by_hash(header_hash) for header_hash in new_canonical_hashes ) old_canonical_blocks = tuple( self.get_block_by_hash(header_hash) for header_hash in old_canonical_hashes ) return imported_block, new_canonical_blocks, old_canonical_blocks
def __exit__(self, exc_type: None, exc_value: None, traceback: None) -> None: if exc_value and isinstance(exc_value, VMError): self.logger.trace( ( "COMPUTATION ERROR: gas: %s | from: %s | to: %s | value: %s | " "depth: %s | static: %s | error: %s" ), self.msg.gas, encode_hex(self.msg.sender), encode_hex(self.msg.to), self.msg.value, self.msg.depth, "y" if self.msg.is_static else "n", exc_value, ) self._error = exc_value if self.should_burn_gas: self.consume_gas( self._gas_meter.gas_remaining, reason=" ".join(( "Zeroing gas due to VM Exception:", str(exc_value), )), ) # suppress VM exceptions return True elif exc_type is None: self.logger.trace( ( "COMPUTATION SUCCESS: from: %s | to: %s | value: %s | " "depth: %s | static: %s | gas-used: %s | gas-remaining: %s" ), encode_hex(self.msg.sender), encode_hex(self.msg.to), self.msg.value, self.msg.depth, "y" if self.msg.is_static else "n", self.msg.gas - self._gas_meter.gas_remaining, self._gas_meter.gas_remaining, )
def apply_message(self) -> BaseComputation: snapshot = self.state.snapshot() if self.msg.depth > STACK_DEPTH_LIMIT: raise StackDepthLimit("Stack depth limit reached") if self.msg.should_transfer_value and self.msg.value: sender_balance = self.state.account_db.get_balance(self.msg.sender) if sender_balance < self.msg.value: raise InsufficientFunds("Insufficient funds: {0} < {1}".format( sender_balance, self.msg.value)) self.state.account_db.delta_balance(self.msg.sender, -1 * self.msg.value) self.state.account_db.delta_balance(self.msg.storage_address, self.msg.value) self.logger.trace( "TRANSFERRED: %s from %s -> %s", self.msg.value, encode_hex(self.msg.sender), encode_hex(self.msg.storage_address), ) self.state.account_db.touch_account(self.msg.storage_address) computation = self.apply_computation( self.state, self.msg, self.transaction_context, ) if computation.is_error: self.state.revert(snapshot) else: self.state.commit(snapshot) return computation
def apply_create_message(self): snapshot = self.state.snapshot() computation = self.apply_message() if computation.is_error: self.state.revert(snapshot) return computation else: contract_code = computation.output if contract_code: contract_code_gas_cost = len( contract_code) * constants.GAS_CODEDEPOSIT try: computation.consume_gas( contract_code_gas_cost, reason="Write contract code for CREATE", ) except OutOfGas as err: # Different from Frontier: reverts state on gas failure while # writing contract code. computation._error = err self.state.revert(snapshot) else: if self.logger: self.logger.trace( "SETTING CODE: %s -> length: %s | hash: %s", encode_hex(self.msg.storage_address), len(contract_code), encode_hex(keccak(contract_code))) self.state.account_db.set_code(self.msg.storage_address, contract_code) self.state.commit(snapshot) else: self.state.commit(snapshot) return computation
def persist_header(self, header: BlockHeader) -> Tuple[BlockHeader, ...]: """ Returns iterable of headers newly on the canonical chain """ is_genesis = header.parent_hash == GENESIS_PARENT_HASH if not is_genesis and not self.header_exists(header.parent_hash): raise ParentNotFound( "Cannot persist block header ({}) with unknown parent ({})". format(encode_hex(header.hash), encode_hex(header.parent_hash))) self.db.set( header.hash, rlp.encode(header), ) if is_genesis: score = header.difficulty else: score = self.get_score(header.parent_hash) + header.difficulty self.db.set( SchemaV1.make_block_hash_to_score_lookup_key(header.hash), rlp.encode(score, sedes=rlp.sedes.big_endian_int), ) try: head_score = self.get_score(self.get_canonical_head().hash) except CanonicalHeadNotFound: new_headers = self._set_as_canonical_chain_head(header) else: if score > head_score: new_headers = self._set_as_canonical_chain_head(header) else: new_headers = tuple() return new_headers
def _selfdestruct(computation, beneficiary): local_balance = computation.state.account_db.get_balance( computation.msg.storage_address) beneficiary_balance = computation.state.account_db.get_balance(beneficiary) # 1st: Transfer to beneficiary computation.state.account_db.set_balance( beneficiary, local_balance + beneficiary_balance) # 2nd: Zero the balance of the address being deleted (must come after # sending to beneficiary in case the contract named itself as the # beneficiary. computation.state.account_db.set_balance(computation.msg.storage_address, 0) computation.logger.trace( "SELFDESTRUCT: %s (%s) -> %s", encode_hex(computation.msg.storage_address), local_balance, encode_hex(beneficiary), ) # 3rd: Register the account to be deleted computation.register_account_for_deletion(beneficiary) raise Halt('SELFDESTRUCT')
def get_transaction_index(self, transaction_hash: Hash32) -> Tuple[BlockNumber, int]: """ Returns a 2-tuple of (block_number, transaction_index) indicating which block the given transaction can be found in and at what index in the block transactions. Raises TransactionNotFound if the transaction_hash is not found in the canonical chain. """ key = SchemaV1.make_transaction_hash_to_block_lookup_key(transaction_hash) try: encoded_key = self.db[key] except KeyError: raise TransactionNotFound( "Transaction {} not found in canonical chain".format(encode_hex(transaction_hash))) transaction_key = rlp.decode(encoded_key, sedes=TransactionKey) return (transaction_key.block_number, transaction_key.index)
def sstore(computation: BaseComputation) -> None: slot, value = computation.stack_pop(num_items=2, type_hint=constants.UINT256) current_value = computation.state.account_db.get_storage( address=computation.msg.storage_address, slot=slot, ) is_currently_empty = not bool(current_value) is_going_to_be_empty = not bool(value) if is_currently_empty: gas_refund = 0 elif is_going_to_be_empty: gas_refund = constants.REFUND_SCLEAR else: gas_refund = 0 if is_currently_empty and is_going_to_be_empty: gas_cost = constants.GAS_SRESET elif is_currently_empty: gas_cost = constants.GAS_SSET elif is_going_to_be_empty: gas_cost = constants.GAS_SRESET else: gas_cost = constants.GAS_SRESET computation.consume_gas(gas_cost, reason="SSTORE: {0}[{1}] -> {2} ({3})".format( encode_hex(computation.msg.storage_address), slot, value, current_value, )) if gas_refund: computation.refund_gas(gas_refund) computation.state.account_db.set_storage( address=computation.msg.storage_address, slot=slot, value=value, )
def finalize_computation(self, transaction, computation): computation = super().finalize_computation(transaction, computation) # # EIP161 state clearing # touched_accounts = collect_touched_accounts(computation) for account in touched_accounts: should_delete = ( self.vm_state.account_db.account_exists(account) and self.vm_state.account_db.account_is_empty(account) ) if should_delete: self.vm_state.logger.trace( "CLEARING EMPTY ACCOUNT: %s", encode_hex(account), ) self.vm_state.account_db.delete_account(account) return computation
if __name__ == "__main__": for (filler_dir, test_dir), test_groups in DIR_STRUCTURE.items(): for test_group, tests in test_groups.items(): for filler, filler_kwargs in tests: test_name = get_test_name(filler) filename = test_name + ".json" filler_src_path = os.path.join(filler_dir, test_group, filename) filler_path = os.path.join(FILLER_PARENT_DIR, filler_src_path) test_path = os.path.join(TEST_PARENT_DIR, test_dir, test_group, filename) for path in [filler_path, test_path]: os.makedirs(os.path.dirname(path), exist_ok=True) formatted_filler = filler_formatter(filler) filler_string = json.dumps(formatted_filler, indent=4, sort_keys=True) with open(filler_path, "w") as filler_file: filler_file.write(filler_string) filler_hash = keccak(filler_string.encode("ascii")) info = { "source": filler_src_path, "sourceHash": encode_hex(filler_hash), } test = fill_test(filler, info=info, **filler_kwargs or {}) with open(test_path, "w") as test_file: json.dump(test, test_file, indent=4, sort_keys=True)
def __call__(self, computation): computation.consume_gas(self.gas_cost, reason=self.mnemonic) value, start_position, size = computation.stack_pop( num_items=3, type_hint=constants.UINT256, ) computation.extend_memory(start_position, size) insufficient_funds = computation.state.account_db.get_balance( computation.msg.storage_address) < value stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT if insufficient_funds or stack_too_deep: computation.stack_push(0) return call_data = computation.memory_read(start_position, size) create_msg_gas = self.max_child_gas_modifier( computation.get_gas_remaining()) computation.consume_gas(create_msg_gas, reason="CREATE") creation_nonce = computation.state.account_db.get_nonce( computation.msg.storage_address) computation.state.account_db.increment_nonce( computation.msg.storage_address) contract_address = generate_contract_address( computation.msg.storage_address, creation_nonce, ) is_collision = computation.state.account_db.account_has_code_or_nonce( contract_address) if is_collision: self.logger.trace( "Address collision while creating contract: %s", encode_hex(contract_address), ) computation.stack_push(0) return child_msg = computation.prepare_child_message( gas=create_msg_gas, to=constants.CREATE_CONTRACT_ADDRESS, value=value, data=b'', code=call_data, create_address=contract_address, ) child_computation = computation.apply_child_computation(child_msg) if child_computation.is_error: computation.stack_push(0) else: computation.stack_push(contract_address) computation.return_gas(child_computation.get_gas_remaining())
def __repr__(self) -> str: return '<Block #{0} {1}>'.format( self.slot_number, encode_hex(self.hash)[2:10], )
def __repr__(self) -> str: return '<BlockHeader #{0} {1}>'.format( self.block_number, encode_hex(self.hash)[2:10], )
def hex_hash(self): return encode_hex(self.hash)