Skip to content

rpc : fix eth_simulateV1 has storage ram batch#20293

Merged
lupin012 merged 15 commits into
mainfrom
lupin012/fix_simulation_has_storage_ram_batch
Apr 12, 2026
Merged

rpc : fix eth_simulateV1 has storage ram batch#20293
lupin012 merged 15 commits into
mainfrom
lupin012/fix_simulation_has_storage_ram_batch

Conversation

@lupin012

@lupin012 lupin012 commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

SimulationIntraBlockStateReader, used by eth_simulateV1, implements HasStorage by querying only RangeAsOf(firstMinTxNum), which reflects the canonical state at the start of the first simulated block. Storage written by prior simulated blocks lives exclusively in the RAM batch (sd.GetMemBatch()) and is invisible to RangeAsOf. When a subsequent simulated block calls HasStorage on a newly deployed contract, it incorrectly returns false.

The concrete impact: EIP-7610 requires CREATE/CREATE2 to revert if the target address already has storage but no code/nonce (collision detection). With the bug, the collision is not detected and CREATE2 succeeds where it should fail.

Fix: added HasPrefixInRAM to the TemporalMemBatch interface, scanning only the in-memory btree for StorageDomain without touching disk. HasStorage now checks the RAM batch first before falling back to RangeAsOf.

lupin012 and others added 9 commits April 2, 2026 19:28
… prior simulated blocks

simulationIntraBlockStateReader.HasStorage only queried RangeAsOf(firstMinTxNum),
missing storage written to the in-memory RAM batch by prior simulated blocks.
This caused false negatives for newly deployed contracts, breaking EIP-7610
CREATE2 collision detection in multi-block simulations.

Fix: add HasPrefixInRAM to TemporalMemBatch interface and implement it as a
btree-only scan (no disk I/O) for StorageDomain. HasStorage now checks the
RAM batch first before falling back to RangeAsOf.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Override called FinalizeTx(rules, NoopWriter) to clear the journal after
applying state overrides. For any account that became empty (nonce=0, code=0x,
balance=0) after the override, FinalizeTx triggered EIP-161 empty-account
removal: DeleteAccount was discarded by NoopWriter but stateObject.deleted was
set to true. This caused IntraBlockState.HasStorage to short-circuit to false
before reaching the state reader, breaking EIP-7610 CREATE2 collision detection
in multi-block eth_simulateV1.

Fix: use SoftFinalise instead of FinalizeTx(NoopWriter). SoftFinalise clears
the journal (preventing revert from undoing overrides) without triggering
EIP-161 account deletion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Override called FinalizeTx(rules, NoopWriter) to flush dirty storage into
originStorage (needed for correct SSTORE gas). However, EIP-161 empty-account
removal also fired: any account that became empty (nonce=0, code=0x, balance=0)
after the override was marked deleted=true in the IBS, even though the deletion
was discarded by NoopWriter. This caused IntraBlockState.HasStorage to
short-circuit to false before reaching the state reader, breaking EIP-7610
CREATE2 collision detection in multi-block eth_simulateV1 when a prior
simulated block had deployed a contract at the overridden address.

Fix: copy rules and set IsSpuriousDragon=false before passing to FinalizeTx.
This preserves the originStorage commit (gas correctness) while preventing
EIP-161 from deleting accounts during stateOverride processing. State overrides
are simulation-only mutations and must not trigger consensus rules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… accounts

In multi-block eth_simulateV1 simulations, stateOverrides.Override calls
FinalizeTx which marks overridden accounts as dirty in stateObjectsDirty.
CommitBlock's MakeWriteSet then iterates all stateObjects and applies EIP-161
to every dirty account — so an override-only account with nonce=0/code=empty
is spuriously deleted, which also wipes its storage via DomainDelPrefix.

Fix: after Override, snapshot and clear stateObjectsDirty
(ExtractAndClearDirty) so CommitBlock only sees transaction-touched accounts.
After CommitBlock, CommitOverrideDirtyAccounts writes the override-only
accounts with EIP-161 disabled, preserving their state in the simulation.

