refactor(fast-inbox): port Leila Wang node cleanups (#25422) - #185
Draft
spalladino wants to merge 1 commit into
Draft
spalladino wants to merge 1 commit into
spalladino wants to merge 1 commit into
Conversation
spalladino
added this pull request to stack #188
September 12, 2026 04:52
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.
Ports Leila Wang's compatible node-side cleanups from #25422 while preserving her Git authorship. The changes trim
redundant archiver sync work, carry the Inbox rolling hash incrementally, validate exact prover message spans, make
streaming state immutable, and require builder message arrays.
Stack position
This is rung 22 of 25 in the Fast Inbox node stack, stacked on
spl/fi-n8-required-prefix. The single commit isauthored by Leila Wang leizciw@gmail.com, with Santiago Palladino as committer. It reconstructs the compatible node-side subset of her commit
504acdc761("Cleanups.") from old PR #25422. #25422 is not a clean standalone branch — its history replays copies of
#25436–#25445, all of which are already in this stack — so the commit was rebuilt against the destination rather
than cherry-picked, and the authorship was carried across by hand so it survives in Git and not only here.
What it changes
The archiver's sync iteration reads the block sync point straight off the blocks store instead of going through
getArchiverSynchPoint, which also reads the message sync point that this call site immediately discards. Nothing inthe rebuilt recovery flow (N3c, FI-S01/S02/S10, N7, FI-S12) reads the discarded half, so the substitution is exact.
The lightweight checkpoint builder no longer retains the checkpoint's entire message array only to hash it once at
completion. It carries the incremental Inbox rolling hash instead: the constructor takes the hash rather than the
list,
startNewCheckpointseeds it with the previous checkpoint's,resumeCheckpointfolds the already-consumedbundle into it, each fully built block extends it,
completeCheckpointreads it, andclonecopies it. A mid-buildthrow still leaves the hash consistent with the blocks actually built, because the extension happens after the block
is complete — the same invariant the old comment described, now expressed on the hash directly.
The checkpoint prover validates its supplied message list before it enqueues anything. The list must span exactly the
previous block header's L1-to-L2 leaf count to the final block's; previously the checkpoint's start count was
derived from the list length, so a short or long list silently misassigned every block's slice and was only caught
by a header mismatch after a block had been fully re-executed. A block whose leaf count falls below its parent's is
also rejected rather than producing a backwards slice.
Streaming checkpoint state in the sequencer's proposal job becomes immutable.
buildBlocksForCheckpointandbuildForcedEndpointBlockreturn the advanced state instead of writing through an aliased object, andproposeCheckpointthreads the returned state into both preflights. The behaviour this encodes — a failed buildattempt leaves the cursor untouched, a forced tail block's advance is what the checkpoint publishes on — was already
true and tested after N3b; this makes it structural rather than a property of where the mutation happened to sit.
BlockBuilderOptions.l1ToL2Messagesbecomes required. Callers pass an empty array where they previously omitted thefield, and the
?? []/?.length ?? 0fallbacks in the validator's checkpoint builder and the sequencer's job goaway. The type, both builders and every mock move in the same commit, so no intermediate state fails to compile.
Deliberately excluded
504acdc761(block_rollup_public_inputs_composer.nr,append_only_tree.nr). Theircontent landed in B4/B5.
failure/catch/failSubTreeProofs(failure ?? …)production hunks, and the test expectation thatwhenSubTreeProofsReady()rejects with the underlying cause rather than the generic"did not complete block processing". Those depend on the deferred proof-lifecycle work and must not enter
this stack. As a consequence the two new prover tests read the validation message off the error the prover logs,
and assert the observable consequences separately (nothing enqueued for a bad span; exactly one block started before
a backwards count is caught). See the caveat below.
011ee1f0481800fe90cacd8c4659bf860e9023de(typed-mock cleanup and retryregression). It can land later as a separate Santiago-authored follow-up once its expectations are checked against
the simplified stack. It is not in this branch and is not attributed to Leila.
does not exist in this repo.
Nothing deferred crept in: the diff has no
DutyBudget, nounverifiable/checkpoint-unverifiable/ sentinelencoding, no
R − Psend cutoff, no Rollup artifact library map, no proposal-size or fee-modifier size change, nooverride-type or Noir-fixture cleanup, and no proof completion/lifetime or archive-after-close work.
Verification
yarn build,yarn formatandyarn lintare all clean fromyarn-project.Suites run in full, base → final on this branch:
JEST_MAX_WORKERS=1)bb_prover_*real-proving files)Red/green on the prover's span validation. Both new failure cases were written first and fail on unchanged code:
with no validation the run proceeds past the bad slice and
whenSubTreeProofsReady()never settles, so each casefails on the 120s suite timeout. After the change both pass in single-digit milliseconds. The third new case —
slicing three messages across blocks at leaf counts 12/12/13 over a parent at 10 — passes on unchanged code and is
the control proving the correct slicing is preserved.
The immutable streaming state is a refactor, so the evidence is the passing pre-change sequencer-client baseline
(12 / 305 / 1 skipped, unchanged after) plus two targeted mutations:
when a build fails" — the direct proof that a failed attempt leaves the cursor untouched;
streamingState = result.streamingStateso the preflights read the initial state instead of the returnedone reddens 13 cases, including every forced-endpoint-tail case — the proof that returning the state is doing
real work rather than restating an alias.
E2E suites were not run and are left to CI. The
bb_prover_*real-proving files were excluded from the prover-clientruns by instruction.
Recorded caveat (no blocking, per the standing instruction)
Excluding the error-propagation hunk from the deferred proof-lifecycle work means the prover's sub-tree promise still rejects with
Checkpoint <id> did not complete block processingrather than the validation error itself, because theexecuteCheckpointfinallyrejects first and first rejection wins. The two new tests therefore assert thevalidation message through the error the prover logs, and assert the behavioural consequences (
isFailed(),onFailed, and how many blocks were enqueued) separately. When the deferred proof-lifecycle work lands, those assertions should move back ontothe rejection, as in Leila's original. It also makes the red side of the red/green a 120s timeout rather than a fast
message mismatch.