fix(archiver): guard getL1ToL2Messages against incomplete message sync#21494
Merged
spalladino merged 1 commit intomerge-train/spartanfrom Mar 13, 2026
Merged
fix(archiver): guard getL1ToL2Messages against incomplete message sync#21494spalladino merged 1 commit intomerge-train/spartanfrom
spalladino merged 1 commit intomerge-train/spartanfrom
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PhilWindle
approved these changes
Mar 13, 2026
Collaborator
|
❌ Failed to cherry-pick to |
This was referenced Mar 13, 2026
Closed
Closed
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.
Motivation
getL1ToL2Messages(checkpointNumber)returns the L1-to-L2 messages for a given checkpoint by reading from the local message store. However, if the message tree for that checkpoint hasn't been fully sealed on L1 yet (or the archiver hasn't synced it), the method silently returns incomplete data — or an empty array for a checkpoint that will eventually have messages. This is indistinguishable from a legitimately empty checkpoint (one where no L1-to-L2 messages were sent).Any caller that uses this result to compute
inHash— the sequencer, validator, or slasher — would derive an incorrect hash, leading to mismatches and potential block validation failures.Approach
The L1 Inbox contract exposes a
treeInProgressvalue: the checkpoint number whose message tree is currently being filled. Trees for checkpoints strictly below this value are sealed and complete. We persist this value in the archiver's message store during each L1 sync cycle and use it as a guard:getL1ToL2Messagesnow throwsL1ToL2MessagesNotReadyErrorif the requested checkpoint number is >=treeInProgress. On first startup (before any sync), the guard is permissive (skipped) since the value hasn't been set yet.This approach was chosen over a simpler "last message checkpoint" bound because it correctly handles empty checkpoints — a checkpoint with zero messages is still sealed once
treeInProgressmoves past it.Changes
L1ToL2MessagesNotReadyError. The message store now persiststreeInProgressas an LMDB singleton and guardsgetL1ToL2Messagesagainst unsealed checkpoints. The L1 synchronizer writes the value on every sync cycle immediately after fetching inbox state.treeInProgressdynamically from both messages and checkpoints. Added unit tests for the guard (sealed, unsealed, unset). Updated the L1 reorg test to expect the new error for unsealed checkpoints.L1ToL2MessageSourceinterface.Fixes A-659