This fixes the stateRoot mismatch in test_28 where a CREATE2-deployed
contract's storage survived across blocks as a collision target.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ExtractAndClearDirty: use maps.Clone instead of manual copy loop
- CommitOverrideDirtyAccounts: pass false directly to updateAccount instead
  of going through a noEIP161Rules intermediate copy
- HasPrefixInRAM non-StorageDomain path: use strings.HasPrefix to avoid
  []byte(k) allocation per entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lupin012 lupin012 added the RPC label Apr 3, 2026
@lupin012 lupin012 marked this pull request as ready for review April 5, 2026 05:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes multi-block eth_simulateV1 state visibility issues so collision detection (EIP-7610 CREATE/CREATE2 rules) correctly observes storage written by prior simulated blocks, including storage that exists only in the in-memory (RAM) batch.

Changes:

  • Add a RAM-only prefix check to TemporalMemBatch and use it in simulationIntraBlockStateReader.HasStorage before falling back to canonical RangeAsOf.
  • Prevent state override finalization from triggering EIP-161 empty-account removal side effects, and ensure override-only accounts are still written during block commit.
  • Add a regression test covering the RAM-batch HasStorage behavior; bump RPC workflow test version to v2.5.0.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
rpc/jsonrpc/eth_simulation.go Ensures override-only accounts aren’t dropped by CommitBlock (EIP-161) and updates HasStorage to check RAM-batch prefixes first.
rpc/jsonrpc/eth_simulation_intrablock_test.go New regression test verifying HasStorage sees storage written only to the RAM batch across simulated blocks.
rpc/ethapi/state_overrides.go Finalizes overrides without SpuriousDragon/EIP-161 empty-account removal to avoid spurious deleted=true flags in simulation.
execution/state/intra_block_state.go Adds helpers to snapshot/clear dirty-account tracking and to commit override-only dirty accounts with EIP-161 disabled.
db/state/temporal_mem_batch.go Implements HasPrefixInRAM for fast RAM-only prefix existence checks (esp. StorageDomain btree).
db/kv/kv_interface.go Extends TemporalMemBatch interface with HasPrefixInRAM.
.github/workflows/scripts/run_rpc_tests_remote_ethereum.sh Updates RPC test suite version to v2.5.0.
.github/workflows/scripts/run_rpc_tests_gnosis.sh Updates RPC test suite version to v2.5.0.
.github/workflows/scripts/run_rpc_tests_ethereum.sh Updates RPC test suite version to v2.5.0.
.github/workflows/scripts/run_rpc_tests_ethereum_latest.sh Updates RPC test suite version to v2.5.0.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rpc/jsonrpc/eth_simulation_intrablock_test.go
Comment thread db/state/temporal_mem_batch.go
@yperbasis yperbasis added this to the 3.5.0 milestone Apr 7, 2026
lupin012 and others added 4 commits April 7, 2026 19:02
- HasPrefixInRAM: use ToStringZeroCopy consistently in both branches
  (StorageDomain btree and domain map) to avoid per-call heap allocations;
  also eliminate the redundant byte→string→byte round-trip in the btree loop
- eth_simulation_intrablock_test: add t.Cleanup(tdb.Close) to prevent
  resource leak across the test suite

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lupin012 lupin012 enabled auto-merge April 12, 2026 05:28
@lupin012 lupin012 added this pull request to the merge queue Apr 12, 2026
Merged via the queue into main with commit fa708fc Apr 12, 2026
35 checks passed
@lupin012 lupin012 deleted the lupin012/fix_simulation_has_storage_ram_batch branch April 12, 2026 07:08
AskAlexSharov added a commit that referenced this pull request Apr 13, 2026
@yperbasis yperbasis modified the milestones: 3.5.0, 3.4.0 Apr 13, 2026
AskAlexSharov added a commit that referenced this pull request Apr 13, 2026
Cherry-pick of #20293 from main.

Fixes EIP-7610 collision detection in multi-block eth_simulateV1:
storage written by prior simulated blocks lives in the RAM batch and was
invisible to HasStorage.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants