Commit d8de6f6
committed
feat(fast-inbox): cap blocks per checkpoint, allow empty blocks anywhere, merge block-root variants (A-1539)
Replaces the "a fully-empty block may only be the first block of a checkpoint" rule with an explicit cap on how many
blocks a checkpoint may contain, asserted in the checkpoint root. Empty (0-tx, 0-msg) blocks become legal at any
position, the six block-root variants collapse to three, and the `is_first_block` public input goes away.
Why: there are no per-block rewards to abuse — L1 pays per proven checkpoint and per mana, never per block — so the
emptiness rule was only weak anti-griefing. Without an explicit cap a proposer could already stuff a checkpoint with
well over a thousand cheap blocks, and the cap bounds the epoch prover's worst case identically for empty and full
blocks. Once it exists the emptiness rule buys nothing, and empty blocks let the sequencer keep a regular block
cadence with no "nothing to include" special case.
Circuits:
- `MAX_BLOCKS_PER_CHECKPOINT` (72, one block per second over the production slot) is added to `constants.nr` and
emitted to `constants.gen.ts` by the generator, so the node and the circuits share one value. It is not consumed by
Solidity, so `ConstantsGen.sol` is unchanged: `ProposedHeader` carries no block count, so L1 cannot check the cap at
propose time and validators must reject over-cap proposals before attesting.
- `CheckpointRootInputsValidator` sums `num_blocks()` over its child rollups and asserts the total is within the cap.
Both checkpoint root variants share the validator, so both get it.
- The six block roots merge to three, keeping the transaction-count axis (0 / 1 / 2 children) because that is what
drives proving time: `block_root`, `block_root_single_tx` and `block_root_no_txs` (the former msgs-only variant,
renamed and now also usable as the first block of a checkpoint). The first/non-first axis disappears: every variant
takes the start message sponge — and, for the tx-less variant, the start sponge blob — as inputs, which the
checkpoint root pins to their initial values for the leftmost block and the block merge pins to the previous
block's end values otherwise. The msgs-only variant's `num_msgs != 0` assert is dropped.
- `is_first_block` is removed from `BlockRollupPublicInputs`, its propagation in `merge_block_rollups`, the right-child
assert in `validate_consecutive_block_rollups` and the leftmost assert in the checkpoint root's inputs validator.
The block-end blob absorb still needs to know whether a block is the checkpoint's first (the l1-to-l2 tree root is
absorbed once per checkpoint), and the composer now derives that from `start_sponge_blob.num_absorbed_fields == 0`
rather than from a witnessed flag. Every block absorbs its block-end fields, so only the leftmost block can start
from an uninitialized sponge blob, and `start_sponge_blob` is itself pinned by the checkpoint root and the block
merge — so the derivation cannot be steered by the prover, while a witnessed flag could have been.
- The checkpoint root's four start-value asserts are now the sole anchoring of a checkpoint to its start; a comment on
them says so, so a later refactor does not drop one assuming a flag still marks the first block.
- Six block-root VK indices become three; the allowed-index lists in the block merge and both checkpoint root variants
shrink accordingly. The block merge no longer needs distinct left/right allowed sets, and the single-block
checkpoint root's footnote about the msgs-only entry being unreachable goes away with the entry itself.
- Deletes the `rollup-block-root-first`, `-first-single-tx`, `-first-empty-tx` crates and the two `-first*-simulated`
crates; renames `rollup-block-root-msgs-only` to `rollup-block-root-no-txs`.
TypeScript: the same three-variant shape in `stdlib` (proving request types, private-input classes, prover interface),
the circuit bindings and artifact lists, and the orchestrator, which now selects the block root by transaction count
alone and passes the start sponges the position implies.
Tests: checkpoint-root tests for exactly-at-cap and cap+1; a fully empty non-first block and a tx-less leftmost block
in the block-root tests, plus a check that only the first block absorbs the extra blob field; a block-merge test that a
mid-checkpoint block claiming an initialized start sponge blob fails continuity.1 parent 7a6439a commit d8de6f6
84 files changed
Lines changed: 684 additions & 7384 deletions
File tree
- barretenberg
- .claude/skills
- gate-counts
- update-prover-toml
- cpp
- noir-projects/fnd/noir-protocol-circuits
- crates
- protocol-test-utils/src/fixtures
- rollup-block-root-first-empty-tx
- src
- rollup-block-root-first-simulated
- src
- rollup-block-root-first-single-tx-simulated
- src
- rollup-block-root-first-single-tx
- src
- rollup-block-root-first
- src
- rollup-block-root-msgs-only
- src
- rollup-block-root-no-txs
- src
- rollup-lib/src
- abis
- block_merge
- tests
- utils
- block_root
- components
- tests
- checkpoint_root
- components
- tests
- tests
- types/src
- scripts
- yarn-project
- bb-prover/src
- prover/server
- test
- end-to-end/src
- single-node/prover/server
- spartan
- noir-protocol-circuits-types/src
- artifacts
- vks
- conversion
- execution
- scripts
- prover-client/src
- orchestrator
- proving_broker
- test
- stdlib/src
- interfaces
- proofs
- rollup
- stats
- tests
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
222 | 222 | | |
223 | 223 | | |
224 | 224 | | |
225 | | - | |
226 | | - | |
| 225 | + | |
| 226 | + | |
227 | 227 | | |
228 | 228 | | |
229 | 229 | | |
| |||
233 | 233 | | |
234 | 234 | | |
235 | 235 | | |
236 | | - | |
237 | | - | |
| 236 | + | |
238 | 237 | | |
239 | 238 | | |
240 | 239 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
48 | | - | |
| 48 | + | |
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
54 | | - | |
| 54 | + | |
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
148 | 148 | | |
149 | 149 | | |
150 | 150 | | |
151 | | - | |
| 151 | + | |
152 | 152 | | |
153 | 153 | | |
154 | 154 | | |
| |||
Lines changed: 1 addition & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
45 | | - | |
46 | 44 | | |
47 | 45 | | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
| 46 | + | |
52 | 47 | | |
53 | 48 | | |
54 | 49 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
267 | 267 | | |
268 | 268 | | |
269 | 269 | | |
270 | | - | |
271 | | - | |
272 | | - | |
273 | 270 | | |
274 | 271 | | |
| 272 | + | |
275 | 273 | | |
276 | 274 | | |
277 | 275 | | |
| |||
Lines changed: 9 additions & 14 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
5 | | - | |
6 | | - | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
11 | | - | |
12 | | - | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
13 | 11 | | |
14 | 12 | | |
15 | 13 | | |
| |||
71 | 69 | | |
72 | 70 | | |
73 | 71 | | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | 72 | | |
79 | 73 | | |
80 | 74 | | |
81 | 75 | | |
82 | 76 | | |
83 | 77 | | |
84 | 78 | | |
85 | | - | |
| 79 | + | |
| 80 | + | |
86 | 81 | | |
87 | 82 | | |
88 | 83 | | |
| |||
Lines changed: 0 additions & 8 deletions
This file was deleted.
0 commit comments