diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 6ba31b4bc3f..663a1a502d0 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -19,6 +19,7 @@ Test fixtures for use by clients are available for each release on the [Github r - ✨ [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) set code of non-empty-storage account test ([#948](https://github.com/ethereum/execution-spec-tests/pull/948)) - ✨ [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Remove delegation behavior of EXTCODE* ([#984](https://github.com/ethereum/execution-spec-tests/pull/984)) - ✨ [EIP-7623](https://eips.ethereum.org/EIPS/eip-7623) Increase calldata cost ([#1004](https://github.com/ethereum/execution-spec-tests/pull/1004)) +- ✨ Add generic precompile-absence test ([#1036](https://github.com/ethereum/execution-spec-tests/pull/1036)) - ✨ Add test for [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537) which uses the full discount table of G2 MSM ([#1038](https://github.com/ethereum/execution-spec-tests/pull/1038)) ### 🛠️ Framework diff --git a/tests/frontier/precompiles/__init__.py b/tests/frontier/precompiles/__init__.py new file mode 100644 index 00000000000..d8c7bf26df0 --- /dev/null +++ b/tests/frontier/precompiles/__init__.py @@ -0,0 +1 @@ +"""Test for precompiles that apply for all forks starting from Frontier.""" diff --git a/tests/frontier/precompiles/test_precompile_absence.py b/tests/frontier/precompiles/test_precompile_absence.py new file mode 100644 index 00000000000..1982ad2f217 --- /dev/null +++ b/tests/frontier/precompiles/test_precompile_absence.py @@ -0,0 +1,74 @@ +"""abstract: Test Calling Precompile Range (close to zero).""" + +import pytest + +from ethereum_test_forks import Fork +from ethereum_test_tools import ( + Account, + Address, + Alloc, + Bytecode, + StateTestFiller, + Storage, + Transaction, +) +from ethereum_test_tools import Opcodes as Op + +UPPER_BOUND = 0x101 +RETURNDATASIZE_OFFSET = 0x10000000000000000 # Must be greater than UPPER_BOUND + + +@pytest.mark.parametrize( + "calldata_size", + [ + pytest.param(0, id="empty_calldata"), + pytest.param(31, id="31_bytes"), + pytest.param(32, id="32_bytes"), + ], +) +@pytest.mark.valid_from("Byzantium") +def test_precompile_absence( + state_test: StateTestFiller, + pre: Alloc, + fork: Fork, + calldata_size: int, +): + """Test that addresses close to zero are not precompiles unless active in the fork.""" + active_precompiles = fork.precompiles() + storage = Storage() + call_code = Bytecode() + for address in range(1, UPPER_BOUND + 1): + if Address(address) in active_precompiles: + continue + call_code += Op.SSTORE( + address, + Op.CALL(gas=0, address=address, args_size=calldata_size), + ) + storage[address] = 1 + if Op.RETURNDATASIZE in fork.valid_opcodes(): + call_code += Op.SSTORE( + address + RETURNDATASIZE_OFFSET, + Op.RETURNDATASIZE, + ) + storage[address + RETURNDATASIZE_OFFSET] = 0 + + call_code += Op.STOP + + entry_point_address = pre.deploy_contract(call_code, storage=storage.canary()) + + tx = Transaction( + to=entry_point_address, + gas_limit=10_000_000, + sender=pre.fund_eoa(), + protected=True, + ) + + state_test( + pre=pre, + tx=tx, + post={ + entry_point_address: Account( + storage=storage, + ) + }, + )