Skip to content

fix(archiver): scan the Inbox deployment block - #170

Draft
spalladino wants to merge 1 commit into
spl/fi-s01-rpc-uncertaintyfrom
spl/fi-s02-deployment-block
Draft

spalladino wants to merge 1 commit into
spl/fi-s01-rpc-uncertaintyfrom
spl/fi-s02-deployment-block

Conversation

@spalladino

@spalladino spalladino commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator

The archiver's scanned cursor is exclusive: ordinary ingestion resumes at the block after it. With no persisted
cursor the archiver falls back to the Inbox deployment block, so the very first pass started one block above it
and never read the block the contracts were deployed in.

That is not an empty block. The Inbox's first message can be emitted by a later transaction inside the same L1
block that deployed the contracts, and skipping it loses message index 0 permanently. No later message can fill
the gap, so every subsequent pass rediscovers the same disagreement between the local log and the Inbox and
never makes progress. A store that a zero-anchor recovery had already rewound onto the deployment block was
stuck in exactly the same way, because the rewound cursor sits on that block by construction.

Ingestion now starts at the deployment block while the cursor still sits on it, and keeps ordinary exclusive
semantics as soon as the cursor has advanced past it. Re-reading that one block costs nothing: the message
store rewrites an unchanged row in place. The zero anchor also reports the deployment block itself instead of
the block after it, which is the honest value for the position the rollback rewinds to.

Because ingestion now begins one block lower, the fixed-size fetch batches shift by one L1 block. Four existing
tests that pin exact batch boundaries were re-pinned to the new ranges; their behavior is unchanged.

Stack position

This is rung 7 of 25 in the Fast Inbox node stack, stacked on spl/fi-s01-rpc-uncertainty.

Provenance

Reconstructs the deployment-block and zero-anchor half of 7d2df1685c from old PR #25440
(AztecProtocol/aztec-packages). The canonicality and lagged-head half of that same commit landed separately on
the branch below this one. Ported as the final behavior rather than cherry-picked, since the destination tree has
drifted.

Tests

Red/green was straightforward here and was done for both paths.

  • archiver/src/archiver-sync.test.ts, new deployment block ingestion describe: eight cases covering a message
    in the deployment block with the head still there and with L1 advanced past it, a later message arriving after
    index 0, a restart over the same store, a store whose cursor was already rewound onto the deployment block, a
    zero-anchor rollback that rewinds onto it and must refill it, an empty deployment block, and exclusive
    semantics once the cursor is past it. Five of the seven ported cases fail against the unchanged synchronizer;
    the other two are controls that must stay green. The zero-anchor refill case was written for this PR (the
    source commit only synthesized the persisted state) and was likewise shown failing first.
  • Four pre-existing batch-boundary tests re-pinned: the scanned cursor after a mid-sync failure (106 -> 107), the
    intercepted intermediate batch (to === 2n -> 3n), the incomplete-response test (to === 2n -> 3n,
    from >= 5n -> 6n, head 4 -> 5) and the deployment-block head test (to >= 3n -> 4n).
  • Full archiver suite, JEST_MAX_WORKERS=1: 23 suites / 678 tests, exit 0 (base: 23 / 670).
  • yarn build green; yarn format and yarn lint clean.

One pre-existing flake was observed in 1 of 6 repeat runs of archiver-sync.test.ts: treats a lookup range entirely above the replacement head as a miss and refills from the deployment reported an advertised synced L1
block of 115 instead of 90. It is the harness race documented on the branch below this one (these tests never
call archiver.start(), so RunningPromise.trigger() does not serialize, and addBlock returns mid-iteration);
the log contents and the pruned blocks always matched. It must not be "fixed" by weakening the assertion.

Deliberately left out

  • The l1-contracts/l1-artifacts/scripts/generate-artifacts.sh hunk of the same source commit. That is an
    L1-contracts change; this repo consumes @aztec-foundation/l1-artifacts as a published package. It belongs in
    aztec-packages.
  • The finalizedL1Block removal and the unreachable synced-status downgrade, which come from a different source
    commit and land in their own PR.
  • No e2e suite was run locally; the archiver e2e paths are left to CI.
  • None of the seven deferred work families was pulled in; the diff was audited for it.

The scanned cursor is exclusive and defaults to the deployment block, so ordinary ingestion resumed one block
later and never read the block the contracts were deployed in. The Inbox's first message can be emitted by a
later transaction in that block, and index 0 was therefore skipped permanently: no later message can fill the
gap, so every pass rediscovered the same disagreement. The same applied to a store a zero-anchor recovery had
already rewound onto the deployment block.

Ingestion now starts at the deployment block while the cursor still sits on it and keeps exclusive semantics
once the cursor has moved past it. Re-reading that one block is harmless, since the store rewrites an unchanged
message in place. The zero anchor also reports the deployment block itself rather than the block after it.
@spalladino
spalladino added this pull request to stack #188 September 12, 2026 04:52
@spalladino spalladino added the ci-draft Run CI on this draft PR label Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-draft Run CI on this draft PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant