fix(archiver): reject checkpoints that repeat a tx hash - #338
Merged
Merged
Conversation
A block that lists a tx hash already stored under a lower (ancestor) block took over that tx's effect entry, so the ancestor served the wrong effect and became unloadable once the later block was pruned. validateCheckpointStructure now rejects a checkpoint that repeats a tx hash across its blocks, and BlockStore refuses to insert a block that repeats a tx owned by a stored ancestor, throwing DuplicateTxHashError and aborting the whole write transaction. Owners at the same or a higher height, or no longer stored at their height, are replaced blocks and are still overwritten.
Document that CheckpointProposed logs of pruned or replaced checkpoints are dropped by the archiveAt check, so a checkpoint the archiver refuses stalls sync only until L1 prunes it, and that proposers send the lazy prune() from their cannot-build fallback even when their own sync is stuck.
spalladino
enabled auto-merge (squash)
September 25, 2026 20:59
alexghr
reviewed
Oct 2, 2026
alexghr
approved these changes
Oct 3, 2026
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.
A checkpoint that repeats a tx hash from an earlier block could permanently corrupt that block in the archiver. Now, we validate that and throw. This stalls the syncing process until a prune comes along.
Context
Tx effects are stored keyed by tx hash alone, and the last write wins. A backup (escape-hatch) checkpoint is stored without being executed, so it can list a tx hash already included in an earlier, proven block. The later block then takes over the tx-effect row. When the later checkpoint is pruned, deleting it also deletes that row. The proven block below it can then no longer be loaded, and the node never fetches it again.
Approach
addCheckpointsbatch is aborted:validateCheckpointStructurerejects a tx hash that appears more than once within a checkpoint;DuplicateTxHashErrorwhen a tx hash already belongs to a lower block that is still stored.checkSync, so a proposer sendsprune()even when its archiver is stuck;processCheckpointProposedLogsdrops the staleCheckpointProposedlog becausearchiveAtno longer matches.archiveAtcheck now describe this recovery path. I also corrected two sequencer comments that said the build-start gate runs aftercheckSync.Fixes A-2181