fix(evm): skip DB storage lookup for newly-created accounts in inspect_storage#290
Conversation
ReviewThe fix is correct and the explanation in the PR body is thorough. Mirroring revm's One concern: missing automated test. CLAUDE.md requires "Always test logic changes." The test plan's stateless-replay bullet appears to be a manual verification, not an automated test case. The bug is narrow but well-defined — a CREATE landing on a pre-funded address followed by a storage read/write on the new contract within the same transaction — and it would be straightforward to reproduce with the in-process test infrastructure used by the rest of the test suite (e.g., a factory contract that deploys to a pre-funded address and then SSTOREs/SLOADs a slot). Without an automated test, the regression path stays open. |
Codecov Report✅ All modified and coverable lines are covered by tests. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Fixes Journal::inspect_storage to avoid database storage lookups for accounts created within the current transaction, preventing stateless replay failures when a CREATE lands on a pre-funded address and touches storage. This aligns the behavior with upstream revm’s sload_with_account short-circuiting.
Changes:
- Capture
account.is_created()early ininspect_storageto survive later re-borrows. - Short-circuit missing-slot reads to
U256::ZEROfor newly-created accounts instead of callingdb.storage(address, key).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
LGTM. My previous concern about missing an automated test has been addressed — |
Journal::inspect_storagepreviously calledself.database.storage(address, key)for any slot missing from the journal cache, including slots on accounts created within the current transaction.Post-CREATE storage is guaranteed empty (EIP-161 / EIP-6780), so this lookup returns
ZEROin the normal case — but it is unsafe under stateless replay.When CREATE lands on a pre-funded address, the account's cache status is
Loadedrather thanCreated, which bypasses revm's short-circuit inState::storageand forwards the call to the witness backend.The witness backend has no entry for that slot (no pre-state value exists) and the replay fails.
This PR mirrors revm's
sload_with_accountbehavior: captureaccount.is_created()before re-borrowing, then short-circuit toU256::ZEROfor newly-created accounts instead of querying the database.Observable behavior of this function is unchanged for every spec: the old code path also resolved to
ZERO(via the DB), and the new path returnsZEROdirectly — the only difference is that no DB call is issued for newly-created accounts.Test plan
cargo test -p mega-evmcargo clippy --workspace --lib --examples --tests --benches --all-features --lockedcargo fmt --all --check