Skip to content

feat(archiver): RpcSyncArchiver that syncs from another node#22732

Draft
spalladino wants to merge 7 commits intomerge-train/spartanfrom
spl/feat/rpc-sync-archiver
Draft

feat(archiver): RpcSyncArchiver that syncs from another node#22732
spalladino wants to merge 7 commits intomerge-train/spartanfrom
spl/feat/rpc-sync-archiver

Conversation

@spalladino
Copy link
Copy Markdown
Contributor

Motivation

The current Archiver is heavyweight: it polls L1, validates attestations, fetches blobs, and doubles as an L2BlockSink for the sequencer. For read-only consumers that just want a local queryable copy of another node's state (RPC gateways, embedded archivers, test harnesses that don't want to replay L1 sync), all that machinery is overkill.

Approach

Added a second archiver variant, RpcSyncArchiver, that reuses the existing archiver store and ArchiverDataSourceBase read APIs but replaces the L1 synchronizer with an L2BlockStream pointed at an upstream ArchiverDataSource. Events from the stream (blocks-added, chain-checkpointed, chain-pruned, chain-proven, chain-finalized) map onto the existing ArchiverDataStoreUpdater primitives. L1→L2 messages are pulled via the source's getL1ToL2Messages RPC and the archiver reconstructs InboxMessage records locally (indices via InboxLeaf.smallestIndexForCheckpoint, rolling hashes chained on the fly).

Changes

  • archiver: new RpcSyncArchiver class and createRpcSyncArchiver factory. No changes to the existing Archiver. README gains a short "Variants" section.
  • archiver (tests): new rpc_sync_archiver.test.ts drives a follower from a real upstream Archiver + FakeL1State through checkpoint sync, message sync, proven advancement, reorg, and idempotent resync.
  • end-to-end: epochs_sync_after_reorg.test.ts now spins up an RpcSyncArchiver against the primary before the node is stopped and asserts tip parity.

…ockStream

Introduces a read-only archiver variant that follows an upstream node's
data source via L2BlockStream instead of polling L1. Useful for
read-only RPC gateways, tools that embed a queryable archiver, or tests
that want an archiver without an L1 stack.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@spalladino spalladino added ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure ci-draft Run CI on draft PRs. labels Apr 22, 2026
spalladino and others added 4 commits April 22, 2026 16:08
…ollower

- handleChainPruned cross-checkpoint branch always emits L2PruneUnproven;
  previously it fell back to L2PruneUncheckpointed when the proven tip
  equalled the target, which was wrong (that event is only for proposed-only
  prunes).
- blocksBeingRemoved now starts at the first block of the first checkpoint
  being removed, not targetBlockNumber + 1, so mid-checkpoint rollback reports
  the full set of removed blocks and the epoch derived from their slot is
  correct.
- In epochs_sync_after_reorg, the RpcSyncArchiver is now created right after
  the primary node is up and checked at every checkpoint-number assertion
  instead of once at the end, avoiding the race against the still-advancing
  primary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
L2BlockStream already awaits each handleBlockStreamEvent call before
emitting the next event, so the extra serialization layer was dead weight.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…sync in RpcSyncArchiver

- Close the underlying data store on stop(); the factory is the sole opener so the archiver owns it.
- Handle chain-pruned events targeting block 0 explicitly to avoid a hot-loop throw from getCheckpointedBlock(0) returning undefined.
- After each block stream batch, compare local and source tips and mark initial sync complete; prevents waitForInitialSync() from hanging when start() was called with blockUntilSync=false.
- Add unit tests covering the above plus multi-block checkpoints, zero-message checkpoints, chain-finalized advancement, and partial-insert recovery.
Adds getL1ToL2Messages to the AztecNode interface + JSON-RPC schema so any
AztecNode (in-process or remote client) can be used as an RpcSyncArchiver source.
Retypes RpcSyncArchiverSource as Pick<AztecNode, ...> to enforce the subset
relationship at compile time, and updates the e2e test to pass the AztecNode
directly to the factory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@AztecBot
Copy link
Copy Markdown
Collaborator

AztecBot commented Apr 22, 2026

Flakey Tests

🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry.

\033FLAKED\033 (8;;http://ci.aztec-labs.com/032c2d1f84603e9b�032c2d1f84603e9b8;;�):  yarn-project/end-to-end/scripts/run_test.sh simple src/e2e_epochs/epochs_sync_after_reorg.test.ts (280s) (code: 0) group:e2e-p2p-epoch-flakes

spalladino and others added 2 commits April 22, 2026 18:00
…al data

The L2BlockStream short-circuits block 0 comparisons internally, but the
local-data provider should still return a real hash rather than undefined
so callers that bypass that short-circuit see consistent behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… source

Messages are no longer persisted locally. The archiver does not run an L1
synchronizer, so it cannot observe inbox reorgs or maintain the rolling-hash
chain safely; every lookup now goes straight to the upstream source, which is
already the source of truth.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants