Skip to content

Commit d8de6f6

Browse files
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

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

barretenberg/.claude/skills/gate-counts/SKILL.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,8 @@ Regenerates `Prover.toml` for: `private-kernel-init` and its `private-kernel-ini
222222
variants, `private-kernel-inner` and its `private-kernel-inner-N` variants,
223223
`private-kernel-reset`, `private-kernel-reset-tail`,
224224
`private-kernel-reset-tail-to-public`, `rollup-tx-base-private`,
225-
`rollup-tx-base-public`, `rollup-block-root-first`,
226-
`rollup-block-root-first-single-tx`, `rollup-checkpoint-root-single-block`,
225+
`rollup-tx-base-public`, `rollup-block-root`,
226+
`rollup-block-root-single-tx`, `rollup-checkpoint-root-single-block`,
227227
`rollup-checkpoint-merge`, `rollup-root`.
228228

229229
**Rollup circuits NOT covered by `full.test`** (incl. `rollup-tx-merge`):
@@ -233,8 +233,7 @@ AZTEC_GENERATE_TEST_DATA=1 FAKE_PROOFS=1 \
233233
yarn workspace @aztec/prover-client test src/orchestrator/orchestrator_single_checkpoint.test.ts
234234
```
235235

236-
Regenerates `Prover.toml` for `rollup-tx-merge`, `rollup-block-root-first-empty-tx`,
237-
`rollup-block-root` (single-tx checkpoint test) and `rollup-block-root-single-tx`,
236+
Regenerates `Prover.toml` for `rollup-tx-merge`, `rollup-block-root-no-txs`,
238237
`rollup-block-merge`, `rollup-checkpoint-root` (multi-block checkpoint test).
239238

240239
> **`rollup-tx-merge`'s `Prover.toml` is regenerated by the prover-client

barretenberg/.claude/skills/update-prover-toml/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@ The circuit list lives in the `forEach(circuitName => ...)` loop in `full.test.t
4545
- `private-kernel-inner`, `private-kernel-inner-2``private-kernel-inner-5`
4646
- `private-kernel-reset-tail`, `private-kernel-reset-tail-to-public` (the terminal resets — these run as part of every tx's tail)
4747
- `rollup-tx-base-private`, `rollup-tx-base-public`
48-
- `rollup-block-root-first`, `rollup-block-root-first-single-tx`
48+
- `rollup-block-root`, `rollup-block-root-single-tx`
4949
- `rollup-checkpoint-root-single-block`, `rollup-checkpoint-merge`
5050
- `rollup-root`
5151

5252
`private-kernel-reset` (the **inner** reset) is deliberately **commented out** of this list and is **not** generated by the test — see the exception below.
5353

54-
Other entries commented out (e.g. `rollup-tx-merge`, `rollup-block-root`, `rollup-block-merge`, `rollup-checkpoint-root`) are also not produced by this flow; the inline comment points to the orchestrator single-checkpoint test for those.
54+
Other entries commented out (e.g. `rollup-tx-merge`, `rollup-block-root-no-txs`, `rollup-block-merge`, `rollup-checkpoint-root`) are also not produced by this flow; the inline comment points to the orchestrator single-checkpoint test for those.
5555

5656
If you add a new circuit crate, add its name to that list so its toml gets generated.
5757

barretenberg/cpp/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ AZTEC_GENERATE_TEST_DATA=1 FAKE_PROOFS=1 yarn workspace @aztec/end-to-end test e
148148

149149
`FAKE_PROOFS=1` skips real proving — runs in ~2 min (orchestrator + witness generation only). Writes 12 `Prover.toml` files under `noir-projects/fnd/noir-protocol-circuits/crates/<circuit>/Prover.toml`.
150150

151-
For circuits not exercised by `full.test.ts` (`rollup-tx-merge`, `rollup-block-root`, `rollup-block-root-single-tx`, `rollup-block-merge`, `rollup-checkpoint-root`, `rollup-block-root-first-empty-tx`), additionally run:
151+
For circuits not exercised by `full.test.ts` (`rollup-tx-merge`, `rollup-block-root-no-txs`, `rollup-block-merge`, `rollup-checkpoint-root`), additionally run:
152152

153153
```bash
154154
AZTEC_GENERATE_TEST_DATA=1 yarn workspace @aztec/prover-client test orchestrator_single_checkpoint

