From ae570c164f51aac16d36ceaee31ce76c6ba59468 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 21 Apr 2025 10:00:20 -0600 Subject: [PATCH 1/7] Move EIP-7873 type from 5 to 6 --- src/ethereum/osaka/blocks.py | 6 ++++-- src/ethereum/osaka/transactions.py | 16 +++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/ethereum/osaka/blocks.py b/src/ethereum/osaka/blocks.py index 3fa125bec8..bb48c74a18 100644 --- a/src/ethereum/osaka/blocks.py +++ b/src/ethereum/osaka/blocks.py @@ -122,8 +122,9 @@ def encode_receipt(tx: Transaction, receipt: Receipt) -> Union[Bytes, Receipt]: return b"\x03" + rlp.encode(receipt) elif isinstance(tx, SetCodeTransaction): return b"\x04" + rlp.encode(receipt) + # Type 5 is skipped as it is used for EIP-7702 delegate signing elif isinstance(tx, EofInitCodeTransaction): - return b"\x05" + rlp.encode(receipt) + return b"\x06" + rlp.encode(receipt) else: return receipt @@ -133,7 +134,8 @@ def decode_receipt(receipt: Union[Bytes, Receipt]) -> Receipt: Decodes a receipt. """ if isinstance(receipt, Bytes): - assert receipt[0] in (1, 2, 3, 4, 5) + # Type 5 is skipped as it is used for EIP-7702 delegate signing + assert receipt[0] in (1, 2, 3, 4, 6) return rlp.decode_to(Receipt, receipt[1:]) else: return receipt diff --git a/src/ethereum/osaka/transactions.py b/src/ethereum/osaka/transactions.py index 91c5edfe3e..5b1549d250 100644 --- a/src/ethereum/osaka/transactions.py +++ b/src/ethereum/osaka/transactions.py @@ -178,8 +178,9 @@ def encode_transaction(tx: Transaction) -> Union[LegacyTransaction, Bytes]: return b"\x03" + rlp.encode(tx) elif isinstance(tx, SetCodeTransaction): return b"\x04" + rlp.encode(tx) + # Type 5 is skipped as it is used for EIP-7702 delegate signing elif isinstance(tx, EofInitCodeTransaction): - return b"\x05" + rlp.encode(tx) + return b"\x06" + rlp.encode(tx) else: raise Exception(f"Unable to encode transaction of type {type(tx)}") @@ -197,7 +198,8 @@ def decode_transaction(tx: Union[LegacyTransaction, Bytes]) -> Transaction: return rlp.decode_to(BlobTransaction, tx[1:]) elif tx[0] == 4: return rlp.decode_to(SetCodeTransaction, tx[1:]) - elif tx[0] == 5: + # Type 5 is skipped as it is used for EIP-7702 delegate signing + elif tx[0] == 6: return rlp.decode_to(EofInitCodeTransaction, tx[1:]) else: raise TransactionTypeError(tx[0]) @@ -242,9 +244,9 @@ def validate_transaction(tx: Transaction) -> Tuple[Uint, Uint]: if isinstance(tx, EofInitCodeTransaction): if len(tx.init_codes) == 0: - raise InvalidTransaction("Type 5 tx with no init codes") + raise InvalidTransaction("Type 6 tx with no init codes") if len(tx.init_codes) > MAX_INIT_CODE_COUNT: - raise InvalidTransaction("Type 5 tx with too many init codes") + raise InvalidTransaction("Type 6 tx with too many init codes") intrinsic_gas, calldata_floor_gas_cost = calculate_intrinsic_cost(tx) if max(intrinsic_gas, calldata_floor_gas_cost) > tx.gas: @@ -317,10 +319,10 @@ def calculate_intrinsic_cost(tx: Transaction) -> Tuple[Uint, Uint]: for init_code in tx.init_codes: if len(init_code) == 0: raise InvalidTransaction( - "Type 5 tx with zero-length init code" + "Type 6 tx with zero-length init code" ) if len(init_code) > 2 * MAX_CODE_SIZE: - raise InvalidTransaction("Type 5 tx with too large init code") + raise InvalidTransaction("Type 6 tx with too large init code") tokens_in_tx += calculate_tokens_in_data(init_code) @@ -645,7 +647,7 @@ def signing_hash_7873(tx: EofInitCodeTransaction) -> Hash32: Hash of the transaction. """ return keccak256( - b"\x05" + b"\x06" + rlp.encode( ( tx.chain_id, From 91c7fdefe829a8b1860cdc7c42eadf0004ae8a70 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 21 Apr 2025 10:17:18 -0600 Subject: [PATCH 2/7] Include EofInitcodeTransaction in TX detection logic --- .../evm_tools/loaders/fork_loader.py | 5 +++++ .../evm_tools/loaders/transaction_loader.py | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/ethereum_spec_tools/evm_tools/loaders/fork_loader.py b/src/ethereum_spec_tools/evm_tools/loaders/fork_loader.py index 1a7af024a8..1a69dcd8a0 100644 --- a/src/ethereum_spec_tools/evm_tools/loaders/fork_loader.py +++ b/src/ethereum_spec_tools/evm_tools/loaders/fork_loader.py @@ -212,6 +212,11 @@ def SetCodeTransaction(self) -> Any: """Set code transaction class of the fork""" return self._module("transactions").SetCodeTransaction + @property + def EofInitCodeTransaction(self) -> Any: + """Eof initcode transaction class of the fork""" + return self._module("transactions").EofInitCodeTransaction + @property def Withdrawal(self) -> Any: """Withdrawal class of the fork""" diff --git a/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py b/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py index b788601400..3750e1a7d0 100644 --- a/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py +++ b/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py @@ -125,6 +125,13 @@ def json_to_blob_versioned_hashes(self) -> List[Bytes32]: for blob_hash in self.raw.get("blobVersionedHashes") ] + def json_to_init_codes(self) -> List[Bytes]: + """Get the EOF init codes of the transaction.""" + return [ + hex_to_hash(init_code) + for init_code in self.raw.get("initcodes") + ] + def json_to_v(self) -> U256: """Get the v value of the transaction.""" return hex_to_u256( @@ -165,7 +172,10 @@ def read(self) -> Any: """Convert json transaction data to a transaction object""" if "type" in self.raw: tx_type = parse_hex_or_int(self.raw.get("type"), Uint) - if tx_type == Uint(4): + if tx_type == Uint(6): + tx_cls = self.fork.EofInitCodeTransaction + tx_byte_prefix = b"\x06" + elif tx_type == Uint(4): tx_cls = self.fork.SetCodeTransaction tx_byte_prefix = b"\x04" elif tx_type == Uint(3): @@ -183,7 +193,10 @@ def read(self) -> Any: else: raise ValueError(f"Unknown transaction type: {tx_type}") else: - if "authorizationList" in self.raw: + if "initcodes" in self.raw: + tx_cls = self.fork.EOFInitCodeTransaction + tx_byte_prefix = b"\x06" + elif "authorizationList" in self.raw: tx_cls = self.fork.SetCodeTransaction tx_byte_prefix = b"\x04" elif "maxFeePerBlobGas" in self.raw: From cba693c5bb63a170868300728db122c97a1a5320 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 21 Apr 2025 16:23:16 -0600 Subject: [PATCH 3/7] More eof-devnet-1 * data to kind ff * 4 byte container size * TXCREATE and EOFCREATE address hashing * TXCREATE container validation * TXCREATE outside of the container * EOFCREATE args order --- src/ethereum/osaka/utils/address.py | 2 +- src/ethereum/osaka/vm/eof/utils.py | 14 +++--- .../osaka/vm/instructions/__init__.py | 1 - src/ethereum/osaka/vm/instructions/system.py | 44 ++++++++++--------- .../evm_tools/loaders/transaction_loader.py | 2 +- 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/ethereum/osaka/utils/address.py b/src/ethereum/osaka/utils/address.py index abf1fd52e2..1012ae1efb 100644 --- a/src/ethereum/osaka/utils/address.py +++ b/src/ethereum/osaka/utils/address.py @@ -140,7 +140,7 @@ def compute_eof_tx_create_contract_address( address: `ethereum.osaka.fork_types.Address` The computed address of the new account. """ - preimage = b"\xff" + address + salt + preimage = b"\xff" + left_pad_zero_bytes(address, 32) + salt computed_address = keccak256(preimage) canonical_address = computed_address[-20:] padded_address = left_pad_zero_bytes(canonical_address, 20) diff --git a/src/ethereum/osaka/vm/eof/utils.py b/src/ethereum/osaka/vm/eof/utils.py index 783da45fa1..aa9d1c0c99 100644 --- a/src/ethereum/osaka/vm/eof/utils.py +++ b/src/ethereum/osaka/vm/eof/utils.py @@ -114,15 +114,15 @@ def metadata_from_container( raise InvalidEof("Invalid number of container sections") for i in range(num_container_sections): - # Get the 2 bytes container_size - if validate and len(container) < counter + 2: + # Get the 4 bytes container_size + if validate and len(container) < counter + 4: raise InvalidEof( f"Container section {i} does not have a size specified" ) container_size = Uint.from_be_bytes( - container[counter : counter + 2] + container[counter : counter + 4] ) - counter += 2 + counter += 4 if validate and container_size == 0: raise InvalidEof("Invalid container size") container_sizes.append(container_size) @@ -133,7 +133,7 @@ def metadata_from_container( # Get 1 byte kind_data kind_data = container[counter] counter += 1 - if validate and kind_data != 4: + if validate and kind_data != 0xff: raise InvalidEof("Invalid kind data") # Get 2 bytes data_size if validate and len(container) < counter + 2: @@ -254,10 +254,10 @@ def container_from_metadata(eof_metadata: EofMetadata) -> bytes: Uint(2), "big" ) for container_size in eof_metadata.container_sizes: - container += container_size.to_bytes(Uint(2), "big") + container += container_size.to_bytes(Uint(4), "big") # Add the kind data - container += b"\x04" + container += b"\xff" container += eof_metadata.data_size.to_bytes(Uint(2), "big") # Add the terminator diff --git a/src/ethereum/osaka/vm/instructions/__init__.py b/src/ethereum/osaka/vm/instructions/__init__.py index f747a8a573..3c7cd8a89a 100644 --- a/src/ethereum/osaka/vm/instructions/__init__.py +++ b/src/ethereum/osaka/vm/instructions/__init__.py @@ -453,7 +453,6 @@ class Ops(enum.Enum): Ops.EXCHANGE, # System Operations Ops.EOFCREATE, - Ops.TXCREATE, Ops.RETURNDATALOAD, Ops.EXTCALL, Ops.EXTDELEGATECALL, diff --git a/src/ethereum/osaka/vm/instructions/system.py b/src/ethereum/osaka/vm/instructions/system.py index d522d5d145..8b6310173f 100644 --- a/src/ethereum/osaka/vm/instructions/system.py +++ b/src/ethereum/osaka/vm/instructions/system.py @@ -1204,6 +1204,10 @@ def eof_tx_create(evm: Evm) -> None: evm : The current EVM frame. """ + # This import causes a circular import error + # if it's not moved inside this method + from ...vm.eof.validation import parse_create_tx_call_data + # STACK tx_init_code_hash = pop(evm.stack).to_be_bytes32() salt = pop(evm.stack).to_be_bytes32() @@ -1217,13 +1221,7 @@ def eof_tx_create(evm: Evm) -> None: ) call_data_words = ceil32(Uint(input_size)) // Uint(32) init_code_gas = init_code_cost(Uint(input_size)) - charge_gas( - evm, - GAS_CREATE - + GAS_KECCAK256_WORD * call_data_words - + extend_memory.cost - + init_code_gas, - ) + charge_gas(evm, GAS_CREATE + extend_memory.cost) # OPERATION if evm.message.is_static: @@ -1235,7 +1233,7 @@ def eof_tx_create(evm: Evm) -> None: evm.message.current_target, salt ) - # tx_env.init_codes are None for all but Type 5 transactions + # tx_env.init_codes are None for all but Type 6 transactions if evm.message.tx_env.init_codes is None: push(evm.stack, U256(0)) else: @@ -1253,14 +1251,21 @@ def eof_tx_create(evm: Evm) -> None: if code is None: push(evm.stack, U256(0)) else: - generic_eof_create( - evm=evm, - endowment=value, - contract_address=contract_address, - init_code=code, - input_offset=input_offset, - input_size=input_size, - ) + try : + eof, calldata = parse_create_tx_call_data(code) + if len(calldata) > 0: + raise InvalidEof("Data after end of container") + generic_eof_create( + evm=evm, + endowment=value, + contract_address=contract_address, + init_code=code, + input_offset=input_offset, + input_size=input_size, + ) + except InvalidEof : + # soft failure + push(evm.stack, U256(0)) # PROGRAM COUNTER evm.pc += Uint(1) @@ -1278,10 +1283,10 @@ def eof_create(evm: Evm) -> None: assert evm.eof is not None # STACK - value = pop(evm.stack) salt = pop(evm.stack).to_be_bytes32() input_offset = pop(evm.stack) input_size = pop(evm.stack) + value = pop(evm.stack) # GAS init_container_index = Uint.from_be_bytes( @@ -1307,10 +1312,9 @@ def eof_create(evm: Evm) -> None: raise WriteInStaticContext("EOFCREATE in static mode") evm.memory += b"\x00" * extend_memory.expand_by - contract_address = compute_create2_contract_address( + contract_address = compute_eof_tx_create_contract_address( evm.message.current_target, - salt, - bytearray(init_container), + salt ) generic_eof_create( diff --git a/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py b/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py index 3750e1a7d0..f656abbbb8 100644 --- a/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py +++ b/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py @@ -128,7 +128,7 @@ def json_to_blob_versioned_hashes(self) -> List[Bytes32]: def json_to_init_codes(self) -> List[Bytes]: """Get the EOF init codes of the transaction.""" return [ - hex_to_hash(init_code) + hex_to_bytes(init_code) for init_code in self.raw.get("initcodes") ] From 623db37c04bfe76d520fb0c08b19e46ca7b1711a Mon Sep 17 00:00:00 2001 From: Guruprasad Kamath Date: Fri, 11 Apr 2025 02:38:01 -0600 Subject: [PATCH 4/7] EXTCALL* to 7702 delegated accounts --- src/ethereum/osaka/fork.py | 1 + src/ethereum/osaka/utils/message.py | 4 ++ src/ethereum/osaka/vm/__init__.py | 1 + src/ethereum/osaka/vm/eoa_delegation.py | 1 + src/ethereum/osaka/vm/instructions/system.py | 49 ++++++++++++++++---- src/ethereum/osaka/vm/interpreter.py | 2 + tests/helpers/__init__.py | 2 +- 7 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/ethereum/osaka/fork.py b/src/ethereum/osaka/fork.py index abe80de75e..5a64bfd2be 100644 --- a/src/ethereum/osaka/fork.py +++ b/src/ethereum/osaka/fork.py @@ -588,6 +588,7 @@ def process_system_transaction( is_static=False, accessed_addresses=set(), accessed_storage_keys=set(), + is_delegated=False, parent_evm=None, eof=None, ) diff --git a/src/ethereum/osaka/utils/message.py b/src/ethereum/osaka/utils/message.py index ad60c4793c..ff4279f7e7 100644 --- a/src/ethereum/osaka/utils/message.py +++ b/src/ethereum/osaka/utils/message.py @@ -54,6 +54,8 @@ def prepare_message( accessed_addresses.update(PRE_COMPILED_CONTRACTS.keys()) accessed_addresses.update(tx_env.access_list_addresses) + is_delegated = False + if isinstance(tx.to, Bytes0): current_target = compute_contract_address( tx_env.origin, @@ -74,6 +76,7 @@ def prepare_message( delegated_address = get_delegated_code_address(code) if delegated_address is not None: + is_delegated = True accessed_addresses.add(delegated_address) code = get_account(block_env.state, delegated_address).code @@ -113,6 +116,7 @@ def prepare_message( is_static=False, accessed_addresses=accessed_addresses, accessed_storage_keys=set(tx_env.access_list_storage_keys), + is_delegated=is_delegated, parent_evm=None, eof=eof, ) diff --git a/src/ethereum/osaka/vm/__init__.py b/src/ethereum/osaka/vm/__init__.py index 1bcd3d9711..15ca7325cc 100644 --- a/src/ethereum/osaka/vm/__init__.py +++ b/src/ethereum/osaka/vm/__init__.py @@ -138,6 +138,7 @@ class Message: is_static: bool accessed_addresses: Set[Address] accessed_storage_keys: Set[Tuple[Address, Bytes32]] + is_delegated: bool parent_evm: Optional["Evm"] eof: Optional["Eof"] diff --git a/src/ethereum/osaka/vm/eoa_delegation.py b/src/ethereum/osaka/vm/eoa_delegation.py index bb6a7e33d9..b802bfe711 100644 --- a/src/ethereum/osaka/vm/eoa_delegation.py +++ b/src/ethereum/osaka/vm/eoa_delegation.py @@ -204,6 +204,7 @@ def set_delegation(message: Message) -> U256: message.code = get_account(state, message.code_address).code if is_valid_delegation(message.code): + message.is_delegated = True message.code_address = Address( message.code[EOA_DELEGATION_MARKER_LENGTH:] ) diff --git a/src/ethereum/osaka/vm/instructions/system.py b/src/ethereum/osaka/vm/instructions/system.py index 8b6310173f..7d01d273c4 100644 --- a/src/ethereum/osaka/vm/instructions/system.py +++ b/src/ethereum/osaka/vm/instructions/system.py @@ -145,6 +145,7 @@ def generic_create( is_static=False, accessed_addresses=evm.accessed_addresses.copy(), accessed_storage_keys=evm.accessed_storage_keys.copy(), + is_delegated=False, parent_evm=evm, eof=None, ) @@ -321,12 +322,6 @@ def generic_call( call_data = memory_read_bytes( evm.memory, memory_input_start_position, memory_input_size ) - code = get_account(evm.message.block_env.state, code_address).code - - if is_delegated_code and len(code) == 0: - evm.gas_left += gas - push(evm.stack, U256(1)) - return eof_version = get_eof_version(code) if eof_version == EofVersion.LEGACY: @@ -359,6 +354,7 @@ def generic_call( is_static=True if is_staticcall else evm.message.is_static, accessed_addresses=evm.accessed_addresses.copy(), accessed_storage_keys=evm.accessed_storage_keys.copy(), + is_delegated=is_delegated_code, parent_evm=evm, eof=eof, ) @@ -819,6 +815,7 @@ def generic_eof_call( value: U256, should_transfer_value: bool, is_static: bool, + is_delegated: bool, allow_legacy_code: bool, ) -> None: """ @@ -846,6 +843,8 @@ def generic_eof_call( Whether the value should be transferred. is_static : Whether the call is static. + is_delegated : + Whether the code is a delegated. allow_legacy_code : Whether to allow legacy code. @@ -919,6 +918,7 @@ def generic_eof_call( is_static=is_static, accessed_addresses=evm.accessed_addresses.copy(), accessed_storage_keys=evm.accessed_storage_keys.copy(), + is_delegated=is_delegated, parent_evm=evm, eof=eof, ) @@ -966,6 +966,15 @@ def ext_call(evm: Evm) -> None: evm.accessed_addresses.add(target_address) access_gas_cost = GAS_COLD_ACCOUNT_ACCESS + code_address = target_address + ( + is_delegated_code, + code_address, + code, + delegated_access_gas_cost, + ) = access_delegation(evm, code_address) + access_gas_cost += delegated_access_gas_cost + create_gas_cost = ( Uint(0) if is_account_alive(evm.message.block_env.state, target_address) @@ -990,10 +999,11 @@ def ext_call(evm: Evm) -> None: caller=evm.message.current_target, target=target_address, current_target=target_address, - code_address=target_address, + code_address=code_address, value=value, should_transfer_value=True, is_static=False, + is_delegated=is_delegated_code, allow_legacy_code=True, ) @@ -1030,6 +1040,15 @@ def ext_delegatecall(evm: Evm) -> None: evm.accessed_addresses.add(target_address) access_gas_cost = GAS_COLD_ACCOUNT_ACCESS + code_address = target_address + ( + is_delegated_code, + code_address, + code, + delegated_access_gas_cost, + ) = access_delegation(evm, code_address) + access_gas_cost += delegated_access_gas_cost + charge_gas(evm, extend_memory.cost + access_gas_cost) # OPERATION @@ -1041,10 +1060,11 @@ def ext_delegatecall(evm: Evm) -> None: caller=evm.message.caller, target=evm.message.current_target, current_target=evm.message.current_target, - code_address=target_address, + code_address=code_address, value=evm.message.value, should_transfer_value=False, is_static=evm.message.is_static, + is_delegated=is_delegated_code, allow_legacy_code=False, ) @@ -1080,6 +1100,15 @@ def ext_staticcall(evm: Evm) -> None: evm.accessed_addresses.add(target_address) access_gas_cost = GAS_COLD_ACCOUNT_ACCESS + code_address = target_address + ( + is_delegated_code, + code_address, + code, + delegated_access_gas_cost, + ) = access_delegation(evm, code_address) + access_gas_cost += delegated_access_gas_cost + charge_gas(evm, extend_memory.cost + access_gas_cost) # OPERATION @@ -1091,10 +1120,11 @@ def ext_staticcall(evm: Evm) -> None: caller=evm.message.current_target, target=target_address, current_target=target_address, - code_address=target_address, + code_address=code_address, value=U256(0), should_transfer_value=False, is_static=True, + is_delegated=is_delegated_code, allow_legacy_code=True, ) @@ -1179,6 +1209,7 @@ def generic_eof_create( is_static=False, accessed_addresses=evm.accessed_addresses.copy(), accessed_storage_keys=evm.accessed_storage_keys.copy(), + is_delegated=False, parent_evm=evm, eof=eof, ) diff --git a/src/ethereum/osaka/vm/interpreter.py b/src/ethereum/osaka/vm/interpreter.py index 4bd4edc914..bda693c44c 100644 --- a/src/ethereum/osaka/vm/interpreter.py +++ b/src/ethereum/osaka/vm/interpreter.py @@ -324,6 +324,8 @@ def execute_code(message: Message) -> Evm: ) try: if evm.message.code_address in PRE_COMPILED_CONTRACTS: + if message.is_delegated: + return evm evm_trace(evm, PrecompileStart(evm.message.code_address)) PRE_COMPILED_CONTRACTS[evm.message.code_address](evm) evm_trace(evm, PrecompileEnd()) diff --git a/tests/helpers/__init__.py b/tests/helpers/__init__.py index 19583c7d77..92ea70508f 100644 --- a/tests/helpers/__init__.py +++ b/tests/helpers/__init__.py @@ -17,7 +17,7 @@ }, "latest_fork_tests": { "url": "https://github.com/gurukamath/latest_fork_tests.git", - "commit_hash": "3962b8c", + "commit_hash": "7a22f8e", "fixture_path": "tests/fixtures/latest_fork_tests", }, } From 63e98a1e5a1fb6ec853d9037a41d9616cb718091 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 22 Apr 2025 13:57:31 -0600 Subject: [PATCH 5/7] Evem more eof-devnet-1 * max_stack_increase updates * TXCREAE and EOFCREATE gas cost updates --- src/ethereum/osaka/vm/eof/stack_height_check.py | 8 ++++---- src/ethereum/osaka/vm/eof/validation.py | 10 +++++----- src/ethereum/osaka/vm/instructions/control_flow.py | 10 ++++------ src/ethereum/osaka/vm/instructions/system.py | 10 +--------- 4 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/ethereum/osaka/vm/eof/stack_height_check.py b/src/ethereum/osaka/vm/eof/stack_height_check.py index 5851acbd15..4507daa9da 100644 --- a/src/ethereum/osaka/vm/eof/stack_height_check.py +++ b/src/ethereum/osaka/vm/eof/stack_height_check.py @@ -33,14 +33,14 @@ def stack_validation_callf(validator: Validator) -> None: ] target_inputs = target_section_type[0] target_outputs = target_section_type[1] - target_max_height = int.from_bytes(target_section_type[2:], "big") + target_max_stack_increase = int.from_bytes(target_section_type[2:], "big") # Stack Height Check if op_metadata.stack_height.min < target_inputs: raise InvalidEof("Invalid stack height") # Stack Overflow Check - if op_metadata.stack_height.max > 1024 - target_max_height + target_inputs: + if op_metadata.stack_height.max > 1024 - target_max_stack_increase: raise InvalidEof("Stack overflow") # Update the stack height after instruction @@ -75,7 +75,7 @@ def stack_validation_jumpf(validator: Validator) -> None: current_outputs = current_section_type[1] target_inputs = target_section_type[0] target_outputs = target_section_type[1] - target_max_height = int.from_bytes(target_section_type[2:], "big") + target_max_stack_increase = int.from_bytes(target_section_type[2:], "big") # Stack Height Check if target_outputs != 0x80: @@ -91,7 +91,7 @@ def stack_validation_jumpf(validator: Validator) -> None: raise InvalidEof("Invalid stack height") # Stack Overflow Check - if op_metadata.stack_height.max > 1024 - target_max_height + target_inputs: + if op_metadata.stack_height.max > 1024 - target_max_stack_increase: raise InvalidEof("Stack overflow") # Update the stack height after instruction diff --git a/src/ethereum/osaka/vm/eof/validation.py b/src/ethereum/osaka/vm/eof/validation.py index 0f6738fc51..f3512c083e 100644 --- a/src/ethereum/osaka/vm/eof/validation.py +++ b/src/ethereum/osaka/vm/eof/validation.py @@ -58,8 +58,8 @@ def validate_body(validator: Validator) -> None: if num_outputs > 128: raise InvalidEof(f"Invalid number of outputs for type {i}") - max_stack_height = Uint.from_be_bytes(type_section[2:]) - if max_stack_height > Uint(1023): + max_stack_increase = Uint.from_be_bytes(type_section[2:]) + if max_stack_increase + Uint(num_inputs) > Uint(1023): raise InvalidEof(f"Invalid max stack height for type {i}") # 4750: Input and output for first section should @@ -160,7 +160,7 @@ def validate_code_section(validator: Validator) -> None: section_type = validator.eof.metadata.type_section_contents[code_index] section_inputs = section_type[0] section_outputs = section_type[1] - section_max_stack_height = Uint.from_be_bytes(section_type[2:]) + section_max_stack_increase = Uint.from_be_bytes(section_type[2:]) # If the return flag from the section type does not agree with # the instructions in the code. @@ -202,8 +202,8 @@ def validate_code_section(validator: Validator) -> None: if computed_maximum_stack_height > 1023: raise InvalidEof("Invalid stack height") - if computed_maximum_stack_height != section_max_stack_height: - raise InvalidEof("Invalid stack height") + if computed_maximum_stack_height != section_max_stack_increase + Uint(section_inputs): + raise InvalidEof("Invalid max stack increase") def get_reached_code_sections( diff --git a/src/ethereum/osaka/vm/instructions/control_flow.py b/src/ethereum/osaka/vm/instructions/control_flow.py index 5683f495ad..7b48c292cf 100644 --- a/src/ethereum/osaka/vm/instructions/control_flow.py +++ b/src/ethereum/osaka/vm/instructions/control_flow.py @@ -307,10 +307,9 @@ def callf(evm: Evm) -> None: target_section = evm.eof.metadata.type_section_contents[ target_section_index ] - target_inputs = Uint(target_section[0]) - target_max_stack_height = Uint.from_be_bytes(target_section[2:]) + target_max_increase = Uint.from_be_bytes(target_section[2:]) - if ulen(evm.stack) > Uint(1024) - target_max_stack_height + target_inputs: + if ulen(evm.stack) > Uint(1024) - target_max_increase: raise StackOverflowError if ulen(evm.return_stack) == Uint(1024): raise StackOverflowError("Return stack overflow") @@ -379,10 +378,9 @@ def jumpf(evm: Evm) -> None: target_section = evm.eof.metadata.type_section_contents[ target_section_index ] - target_inputs = Uint(target_section[0]) - target_max_stack_height = Uint.from_be_bytes(target_section[2:]) + target_max_stack_increase = Uint.from_be_bytes(target_section[2:]) - if ulen(evm.stack) > Uint(1024) - target_max_stack_height + target_inputs: + if ulen(evm.stack) > Uint(1024) - target_max_stack_increase : raise StackOverflowError # PROGRAM COUNTER diff --git a/src/ethereum/osaka/vm/instructions/system.py b/src/ethereum/osaka/vm/instructions/system.py index 7d01d273c4..7a063ce7c3 100644 --- a/src/ethereum/osaka/vm/instructions/system.py +++ b/src/ethereum/osaka/vm/instructions/system.py @@ -1250,8 +1250,6 @@ def eof_tx_create(evm: Evm) -> None: extend_memory = calculate_gas_extend_memory( evm.memory, [(input_offset, input_size)] ) - call_data_words = ceil32(Uint(input_size)) // Uint(32) - init_code_gas = init_code_cost(Uint(input_size)) charge_gas(evm, GAS_CREATE + extend_memory.cost) # OPERATION @@ -1329,14 +1327,8 @@ def eof_create(evm: Evm) -> None: init_container = evm.eof.metadata.container_section_contents[ init_container_index ] - init_container_size = evm.eof.metadata.container_sizes[ - init_container_index - ] - init_code_gas = ( - GAS_KECCAK256_WORD * ceil32(init_container_size) // Uint(32) - ) - charge_gas(evm, GAS_CREATE + extend_memory.cost + init_code_gas) + charge_gas(evm, GAS_CREATE + extend_memory.cost) # OPERATION if evm.message.is_static: From 024137b959c761838d1cd4cbf246877f01f85094 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 22 Apr 2025 16:11:00 -0600 Subject: [PATCH 6/7] formatting --- src/ethereum/osaka/vm/eof/utils.py | 2 +- src/ethereum/osaka/vm/eof/validation.py | 4 +++- src/ethereum/osaka/vm/instructions/control_flow.py | 2 +- src/ethereum/osaka/vm/instructions/system.py | 9 ++++----- .../evm_tools/loaders/transaction_loader.py | 3 +-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ethereum/osaka/vm/eof/utils.py b/src/ethereum/osaka/vm/eof/utils.py index aa9d1c0c99..83b0ab682a 100644 --- a/src/ethereum/osaka/vm/eof/utils.py +++ b/src/ethereum/osaka/vm/eof/utils.py @@ -133,7 +133,7 @@ def metadata_from_container( # Get 1 byte kind_data kind_data = container[counter] counter += 1 - if validate and kind_data != 0xff: + if validate and kind_data != 0xFF: raise InvalidEof("Invalid kind data") # Get 2 bytes data_size if validate and len(container) < counter + 2: diff --git a/src/ethereum/osaka/vm/eof/validation.py b/src/ethereum/osaka/vm/eof/validation.py index f3512c083e..e1c4a6fb65 100644 --- a/src/ethereum/osaka/vm/eof/validation.py +++ b/src/ethereum/osaka/vm/eof/validation.py @@ -202,7 +202,9 @@ def validate_code_section(validator: Validator) -> None: if computed_maximum_stack_height > 1023: raise InvalidEof("Invalid stack height") - if computed_maximum_stack_height != section_max_stack_increase + Uint(section_inputs): + if computed_maximum_stack_height != section_max_stack_increase + Uint( + section_inputs + ): raise InvalidEof("Invalid max stack increase") diff --git a/src/ethereum/osaka/vm/instructions/control_flow.py b/src/ethereum/osaka/vm/instructions/control_flow.py index 7b48c292cf..941e8201e0 100644 --- a/src/ethereum/osaka/vm/instructions/control_flow.py +++ b/src/ethereum/osaka/vm/instructions/control_flow.py @@ -380,7 +380,7 @@ def jumpf(evm: Evm) -> None: ] target_max_stack_increase = Uint.from_be_bytes(target_section[2:]) - if ulen(evm.stack) > Uint(1024) - target_max_stack_increase : + if ulen(evm.stack) > Uint(1024) - target_max_stack_increase: raise StackOverflowError # PROGRAM COUNTER diff --git a/src/ethereum/osaka/vm/instructions/system.py b/src/ethereum/osaka/vm/instructions/system.py index 7a063ce7c3..6446283873 100644 --- a/src/ethereum/osaka/vm/instructions/system.py +++ b/src/ethereum/osaka/vm/instructions/system.py @@ -1280,10 +1280,10 @@ def eof_tx_create(evm: Evm) -> None: if code is None: push(evm.stack, U256(0)) else: - try : + try: eof, calldata = parse_create_tx_call_data(code) if len(calldata) > 0: - raise InvalidEof("Data after end of container") + raise InvalidEof("Data after end of container") generic_eof_create( evm=evm, endowment=value, @@ -1292,7 +1292,7 @@ def eof_tx_create(evm: Evm) -> None: input_offset=input_offset, input_size=input_size, ) - except InvalidEof : + except InvalidEof: # soft failure push(evm.stack, U256(0)) @@ -1336,8 +1336,7 @@ def eof_create(evm: Evm) -> None: evm.memory += b"\x00" * extend_memory.expand_by contract_address = compute_eof_tx_create_contract_address( - evm.message.current_target, - salt + evm.message.current_target, salt ) generic_eof_create( diff --git a/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py b/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py index f656abbbb8..5ae4caea27 100644 --- a/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py +++ b/src/ethereum_spec_tools/evm_tools/loaders/transaction_loader.py @@ -128,8 +128,7 @@ def json_to_blob_versioned_hashes(self) -> List[Bytes32]: def json_to_init_codes(self) -> List[Bytes]: """Get the EOF init codes of the transaction.""" return [ - hex_to_bytes(init_code) - for init_code in self.raw.get("initcodes") + hex_to_bytes(init_code) for init_code in self.raw.get("initcodes") ] def json_to_v(self) -> U256: From cd2e854b8088693db14f6e61177b8a0bde5ce9b0 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 23 Apr 2025 19:26:54 -0600 Subject: [PATCH 7/7] validation speedup --- src/ethereum/osaka/vm/eof/validation.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ethereum/osaka/vm/eof/validation.py b/src/ethereum/osaka/vm/eof/validation.py index e1c4a6fb65..d8feec70ad 100644 --- a/src/ethereum/osaka/vm/eof/validation.py +++ b/src/ethereum/osaka/vm/eof/validation.py @@ -81,7 +81,6 @@ def update_successor_stack_height(validator: Validator) -> None: section_metadata = validator.sections[index] code = validator.eof.metadata.code_section_contents[index] op_metadata = section_metadata[validator.current_pc] - valid_opcode_positions = list(section_metadata.keys()) current_stack_height = validator.current_stack_height assert current_stack_height is not None @@ -95,7 +94,7 @@ def update_successor_stack_height(validator: Validator) -> None: ) if ( successor_position + Uint(1) > ulen(code) - or successor_position not in valid_opcode_positions + or successor_position not in section_metadata.keys() ): raise InvalidEof("Invalid successor or jump destination")