From c83f348ffe1fbc9bb7202d30e2b8e6993121e31c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 22 May 2026 10:20:40 +0200 Subject: [PATCH] feat(tests): EIP-8037 reject when calldata_floor > TX_MAX_GAS_LIMIT EIP-8037 requires max(intrinsic_regular, calldata_floor) <= TX_MAX_GAS_LIMIT. The existing `tx.gas_limit < total_intrinsic` check already covers the intrinsic-regular arm, so only the calldata_floor arm is observably untested. Parametrize types 1 and 2 over floor_binds, intrinsic_binds, and neither_binds. evmone amsterdam/main without fd35d839 fails the floor_binds rows; geth bal-devnet-7 and EELS pass all. --- .../test_intrinsic_cap_at_validation.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_intrinsic_cap_at_validation.py diff --git a/tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_intrinsic_cap_at_validation.py b/tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_intrinsic_cap_at_validation.py new file mode 100644 index 00000000000..4a80697c1c8 --- /dev/null +++ b/tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_intrinsic_cap_at_validation.py @@ -0,0 +1,100 @@ +""" +Test EIP-8037 intrinsic-or-floor cap at tx validation. + +Tests for [EIP-8037: State Creation Gas Cost Increase] +(https://eips.ethereum.org/EIPS/eip-8037). +""" + +import pytest +from execution_testing import ( + AccessList, + Account, + Address, + Alloc, + Fork, + Op, + StateTestFiller, + Transaction, + TransactionException, +) + +from .spec import ref_spec_8037 + +REFERENCE_SPEC_GIT_PATH = ref_spec_8037.git_path +REFERENCE_SPEC_VERSION = ref_spec_8037.version + + +@pytest.mark.parametrize( + "scenario, expected_exception", + [ + pytest.param( + "floor_binds", + TransactionException.INTRINSIC_GAS_TOO_LOW, + id="floor_binds", + marks=pytest.mark.exception_test, + ), + pytest.param( + "intrinsic_binds", + TransactionException.INTRINSIC_GAS_TOO_LOW, + id="intrinsic_binds", + marks=pytest.mark.exception_test, + ), + pytest.param("neither_binds", None, id="neither_binds"), + ], +) +@pytest.mark.parametrize( + "tx_type", + [pytest.param(1, id="type_1"), pytest.param(2, id="type_2")], +) +@pytest.mark.valid_from("EIP8037") +def test_intrinsic_or_floor_cap_at_validation( + state_test: StateTestFiller, + pre: Alloc, + fork: Fork, + tx_type: int, + scenario: str, + expected_exception: TransactionException | None, +) -> None: + """ + Reject when ``max(intrinsic_regular, calldata_floor) > TX_MAX_GAS_LIMIT``. + + Type 0 lacks an access list to vary intrinsic independently of floor; + type 4 would need thousands of signed authorizations. + """ + cap = fork.transaction_gas_limit_cap() + assert cap is not None + gas_costs = fork.gas_costs() + floor_per_byte = gas_costs.TX_DATA_TOKEN_FLOOR * 4 + + if scenario == "floor_binds": + data = b"\x01" * ((cap - gas_costs.TX_BASE) // floor_per_byte + 1) + access_list = [] + elif scenario == "intrinsic_binds": + data = b"" + n = (cap - gas_costs.TX_BASE) // gas_costs.TX_ACCESS_LIST_ADDRESS + 1 + access_list = [ + AccessList(address=Address(i + 1), storage_keys=[]) + for i in range(n) + ] + else: + data = b"" + access_list = [] + + contract = pre.deploy_contract(Op.STOP) + fee_args: dict[str, int] = ( + {"gas_price": 10} + if tx_type == 1 + else {"max_fee_per_gas": 10, "max_priority_fee_per_gas": 0} + ) + tx = Transaction( + ty=tx_type, + sender=pre.fund_eoa(), + to=contract, + data=data, + access_list=access_list, + gas_limit=cap + 1, + error=expected_exception, + **fee_args, + ) + post = {} if expected_exception else {contract: Account(code=Op.STOP)} + state_test(pre=pre, post=post, tx=tx)