diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index df43e0f9c5..7f03e0482b 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -29,6 +29,7 @@ Test fixtures for use by clients are available for each release on the [Github r - ✨ Expand cases to test *CALL opcodes causing OOG ([#1703](https://github.com/ethereum/execution-specs/pull/1703)). - ✨ Add tests for `modexp` and `ripemd` precompiled contracts ([#1691](https://github.com/ethereum/execution-specs/pull/1691)). - ✨ Add `ecrecover` precompile tests originating form `evmone` unittests ([#1685](https://github.com/ethereum/execution-specs/pull/1685)). +- ✨ Add tests that EIP-1559 and EIP-2930 typed txs are invalid and void before their fork ([#1754](https://github.com/ethereum/execution-specs/pull/1754)). ## [v5.3.0](https://github.com/ethereum/execution-spec-tests/releases/tag/v5.3.0) - 2025-10-09 diff --git a/packages/testing/src/execution_testing/client_clis/clis/ethrex.py b/packages/testing/src/execution_testing/client_clis/clis/ethrex.py index 88ff0c510b..96447c8377 100644 --- a/packages/testing/src/execution_testing/client_clis/clis/ethrex.py +++ b/packages/testing/src/execution_testing/client_clis/clis/ethrex.py @@ -50,6 +50,9 @@ class EthrexExceptionMapper(ExceptionMapper): TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH: ( r"blob version not supported|Invalid blob versioned hash" ), + TransactionException.TYPE_3_TX_PRE_FORK: ( + r"Type 2 transactions are not supported before the London fork" + ), TransactionException.TYPE_3_TX_PRE_FORK: ( r"blob versioned hashes not supported|" r"Type 3 transactions are not supported before the Cancun fork" diff --git a/packages/testing/src/execution_testing/client_clis/clis/evmone.py b/packages/testing/src/execution_testing/client_clis/clis/evmone.py index 21e1e07ae6..da9c0a1d7d 100644 --- a/packages/testing/src/execution_testing/client_clis/clis/evmone.py +++ b/packages/testing/src/execution_testing/client_clis/clis/evmone.py @@ -350,6 +350,8 @@ class EvmoneExceptionMapper(ExceptionMapper): ), TransactionException.TYPE_4_TX_PRE_FORK: "transaction type not supported", TransactionException.TYPE_3_TX_PRE_FORK: "transaction type not supported", + TransactionException.TYPE_2_TX_PRE_FORK: "transaction type not supported", + TransactionException.TYPE_1_TX_PRE_FORK: "transaction type not supported", TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH: "invalid blob hash version", TransactionException.TYPE_3_TX_BLOB_COUNT_EXCEEDED: "blob gas limit exceeded", TransactionException.TYPE_3_TX_ZERO_BLOBS: "empty blob hashes list", diff --git a/packages/testing/src/execution_testing/client_clis/clis/geth.py b/packages/testing/src/execution_testing/client_clis/clis/geth.py index f28b3e4ea5..d56e896487 100644 --- a/packages/testing/src/execution_testing/client_clis/clis/geth.py +++ b/packages/testing/src/execution_testing/client_clis/clis/geth.py @@ -54,6 +54,12 @@ class GethExceptionMapper(ExceptionMapper): TransactionException.PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS: ( "max priority fee per gas higher than max fee per gas" ), + TransactionException.TYPE_1_TX_PRE_FORK: ( + "transaction type not supported" + ), + TransactionException.TYPE_2_TX_PRE_FORK: ( + "transaction type not supported" + ), TransactionException.TYPE_3_TX_PRE_FORK: ( "transaction type not supported" ), diff --git a/packages/testing/src/execution_testing/client_clis/clis/nethermind.py b/packages/testing/src/execution_testing/client_clis/clis/nethermind.py index 242c60c6b9..bf3eccf1a8 100644 --- a/packages/testing/src/execution_testing/client_clis/clis/nethermind.py +++ b/packages/testing/src/execution_testing/client_clis/clis/nethermind.py @@ -395,6 +395,12 @@ class NethermindExceptionMapper(ExceptionMapper): TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS: ( "InsufficientMaxFeePerBlobGas: Not enough to cover blob gas fee" ), + TransactionException.TYPE_1_TX_PRE_FORK: ( + "InvalidTxType: Transaction type in Custom is not supported" + ), + TransactionException.TYPE_2_TX_PRE_FORK: ( + "InvalidTxType: Transaction type in Custom is not supported" + ), TransactionException.TYPE_3_TX_PRE_FORK: ( "InvalidTxType: Transaction type in Custom is not supported" ), diff --git a/packages/testing/src/execution_testing/exceptions/exceptions.py b/packages/testing/src/execution_testing/exceptions/exceptions.py index 53d57f06f8..8abf5d031b 100644 --- a/packages/testing/src/execution_testing/exceptions/exceptions.py +++ b/packages/testing/src/execution_testing/exceptions/exceptions.py @@ -269,6 +269,10 @@ class TransactionException(ExceptionBase): """ Transaction's initcode for a contract-creating transaction is too large. """ + TYPE_1_TX_PRE_FORK = auto() + """Transaction type 1 included before activation fork.""" + TYPE_2_TX_PRE_FORK = auto() + """Transaction type 2 included before activation fork.""" TYPE_3_TX_PRE_FORK = auto() """Transaction type 3 included before activation fork.""" TYPE_3_TX_ZERO_BLOBS_PRE_FORK = auto() diff --git a/packages/testing/src/execution_testing/exceptions/exceptions/transaction.py b/packages/testing/src/execution_testing/exceptions/exceptions/transaction.py index ee67b0d55e..7e25bb38fc 100644 --- a/packages/testing/src/execution_testing/exceptions/exceptions/transaction.py +++ b/packages/testing/src/execution_testing/exceptions/exceptions/transaction.py @@ -153,6 +153,10 @@ class TransactionException(ExceptionBase): """ Transaction's initcode for a contract-creating transaction is too large. """ + TYPE_1_TX_PRE_FORK = auto() + """Transaction type 1 included before activation fork.""" + TYPE_2_TX_PRE_FORK = auto() + """Transaction type 2 included before activation fork.""" TYPE_3_TX_PRE_FORK = auto() """Transaction type 3 included before activation fork.""" TYPE_3_TX_ZERO_BLOBS_PRE_FORK = auto() diff --git a/tests/berlin/eip2930_access_list/test_tx_type.py b/tests/berlin/eip2930_access_list/test_tx_type.py new file mode 100644 index 0000000000..227a62a25a --- /dev/null +++ b/tests/berlin/eip2930_access_list/test_tx_type.py @@ -0,0 +1,91 @@ +"""Test the tx type validation for EIP-2930.""" + +import pytest +from execution_testing import ( + Account, + Alloc, + Environment, + Fork, + StateTestFiller, + Transaction, + TransactionException, +) +from execution_testing import Opcodes as Op +from execution_testing.forks import Berlin, Byzantium +from requests_cache import Callable + +from .spec import ref_spec_2930 + +REFERENCE_SPEC_GIT_PATH = ref_spec_2930.git_path +REFERENCE_SPEC_VERSION = ref_spec_2930.version + + +@pytest.fixture +def eip2930_tx_validity_test( + state_test: StateTestFiller, pre: Alloc, fork: Fork, env: Environment +) -> Callable[[], None]: + """ + Returns a function which applies a `state_test`, where a typed transaction + is either valid and has an effect on state or not, depending on the fork. + """ + + def test_function() -> None: + valid = fork >= Berlin + + account = pre.deploy_contract( + code=Op.SSTORE(0, 1), + storage={0: 0xDEADBEEF}, + ) + sender = pre.fund_eoa() + + tx = Transaction( + to=account, + sender=sender, + gas_limit=100_000, + access_list=[], + protected=fork >= Byzantium, + error=TransactionException.TYPE_1_TX_PRE_FORK + if not valid + else None, + ) + + post = {account: Account(storage={0: 0xDEADBEEF if not valid else 1})} + if not valid: + post[sender] = pre[sender] # type: ignore + + state_test(env=env, pre=pre, post=post, tx=tx) + + return test_function + + +@pytest.mark.ported_from( + [ + "https://github.com/ethereum/legacytests/blob/master/src/LegacyTests/Cancun/GeneralStateTestsFiller/stExample/accessListExampleFiller.yml" + ], + pr=["https://github.com/ethereum/execution-specs/pull/1754"], +) +@pytest.mark.exception_test +@pytest.mark.valid_until("Istanbul") +def test_eip2930_tx_invalid( + eip2930_tx_validity_test: Callable[[], None], +) -> None: + """ + Tests that an EIP-2930 tx has no effect before Berlin. + """ + eip2930_tx_validity_test() + + +@pytest.mark.ported_from( + [ + "https://github.com/ethereum/legacytests/blob/master/src/LegacyTests/Cancun/GeneralStateTestsFiller/stExample/accessListExampleFiller.yml" + ], + pr=["https://github.com/ethereum/execution-specs/pull/1754"], +) +@pytest.mark.valid_from("Berlin") +def test_eip2930_tx_valid( + eip2930_tx_validity_test: Callable[[], None], +) -> None: + """ + Tests that an EIP-2930 tx has an effect after Berlin. + """ + eip2930_tx_validity_test() diff --git a/tests/london/__init__.py b/tests/london/__init__.py new file mode 100644 index 0000000000..e2cf7b60f5 --- /dev/null +++ b/tests/london/__init__.py @@ -0,0 +1 @@ +"""Test cases for EVM functionality introduced in London.""" diff --git a/tests/london/eip1559_fee_market_change/__init__.py b/tests/london/eip1559_fee_market_change/__init__.py new file mode 100644 index 0000000000..ffcf07efa0 --- /dev/null +++ b/tests/london/eip1559_fee_market_change/__init__.py @@ -0,0 +1,3 @@ +""" +Tests for [EIP-1559: Fee market change for ETH 1.0 chain](https://eips.ethereum.org/EIPS/eip-1559). +""" diff --git a/tests/london/eip1559_fee_market_change/spec.py b/tests/london/eip1559_fee_market_change/spec.py new file mode 100644 index 0000000000..0e9d0a59f8 --- /dev/null +++ b/tests/london/eip1559_fee_market_change/spec.py @@ -0,0 +1,16 @@ +"""Defines EIP-1559 specification constants and functions.""" + +from dataclasses import dataclass + + +@dataclass(frozen=True) +class ReferenceSpec: + """Defines the reference spec version and git path.""" + + git_path: str + version: str + + +ref_spec_1559 = ReferenceSpec( + "EIPS/eip-1559.md", "ba6c342c23164072adb500c3136e3ae6eabff306" +) diff --git a/tests/london/eip1559_fee_market_change/test_tx_type.py b/tests/london/eip1559_fee_market_change/test_tx_type.py new file mode 100644 index 0000000000..4ff52d099c --- /dev/null +++ b/tests/london/eip1559_fee_market_change/test_tx_type.py @@ -0,0 +1,91 @@ +"""Test the tx type validation for EIP-1559.""" + +import pytest +from execution_testing import ( + Account, + Alloc, + Environment, + Fork, + StateTestFiller, + Transaction, + TransactionException, +) +from execution_testing import Opcodes as Op +from execution_testing.forks import Byzantium, London +from requests_cache import Callable + +from .spec import ref_spec_1559 + +REFERENCE_SPEC_GIT_PATH = ref_spec_1559.git_path +REFERENCE_SPEC_VERSION = ref_spec_1559.version + + +@pytest.fixture +def eip1559_tx_validity_test( + state_test: StateTestFiller, pre: Alloc, fork: Fork, env: Environment +) -> Callable[[], None]: + """ + Returns a function which applies a `state_test`, where a typed transaction + is either valid and has an effect on state or not, depending on the fork. + """ + + def test_function() -> None: + valid = fork >= London + + account = pre.deploy_contract( + code=Op.SSTORE(0, 1), + storage={0: 0xDEADBEEF}, + ) + sender = pre.fund_eoa() + + tx = Transaction( + to=account, + sender=sender, + gas_limit=100_000, + max_priority_fee_per_gas=1, + protected=fork >= Byzantium, + error=TransactionException.TYPE_2_TX_PRE_FORK + if not valid + else None, + ) + + post = {account: Account(storage={0: 0xDEADBEEF if not valid else 1})} + if not valid: + post[sender] = pre[sender] # type: ignore + + state_test(env=env, pre=pre, post=post, tx=tx) + + return test_function + + +@pytest.mark.ported_from( + [ + "https://github.com/ethereum/legacytests/blob/master/Cancun/GeneralStateTests/stEIP1559/typeTwoBerlin.json" + ], + pr=["https://github.com/ethereum/execution-specs/pull/1754"], +) +@pytest.mark.exception_test +@pytest.mark.valid_until("Berlin") +def test_eip1559_tx_invalid( + eip1559_tx_validity_test: Callable[[], None], +) -> None: + """ + Tests that an EIP-1559 tx has no effect before London. + """ + eip1559_tx_validity_test() + + +@pytest.mark.ported_from( + [ + "https://github.com/ethereum/legacytests/blob/master/Cancun/GeneralStateTests/stEIP1559/typeTwoBerlin.json" + ], + pr=["https://github.com/ethereum/execution-specs/pull/1754"], +) +@pytest.mark.valid_from("London") +def test_eip1559_tx_valid( + eip1559_tx_validity_test: Callable[[], None], +) -> None: + """ + Tests that an EIP-1559 tx has an effect after London. + """ + eip1559_tx_validity_test() diff --git a/tests/static/state_tests/stEIP1559/typeTwoBerlinFiller.yml b/tests/static/state_tests/stEIP1559/typeTwoBerlinFiller.yml deleted file mode 100644 index 389580ac6c..0000000000 --- a/tests/static/state_tests/stEIP1559/typeTwoBerlinFiller.yml +++ /dev/null @@ -1,60 +0,0 @@ -typeTwoBerlin: - _info: - comment: Ori Pomerantz qbzzt1@gmail.com - - env: - currentCoinbase: 2adc25665018aa1fe0e6bc666dac8fc2697ff9ba - currentDifficulty: 0x20000 - currentGasLimit: 0xFF112233445566 - currentNumber: 1 - currentTimestamp: 1000 - currentBaseFee: 1000 - - - pre: - : - balance: '1000000000000000000' - code: | - :yul berlin - { - sstore(0, add(1,1)) - } - nonce: '0' - storage: {} - - : - balance: '1000000000000000000' - code: '0x' - nonce: 1 - storage: {} - - - transaction: - data: - - data: :label declaredKeyWrite :raw 0x00 - accessList: [] - maxFeePerGas: 1000 - maxPriorityFeePerGas: 1000 - gasLimit: - - '400000' - nonce: 1 - to: - value: - - '100000' - secretKey: "" - - - expect: - - - indexes: - data: !!int -1 - gas: !!int -1 - value: !!int -1 - - network: - - '>=Cancun' - result: - : - storage: - 0: 2 - diff --git a/tests/static/state_tests/stExample/accessListExampleFiller.yml b/tests/static/state_tests/stExample/accessListExampleFiller.yml deleted file mode 100644 index 67b8469168..0000000000 --- a/tests/static/state_tests/stExample/accessListExampleFiller.yml +++ /dev/null @@ -1,66 +0,0 @@ -accessListExample: - _info: - comment: A test shows accessList transaction example - - env: - currentCoinbase: 2adc25665018aa1fe0e6bc666dac8fc2697ff9ba - currentDifficulty: 0x20000 - currentGasLimit: 0xFF112233445566 - currentNumber: 1 - currentTimestamp: 1000 - - expect: - - network: - - '>=Cancun' - result: - : - storage: - 0x00: 2 - - - - pre: - : - balance: '1000000000000000000' - code: | - { - ; Can also add lll style comments here - [[0]] (ADD 1 1) - } - nonce: '0' - storage: {} - - : - balance: '1000000000000000000' - code: '0x' - nonce: '0' - storage: {} - - - transaction: - data: - - data: :label declaredKeyWrite :raw 0x00 - accessList: - - address: - storageKeys: - - 0x00 - - 0x01 - - address: 0x195e7baea6a6c7c4c2dfeb977efac326af552d87 - storageKeys: - - 0x00 - - - data: :label declaredKeyWrite2 :raw 0x00 - accessList: - - address: 0x195e7baea6a6c7c4c2dfeb977efac326af552d87 - storageKeys: - - 0x00 - - gasLimit: - - '400000' - gasPrice: '10' - nonce: '0' - to: - value: - - '100000' - secretKey: "" -