Skip to content

fix(spec-specs): wipe pre-existing storage on contract creation from Cancun onward - #3508

Open
spencer-tb wants to merge 1 commit into
ethereum:forks/amsterdamfrom
spencer-tb:fix/create-collision-storage-clears
Open

fix(spec-specs): wipe pre-existing storage on contract creation from Cancun onward#3508
spencer-tb wants to merge 1 commit into
ethereum:forks/amsterdamfrom
spencer-tb:fix/create-collision-storage-clears

Conversation

@spencer-tb

@spencer-tb spencer-tb commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Description

Contract creation over an account with zero nonce, no code and non-empty storage kept the old storage from Cancun onward, while Frontier through Shanghai wipe it. The older trackers record wiped addresses in storage_clears so reads stop falling back to earlier block writes or the pre-state; the trackers from Cancun onward never had it, and destroy_storage only dropped same-transaction writes. The case became reachable in the spec when #3417 removed the EIP-7610 storage check from account_deployable.

Port storage_clears to the nine trackers from Cancun to Amsterdam so every fork follows the Yellow Paper, which sets the created account's storage to the empty trie, and make the Amsterdam BAL builder read cleared storage as zero when diffing later transactions. The same path covers the deletion of an empty account that still holds storage.

Add storage-only creation tests to test_create_collision.py for the creation transaction and the create opcodes. The initcode stores one more than it loads from a pre-seeded slot, so a wiped target stores 1, a retained one stores 2 and an aborted creation deploys nothing. These are the first fixtures that fail a client still enforcing EIP-7610. That EIP was never activated in any fork: ethereum/tests applied it retroactively in 2024 and clients and EELS followed, so the tests are valid from Frontier like the removal itself.

There is no way to test the removal without also deciding what happens to the old storage. A fixture pins the state and receipts roots, and even an initcode that overwrites every old slot pays different SSTORE gas for a wiped slot than for a retained one. This PR decides for the Yellow Paper wipe. Reading current client code (not verified against binaries): geth master has already dropped the check and keeps the old storage, Nethermind keeps it for a funded target and clears it for an EIP-161-dead one, and Erigon, Besu, Nimbus and EthereumJS clear it. Geth and Nethermind would fail these fixtures today.

The case is unreachable on any live chain. The 28 mainnet accounts of this shape date from before Spurious Dragon, their creator nonces are spent, and reaching one needs a keccak preimage. EIP-8253 (proposed for Hegotá) bumps their nonces so EIP-684 rejects the creation in every client, which ends the question. Until then the fixtures only decide what clients agree to for tests. Slots wiped by the creation that the transaction never touches do not appear in the BAL, since the pre-state cannot enumerate storage; the slot the initcode reads shows up as a storage read.

The new tests pass from Frontier to Amsterdam with the fix and fail on Cancun and Amsterdam without it. The restored pre-EIP-7610 Cancun fixtures from ethereum/legacytests#18 pass through tests/json_loader with the fix, where the Cancun cases failed before.

Related Issues or PRs

Follow-up to #3417 and #3425. Related to ethereum/legacytests#17, ethereum/legacytests#18 and EIP-8253.

Checklist

  • Ran fast static checks to avoid CI fails, see Code Standards & Verifying Changes: just static
  • PR title has the form <type>(<area>): <title>, where <type> and <area> come from an appropriate C-<type>, respectively A-<area>, label. The title should match the target squash commit message.

@spencer-tb spencer-tb added C-bug Category: this is a bug, deviation, or other problem A-spec-specs Area: Specification—The Ethereum specification itself (eg. `src/ethereum/*`) A-tests Area: Consensus tests. labels Sep 2, 2026
@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.02%. Comparing base (ad19524) to head (fd73a4a).
⚠️ Report is 3 commits behind head on forks/amsterdam.

Additional details and impacted files
@@               Coverage Diff                @@
##           forks/amsterdam    #3508   +/-   ##
================================================
  Coverage            94.01%   94.02%           
================================================
  Files                  624      624           
  Lines                36905    36964   +59     
  Branches              3326     3344   +18     
================================================
+ Hits                 34695    34754   +59     
  Misses                1533     1533           
  Partials               677      677           
Flag Coverage Δ
unittests 94.02% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@spencer-tb
spencer-tb marked this pull request as ready for review September 3, 2026 08:55
@gurukamath gurukamath self-assigned this Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-spec-specs Area: Specification—The Ethereum specification itself (eg. `src/ethereum/*`) A-tests Area: Consensus tests. C-bug Category: this is a bug, deviation, or other problem

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants