diff --git a/packages/testing/src/execution_testing/cli/pytest_commands/plugins/filler/filler.py b/packages/testing/src/execution_testing/cli/pytest_commands/plugins/filler/filler.py index eb7cca48a2..628d8df621 100644 --- a/packages/testing/src/execution_testing/cli/pytest_commands/plugins/filler/filler.py +++ b/packages/testing/src/execution_testing/cli/pytest_commands/plugins/filler/filler.py @@ -1424,7 +1424,6 @@ def base_test_parametrizer_func( fixture_source_url: str, gas_benchmark_value: int, fixed_opcode_count: int | None, - witness_generator: Any, ) -> Any: """ Fixture used to instantiate an auto-fillable BaseTest object from @@ -1577,11 +1576,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: _info_metadata=t8n._info_metadata, ) - # Generate witness data if witness functionality is enabled via - # the witness plugin - if witness_generator is not None: - witness_generator(fixture) - fixture_path = fixture_collector.add_fixture( node_to_test_info(request.node), fixture, diff --git a/packages/testing/src/execution_testing/cli/pytest_commands/plugins/filler/witness.py b/packages/testing/src/execution_testing/cli/pytest_commands/plugins/filler/witness.py deleted file mode 100644 index f150dbc74a..0000000000 --- a/packages/testing/src/execution_testing/cli/pytest_commands/plugins/filler/witness.py +++ /dev/null @@ -1,146 +0,0 @@ -""" -Pytest plugin for witness functionality. - -Provides --witness command-line option that checks for the witness-filler tool -in PATH and generates execution witness data for blockchain test fixtures when -enabled. -""" - -import shutil -import subprocess -from typing import Callable, List - -import pytest - -from execution_testing.base_types import EthereumTestRootModel -from execution_testing.fixtures.blockchain import ( - BlockchainFixture, - FixtureBlock, - WitnessChunk, -) -from execution_testing.forks import Paris - - -class WitnessFillerResult(EthereumTestRootModel[List[WitnessChunk]]): - """ - Model that defines the expected result from the `witness-filler` command. - """ - - root: List[WitnessChunk] - - -class Merge(Paris): - """ - Paris fork that serializes as 'Merge' for witness-filler compatibility. - - IMPORTANT: This class MUST be named 'Merge' (not 'MergeForWitness' or - similar) because the class name is used directly in Pydantic serialization, - and witness-filler expects exactly 'Merge' for this fork. - """ - - pass - - -def pytest_addoption(parser: pytest.Parser) -> None: - """Add witness command-line options to pytest.""" - witness_group = parser.getgroup( - "witness", "Arguments for witness functionality" - ) - witness_group.addoption( - "--witness", - "--witness-the-fitness", - action="store_true", - dest="witness", - default=False, - help=( - "Generate execution witness data for blockchain test fixtures " - "using the witness-filler tool (must be installed separately)." - ), - ) - - -def pytest_configure(config: pytest.Config) -> None: - """ - Pytest hook called after command line options have been parsed. - - If --witness is enabled, checks that the witness-filler tool is available - in PATH. - """ - if config.getoption("witness"): - # Check if witness-filler binary is available in PATH - if not shutil.which("witness-filler"): - repo = "https://github.com/kevaundray/reth.git" # noqa: E501 - pytest.exit( - "witness-filler tool not found in PATH. Please build and " - f"install witness-filler from {repo} before using " - f"--witness flag.\nExample: cargo install --git {repo} " - "witness-filler", - 1, - ) - - -@pytest.fixture -def witness_generator( - request: pytest.FixtureRequest, -) -> Callable[[BlockchainFixture], None] | None: - """ - Provide a witness generator function if --witness is enabled. - - Returns: None if witness functionality is disabled. Callable that generates - witness data for a BlockchainFixture if enabled. - """ - if not request.config.getoption("witness"): - return None - - def generate_witness(fixture: BlockchainFixture) -> None: - """ - Generate witness data for a blockchain fixture using the witness-filler - tool. - """ - if not isinstance(fixture, BlockchainFixture): - return None - - # Hotfix: witness-filler expects "Merge" but execution-spec-tests uses - # "Paris" - original_fork = None - if fixture.fork is Paris: - original_fork = fixture.fork - fixture.fork = Merge - - try: - result = subprocess.run( - ["witness-filler"], - input=fixture.model_dump_json(by_alias=True), - text=True, - capture_output=True, - ) - finally: - if original_fork is not None: - fixture.fork = original_fork - - if result.returncode != 0: - raise RuntimeError( - f"witness-filler tool failed with exit code " - f"{result.returncode}. stderr: {result.stderr}" - ) - - try: - result_model = WitnessFillerResult.model_validate_json( - result.stdout - ) - witnesses = result_model.root - - for i, witness in enumerate(witnesses): - if i < len(fixture.blocks): - block = fixture.blocks[i] - if isinstance(block, FixtureBlock): - block.execution_witness = witness - except Exception as e: - output = result.stdout[:500] - suffix = "..." if len(result.stdout) > 500 else "" - raise RuntimeError( - f"Failed to parse witness data from witness-filler tool. " - f"Output was: {output}{suffix}" - ) from e - - return generate_witness diff --git a/packages/testing/src/execution_testing/cli/pytest_commands/plugins/help/help.py b/packages/testing/src/execution_testing/cli/pytest_commands/plugins/help/help.py index 76769f6d9c..9d299b1bc9 100644 --- a/packages/testing/src/execution_testing/cli/pytest_commands/plugins/help/help.py +++ b/packages/testing/src/execution_testing/cli/pytest_commands/plugins/help/help.py @@ -105,7 +105,6 @@ def pytest_configure(config: pytest.Config) -> None: "defining debug", "pre-allocation behavior during test filling", "ported", - "witness", "benchmark", ], ) diff --git a/packages/testing/src/execution_testing/cli/pytest_commands/pytest_ini_files/pytest-fill.ini b/packages/testing/src/execution_testing/cli/pytest_commands/pytest_ini_files/pytest-fill.ini index 37b44bf643..74d65dd5e7 100644 --- a/packages/testing/src/execution_testing/cli/pytest_commands/pytest_ini_files/pytest-fill.ini +++ b/packages/testing/src/execution_testing/cli/pytest_commands/pytest_ini_files/pytest-fill.ini @@ -10,7 +10,6 @@ addopts = -p execution_testing.cli.pytest_commands.plugins.forks.forks -p execution_testing.cli.pytest_commands.plugins.concurrency -p execution_testing.cli.pytest_commands.plugins.filler.pre_alloc - -p execution_testing.cli.pytest_commands.plugins.filler.witness -p execution_testing.cli.pytest_commands.plugins.filler.ported_tests -p execution_testing.cli.pytest_commands.plugins.filler.static_filler -p execution_testing.cli.pytest_commands.plugins.shared.benchmarking diff --git a/packages/testing/src/execution_testing/fixtures/blockchain.py b/packages/testing/src/execution_testing/fixtures/blockchain.py index 6b15039515..e2bad75ae5 100644 --- a/packages/testing/src/execution_testing/fixtures/blockchain.py +++ b/packages/testing/src/execution_testing/fixtures/blockchain.py @@ -1,6 +1,5 @@ """BlockchainTest types.""" -import json from functools import cached_property from typing import ( Annotated, @@ -597,24 +596,6 @@ def from_withdrawal(cls, w: WithdrawalGeneric) -> Self: return cls(**w.model_dump()) -class WitnessChunk(CamelModel): - """Represents execution witness data for a block.""" - - state: List[str] - codes: List[str] - keys: List[str] - headers: List[str] - - @classmethod - def parse_witness_chunks(cls, s: str) -> List[Self]: - """ - Parse multiple witness chunks from JSON string. - - Returns a list of WitnessChunk instances parsed from the JSON array. - """ - return [cls(**obj) for obj in json.loads(s)] - - class FixtureBlockBase(CamelModel): """ Representation of an Ethereum block within a test Fixture without RLP @@ -643,7 +624,6 @@ def strip_block_number_computed_field(cls, data: Any) -> Any: ) withdrawals: List[FixtureWithdrawal] | None = None receipts: List[FixtureTransactionReceipt] | None = None - execution_witness: WitnessChunk | None = None block_access_list: BlockAccessList | None = Field( None, description="EIP-7928 Block Access List" ) diff --git a/packages/testing/src/execution_testing/specs/benchmark.py b/packages/testing/src/execution_testing/specs/benchmark.py index 96b8eacf5f..abe0df496d 100644 --- a/packages/testing/src/execution_testing/specs/benchmark.py +++ b/packages/testing/src/execution_testing/specs/benchmark.py @@ -290,6 +290,9 @@ class BenchmarkTest(BaseTest): fixed_opcode_count: float | None = None target_opcode: Op | None = None code_generator: BenchmarkCodeGenerator | None = None + # By default, benchmark tests require neither of these + include_full_post_state_in_output: bool = False + include_tx_receipts_in_output: bool = False supported_fixture_formats: ClassVar[ Sequence[FixtureFormat | LabeledFixtureFormat] @@ -491,6 +494,8 @@ def generate_blockchain_test(self) -> BlockchainTest: pre=self.pre, post=self.post, blocks=self.blocks, + include_full_post_state_in_output=self.include_full_post_state_in_output, + include_tx_receipts_in_output=self.include_tx_receipts_in_output, ) def _verify_target_opcode_count( diff --git a/packages/testing/src/execution_testing/specs/blockchain.py b/packages/testing/src/execution_testing/specs/blockchain.py index 7eb221363c..563bc1df35 100644 --- a/packages/testing/src/execution_testing/specs/blockchain.py +++ b/packages/testing/src/execution_testing/specs/blockchain.py @@ -279,6 +279,11 @@ class Block(Header): If set, the block is expected to produce an error response from the Engine API. """ + include_receipts_in_output: bool | None = None + """ + If set to `True`, the block’s output fixture representation will include + full transaction receipts. If unset, the test-level value is used. + """ txs: List[Transaction] = Field(default_factory=list) """List of transactions included in the block.""" ommers: List[Header] | None = None @@ -378,7 +383,9 @@ class BuiltBlock(CamelModel): fork: Fork block_access_list: BlockAccessList | None - def get_fixture_block(self) -> FixtureBlock | InvalidFixtureBlock: + def get_fixture_block( + self, *, include_receipts: bool = True + ) -> FixtureBlock | InvalidFixtureBlock: """Get a FixtureBlockBase from the built block.""" fixture_block = FixtureBlockBase( header=self.header, @@ -398,7 +405,7 @@ def get_fixture_block(self) -> FixtureBlock | InvalidFixtureBlock: ) for i, r in enumerate(self.result.receipts) ] - if self.result.receipts + if self.result.receipts and include_receipts else None ), block_access_list=self.block_access_list @@ -499,11 +506,15 @@ class BlockchainTest(BaseTest): blocks: List[Block] genesis_environment: Environment = Field(default_factory=Environment) chain_id: int = 1 - exclude_full_post_state_in_output: bool = False + include_full_post_state_in_output: bool = True """ - Exclude the post state from the fixture output. In this case, the state + Include the post state in the fixture output. Otherwise, the state verification is only performed based on the state root. """ + include_tx_receipts_in_output: bool = True + """ + Include transaction receipts in the fixture output. + """ _benchmark_opcode_count: OpcodeCount | None = PrivateAttr(None) @@ -872,6 +883,7 @@ def make_fixture( head = genesis.header.block_hash invalid_blocks = 0 for i, block in enumerate(self.blocks): + is_last_block = i == len(self.blocks) - 1 # This is the most common case, the RLP needs to be constructed # based on the transactions to be included in the block. # Set the environment according to the block to execute. @@ -880,9 +892,18 @@ def make_fixture( block=block, previous_env=env, previous_alloc=alloc, - last_block=i == len(self.blocks) - 1, + last_block=is_last_block, + ) + include_receipts = ( + block.include_receipts_in_output + if block.include_receipts_in_output is not None + else self.include_tx_receipts_in_output + ) + fixture_blocks.append( + built_block.get_fixture_block( + include_receipts=include_receipts + ) ) - fixture_blocks.append(built_block.get_fixture_block()) # BAL verification already done in to_fixture_bal() if # expected_block_access_list set @@ -918,10 +939,10 @@ def make_fixture( last_block_hash=head, pre=pre, post_state=alloc - if not self.exclude_full_post_state_in_output + if self.include_full_post_state_in_output else None, post_state_hash=state_root - if self.exclude_full_post_state_in_output + if not self.include_full_post_state_in_output else None, config=FixtureConfig( fork=self.fork, @@ -1004,7 +1025,7 @@ def make_hive_fixture( "payloads": fixture_payloads, "last_block_hash": head_hash, "post_state_hash": state_root - if self.exclude_full_post_state_in_output + if not self.include_full_post_state_in_output else None, "config": FixtureConfig( fork=self.fork, @@ -1023,7 +1044,7 @@ def make_hive_fixture( fixture_data.update( { "post_state": alloc - if not self.exclude_full_post_state_in_output + if self.include_full_post_state_in_output else None, "pre_hash": "", # Will be set by BaseTestWrapper } @@ -1052,7 +1073,7 @@ def make_hive_fixture( ), "pre": pre, "post_state": alloc - if not self.exclude_full_post_state_in_output + if self.include_full_post_state_in_output else None, } ) @@ -1063,7 +1084,7 @@ def make_hive_fixture( { "pre": pre, "post_state": alloc - if not self.exclude_full_post_state_in_output + if self.include_full_post_state_in_output else None, } ) diff --git a/tests/constantinople/eip1052_extcodehash/__init__.py b/tests/constantinople/eip1052_extcodehash/__init__.py new file mode 100644 index 0000000000..d9d661752c --- /dev/null +++ b/tests/constantinople/eip1052_extcodehash/__init__.py @@ -0,0 +1 @@ +"""Cross-client EIP-1052 EXTCODEHASH Tests.""" diff --git a/tests/constantinople/eip1052_extcodehash/test_extcodehash.py b/tests/constantinople/eip1052_extcodehash/test_extcodehash.py new file mode 100644 index 0000000000..47046b32d5 --- /dev/null +++ b/tests/constantinople/eip1052_extcodehash/test_extcodehash.py @@ -0,0 +1,310 @@ +""" +Test EIP-1052 EXTCODEHASH. +""" + +import pytest +from execution_testing import ( + Account, + Alloc, + Op, + StateTestFiller, + Storage, + Transaction, + compute_create2_address, + compute_create_address, +) + +from ethereum.crypto.hash import keccak256 + +REFERENCE_SPEC_GIT_PATH = "EIPS/eip-1052.md" +REFERENCE_SPEC_VERSION = "2dcbc7ce1563e9624e137e9d447374600af876fa" + +pytestmark = [ + pytest.mark.valid_from("ConstantinopleFix"), +] + + +@pytest.mark.ported_from( + [ + "https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stExtCodeHash/extCodeHashNonExistingAccountFiller.yml", # noqa: E501 + "https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stExtCodeHash/extCodeHashAccountWithoutCodeFiller.yml", # noqa: E501 + ], + pr=["https://github.com/ethereum/execution-specs/pull/2237"], +) +@pytest.mark.parametrize("target_exists", [True, False]) +def test_extcodehash_of_empty( + state_test: StateTestFiller, + pre: Alloc, + target_exists: bool, +) -> None: + """ + Test EXTCODEHASH/EXTCODESIZE for non-existent and empty accounts. + """ + storage = Storage() + target_address = pre.empty_account() + + if target_exists: + pre.fund_address(target_address, 1) + + expected_hash = keccak256(b"") if target_exists else 0 + code = Op.SSTORE( + storage.store_next(expected_hash), + Op.EXTCODEHASH(target_address), + ) + Op.SSTORE( + storage.store_next(0), + Op.EXTCODESIZE(target_address), + ) + + code_address = pre.deploy_contract(code) + + tx = Transaction( + sender=(pre.fund_eoa()), + to=code_address, + value=1, + gas_limit=400_000, + ) + + state_test( + pre=pre, + post={ + code_address: Account(storage=storage), + }, + tx=tx, + ) + + +@pytest.mark.ported_from( + [ + "https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stExtCodeHash/extcodehashEmpty_ParisFiller.yml", # noqa: E501 + ], + pr=["https://github.com/ethereum/execution-specs/pull/2237"], +) +def test_extcodehash_empty_send_value( + state_test: StateTestFiller, + pre: Alloc, +) -> None: + """ + Test EXTCODEHASH of non-existent account before and after sending value. + + Verify that EXTCODEHASH transitions from 0 to keccak256("") when + the account receives value within the same transaction. + """ + storage = Storage() + target_address = pre.empty_account() + + code = ( + # EXTCODEHASH before sending value: expect 0 (non-existent). + Op.SSTORE( + storage.store_next(0), + Op.EXTCODEHASH(target_address), + ) + # Send 1 wei to target, creating the account. + + Op.CALL(gas=Op.GAS, address=target_address, value=1) + # EXTCODEHASH after sending value: expect keccak256(""). + + Op.SSTORE( + storage.store_next(keccak256(b"")), + Op.EXTCODEHASH(target_address), + ) + ) + + code_address = pre.deploy_contract(code, balance=10**18) + + tx = Transaction( + sender=pre.fund_eoa(), + to=code_address, + gas_limit=400_000, + ) + + state_test( + pre=pre, + post={ + code_address: Account(storage=storage), + }, + tx=tx, + ) + + +@pytest.mark.ported_from( + [ + "https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stExtCodeHash/extcodehashEmpty_ParisFiller.yml", # noqa: E501 + ], + pr=["https://github.com/ethereum/execution-specs/pull/2237"], +) +@pytest.mark.pre_alloc_mutable +@pytest.mark.parametrize( + "account,call_before,expected_hash,expected_size,expected_copy", + [ + pytest.param( + Account(nonce=1), + False, + keccak256(b""), + 0, + 0, + id="nonce-only", + ), + pytest.param( + Account(balance=1), + False, + keccak256(b""), + 0, + 0, + id="balance-only", + ), + pytest.param( + Account( + balance=10, + storage={0x00: 0x01000000, 0xFFFFFFF: 0xFFFFFFFF}, + ), + False, + keccak256(b""), + 0, + 0, + id="balance-storage", + ), + pytest.param( + Account(code=Op.STOP), + False, + keccak256(bytes(Op.STOP)), + 1, + 0, + id="single-byte-code", + ), + pytest.param( + Account(balance=100, code=Op.PUSH2(0x60A7) + Op.SELFDESTRUCT), + True, + keccak256(bytes(Op.PUSH2(0x60A7) + Op.SELFDESTRUCT)), + 4, + bytes(Op.PUSH2(0x60A7) + Op.SELFDESTRUCT).ljust(32, b"\0"), + id="selfdestruct", + ), + ], +) +def test_extcodehash_empty_account_variants( + state_test: StateTestFiller, + pre: Alloc, + account: Account, + call_before: bool, + expected_hash: bytes, + expected_size: int, + expected_copy: int | bytes, +) -> None: + """ + Test EXTCODEHASH/EXTCODESIZE/EXTCODECOPY for empty-account variants. + """ + storage = Storage() + target_address = pre.empty_account() + pre[target_address] = account + + code = Op.JUMPDEST + ( + Op.CALL(gas=Op.GAS, address=target_address, value=0) + if call_before + else Op.NOOP + ) + + code += ( + Op.SSTORE( + storage.store_next(expected_size), + Op.EXTCODESIZE(target_address), + ) + + Op.SSTORE( + storage.store_next(expected_hash), + Op.EXTCODEHASH(target_address), + ) + + Op.EXTCODECOPY(target_address, 0, 0, 32) + + Op.SSTORE( + storage.store_next(expected_copy), + Op.MLOAD(0), + ) + ) + + code_address = pre.deploy_contract(code, balance=10**18) + + tx = Transaction( + sender=pre.fund_eoa(), + to=code_address, + value=1, + gas_limit=400_000, + ) + + state_test( + pre=pre, + post={ + code_address: Account(storage=storage), + }, + tx=tx, + ) + + +@pytest.mark.ported_from( + [ + "https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stExtCodeHash/extcodehashEmpty_ParisFiller.yml", # noqa: E501 + ], + pr=["https://github.com/ethereum/execution-specs/pull/2237"], +) +@pytest.mark.parametrize("opcode", [Op.CREATE, Op.CREATE2]) +def test_extcodehash_empty_contract_creation( + state_test: StateTestFiller, + pre: Alloc, + opcode: Op, +) -> None: + """ + Test EXTCODEHASH/EXTCODESIZE for empty contracts created with + CREATE/CREATE2. + """ + storage = Storage() + initcode = Op.RETURN(0, 0) + expected_hash = keccak256(b"") + + created_slot = storage.store_next(0) + hash_slot = storage.store_next(expected_hash) + size_slot = storage.store_next(0) + copy_slot = storage.store_next(0) + + create_op = ( + opcode(value=0, offset=0, size=len(initcode), salt=0) + if opcode == Op.CREATE2 + else opcode(value=0, offset=0, size=len(initcode)) + ) + + code = ( + Op.MSTORE(0, Op.PUSH32(bytes(initcode).ljust(32, b"\0"))) + + Op.SSTORE(created_slot, create_op) + + Op.SSTORE( + hash_slot, + Op.EXTCODEHASH(Op.SLOAD(created_slot)), + ) + + Op.SSTORE( + size_slot, + Op.EXTCODESIZE(Op.SLOAD(created_slot)), + ) + + Op.EXTCODECOPY(Op.SLOAD(created_slot), 0, 0, 32) + + Op.SSTORE(copy_slot, Op.MLOAD(0)) + + Op.STOP + ) + + code_address = pre.deploy_contract(code) + created_address = ( + compute_create2_address( + address=code_address, + salt=0, + initcode=initcode, + ) + if opcode == Op.CREATE2 + else compute_create_address(address=code_address, nonce=1) + ) + storage[created_slot] = created_address + + tx = Transaction( + sender=pre.fund_eoa(), + to=code_address, + gas_limit=400_000, + ) + + state_test( + pre=pre, + post={ + code_address: Account(storage=storage), + created_address: Account(nonce=1, code=b""), + }, + tx=tx, + ) diff --git a/tests/static/state_tests/stExtCodeHash/extCodeHashAccountWithoutCodeFiller.yml b/tests/static/state_tests/stExtCodeHash/extCodeHashAccountWithoutCodeFiller.yml deleted file mode 100644 index f1fd6ccd15..0000000000 --- a/tests/static/state_tests/stExtCodeHash/extCodeHashAccountWithoutCodeFiller.yml +++ /dev/null @@ -1,77 +0,0 @@ -# EXTCODEHASH to an account without code ---- -extCodeHashAccountWithoutCode: - env: - currentCoinbase: 2adc25665018aa1fe0e6bc666dac8fc2697ff9ba - currentDifficulty: '0x20000' - currentGasLimit: "1000000" - currentNumber: "1" - currentTimestamp: "1000" - pre: - : - balance: '1000000000000000000' - code: | - { - (CALL 150000 0 0 0 0 32) - (RETURNDATACOPY 0 0 32) - [[0]] (MLOAD 0) - (CALL 150000 0 0 0 0 32) - (RETURNDATACOPY 0 0 32) - [[1]] (MLOAD 0) - } - nonce: '0' - storage: {} - : - balance: '1000000000000000000' - code: | - { - (MSTORE 0 (EXTCODEHASH )) - (RETURN 0 32) - } - nonce: '0' - storage: {} - : - balance: '1000000000000000000' - code: | - { - (MSTORE 0 (EXTCODESIZE )) - (RETURN 0 32) - } - nonce: '0' - storage: {} - # account without code - : - balance: '1000000000000000000' - code: '' - nonce: '0' - storage: {} - : - balance: '1000000000000000000' - code: '' - nonce: '0' - storage: {} - expect: - - indexes: - data: !!int -1 - gas: !!int -1 - value: !!int -1 - network: - - '>=Cancun' - result: - : - balance: '1000000000000000001' - storage: { - "0x00": '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470', - "0x01": '0' - } - transaction: - data: - - '' - gasLimit: - - '400000' - gasPrice: '10' - nonce: '0' - secretKey: "" - to: - value: - - '1' diff --git a/tests/static/state_tests/stExtCodeHash/extCodeHashNonExistingAccountFiller.yml b/tests/static/state_tests/stExtCodeHash/extCodeHashNonExistingAccountFiller.yml deleted file mode 100644 index 3c5238b4d7..0000000000 --- a/tests/static/state_tests/stExtCodeHash/extCodeHashNonExistingAccountFiller.yml +++ /dev/null @@ -1,73 +0,0 @@ -# EXTCODEHASH to a not existing account must be 0 ---- -extCodeHashNonExistingAccount: - env: - currentCoinbase: 2adc25665018aa1fe0e6bc666dac8fc2697ff9ba - currentDifficulty: '0x20000' - currentGasLimit: "1000000" - currentNumber: "1" - currentTimestamp: "1000" - pre: - 095e7baea6a6c7c4c2dfeb977efac326af552d87: - balance: '1000000000000000000' - code: | - { - (CALL 150000 0xdeadbeef00000000000000000000000000000000 0 0 0 0 32) - (RETURNDATACOPY 0 0 32) - [[0]] (MLOAD 0) - (CALL 150000 0xaeadbeef00000000000000000000000000000000 0 0 0 0 32) - (RETURNDATACOPY 0 0 32) - [[1]] (MLOAD 0) - } - nonce: '0' - storage: {} - deadbeef00000000000000000000000000000000: - balance: '1000000000000000000' - code: | - { - (MSTORE 0 (EXTCODEHASH 0xdeadbeef00000000000000000000000000000001)) - (RETURN 0 32) - } - nonce: '0' - storage: {} - aeadbeef00000000000000000000000000000000: - balance: '1000000000000000000' - code: | - { - (MSTORE 0 (EXTCODESIZE 0xdeadbeef00000000000000000000000000000001)) - (RETURN 0 32) - } - nonce: '0' - storage: {} - a94f5374fce5edbc8e2a8697c15331677e6ebf0b: - balance: '1000000000000000000' - code: '' - nonce: '0' - storage: {} - expect: - - indexes: - data: !!int -1 - gas: !!int -1 - value: !!int -1 - network: - - '>=Cancun' - result: - 095e7baea6a6c7c4c2dfeb977efac326af552d87: - balance: '1000000000000000001' - storage: { - "0x00": '0', - "0x01": '0' - } - deadbeef00000000000000000000000000000001: - shouldnotexist: '1' - transaction: - data: - - '' - gasLimit: - - '400000' - gasPrice: '10' - nonce: '0' - secretKey: 45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8 - to: 095e7baea6a6c7c4c2dfeb977efac326af552d87 - value: - - '1' diff --git a/tests/static/state_tests/stExtCodeHash/extcodehashEmpty_ParisFiller.yml b/tests/static/state_tests/stExtCodeHash/extcodehashEmpty_ParisFiller.yml deleted file mode 100644 index 7769bdd989..0000000000 --- a/tests/static/state_tests/stExtCodeHash/extcodehashEmpty_ParisFiller.yml +++ /dev/null @@ -1,369 +0,0 @@ -# The extcodehash opcode returns zero when an account is truly empty -# (no data what so ever), or when an account only has storage entries. -# -# When an account has either a balance or a nonce, extcodehash returns -# the hash of the empty string. -# -# This test was requested in issue https://github.com/ethereum/tests/issues/581 - -extcodehashEmpty_Paris: - env: - currentCoinbase: 2adc25665018aa1fe0e6bc666dac8fc2697ff9ba - currentDifficulty: 0x20000 - currentGasLimit: 100000000 - currentNumber: 1 - currentTimestamp: 1000 - - _info: - comment: Ori Pomerantz qbzzt1@gmail.com - - pre: - - cccccccccccccccccccccccccccccccccccccccc: - balance: '0x0ba1a9ce0ba1a9ce' - code: | - { - (def 'addr $4) - (def 'NOP 0) - - ; If the address is above 0x2000, we should call it first - ; and then check the extcodehash - (if (> addr 0x2000) - (call (gas) addr 0 0 0 0 0) - NOP - ) - - ; Normal result - [[0]] (extcodesize addr) - [[1]] (extcodehash addr) - (extcodecopy addr 0 0 @@0) - [[2]] @0 - - ; Send a wei to the account and see that you ALWAYS get the - ; empty string's hash, but only for "normal", sub 0x2000 addresses - (if (< addr 0x2000) - (call (gas) addr 1 0 0 0 0) - NOP - ) - [[3]] (extcodehash addr) - - ; As long as we're here, check the gas cost of EXTCODEHASH - ; Note that the space between the (gas) checks also includes: - ; GAS 2 - ; PUSH1 3 - ; MSTORE 6 - ; PUSH1 3 - ; CALLDATALOAD 3 - ; << EXTCODEHASH is here >> - ; POP 2 - - [0x20] (gas) - (extcodehash addr) - [0x40] (gas) - [[4]] (- @0x20 @0x40 19) - - ; Also, the EXTCODEHASH cost here is for a previously touched - ; account, which makes it a lot lower (>=Cancun) - } - nonce: '0' - storage: {} - - - # Really empty, the EXTCODEHASH is zero - # 0000000000000000000000000000000000001000: - # balance: 0 - # code: 0x - # nonce: 0 - # storage: {} - - - # If there is a balance, it's the hash of the empty string - 0000000000000000000000000000000000001001: - balance: 1 - code: 0x - nonce: 0 - storage: {} - - - - # The actual balance doesn't matter - 0000000000000000000000000000000000001101: - balance: 0x100000000000000 - code: 0x - nonce: 0 - storage: {} - - - # If there is a nonce, it's also the hash of the empty string - 0000000000000000000000000000000000001002: - balance: 0 - code: 0x - nonce: 1 - storage: {} - - # The nonce value doesn't matter - 0000000000000000000000000000000000001102: - balance: 0 - code: 0x - nonce: 1000000000000 - storage: {} - - - # Storage doesn't make it look an account exists - 0000000000000000000000000000000000001003: - balance: 10 - code: 0x - nonce: 0 - storage: - 0x00: 0x01000000 - 0xFFFFFFF: 0xFFFFFFFF - - 0000000000000000000000000000000000001004: - balance: 0 - code: :raw 0x00 - nonce: 0 - storage: {} - - - # What happens when a contract commits suicide? - # (nothing, suicide is not processed until the end of the transaction) - 000000000000000000000000000000000000DEAD: - balance: 100 - code: :raw 0x6160A7FF - nonce: 0 - storage: {} - - - # What happens when it CREATEs another contract, - # and that one is empty? - # - # The new contract is created with nonce:1, so it is never empty - # and EXTCODEHASH always returns the hash of the empty string - 0000000000000000000000000000000000C0EA7E: - balance: 100 - code: | - { - (def 'constructorCode 0x100) - (def 'constructorLength 0x020) - (def 'addr 0x040) - - [constructorLength] (lll - { - ; The constructor code, nothing happens - ; except we return an empty buffer with "all" - ; the code of the created contract - (return 0 0) - } - constructorCode ; write to 0x100 and above - ) - - [addr] (create 0 constructorCode @constructorLength) - [[0]] (extcodehash @addr) - } - nonce: 0 - storage: {} - - - - # What happens when it CREATE2s another contract, - # and that one is empty? - # - # The new contract is created with nonce:1, so it is never empty - # and EXTCODEHASH always returns the hash of the empty string - 000000000000000000000000000000000C0EA7E2: - balance: 100 - code: | - { - (def 'constructorCode 0x100) - (def 'constructorLength 0x020) - (def 'addr 0x040) - - [constructorLength] (lll - { - ; The constructor code, nothing happens - ; except we return an empty buffer with "all" - ; the code of the created contract - (return 0 0) - } - constructorCode ; write to 0x100 and above - ) - - [addr] (create2 0 constructorCode @constructorLength 0x60A7) - [[0]] (extcodehash @addr) - [[1]] @addr - } - nonce: 0 - storage: {} - - - - a94f5374fce5edbc8e2a8697c15331677e6ebf0b: - balance: '0x0ba1a9ce0ba1a9ce' - code: 0x - nonce: 0 - storage: {} - - - transaction: - data: - # These give an EXTCODEHASH of zero - - :label empty :abi f(uint) 0x1000 - - :label storage :abi f(uint) 0x1003 - - # These give an EXTCODEHASH of the empty string - - :label balance :abi f(uint) 0x1001 - - :label balance :abi f(uint) 0x1101 - - :label nonce :abi f(uint) 0x1002 - - :label nonce :abi f(uint) 0x1102 - - # There is a difference between not having code, and having - # a single byte of 00 as the code - - :label hasCode :abi f(uint) 0x1004 - - - # This contract commits suicide and then we EXTCODEHASH it - # However, it seems that suicides don't happen before the end - # of the transaction - - :label dead :abi f(uint) 0xDEAD - - - # When we create an empty contract, what happens? - - :label born :abi f(uint) 0x00C0EA7E - - :label born2 :abi f(uint) 0x0C0EA7E2 - - - gasLimit: - - '16777216' - gasPrice: '10' - nonce: '0' - to: cccccccccccccccccccccccccccccccccccccccc - value: - - '1' - secretKey: "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" - - - expect: - - - indexes: - data: - - :label storage - gas: !!int -1 - value: !!int -1 - network: - - '>=Cancun' - result: - cccccccccccccccccccccccccccccccccccccccc: - storage: - 0x00: 0x00 - 0x01: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 - 0x02: 0x00 - 0x03: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 - 0x04: 0x64 # 100 - - - indexes: - data: - - :label empty - gas: !!int -1 - value: !!int -1 - network: - - '>=Cancun' - result: - cccccccccccccccccccccccccccccccccccccccc: - storage: - 0x00: 0x00 - 0x01: 0x00 - 0x02: 0x00 - 0x03: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 - 0x04: 0x64 # 100 - - - - - - indexes: - data: - - :label balance - - :label nonce - gas: !!int -1 - value: !!int -1 - network: - - '>=Cancun' - result: - cccccccccccccccccccccccccccccccccccccccc: - storage: - 0x00: 0x00 - 0x01: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 - 0x02: 0x00 - 0x03: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 - 0x04: 0x64 # 100 - - - - - - indexes: - data: - - :label hasCode - gas: !!int -1 - value: !!int -1 - network: - - '>=Cancun' - result: - cccccccccccccccccccccccccccccccccccccccc: - storage: - 0x00: 0x01 - 0x01: 0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a - 0x02: 0x00 - 0x03: 0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a - 0x04: 0x64 - - - - - indexes: - data: - - :label dead - gas: !!int -1 - value: !!int -1 - network: - - '>=Cancun' - result: - cccccccccccccccccccccccccccccccccccccccc: - storage: - 0x00: 0x04 - 0x01: 0x2951f94cc6db6e9b3de9e43ccbd2c84491c46fc3be255c6634299f82b37baaf8 - 0x02: 0x6160a7ff00000000000000000000000000000000000000000000000000000000 - 0x03: 0x2951f94cc6db6e9b3de9e43ccbd2c84491c46fc3be255c6634299f82b37baaf8 - 0x04: 0x64 # 100 - - - - - indexes: - data: - - :label born - gas: !!int -1 - value: !!int -1 - network: - - '>=Cancun' - result: - # We don't care about C0EA7E (which obviously is not empty) - # We care about the account it creates. - 0000000000000000000000000000000000C0EA7E: - storage: - 0x00: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 - - - - - indexes: - data: - - :label born2 - gas: !!int -1 - value: !!int -1 - network: - - '>=Cancun' - result: - # We don't care about C0EA7E2 (which obviously is not empty) - # We care about the account it creates. - 000000000000000000000000000000000C0EA7E2: - storage: - 0x00: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 - 0x01: 0xb41b458cea588432cef2494454a360143004984c - b41b458cea588432cef2494454a360143004984c: - nonce: 1