feat(tests): EIP-8037 - CALL with value to selfdestructed account#2646
Merged
spencer-tb merged 2 commits intoApr 19, 2026
Conversation
58a639c to
d2a6c58
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## eips/amsterdam/eip-8037 #2646 +/- ##
==========================================================
Coverage ? 88.18%
==========================================================
Files ? 524
Lines ? 31120
Branches ? 3036
==========================================================
Hits ? 27444
Misses ? 3161
Partials ? 515
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
b9f0afa to
23a638d
Compare
d2a6c58 to
e42ab1f
Compare
e42ab1f to
ef6a264
Compare
629b34b to
9755dba
Compare
5 tasks
ef6a264 to
d4ffd74
Compare
9755dba to
3e1d7c4
Compare
ba78c62 to
7286786
Compare
3e1d7c4 to
44b47cc
Compare
7286786 to
5cf982e
Compare
ddfdb0d
into
ethereum:eips/amsterdam/eip-8037
12 of 15 checks passed
4 tasks
spencer-tb
added a commit
to spencer-tb/execution-specs
that referenced
this pull request
Apr 19, 2026
…efund EIP-11532 (merged as PR ethereum#2707) refunds the CREATE's `GAS_NEW_ACCOUNT` at end-of-tx when the created account is also destroyed in the same transaction. This broke three tests in `test_state_gas_call.py` (added by PR ethereum#2646 before ethereum#2707 merged) that asserted `header.gas_used == new_account_state_gas`; after the refund `block_state_gas_used` is zero and the header reports `block_regular` instead. Affected tests (20 variants): test_call_value_to_self_destructed_header_gas_used test_call_value_to_self_destructed_burns_value test_call_zero_value_to_self_destructed_same_tx_account The original discriminator intent (no spurious GAS_NEW_ACCOUNT charge on the CALL) still holds: a buggy extra charge would push `state_gas_used` to 131,488 and bump the header above `new_account_state_gas`. Pin the expected `header.gas_used` to the empirical `block_regular` per variant, with a build-time `assert expected < new_account_state_gas` so the spurious-charge discriminator stays sharp.
4 tasks
spencer-tb
added a commit
to spencer-tb/execution-specs
that referenced
this pull request
Apr 20, 2026
…efund EIP-11532 (merged as PR ethereum#2707) refunds the CREATE's `GAS_NEW_ACCOUNT` at end-of-tx when the created account is also destroyed in the same transaction. This broke three tests in `test_state_gas_call.py` (added by PR ethereum#2646 before ethereum#2707 merged) that asserted `header.gas_used == new_account_state_gas`; after the refund `block_state_gas_used` is zero and the header reports `block_regular` instead. Affected tests (20 variants): test_call_value_to_self_destructed_header_gas_used test_call_value_to_self_destructed_burns_value test_call_zero_value_to_self_destructed_same_tx_account The original discriminator intent (no spurious GAS_NEW_ACCOUNT charge on the CALL) still holds: a buggy extra charge would push `state_gas_used` to 131,488 and bump the header above `new_account_state_gas`. Pin the expected `header.gas_used` to the empirical `block_regular` per variant, with a build-time `assert expected < new_account_state_gas` so the spurious-charge discriminator stays sharp.
4 tasks
spencer-tb
added a commit
to spencer-tb/execution-specs
that referenced
this pull request
Apr 20, 2026
EIP-11532 (merged as ethereum#2707) refunds the CREATE's `GAS_NEW_ACCOUNT` at end-of-tx when the created account is also destroyed in the same transaction. Three tests in `test_state_gas_call.py` (added by ethereum#2646 before ethereum#2707 merged) asserted `header.gas_used == new_account_state_gas`; after the refund `block_state_gas_used` is zero, so the header reports `block_regular` instead and those assertions fail. Drop the brittle `header_verify` from the three tests. Remaining post-state checks still validate the semantics each test cares about. Affected (20 variants across `blockchain_test` and `blockchain_test_engine`): test_call_value_to_self_destructed_header_gas_used test_call_value_to_self_destructed_burns_value test_call_zero_value_to_self_destructed_same_tx_account
spencer-tb
added a commit
to spencer-tb/execution-specs
that referenced
this pull request
Apr 21, 2026
…hereum#2646) Co-authored-by: spencer-tb <spencer.tb@ethereum.org>
spencer-tb
added a commit
to spencer-tb/execution-specs
that referenced
this pull request
Apr 21, 2026
…hereum#2646) Co-authored-by: spencer-tb <spencer.tb@ethereum.org>
9 tasks
spencer-tb
added a commit
to spencer-tb/execution-specs
that referenced
this pull request
May 22, 2026
…hereum#2646) Co-authored-by: spencer-tb <spencer.tb@ethereum.org>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🗒️ Description
Adds test coverage for CALL with value to an account that was selfdestructed (per EIP-6780), both the same transaction case and the pre existing case. No spec change: EIP-8037 and EIP-6780 together already produce the correct behavior, and this PR documents it with strict
header_verifydiscriminators.Related EIP spec clarification: ethereum/EIPs#11532 (point 5).
Behavior under test
When an account is created and then selfdestructed in the same transaction, EIP-6780 defers deletion to the end of the transaction. During the transaction the account still has
nonce = 1from the CREATE, so it is neither empty nor nonexistent and the new account creation gate does not fire on a subsequent CALL with value, noGAS_NEW_ACCOUNTstate gas is charged. End of the transaction destruction still removes the account regardless of any value received after SELFDESTRUCT, so value transferred by the CALL is burned along with the destroyed account. Combined with the same transaction SELFDESTRUCT state gas refund (#2707), the net state gas across theCREATE + SELFDESTRUCT + CALL(value)lifecycle is zero.For a pre existing contract that runs SELFDESTRUCT, EIP-6780 does not queue it for destruction, so a subsequent CALL sees an existing, code carrying account and the new account creation gate does not fire either.
Tests
All in
tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_call.py. Theinit_code_at_high_byteshelper is moved tospec.pyfor reuse with the related PR #2707.test_call_value_to_self_destructed_same_tx_account, smoke test parametrizedcreate_opcode=[CREATE, CREATE2]. Confirms the happy path runs to completion. Strict discrimination lives intest_call_value_to_self_destructed_header_gas_used.test_call_value_to_self_destructed_header_gas_used, strictheader_verifydiscriminator parametrizedcreate_opcode=[CREATE, CREATE2]×selfdestruct_beneficiary=[self, external]. Block headergas_usedequals exactly oneGAS_NEW_ACCOUNT(only the CREATE's state charge), proving no second charge from the CALL.test_call_value_to_self_destructed_burns_value, strictheader_verifyparametrizedcreate_opcode=[CREATE, CREATE2]×call_value=[1 wei, 1 ether]. Block header gas used equals oneGAS_NEW_ACCOUNT. Post state asserts the created address isNONEXISTENTand the orchestrator balance is zero, proving the value is burned when end of the transaction destruction runs.test_call_zero_value_to_self_destructed_same_tx_account, strictheader_verifyparametrizedcreate_opcode=[CREATE, CREATE2]. Value transfer gates the new account charge, so a zero value CALL never triggers it. Block header equals oneGAS_NEW_ACCOUNT.test_call_value_to_pre_existing_selfdestructed_account, strictheader_verifyparametrizedbeneficiary_type=[eoa, contract]. Pre deployed contract runs SELFDESTRUCT, then the orchestrator does a value bearing CALL and a sequence of cold SSTORE probes that make block state gas dominate. Block header gas used equalsnum_probes * sstore_state_gasexactly. A spurious new account charge on the value bearing CALL would push the header up by that charge.🔗 Related Issues or PRs
✅ Checklist
just statictype(scope):.