From 80dbc0aff1e958337e096202b42234ae4cfe5832 Mon Sep 17 00:00:00 2001 From: Felix H Date: Thu, 11 Jun 2026 17:26:42 +0200 Subject: [PATCH 1/4] feat: test for nethermind statetest crash reproduction --- tests/frontier/touch/test_touch.py | 50 ++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/frontier/touch/test_touch.py b/tests/frontier/touch/test_touch.py index 6a70146af72..3a928251ceb 100644 --- a/tests/frontier/touch/test_touch.py +++ b/tests/frontier/touch/test_touch.py @@ -43,3 +43,53 @@ def test_zero_gas_price_and_touching( tx=tx, post={contract: Account(storage={0: value})}, ) + + +@pytest.mark.valid_from("Frontier") +@pytest.mark.valid_before("EIP1559") +@pytest.mark.eels_base_coverage +def test_zero_gas_price_nonexistent_sender( + state_test: StateTestFiller, + pre: Alloc, +) -> None: + """ + Test a zero gasprice, zero value transaction from a sender that does not + exist in the pre-state. + + Because the transaction is free (gas_price=0) and transfers no value, no + balance is ever deducted from the sender, so the sender account is only + materialized when its nonce is incremented. Clients must create the sender + account in this case rather than failing on a missing account. + + Triggers a Nethermind state-test-runner crash: the runner identifies the + sender by secret key but signs the tx with a placeholder signature. When + the sender is absent from the pre-state, RecoverSenderIfNeeded re-recovers + a bogus sender from that placeholder, never creates it, and the nonce + increment then dereferences a null account. Not reachable in production, + where the real signature recovers the correct (and created) sender. + """ + # amount=0 means the sender is NOT added to the pre-alloc. + sender = pre.fund_eoa(amount=0) + + contract = pre.deploy_contract( + code=(Op.SSTORE(0, 0x01) + Op.STOP), + ) + + tx = Transaction( + gas_limit=500_000, + to=contract, + gas_price=0, # Part of the test, do not change. + value=0, # Part of the test, do not change. + sender=sender, + protected=False, + ) + + state_test( + env=Environment(), + pre=pre, + tx=tx, + post={ + contract: Account(storage={0: 0x01}), + sender: Account(nonce=1, balance=0), + }, + ) From c8a69edfe9da6e269bc5faabff4a6ea450eb9c8e Mon Sep 17 00:00:00 2001 From: felix Date: Fri, 12 Jun 2026 16:03:41 +0200 Subject: [PATCH 2/4] Update tests/frontier/touch/test_touch.py Co-authored-by: spencer --- tests/frontier/touch/test_touch.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/frontier/touch/test_touch.py b/tests/frontier/touch/test_touch.py index 3a928251ceb..872d332f5ea 100644 --- a/tests/frontier/touch/test_touch.py +++ b/tests/frontier/touch/test_touch.py @@ -61,12 +61,6 @@ def test_zero_gas_price_nonexistent_sender( materialized when its nonce is incremented. Clients must create the sender account in this case rather than failing on a missing account. - Triggers a Nethermind state-test-runner crash: the runner identifies the - sender by secret key but signs the tx with a placeholder signature. When - the sender is absent from the pre-state, RecoverSenderIfNeeded re-recovers - a bogus sender from that placeholder, never creates it, and the nonce - increment then dereferences a null account. Not reachable in production, - where the real signature recovers the correct (and created) sender. """ # amount=0 means the sender is NOT added to the pre-alloc. sender = pre.fund_eoa(amount=0) From 970eb65cbf9cde088a35ce8a45348da5e41a13ce Mon Sep 17 00:00:00 2001 From: felix Date: Fri, 12 Jun 2026 16:04:25 +0200 Subject: [PATCH 3/4] Update tests/frontier/touch/test_touch.py Co-authored-by: spencer --- tests/frontier/touch/test_touch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/frontier/touch/test_touch.py b/tests/frontier/touch/test_touch.py index 872d332f5ea..d6e55c35593 100644 --- a/tests/frontier/touch/test_touch.py +++ b/tests/frontier/touch/test_touch.py @@ -47,7 +47,6 @@ def test_zero_gas_price_and_touching( @pytest.mark.valid_from("Frontier") @pytest.mark.valid_before("EIP1559") -@pytest.mark.eels_base_coverage def test_zero_gas_price_nonexistent_sender( state_test: StateTestFiller, pre: Alloc, From 880fb549e5a0f659c353231d747c7cf553835e12 Mon Sep 17 00:00:00 2001 From: spencer Date: Mon, 15 Jun 2026 12:37:52 +0100 Subject: [PATCH 4/4] Update tests/frontier/touch/test_touch.py --- tests/frontier/touch/test_touch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/frontier/touch/test_touch.py b/tests/frontier/touch/test_touch.py index d6e55c35593..24af5667c61 100644 --- a/tests/frontier/touch/test_touch.py +++ b/tests/frontier/touch/test_touch.py @@ -69,7 +69,6 @@ def test_zero_gas_price_nonexistent_sender( ) tx = Transaction( - gas_limit=500_000, to=contract, gas_price=0, # Part of the test, do not change. value=0, # Part of the test, do not change.