Skip to content

refactor(archiver)!: unify L2BlockSource checkpoint lookups via query objects#22933

Merged
PhilWindle merged 1 commit intomerge-train/spartanfrom
spl/checkpoint-api-unify
May 6, 2026
Merged

refactor(archiver)!: unify L2BlockSource checkpoint lookups via query objects#22933
PhilWindle merged 1 commit intomerge-train/spartanfrom
spl/checkpoint-api-unify

Conversation

@spalladino
Copy link
Copy Markdown
Contributor

@spalladino spalladino commented May 4, 2026

Motivation

Clean up the checkpoint side of L2BlockSource. PR #22809 already collapsed the block-side API into 4 query-shaped methods over 2 return types; the checkpoint surface was left with the pre-refactor sprawl (9 narrow methods over 4 return shapes, parallel by-number / by-range / by-epoch entrypoints, and a wire-level alias that conflated proposed and confirmed checkpoints). This change applies the same simplification.

Fixes A-979

Approach

L2BlockSource checkpoint methods reduce to 4 query-shaped readers (getCheckpoint, getCheckpoints, getCheckpointData, getCheckpointsData) over 2 return shapes (PublishedCheckpoint, CheckpointData), plus a polymorphic getProposedCheckpointData(query?) for the proposed-only path. Three new query types live next to BlockQuery/BlocksQuery. On-disk format and BlockStore primitives are unchanged — the simplification is at the API boundary. The public RPC's getCheckpoint keeps the same wire signature but gains a confirmed→proposed fallback (for {number}/{slot}/'proposed' lookups) and BadRequestError guards for incompatible include* flags.

API surface change

Methods removed from L2BlockSource

getCheckpoints(from, limit), getCheckpointData(n), getCheckpointDataRange(from, limit), getCheckpointsForEpoch(epoch), getCheckpointsDataForEpoch(epoch), getCheckpointNumberBySlot(slot), getLastCheckpoint(), getLastProposedCheckpoint(). Dead methods on data_source_base also removed: getCheckpointHeader, getLastBlockNumberInCheckpoint, getSynchedCheckpointNumber.

Methods added to L2BlockSource

getCheckpoint(query: CheckpointQuery): Promise<PublishedCheckpoint | undefined>
getCheckpoints(query: CheckpointsQuery): Promise<PublishedCheckpoint[]>
getCheckpointData(query: CheckpointQuery): Promise<CheckpointData | undefined>
getCheckpointsData(query: CheckpointsQuery): Promise<CheckpointData[]>
getProposedCheckpointData(query?: ProposedCheckpointQuery): Promise<ProposedCheckpointData | undefined>

type CheckpointQuery         = { number } | { slot } | { tag: 'checkpointed' | 'proven' | 'finalized' }
type CheckpointsQuery        = { from, limit } | { epoch }
type ProposedCheckpointQuery = { number } | { slot } | { tag: 'proposed' }

Public RPC (AztecNode) wire-level changes

  • getCheckpointsDataForEpoch(epoch) removed; getCheckpointsData(query: CheckpointsQuery) added (range or epoch).
  • 'latest' removed from CheckpointParameter.
  • 'proposed' semantics changed: previously aliased to "latest L1-confirmed checkpoint" (a documented foot-gun); now getCheckpoint('proposed') strictly targets the proposed-checkpoint store, and getCheckpointNumber('proposed') returns the proposed-tip number with confirmed fallback.
  • getCheckpoint({ number }) / ({ slot }) now check confirmed first then fall back to proposed; tag-based lookups ('checkpointed' / 'proven' / 'finalized') do not fall back.
  • getCheckpoint('proposed', { includeL1PublishInfo: true | includeAttestations: true }) and the same flags on a by-number/by-slot lookup that resolves to a proposed entry now throw BadRequestError (proposed checkpoints have no L1 publish info or attestations).

Types kept

CheckpointData, CommonCheckpointData (structural base of CheckpointData / ProposedCheckpointInput), ProposedCheckpointData, ProposedCheckpointInput, PublishedCheckpoint, Checkpoint. No structural-type deletions.

Migration guidance for wallet/SDK consumers is in docs/docs-developers/docs/resources/migration_notes.md.

