🐛 fix(state): fall back to scalar RPCs when fork lacks eth_getProof - #2094
🐛 fix(state): fall back to scalar RPCs when fork lacks eth_getProof#2094roninjin10 wants to merge 2 commits into
Conversation
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.
Treat both all-zero provider hashes and canonical empty hashes as nonexistent accounts, and cover both representations in regression tests. Guard the proof capability cache and align the new fallback tests with explicit return-type lint rules. Co-authored-by: Edward Bramanti <edward@bramanti.org>
🦋 Changeset detectedLatest commit: f361264 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 |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
📝 WalkthroughWalkthroughFork account hydration now falls back to block-pinned scalar RPC calls when ChangesFork account hydration
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ForkAccountLoader
participant ForkTransport
participant ContractCodeCache
ForkAccountLoader->>ForkTransport: Request eth_getProof at fork block
ForkTransport-->>ForkAccountLoader: Return unsupported-method error
ForkAccountLoader->>ForkTransport: Request balance, transaction count, and code
ForkTransport-->>ForkAccountLoader: Return block-pinned scalar data
ForkAccountLoader->>ContractCodeCache: Store fetched bytecode
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/state/src/actions/getAccountFromProvider.spec.ts (1)
94-94: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd an explicit return type to the mock RPC handler.
Declare the async callback return type, such as
Promise<unknown>or a concrete RPC-result union. This keeps the new test helper type-safe.As per coding guidelines, “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` at line 94, Update the async mock RPC handler passed to request with an explicit return type annotation, using Promise<unknown> or the appropriate concrete RPC-result union. Keep its existing method and params typing and behavior unchanged.Source: Coding guidelines
packages/state/src/actions/getAccountFromProvider.js (1)
14-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winComplete the JSDoc for the new functions.
Add a working
@examplewith required imports to both JSDoc blocks. At Lines 39-51, document propagated RPC failures with@throws.As per coding guidelines, “We always include complete jsdoc information including
@throws@exampleetc.” and “Include imports in examples in JSDoc.”Also applies to: 39-51
🤖 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 - 37, Complete the JSDoc for isMethodUnavailableError and the adjacent exported function covering lines 39–51 by adding runnable `@example` sections with all required imports. Add `@throws` documentation to the latter function for propagated RPC failures, preserving the existing behavior and accurately describing its inputs and return value.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.
Nitpick comments:
In `@packages/state/src/actions/getAccountFromProvider.js`:
- Around line 14-37: Complete the JSDoc for isMethodUnavailableError and the
adjacent exported function covering lines 39–51 by adding runnable `@example`
sections with all required imports. Add `@throws` documentation to the latter
function for propagated RPC failures, preserving the existing behavior and
accurately describing its inputs and return value.
In `@packages/state/src/actions/getAccountFromProvider.spec.ts`:
- Line 94: Update the async mock RPC handler passed to request with an explicit
return type annotation, using Promise<unknown> or the appropriate concrete
RPC-result union. Keep its existing method and params typing and behavior
unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ee75d77e-0adb-40b3-ac4f-4ae30123af6f
📒 Files selected for processing (5)
.changeset/proud-otters-prove.mdpackages/state/src/actions/getAccount.jspackages/state/src/actions/getAccount.spec.tspackages/state/src/actions/getAccountFromProvider.jspackages/state/src/actions/getAccountFromProvider.spec.ts
Supersedes #2093
Closes #2093
Carries Edward Bramanti's scalar RPC fallback forward with the requested correctness and lint follow-ups.
Tests:
Summary by CodeRabbit