db/kv/membatchwithdb: delegate HistorySeek / HistoryRange to backing tx#20624
Merged
Conversation
MemoryMutation.HistorySeek and HistoryRange were left as
`panic("not supported")` placeholders with the correct delegation
commented out. Every sibling temporal-read method on MemoryMutation
already delegates to the backing tx — GetLatest, GetAsOf, RangeAsOf,
IndexRange, HistoryStartFrom. The two outliers just hadn't been
wired when nothing called them.
A caller appeared in PR #20485 (RCacheV2 fast path in
DerivePriorReceipts): when a serial-executor block is reached via
ExecModule.updateForkChoice, reads flow through the block overlay
(MemoryMutation). ReadReceiptCacheV2 issues a HistorySeek on the
RCacheDomain to read a receipt for a txNum strictly older than the
block being processed. That panics the executor at
execution/stagedsync/exec3_serial.go:402 via DerivePriorReceipts.
Delegating to the backing tx is correct, not a workaround:
- The overlay never writes to history / domain tables
(grep -rnE "indexKeys|historyKey|InvertedIndexWriter|DomainBufferedWriter"
in db/kv/membatchwithdb/ is empty). The overlay's scope is
block-level metadata: headers, TDs, bodies, canonical hashes,
BAL bytes (see execution/execmodule/inserters.go).
- History writes take the DomainBufferedWriter / SharedDomains path,
which is a separate layer. Any HistorySeek routed through the
overlay is asking for data that lives exclusively in committed
DB state or frozen snapshot files — the base tx is authoritative.
- The commented-out line in the original code already contained the
correct implementation.
Repro: wipe chaindata/ while retaining snapshots/ (post-Fusaka
mainnet) and restart. The first forkchoice-triggered execution
resumes mid-block (startTxIndex > 0), hits
DerivePriorReceipts -> ReadReceiptCacheV2 -> HistorySeek -> panic.
After this change the overlay forwards both calls to m.db and the
sync makes progress.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
yperbasis
approved these changes
Apr 17, 2026
yperbasis
left a comment
Member
There was a problem hiding this comment.
Suggestions (minor, non-blocking)
- HistoryStartFrom precedent: it returns 0 for the detached case (line 888-893), while the new methods return an error. The error path is the right call here (silent zero would mask
bugs for value-returning lookups), but worth a sanity check that no caller treats HistorySeek/HistoryRange errors as "panic" equivalents elsewhere. - Message wording: "MemoryMutation: history read requires backing tx (detached overlay)" — fine, but you could distinguish HistorySeek vs HistoryRange in the message if you ever need
to grep panicking call sites. Not important.
4 tasks
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.
Summary
panic(\"not supported\")that aborts post-Fusaka mainnet sync resumed from snapshots-only (chaindata wiped, snapshots kept).MemoryMutation.HistorySeekandHistoryRangewere placeholders; the correct delegation was already commented out. This PR just flips them to delegate to the backing tx, matching every sibling temporal-read method.Repro
On a post-Fusaka mainnet datadir, keep
snapshots/, wipechaindata/, and starterigon. The first forkchoice-triggered execution resumes mid-block (startTxIndex > 0) and takes the partial-block receipt reconstruction path added in #20452. That callsreceipts.DerivePriorReceipts, which on top of the RCacheV2 fast path (#20485) issuestx.HistorySeek(kv.RCacheDomain, …). When the containing executor runs throughExecModule.updateForkChoice, the tx is the block overlay (MemoryMutation), andHistorySeekpanics:Why delegation is correct (not a workaround)
MemoryMutationalready delegates to the backing tx:GetLatest,GetAsOf,RangeAsOf,IndexRange,HistoryStartFrom. The two outliers just hadn't been wired.execution/execmodule/inserters.go). History writes flow throughDomainBufferedWriter/SharedDomains, not through the overlay.grep -rnE \"indexKeys|historyKey|InvertedIndexWriter|DomainBufferedWriter\" db/kv/membatchwithdb/is empty.HistorySeekrouted through the overlay is therefore asking for data that lives exclusively in committed DB state or frozen snapshot files. The base tx is authoritative; the overlay has nothing to add.Test plan
make lint— 0 issuesmake erigon— builds cleango test -short ./db/kv/membatchwithdb/...— passeschaindata// keepsnapshots/, restart — sync now progresses past the first forkchoice-triggered execution instead of panicking (next hit in our testing was the unrelated stale-read bug tracked in follow-up).🤖 Generated with Claude Code