Skip to content

execution/execmodule: wire stateCache into canonical UpdateForkChoice#21042

Merged
mh0lt merged 1 commit intomainfrom
mh/wire-statecache-canonical-forkchoice
May 8, 2026
Merged

execution/execmodule: wire stateCache into canonical UpdateForkChoice#21042
mh0lt merged 1 commit intomainfrom
mh/wire-statecache-canonical-forkchoice

Conversation

@mh0lt
Copy link
Copy Markdown
Contributor

@mh0lt mh0lt commented May 7, 2026

Summary

SharedDomains.SetStateCache was only invoked from ValidateChain (fork-validation path, exec_module.go:523). The canonical execution path in updateForkChoice constructs its own SharedDomains (forkchoice.go:211) and runs the staged sync pipeline through it without ever wiring the cache, so every Account/Storage/Code read on the canonical path went straight to aggTx (MDBX → snapshot files) uncached.

Why it was invisible

Hit/miss counters for the stateCache layer aren't surfaced in metrics — sd.metrics.CacheReadCount only tracks sd.mem hits, and CacheGetCount is a defined-but-never-incremented field. So a quick glance at [domain reads] log lines (cache=2 puts=8 ... gets=0) gave no signal that the cache layer wasn't being consulted at all on the canonical path.

A diagnostic log added inside SetStateCache confirmed it fired zero times across 611 canonical engine_newPayloadV4 → engine_forkchoiceUpdatedV3 calls on a perf-devnet-3 cold bench under EXEC3_PARALLEL=true.

Fix

One-line addition in updateForkChoice after the existing SetInMemHistoryReads call:

currentContext.SetStateCache(e.stateCache)

Mirrors what ValidateChain does. SetStateCache is already gated on dbg.UseStateCache and a non-nil cache, so behavior is unchanged when either is false.

Effect

After the fix, the same cold bench on perf-devnet-3 shows the cache absorbing ~23% of reads on the SSTORE-bloat TEST block, with MDBX read count dropping from 68 to 19 per block. File-read count is essentially unchanged because cache misses still fall through to the snapshot-file path — but the cache is now actually doing its job on the canonical path, which was its design intent.

Correctness preserved: 0 trie-root divergences across the canonical SETUP+TEST sequence.

Test plan

  • CI green (make lint, unit tests)
  • perf-devnet-3 cold bench under EXEC3_PARALLEL=true: SETUP 610 blocks + TEST block all VALID, 0 divergences
  • [state-cache] SetStateCache enabled on SD (diagnostic log added during investigation, not part of this PR) confirmed firing 613 times across the bench

🤖 Generated with Claude Code

SetStateCache(e.stateCache) was only called from ValidateChain (fork
validation). The canonical execution path in updateForkChoice constructs
its own SharedDomains and runs the staged sync pipeline through it
without ever wiring the cache, so every Account/Storage/Code read on
the canonical path went straight to aggTx (MDBX -> snapshot files)
uncached.

Effect was invisible because hit/miss counters for the cache layer were
not exposed in metrics — only the sd.mem hit count was. Diagnostic
log + counter audit on a perf-devnet-3 cold bench confirmed
SetStateCache fired zero times across 611 canonical payload validations
under EXEC3_PARALLEL=true. After this one-line plumbing fix, the same
bench shows the cache absorbing ~23% of CommitmentDomain-adjacent
reads on the bloat TEST block, with MDBX read count dropping from 68
to 19. Correctness preserved (0 trie-root divergences across the
canonical SETUP+TEST sequence).

ValidateChain's own SetStateCache call at exec_module.go:523 is left
unchanged — fork validation already had it. This PR is the missing
counterpart for the canonical path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mh0lt mh0lt requested a review from yperbasis as a code owner May 7, 2026 15:08
@yperbasis yperbasis requested a review from taratorio May 8, 2026 09:46
@mh0lt mh0lt added this pull request to the merge queue May 8, 2026
Merged via the queue into main with commit 9907f6e May 8, 2026
38 checks passed
@mh0lt mh0lt deleted the mh/wire-statecache-canonical-forkchoice branch May 8, 2026 11:15
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