Skip to content

feat(anvil): Multicall3 prefetch + multi-RPC load balancing#14268

Closed
qa-august-l wants to merge 1 commit intofoundry-rs:masterfrom
qa-august-l:feat/multicall-prefetch
Closed

feat(anvil): Multicall3 prefetch + multi-RPC load balancing#14268
qa-august-l wants to merge 1 commit intofoundry-rs:masterfrom
qa-august-l:feat/multicall-prefetch

Conversation

@qa-august-l
Copy link
Copy Markdown

Summary

Two optimizations for Anvil fork mode that dramatically reduce eth_call latency for Multicall3 requests:

  • Multicall3 Prefetch: When eth_call targets Multicall3 aggregate3, prefetches all touched storage slots via one eth_createAccessList + concurrent eth_getStorageAt into the BlockchainDb cache before EVM execution. Turns serial RPC round-trips into parallel batch fetches. Best-effort — failures silently fall back to on-demand fetching. Local dirty state always takes precedence over prefetched data.

  • Multi-RPC Load Balancing: --fork-url now accepts multiple values. A new LoadBalancedTransport distributes requests via atomic round-robin across backends. The existing RetryBackoffLayer naturally fails over to the next backend on error.

Performance

9-subcall multicall against BSC mainnet fork with 3 RPC endpoints:

Scenario Time
Before (serial, single RPC) >10s (often timeout)
After — cold cache ~3.8s
After — warm cache ~0.1s

Usage

# Multi-RPC load balancing
anvil --fork-url https://rpc1.example.com --fork-url https://rpc2.example.com

# Single URL still works identically
anvil --fork-url https://rpc1.example.com

Test plan

  • Unit tests: Multicall3 ABI decode (3 tests), LoadBalancedTransport round-robin (3 tests)
  • Integration: Multicall3 eth_call succeeds in fork mode
  • Data correctness — clean state: multicall returns correct upstream balance
  • Data correctness — dirty state: after anvil_set_balance, multicall returns local modified value (NOT prefetched upstream value)
  • Data correctness — mixed state: single multicall with both dirty + clean addresses returns correct values for both
  • Integration: multi-URL fork bootstraps and reads state
  • All existing fork tests pass (68/68, 6 pre-existing flaky failures unrelated)

Closes #14265

Two optimizations for Anvil fork mode:

**Multicall3 Prefetch:**
When `eth_call` targets Multicall3 `aggregate3`, prefetches all touched
storage slots via one `eth_createAccessList` + concurrent `eth_getStorageAt`
into the `BlockchainDb` cache before EVM execution. Turns serial RPC
round-trips into parallel batch fetches. Best-effort — failures silently
fall back to on-demand fetching. Local dirty state always takes precedence
over prefetched data.

**Multi-RPC Load Balancing:**
`--fork-url` now accepts multiple values. A new `LoadBalancedTransport`
distributes requests via atomic round-robin across backends. The existing
`RetryBackoffLayer` naturally fails over to the next backend on error.

Performance (9-subcall multicall, 3 RPCs):
- Before: >10s (serial storage fetches, rate-limited)
- After (cold): ~3.8s (parallel prefetch across 3 RPCs)
- After (cached): ~0.1s

Closes foundry-rs#14265
Copy link
Copy Markdown
Collaborator

@mablr mablr left a comment

Choose a reason for hiding this comment

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

Thanks for you contribution but this seems to overlap w/ #14280

@mablr
Copy link
Copy Markdown
Collaborator

mablr commented Apr 23, 2026

feel free to re-open w/ smaller scope :)

@mablr mablr closed this Apr 23, 2026
@github-project-automation github-project-automation Bot moved this to Done in Foundry Apr 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

feat(anvil): support multiple fork URLs with load balancing

2 participants