Changes

  • stdlib: New query types (CheckpointQuery, CheckpointsQuery, ProposedCheckpointQuery) + Zod schemas in block/l2_block_source.ts. 'latest' literal removed from interfaces/checkpoint_parameter.ts. NormalizedCheckpointDispatch type for the server's parameter normalizer. ArchiverApiSchema and AztecNode schema updated. computeL2ToL1MembershipWitness switched to the new query shape.
  • archiver: data_source_base adds resolveCheckpointQuery / resolveCheckpointsQuery mirroring the block-side helpers, implements the 4 confirmed methods plus the polymorphic proposed lookup. BlockStore adds getProposedCheckpointBySlot(slot). MockArchiver and mock_l2_block_source updated to match the new interface.
  • aztec-node: server.ts adds the confirmed→proposed fallback flow with the two BadRequestError guards in getCheckpoint, sources all tips from a single getL2Tips() call in getCheckpointNumber, and routes the public RPC through the new internal methods. New pure-projection helper projectProposedToCheckpointResponse in block_response_helpers.ts.
  • consumer migrations: prover-node (collapses two checkpoint fetches into one getCheckpoints({ epoch })), world-state, slasher, sequencer (checkpoint_proposal_job, sequencer), validator (proposal_handler), L2BlockStream, pxe block_stream_source, telemetry wrapper, and 10 e2e files updated to the new query shapes.
  • tests: 48 new it() blocks covering each query discriminant, the throw guards, the confirmed→proposed fallback, the polymorphic getProposedCheckpointData dispatch, and BlockStore.getProposedCheckpointBySlot.
  • docs: migration_notes.md updated with the breaking changes for downstream wallet/SDK consumers.

@spalladino spalladino force-pushed the spl/checkpoint-api-unify branch from b8c6577 to 928510b Compare May 4, 2026 19:20
@spalladino spalladino marked this pull request as ready for review May 4, 2026 19:30
Base automatically changed from spl/internal-archiver-api-review to merge-train/spartan May 5, 2026 09:04
… objects

Apply the same simplification PR #22809 made to the block-side API to the
checkpoint-side API: collapse 9 narrow methods over 4 return shapes into 4
query-shaped methods over 2 return shapes, plus a polymorphic proposed-checkpoint
lookup. Tightens the public RPC: removes the 'latest' / 'proposed' alias foot-gun,
adds a confirmed->proposed fallback for by-number/by-slot lookups, and rejects
incompatible include flags up-front.

BREAKING CHANGE: `getCheckpointsDataForEpoch` removed; `'latest'` removed from
`CheckpointParameter`; `'proposed'` semantics tightened (was alias for latest
confirmed, now strictly the proposed map / proposed-tip with confirmed fallback);
`getCheckpoint('proposed', { includeAttestations | includeL1PublishInfo })` and
proposed-fallback equivalents now throw `BadRequestError`.
@spalladino spalladino force-pushed the spl/checkpoint-api-unify branch from 928510b to 069d262 Compare May 5, 2026 12:04
@PhilWindle PhilWindle merged commit 7f38437 into merge-train/spartan May 6, 2026
14 checks passed
@PhilWindle PhilWindle deleted the spl/checkpoint-api-unify branch May 6, 2026 15:12
PhilWindle added a commit that referenced this pull request May 6, 2026
PR #22933 (and earlier #22809) reshaped L2BlockSource: getBlockHeader,
getCheckpointsForEpoch, and the positional getCheckpoints(from, limit)
were removed. L2TipsMemoryStore also gained a required initialBlockHash
constructor argument.

- getBlockHeader(n) -> (await getBlockData({ number: n }))?.header
- getCheckpointsForEpoch(epoch) -> getCheckpoints({ epoch }), with
  field access moving from .number/.blocks to .checkpoint.number/.blocks
- startProof folds the two-call pattern (checkpoints + separate
  attestations fetch) into one getCheckpoints({ epoch }) call since
  PublishedCheckpoint already carries attestations per entry
- L2TipsMemoryStore initialised in the constructor body with
  l2BlockSource.getGenesisBlockHash()

Test updates mirror the production migration; also restores the
beforeEach getBlockData mock to return a header for any block number
(the merge resolution had narrowed it to a single block, breaking the
checkpoint-driven flow tests).
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