noir-projects/fnd/noir-protocol-circuits/Nargo.template.toml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,9 @@ members = [
4141
"crates/rollup-tx-merge",
4242
"crates/rollup-block-root",
4343
"crates/rollup-block-root-simulated",
44-
"crates/rollup-block-root-first",
45-
"crates/rollup-block-root-first-simulated",
4644
"crates/rollup-block-root-single-tx",
4745
"crates/rollup-block-root-single-tx-simulated",
48-
"crates/rollup-block-root-first-single-tx",
49-
"crates/rollup-block-root-first-single-tx-simulated",
50-
"crates/rollup-block-root-first-empty-tx",
51-
"crates/rollup-block-root-msgs-only",
46+
"crates/rollup-block-root-no-txs",
5247
"crates/rollup-block-merge",
5348
"crates/rollup-checkpoint-root",
5449
"crates/rollup-checkpoint-root-simulated",

noir-projects/fnd/noir-protocol-circuits/bootstrap.sh

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,9 @@ function test_cmds {
267267
rollup-tx-base-private
268268
rollup-tx-base-public
269269
rollup-tx-merge
270-
rollup-block-root-first
271-
rollup-block-root-first-single-tx
272-
rollup-block-root-first-empty-tx
273270
rollup-block-root
274271
rollup-block-root-single-tx
272+
rollup-block-root-no-txs
275273
rollup-block-merge
276274
rollup-checkpoint-root
277275
rollup-checkpoint-root-single-block

noir-projects/fnd/noir-protocol-circuits/crates/protocol-test-utils/src/fixtures/vk_tree.nr

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
use crate::utils::pad_end;
22
use types::{
33
constants::{
4-
BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX, HIDING_KERNEL_TO_PUBLIC_VK_INDEX,
5-
INBOX_PARITY_1024_VK_INDEX, INBOX_PARITY_256_VK_INDEX, INBOX_PARITY_64_VK_INDEX,
6-
MEGA_KERNEL_VK_LENGTH_IN_FIELDS, PRIVATE_KERNEL_INIT_2_VK_INDEX,
7-
PRIVATE_KERNEL_INIT_3_VK_INDEX,
8-
PRIVATE_KERNEL_INIT_4_VK_INDEX, PRIVATE_KERNEL_INIT_5_VK_INDEX,
9-
PRIVATE_KERNEL_INNER_2_VK_INDEX, PRIVATE_KERNEL_INNER_3_VK_INDEX,
10-
PRIVATE_KERNEL_INNER_4_VK_INDEX, PRIVATE_KERNEL_INNER_5_VK_INDEX,
11-
PRIVATE_KERNEL_RESET_VK_INDEX, ROOT_ROLLUP_VK_INDEX, ULTRA_VK_LENGTH_IN_FIELDS,
12-
VK_TREE_HEIGHT,
4+
HIDING_KERNEL_TO_PUBLIC_VK_INDEX, INBOX_PARITY_1024_VK_INDEX, INBOX_PARITY_256_VK_INDEX,
5+
INBOX_PARITY_64_VK_INDEX, MEGA_KERNEL_VK_LENGTH_IN_FIELDS, PRIVATE_KERNEL_INIT_2_VK_INDEX,
6+
PRIVATE_KERNEL_INIT_3_VK_INDEX, PRIVATE_KERNEL_INIT_4_VK_INDEX,
7+
PRIVATE_KERNEL_INIT_5_VK_INDEX, PRIVATE_KERNEL_INNER_2_VK_INDEX,
8+
PRIVATE_KERNEL_INNER_3_VK_INDEX, PRIVATE_KERNEL_INNER_4_VK_INDEX,
9+
PRIVATE_KERNEL_INNER_5_VK_INDEX, PRIVATE_KERNEL_RESET_VK_INDEX, ROOT_ROLLUP_VK_INDEX,
10+
ULTRA_VK_LENGTH_IN_FIELDS, VK_TREE_HEIGHT,
1311
},
1412
merkle_tree::merkle_tree::MerkleTree,
1513
proof::{verification_key::VerificationKey, vk_data::VkData},
@@ -71,18 +69,15 @@ pub global VK_MERKLE_TREE: MerkleTree<VK_TREE_WIDTH> = {
7169
leaves[PRIVATE_KERNEL_INNER_5_VK_INDEX] =
7270
generate_fake_chonk_vk_for_index(PRIVATE_KERNEL_INNER_5_VK_INDEX).hash;
7371

74-
// The message-only block root lives past the reset-variant range, so it's not covered by the rollup-honk loop below.
75-
leaves[BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX] =
76-
generate_fake_rollup_honk_vk_for_index(BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX).hash;
77-
7872
// Rollup Honk
7973
for i in HIDING_KERNEL_TO_PUBLIC_VK_INDEX + 1..PRIVATE_KERNEL_RESET_VK_INDEX {
8074
leaves[i] = generate_fake_rollup_honk_vk_for_index(i).hash;
8175
}
8276

8377
// Honk
8478
// The inbox parity ladder circuits are plain UltraHonk (not rollup-honk) and live past the reset range.
85-
leaves[INBOX_PARITY_64_VK_INDEX] = generate_fake_honk_vk_for_index(INBOX_PARITY_64_VK_INDEX).hash;
79+
leaves[INBOX_PARITY_64_VK_INDEX] =
80+
generate_fake_honk_vk_for_index(INBOX_PARITY_64_VK_INDEX).hash;
8681
leaves[INBOX_PARITY_256_VK_INDEX] =
8782
generate_fake_honk_vk_for_index(INBOX_PARITY_256_VK_INDEX).hash;
8883
leaves[INBOX_PARITY_1024_VK_INDEX] =

noir-projects/fnd/noir-protocol-circuits/crates/rollup-block-root-first-empty-tx/Nargo.toml

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)