perf(cold-start): eth_createAccessList two-shot warming for fast first boot - #32
Closed
KaiCode2 wants to merge 2 commits into
Closed
perf(cold-start): eth_createAccessList two-shot warming for fast first boot#32KaiCode2 wants to merge 2 commits into
KaiCode2 wants to merge 2 commits into
Conversation
…t boot A layout-free pool's (Curve/Balancer) first cold start ran the get_dy / getPoolTokens discover call in local revm over a cold cache, faulting each SLOAD one-at-a-time over RPC. This adds a two-shot fast path: derive the read-set with one eth_createAccessList, bulk-load it, then run the discover warm (no serial faulting). Measured Tricrypto2 first boot ~728ms -> ~431ms (~1.7x) on a public endpoint; the gap widens on higher-latency providers. - cold_start_many primes any fallback pool whose planner declares a discover call (generic: Curve/Balancer + any future discover-based adapter) before the per-pool cold-start, which then runs warm. New AdapterRegistry::cold_start_primed is the single-pool async entry (delegates to cold_start_many). Opt out via with_access_list_discovery(false). - Graceful fallback: unsupported provider / reverted call / per-pool failure -> local discovery. The access list only prewarms; the local discover stays authoritative and self-heals an incomplete list -> no correctness risk. - Interop fixes: gasPrice = the PINNED block's baseFee (the latest suggested price can sit below a historical block's baseFee); null-tolerant deserialization (geth returns storageKeys: null for touched-but-storageless accounts). Adds serde (already in the graph via alloy/revm). Tests: offline mock proves priming eliminates serial faults + graceful fallback; env-gated access_list_discovery_rpc asserts primed == local read-set for real 3pool/Tricrypto2; curve_cold_start_phases gains an access-list-first-boot row. 219 tests pass; clippy/doc/all-features clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #31 (
perf/curve-cold-start) — review/merge that first.Problem
#31 made repeat warms of layout-free pools (Curve/Balancer) fast, but the
first-ever boot of an unknown pool still ran the
get_dy/getPoolTokensdiscover call in local revm over a cold cache — faulting each SLOAD one-at-a-time
over RPC. That serial faulting dominates a cold first boot.
Change
Two-shot cold warming: derive the read-set with one
eth_createAccessList,bulk-load it through the
EvmCache, then run the discover warm (no serialfaulting).
evm-fork-cachenow has acache-owned access-list read-set prewarm primitive on branch
feat/access-list-read-set-prewarm, commit0c9af358d90c87e6452d5b3f1e252822043269f2. This branch is pinned to thatexact commit until the cache crate publishes the primitive.
cold_start_manyprimes fallback pools whose planner declares a discovercall — generic over Curve/Balancer and future discover-based adapters, with
zero new adapter trait surface. The per-pool cold-start then runs warm and
finalizes as usual.
AdapterRegistry::cold_start_primed(pool, cache, policy)is the single-poolasync entry point. It no longer asks users to pass a separate provider/RPC; it
uses the provider/fetchers already installed on the
EvmCache.without
eth_createAccessList, a reverted call, or any per-pool failuretransparently falls back to local discovery. Opt out with
with_access_list_discovery(false).stays authoritative and self-heals an incomplete list.
Measured
Paid endpoint rerun requested in review:
Run used the paid Alchemy mainnet
E2E_RPC_URLfrom.envwith the example'sgzip-enabled HTTP client. Tricrypto2, block
25_481_590, 5 iterations:The benchmark section in
docs/benchmarks.mdhas been refreshed with thesepaid-RPC numbers.
Interop / API notes
gasPrice = pinned block baseFeerule and null-toleranteth_createAccessListresponse decoding now live inevm-fork-cache, not inthis AMM crate.
serdedependency added only for lenient access-list decoding wasremoved.
cold_start_manystill accepts a provider because its known-read-set path runsexplicit storage programs; the new access-list discovery path itself uses the
cache-owned provider/fetcher primitive.
Verification
cargo fmt --checkcargo check --all-targetscargo clippy --all-targets --no-deps -- -D warningscargo test --test cold_start_adoptionset -a; source /Users/kaialdag/Desktop/dev/egg/crates/evm-amm-state/.env; set +a; cargo test --test access_list_discovery_rpc -- --ignored --nocaptureset -a; source /Users/kaialdag/Desktop/dev/egg/crates/evm-amm-state/.env; set +a; CURVE_PHASES_ITERS=5 cargo run --release --example curve_cold_start_phases