🐛 fix(state): fall back to scalar RPCs when fork lacks eth_getProof - #2093
🐛 fix(state): fall back to scalar RPCs when fork lacks eth_getProof#2093ebramanti wants to merge 1 commit into
eth_getProof#2093Conversation
|
@ebramanti is attempting to deploy a commit to the evmts Team on Vercel. A member of the Team first needs to authorize it. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthrough
ChangesFork account hydration
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant getAccountFromProvider
participant ForkTransport
participant ContractCodeCache
getAccountFromProvider->>ForkTransport: eth_getProof
ForkTransport-->>getAccountFromProvider: unsupported-method error
getAccountFromProvider->>ForkTransport: balance, nonce, and code at fork block
ForkTransport-->>getAccountFromProvider: scalar account data
getAccountFromProvider->>ContractCodeCache: prime contract-code cache
getAccountFromProvider-->>getAccountFromProvider: compute codeHash and create account
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
eth_getProof
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/state/src/actions/getAccountFromProvider.spec.ts (1)
79-296: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd explicit return types to the new functions.
Add an explicit object return type to
createRecordingTransport. AddnumbertomethodCount. AddPromise<void>to each new asyncitcallback.As per coding guidelines,
**/*.{ts,tsx}: “We always explicitly type return types.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/state/src/actions/getAccountFromProvider.spec.ts` around lines 79 - 296, The new helper and test callbacks lack explicit return types. Update createRecordingTransport with its concrete object return type, annotate methodCount as returning number, and annotate every async it callback in the scalar fallback describe block with Promise<void>.Source: Coding guidelines
packages/state/src/actions/getAccountFromProvider.js (1)
14-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winComplete the JSDoc for both functions.
Add working
@exampleblocks with imports. Document propagated errors with@throwsforisMethodUnavailableErrorandgetAccountFromProvider.As per coding guidelines,
**/*.js: “We always include complete jsdoc information including@throws@exampleetc.”Also applies to: 37-48
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/state/src/actions/getAccountFromProvider.js` around lines 14 - 23, Complete the JSDoc for both isMethodUnavailableError and getAccountFromProvider by adding import-based, working `@example` blocks and documenting propagated errors with `@throws`. Keep the existing descriptions and behavior unchanged, and ensure each example reflects the actual function API.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/state/src/actions/getAccountFromProvider.js`:
- Around line 29-30: Update the error-message predicate in
getAccountFromProvider to accept “unavailable” method wording, including “Method
unavailable” and “method is unavailable,” alongside the existing not
available/found/supported patterns while retaining the -32600 requirement. Add a
matching test next to the Monad case verifying these messages use the scalar
fallback instead of being rethrown.
---
Nitpick comments:
In `@packages/state/src/actions/getAccountFromProvider.js`:
- Around line 14-23: Complete the JSDoc for both isMethodUnavailableError and
getAccountFromProvider by adding import-based, working `@example` blocks and
documenting propagated errors with `@throws`. Keep the existing descriptions and
behavior unchanged, and ensure each example reflects the actual function API.
In `@packages/state/src/actions/getAccountFromProvider.spec.ts`:
- Around line 79-296: The new helper and test callbacks lack explicit return
types. Update createRecordingTransport with its concrete object return type,
annotate methodCount as returning number, and annotate every async it callback
in the scalar fallback describe block with Promise<void>.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: dfc2b737-5948-420a-b7e0-a2b0c0bb0fa4
📒 Files selected for processing (3)
.changeset/proud-otters-prove.mdpackages/state/src/actions/getAccountFromProvider.jspackages/state/src/actions/getAccountFromProvider.spec.ts
Fork account hydration previously required an empty-storageKeys eth_getProof from the fork provider — the only RPC path for loading an account's balance/nonce/codeHash/storageRoot. Chains that do not serve eth_getProof (Monad mainnet, ZKsync OS, Moonbeam) therefore failed on the first touch of any uncached account. getAccountFromProvider now probes eth_getProof once per fork transport and, on a method-unavailable error (-32601, -32004, or -32600 with a 'not available/found/supported' message, matched across the viem cause chain), permanently downgrades that transport to three concurrent scalar calls — eth_getBalance + eth_getTransactionCount + eth_getCode — pinned to the same fork block. codeHash is computed locally via keccak256(code); storageRoot defaults to the canonical empty trie root, which EVM execution never reads (storage is fetched per-slot via eth_getStorageAt) and which exactly satisfies getAccount's nonexistent-account predicate. This is the same fork mechanism used by Foundry, Hardhat/EDR, and Ganache. The fetched bytecode primes both contract-code caches, so the fallback costs no extra round trips versus the proof path once code is needed. The capability flag is a module-level WeakMap keyed by the fork transport object (reference-stable across state-manager deep/shallow copies), so the downgrade survives the per-call VM clone in tevmCall. All other errors rethrow unchanged; uncoded errors never trigger the downgrade. The public eth_getProof action and light-client reads are unaffected and continue to fail honestly on such chains. Verified: full @tevm/state suite (157 passed) with coverage gates; end-to-end smoke via createTevmNode against a deterministic Monad-shaped mock (probe → fallback → sticky, one eth_getProof total) and against live Monad mainnet (chainId 143): WMON codeHash === keccak256(eth_getCode), block-pinned balance parity with direct RPC, nonexistent account → AccountNotFound.
cba1061 to
26332f6
Compare
🦋 Changeset detectedLatest commit: 26332f6 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
Description
Fork account hydration falls back to
eth_getBalance+eth_getTransactionCount+eth_getCodeon providers that do not serveeth_getProof.Motivation
Tevm's fork mode hydrates every uncached remote account through a single empty-
storageKeyseth_getProofcall ingetAccountFromProvider— the only RPC path for loading an account's balance/nonce/codeHash/storageRoot. Some EVM chains do not serveeth_getProofat all, so a fork starts fine (startup only needseth_chainId+eth_getBlockByNumber) and then dies on the first touch of any uncached account — the firsttevmCall,tevmSetAccount,tevmDeal, oreth_createAccessList.Monad mainnet (chainId 143) does not serve
eth_getProofon any provider, so tevm cannot fork it today. The gap is not Monad-specific — ZKsync OS chains officially don't support it and Moonbeam lists it as unsupported — while all of them serve the scalar quartet (eth_getBalance/eth_getTransactionCount/eth_getCode/eth_getStorageAt).Tevm is the outlier here only because it inherited EthereumJS
RPCStateManager's proof-coupled loader. Every other major fork simulator already uses the scalar mechanism this PR falls back to:get_balance+get_transaction_count+get_code_at, with its own availability downgrade (ACCOUNT_FETCH_SEPARATE_REQUESTS) (foundry-fork-db backend.rs)tokio::try_join!and synthesizescode_hash: Bytecode::hash_slow(code)(edr client.rs)codeHash = keccak(code)computed locallyChange
getAccountFromProviderstill prefers the single-round-tripeth_getProof. On a method-unavailable error —-32601,-32004, or-32600with a "not available/found/supported" message, matched across the error cause chain via viem'sBaseError.walk— it permanently downgrades that fork transport to the three concurrent scalar calls, pinned to the same resolved fork block. All other errors rethrow unchanged; uncoded errors (network failures wrapped asUnknownRpcError) never trigger the downgrade. The fetched bytecode primes both contract-code caches, and the publiceth_getProofaction and light-client verified reads are untouched.Additional Information
Summary by CodeRabbit
New Features
Bug Fixes