Skip to content

feat(fast-inbox): block proposals carry a bucket reference (A-1381) - #24786

Closed
spalladino wants to merge 2 commits into
spl/a-1380-world-state-per-blockfrom
spl/a-1381-proposal-bucket-ref
Closed

feat(fast-inbox): block proposals carry a bucket reference (A-1381)#24786
spalladino wants to merge 2 commits into
spl/a-1380-world-state-per-blockfrom
spl/a-1381-proposal-bucket-ref

Conversation

@spalladino

Copy link
Copy Markdown
Contributor

Adds an optional InboxBucketRef (bucketSeq, bucketTimestamp, inboxRollingHash) to BlockProposal and to the last block of CheckpointProposal (AZIP-22 Fast Inbox), so validators can derive the consumed L1-to-L2 message bundle from their own Inbox view instead of trusting a proposer-supplied list. Plumbing only for now — the sequencer passes undefined pre-flip (populated in FI-12) and the legacy validation path ignores it (validated in FI-13).

  • Signed, not an unsigned lookup aid: the reference lives inside the signed payload (getPayloadToSign), so a relay cannot strip or inject it without breaking signature recovery. The checkpoint header's inboxRollingHash remains the consensus commitment; a wrong reference can only miss the Inbox lookup. This discharges the P2-2 residual from the A-1371 design (signedness + republish path).
  • Optional-tail wire encoding, no topic-version bump: an unset proposal serializes byte-identically to the legacy format, and decoders treat EOF after the existing fields as "no reference", so mixed-version gossip keeps working. Gossip topic versions derive from deployment identity, not node software version, so mixed decoders are a hard requirement.
  • Wire-compat evidence: golden fixtures captured from the pre-change bytes pin (a) unset serialization is byte-identical, (b) legacy buffers decode as no-reference, for both proposal types.
  • CheckpointProposal enforces at construction that a set last-block reference's rolling hash equals the checkpoint header's inboxRollingHash, mirroring the existing inHash cross-check.
  • Audited every BlockProposal.fromBuffer / CheckpointProposal.fromBuffer decode site in p2p/src and message_validator.ts: none assume a strict buffer length, so the appended tail is tolerated.

Tests: InboxBucketRef round-trip/equals/schema; block + checkpoint proposal round-trips with the reference set (with and without signed txs); byte-identity vs golden fixtures when unset; legacy-buffer tolerance; signature coverage (recovery over a set reference, and recovery breaks when the reference is tampered with or injected); payload hashes differ set-vs-unset; checkpoint header-consistency check throws on mismatch.

@spalladino spalladino changed the title feat: block proposals carry a bucket reference (A-1381) feat(fast-inbox): block proposals carry a bucket reference (A-1381) Jul 19, 2026
@spalladino
spalladino force-pushed the spl/a-1380-world-state-per-block branch from 5c3c18d to d491955 Compare July 19, 2026 14:05
@spalladino
spalladino force-pushed the spl/a-1381-proposal-bucket-ref branch 2 times, most recently from 123af00 to 9bdee0d Compare July 19, 2026 17:57
@spalladino
spalladino force-pushed the spl/a-1380-world-state-per-block branch from d491955 to 8cf709e Compare July 19, 2026 17:57
@spalladino
spalladino force-pushed the spl/a-1381-proposal-bucket-ref branch from 9bdee0d to 9973f4f Compare July 19, 2026 20:48
@spalladino
spalladino force-pushed the spl/a-1380-world-state-per-block branch 2 times, most recently from 5b1f4f2 to befe2cf Compare July 20, 2026 15:30
@spalladino
spalladino force-pushed the spl/a-1381-proposal-bucket-ref branch 2 times, most recently from 3b13708 to 4d4af43 Compare July 20, 2026 17:28
@spalladino
spalladino force-pushed the spl/a-1380-world-state-per-block branch from 0b772e7 to fa3bf1f Compare July 20, 2026 21:21
@spalladino
spalladino force-pushed the spl/a-1381-proposal-bucket-ref branch from 4d4af43 to 4e21b51 Compare July 20, 2026 21:21
@spalladino
spalladino force-pushed the spl/a-1380-world-state-per-block branch from fa3bf1f to 5c1fb65 Compare July 21, 2026 02:58
@spalladino
spalladino force-pushed the spl/a-1381-proposal-bucket-ref branch from 4e21b51 to 8700011 Compare July 21, 2026 02:58
@spalladino
spalladino force-pushed the spl/a-1380-world-state-per-block branch from 5c1fb65 to ff85153 Compare July 21, 2026 03:39
@spalladino
spalladino force-pushed the spl/a-1381-proposal-bucket-ref branch 2 times, most recently from 7f36f7b to e9ea2cf Compare July 27, 2026 20:53
@spalladino
spalladino force-pushed the spl/a-1380-world-state-per-block branch from ff85153 to 6022263 Compare July 27, 2026 20:53
…rence (A-1381)

Adds an optional InboxBucketRef (bucketSeq, bucketTimestamp, inboxRollingHash)
to BlockProposal and to the last block of CheckpointProposal (AZIP-22 Fast
Inbox), so validators can derive the consumed message bundle from their own
Inbox view rather than trusting a proposer-supplied list.

- The reference goes inside the signed payload (getPayloadToSign), so a relay
  cannot strip or inject it without breaking signature recovery. The checkpoint
  header's inboxRollingHash remains the consensus commitment; a wrong reference
  can only miss the lookup.
- Optional-tail wire encoding: unset proposals serialize byte-identically to the
  legacy format, and decoders treat EOF after the existing fields as "no
  reference", so mixed-version gossip keeps working with no topic-version bump.
