Skip to content

🐛 fix(state): fall back to scalar RPCs when fork lacks eth_getProof - #2094

Open
roninjin10 wants to merge 2 commits into
mainfrom
shepherd/tevm-monorepo-pr-2093
Open

🐛 fix(state): fall back to scalar RPCs when fork lacks eth_getProof#2094
roninjin10 wants to merge 2 commits into
mainfrom
shepherd/tevm-monorepo-pr-2093

Conversation

@roninjin10

@roninjin10 roninjin10 commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Supersedes #2093

Closes #2093

Carries Edward Bramanti's scalar RPC fallback forward with the requested correctness and lint follow-ups.

  • recognize nonexistent fork accounts under both all-zero provider hashes and canonical empty hashes
  • add dual-encoding regression coverage
  • guard the per-transport WeakMap downgrade cache when no transport is present
  • add explicit return types to the new TypeScript test helpers and callbacks
  • correct the changeset wording

Tests:

  • packages/state: vitest run src/actions/ (30 files, 129 tests passed)
  • packages/memory-client: vitest run src/test (62 files passed, 9 skipped; 146 tests passed, 11 todo)
  • @tevm/state typecheck
  • Biome check on changed source and test files

Summary by CodeRabbit

  • Bug Fixes
    • Improved forked account loading when proof-based retrieval is unavailable.
    • Added fallback retrieval for balances, transaction counts, and contract code while preserving fork-block accuracy.
    • Improved detection of empty and nonexistent accounts across different provider responses.
    • Loaded contract bytecode into the cache during fallback account hydration.
    • Prevented repeated fallback detection for the same connection.

ebramanti and others added 2 commits August 4, 2026 22:58
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-bot

changeset-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f361264

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@tevm/state Patch

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

@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
node Ready Ready Preview Aug 7, 2026 3:23am
tevm-monorepo-app Ready Ready Preview Aug 7, 2026 3:23am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
tevm-monorepo-tevm Ignored Ignored Aug 7, 2026 3:23am

Request Review

@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Fork account hydration now falls back to block-pinned scalar RPC calls when eth_getProof is unavailable. The fallback caches bytecode and preserves unrelated provider errors. Empty-account detection accepts zero-filled and canonical hashes.

Changes

Fork account hydration

Layer / File(s) Summary
Proof capability detection and scalar hydration
packages/state/src/actions/getAccountFromProvider.js
Unsupported eth_getProof errors are detected across nested causes and cached per transport. Fallback requests fetch balance, transaction count, and code at the fork block, then prime contract-code caches.
Empty-account hash handling
packages/state/src/actions/getAccount.js, packages/state/src/actions/getAccount.spec.ts
Account checks compare byte arrays and accept both zero-filled and canonical empty code and storage hashes.
Fallback behavior validation and release metadata
packages/state/src/actions/getAccountFromProvider.spec.ts, .changeset/proud-otters-prove.md
Tests cover proof success, fallback errors, error propagation, transport downgrade caching, block pinning, cache reuse, and nonexistent accounts. A patch changeset documents the behavior.

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
Loading

Possibly related PRs

  • evmts/tevm#2093: Directly matches the fallback hydration logic, changeset, and tests.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the primary change: scalar RPC fallback when fork providers lack eth_getProof.
Description check ✅ Passed The description explains the change, lists relevant behavior, and documents tests; missing template headings are non-critical.
Linked Issues check ✅ Passed The implementation and tests address the linked issue objectives, including fallback detection, pinned scalar calls, caching, error handling, and empty-account recognition.
Out of Scope Changes check ✅ Passed The code, tests, changeset, and lint/type updates directly support the linked issue and stated pull request objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch shepherd/tevm-monorepo-pr-2093

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (2)
packages/state/src/actions/getAccountFromProvider.spec.ts (1)

94-94: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add 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 win

Complete the JSDoc for the new functions.

Add a working @example with 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 @example etc.” 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

📥 Commits

Reviewing files that changed from the base of the PR and between 6199d04 and f361264.

📒 Files selected for processing (5)
  • .changeset/proud-otters-prove.md
  • packages/state/src/actions/getAccount.js
  • packages/state/src/actions/getAccount.spec.ts
  • packages/state/src/actions/getAccountFromProvider.js
  • packages/state/src/actions/getAccountFromProvider.spec.ts

@roninjin10
roninjin10 enabled auto-merge August 7, 2026 03:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants