feat(archiver): decouple calldata from blob fetching in L1 synchronizer#22472
Conversation
|
Got to consider race condition where a proposer pushes their proposed checkpoint to its archiver before the previous checkpoint is checkpointed on L1, but this requires a larger change on the block store. |
| ? undefined | ||
| : await this.store.getProposedCheckpointOnly(); | ||
| const last = calldataCheckpoints[calldataCheckpoints.length - 1]; | ||
| const toPromote = |
There was a problem hiding this comment.
to Promote is only used as a boolean? The logs can just use last directly?
| description: 'Skip validating checkpoint attestations (for testing purposes only)', | ||
| ...booleanConfigHelper(false), | ||
| }, | ||
| skipPromoteProposedCheckpointDuringL1Sync: { |
There was a problem hiding this comment.
is it worth prefixing this option with test_
| } | ||
|
|
||
| // And persist the promoted checkpoint if it passed validation | ||
| if (toPromote && validCheckpoints.some(c => c.checkpoint.number === toPromote.checkpointNumber)) { |
There was a problem hiding this comment.
this .some and .find below are doing the same search. could probably extract it
| const [processDuration, result] = await elapsed(() => | ||
| execInSpan(this.tracer, 'Archiver.addCheckpoints', () => | ||
| this.updater.addCheckpoints(validCheckpoints, updatedValidationResult), | ||
| this.updater.addCheckpoints(checkpointsToAdd, updatedValidationResult), |
There was a problem hiding this comment.
should addCheckpoints + promoteProposed be able to be updated within the same call? Ideally these should update atomically? could have some kind of queue + flush
| this.log.debug( | ||
| `Building published checkpoint from proposed ${toPromote.checkpointNumber} (skipping blob fetch)`, | ||
| ); | ||
| const blocks = await this.store.getBlocks(BlockNumber(proposed.startBlock), proposed.blockCount); |
There was a problem hiding this comment.
just realised getBlocks does not assert that blockCount blocks are returned
| return await this.db.transactionAsync(async () => { | ||
| const proposed = await this.getProposedCheckpointOnly(); | ||
| if (!proposed) { | ||
| throw new Error('Cannot promote proposed checkpoint: no proposed checkpoint exists'); |
There was a problem hiding this comment.
not for now but this file has a big variance in custom error / text error
6e9e318 to
52250fe
Compare
Splits checkpoint retrieval into two phases: first fetch calldata only (header, attestations, archive root), then check if a proposed checkpoint with matching header already exists in the store. If so, skip blob fetching and promote the proposed checkpoint to confirmed. Otherwise, fetch blobs in parallel as before. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move promote to after attestation validation to avoid persisting invalid checkpoints (split into build + persist steps) - Add validateCheckpoint call in promote path - Add archive root comparison to proposed checkpoint match condition - Remove dead retrieveCheckpointsFromRollup and processCheckpointProposedLogs - Pass pendingChainValidationStatus to promote path Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
52250fe to
20c5f7c
Compare
48236ce
into
spl/fix-genesis-world-state-again
…er (#22716) Reopening #22472 which was accidentally merged ## Motivation When the node is a validator that already built a checkpoint locally (via `addProposedBlock` + `setProposedCheckpoint`), the blocks are already in the archiver store. Fetching blobs from the beacon chain is redundant and expensive, especially during sync. This decouples calldata and blob retrieval so we can skip blob fetching when the proposed checkpoint matches. ## Approach Split `retrieveCheckpointsFromRollup` into two phases: (1) fetch calldata only (header, attestations, archive root), (2) check the archiver store for a proposed checkpoint with matching header. If found, promote it to confirmed via a fast path. Otherwise, fetch blobs in parallel (same `asyncPool(10, ...)` concurrency as before) and store as normal. ## Changes - **archiver (l1/data_retrieval.ts)**: New `CalldataOnlyCheckpoint` type, `retrieveCheckpointCalldataFromRollup` (calldata-only fetch), and `fetchBlobsAndBuildPublishedCheckpoint` (deferred blob fetch). Existing functions left intact. - **archiver (store/block_store.ts)**: New `promoteProposedToCheckpointed` method that reads existing blocks from store, writes a confirmed checkpoint entry with L1 metadata + attestations, and clears the proposed singleton. - **archiver (store/kv_archiver_store.ts)**: Pass-through for `promoteProposedToCheckpointed`. - **archiver (modules/data_store_updater.ts)**: New `promoteProposedCheckpoint` wrapper that handles validation status and tips cache refresh. - **archiver (modules/l1_synchronizer.ts)**: `handleCheckpoints` now partitions calldata checkpoints into promote-vs-fetch-blobs, fetches blobs in parallel for non-matching ones, promotes the matched one, then merges results for validation. Fixes A-877 --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Motivation
When the node is a validator that already built a checkpoint locally (via
addProposedBlock+setProposedCheckpoint), the blocks are already in the archiver store. Fetching blobs from the beacon chain is redundant and expensive, especially during sync. This decouples calldata and blob retrieval so we can skip blob fetching when the proposed checkpoint matches.Approach
Split
retrieveCheckpointsFromRollupinto two phases: (1) fetch calldata only (header, attestations, archive root), (2) check the archiver store for a proposed checkpoint with matching header. If found, promote it to confirmed via a fast path. Otherwise, fetch blobs in parallel (sameasyncPool(10, ...)concurrency as before) and store as normal.Changes
CalldataOnlyCheckpointtype,retrieveCheckpointCalldataFromRollup(calldata-only fetch), andfetchBlobsAndBuildPublishedCheckpoint(deferred blob fetch). Existing functions left intact.promoteProposedToCheckpointedmethod that reads existing blocks from store, writes a confirmed checkpoint entry with L1 metadata + attestations, and clears the proposed singleton.promoteProposedToCheckpointed.promoteProposedCheckpointwrapper that handles validation status and tips cache refresh.handleCheckpointsnow partitions calldata checkpoints into promote-vs-fetch-blobs, fetches blobs in parallel for non-matching ones, promotes the matched one, then merges results for validation.Fixes A-877