- CheckpointProposal enforces at construction that a set last-block reference's
  rolling hash equals the checkpoint header's inboxRollingHash, mirroring the
  existing inHash cross-check.
- Plumbing only: the sequencer passes undefined pre-flip and the legacy
  validation path ignores the field (populated in FI-12, validated in FI-13).

Golden fixtures pin the pre-change bytes for the byte-identity and cross-version
tolerance tests.
@spalladino

Copy link
Copy Markdown
Contributor Author

Superseded by #25037.

The Fast Inbox stack has been regrouped from 20 per-issue PRs (plus 2 umbrellas) down to 3 area PRs plus an umbrella, and rebased onto merge-train/spartan including #25007 (the noir-projects fnd//labs/ split). This PR's diff is preserved verbatim as a single squashed commit in #25037, and this description is preserved in that commit's message.

New structure: #25036 (circuits + L1) → #25037 (node + flip) → #25038 (cleanup), with #25039 as the full-stack umbrella. The original branch for this PR is left on the remote as a recovery point.

Closing here to cut the rebase and review overhead of maintaining 22 PRs; the work is not abandoned.

@spalladino spalladino closed this Jul 28, 2026
spalladino added a commit that referenced this pull request Jul 28, 2026
…387)

FI-17 of the Fast Inbox (AZIP-22) stack. Stacked on #24791 (A-1386); it removes the legacy `inHash` from the checkpoint header now that the consensus flip (#24789, A-1384) has switched validation to the streaming rolling hash. After this PR, `inboxRollingHash` is the checkpoint's only inbox commitment.

## Consensus-format change

- The checkpoint header loses its `inHash` field across all three preimage layers in lockstep: noir `CheckpointHeader` (`checkpoint_header.nr`), TS `CheckpointHeader` (`stdlib/src/rollup/checkpoint_header.ts`), and Solidity `ProposedHeaderLib` (struct + hash packing). The field ordering is otherwise unchanged; the header shrinks by one field (32 bytes: `CHECKPOINT_HEADER_SIZE_IN_BYTES` 380 to 348, `CHECKPOINT_HEADER_LENGTH` 14 to 13).
- The header-hash fixtures were regenerated from `checkpoint_header.test.ts` (the established workflow) and pasted into the noir tests; the p2p golden-byte fixture (`wire_compat_fixtures.ts`) was refreshed for the checkpoint-proposal serialization, which shrinks by exactly the one removed field. The block-proposal wire fixture is unchanged (block-level `inHash` is out of scope, see A-1388).

## Circuits and constants

- Strips the dead unconstrained `in_hash` pass-through from the sized `InboxParity<S>` circuit and `ParityPublicInputs` (noir + TS + the hand-written `noir-protocol-circuits-types` conversion wrappers). The circuit is kept (sized-parity, per FI-06's topology decision), so no VK-tree indices move.
- Retires `NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP` (replaced everywhere by `MAX_L1_TO_L2_MSGS_PER_CHECKPOINT`, same value 1024) and the now-dead `NUM_MSGS_PER_BASE_PARITY`, `NUM_BASE_PARITY_PER_ROOT_PARITY`, and `L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH`. Generated constants (`constants.gen.ts`, `ConstantsGen.sol`) were regenerated via `remake-constants`.
- Deletes `FrontierLib.sol` and its tests (`Parity.t.sol`, the `Frontier` harness and merkle test) now that their last users are gone.

## Verification

- Noir: `types::checkpoint_header` (5/5), `rollup_lib::parity` and `checkpoint_root::parity_tests` (15/15), and the checkpoint-root header-assembly path pass locally. The full `checkpoint_root` suite (68 tests) is too slow to run in full locally and rides CI.
- Solidity: `forge test` green across `Rollup`, `RollupFieldRange`, `Inbox`, `InboxBuckets`, `RollupGetters` (76/76), covering header hashing and the regenerated checkpoint fixtures.
- Jest: `checkpoint_header`, the p2p wire-compat suites, and the parity/messaging suites pass (43 tests), confirming the fixture regeneration is byte-consistent.
- VK/artifact/Prover.toml regeneration and the generated Noir ABI types ride CI (local `yarn build` in `noir-protocol-circuits-types` / `simulator` / `prover-client` is expected to fail on stale circuit artifacts until then); e2e and the broken-zone typecheck are the CI-of-record for those.

## Stack

Part of the Fast Inbox stack #24784 through #24791 (umbrella #24774): A-1379 (#24784), A-1380 (#24785), A-1381 (#24786), A-1382 (#24787), A-1383 (#24788), A-1384 flip (#24789), A-1385 (#24790), A-1386 (#24791, base of this PR).

Resolves A-1387.


## l1 publisher inbox consumption via the streaming selector (CI fix, pass-8)

The A-1387 inHash-removal rewrite left `l1_publisher.integration.test.ts` hardcoding `previousInboxRollingHash = Fr.ZERO` and `bucketHint = 0n` while consuming real L1→L2 messages, so message-consuming checkpoints reverted on L1 with `Rollup__InvalidInboxRollingHash` / `UnconsumedInboxMessages` (masked every prior CI round behind earlier failures). `INBOX_LAG_SECONDS` is an L1-time censorship cutoff, not whole checkpoints, so no checkpoint-depth shift register reproduces the aged bucket set. The test now mirrors the real Inbox buckets into its `MockL1ToL2MessageSource` and reuses the production `selectInboxBucketForBlock` (which mirrors `ProposeLib.validateInboxConsumption`) to pick exactly the buckets each checkpoint must consume, deriving the consumed bundle, the propose bucket hint, and the header rolling hash from that one selection. Box: 13/13, verified at a-1387 and a-1388.


Replaces #24792.
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.

1 participant