Skip to content

Commit b9a15d2

Browse files
committed
feat(fast-inbox): add block_root_msgs_only_rollup circuit for no-tx blocks with messages (A-1375)
Stacked on #24603 (A-1374). AZIP-22 Fast Inbox, FI-05. ## What Adds `block_root_msgs_only_rollup` (crate `rollup-block-root-msgs-only`, VK index `BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX`) — a **non-first, transaction-less** block that still inserts a non-empty L1→L2 message bundle. This lets a proposer keep draining the Inbox into a checkpoint when the tx pool is dry. It is completely inert pre-flip: nothing in the node produces this shape until FI-12. ## Circuit Modeled on the first-empty variant but for a mid-checkpoint position (`block_root_msgs_only_rollup.nr`): - asserts `num_msgs > 0` (a message-only block with no messages has no reason to exist); - inherits `start_sponge_blob` and `start_msg_sponge` from the previous block (non-empty), sets `is_first_block = false`, appends the bundle to the L1→L2 tree and absorbs the message sponge, threads the start sponge blob through unchanged (no tx effects); - deliberately cannot be leftmost — the checkpoint root requires the leftmost rollup's `is_first_block` to be true. Composes via a new `new_from_no_rollups_with_start_sponge_blob` (a `new_from_no_rollups` that takes an inherited sponge blob instead of an empty one; the first-empty variant now delegates to it, preserving its empty-sponge start). ## Wiring - `BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX` added to the vk tree and the `ALLOWED_PREVIOUS_VK_INDICES` of the block-merge and both checkpoint-root variants. - New crate + Nargo registration; `pinned-build.tar.gz` regenerated. - TS: proving request type + schema + `ProvingJobResultsMap` entry, the `ServerCircuitProver` interface method and all implementers (bb-prover, `TestCircuitProver`, `MockProver`, `BrokerCircuitProverFacade`), the proving-broker queue map + priority list + job-controller dispatch, and npct artifact/type generation. ## Tests Noir (`rollup_lib`, 386 passed) covers the roadmap done-when — a checkpoint `[first block, msgs-only block, normal block]` — plus the failure cases: `num_msgs == 0` rejected, a msgs-only block cannot be leftmost, and merge continuity catches a bad hinted `start_msg_sponge`. `yarn build`, lint, and the orchestrator + proving-broker suites (123) are green. Cross-chain `l1_to_l2` e2e: only the two pre-registered-flaky duplicate-consume cases fail (a pre-existing PXE nullifier-sync issue, unrelated). A codex review found no soundness or wiring bugs. ## Deferred to FI-12/FI-15 (orchestrator selection + integration test) `block-proving-state.ts` selecting this variant, and an orchestrator integration test driving a mid-checkpoint msgs-only block, are intentionally **not** in this PR. Driving one requires reworking the transitional per-block message *distribution*: today the first block carries the whole padded checkpoint bundle and non-first blocks inherit the full checkpoint sponge and absorb nothing, so a msgs-only block absorbing real messages mid-chain would break both the block-merge `right.start_msg_sponge == left.end_msg_sponge` continuity and the checkpoint-root `merged.end_msg_sponge == parity.end_sponge` check. That distribution rework belongs with the sequencer that actually produces these blocks (FI-12) and its live-path e2e (FI-15). The circuit is fully proven by the noir tests, and the existing `BlockProvingState` guard still rejects non-first zero-tx blocks, so nothing can construct the shape until that work lands. ## Proving-result schema (CI fix) The `ProvingJobResult` Zod discriminated union was missing a member for the new `BLOCK_ROOT_MSGS_ONLY_ROLLUP` request type added here, so once the flip (A-1384) lets the node actually produce a message-only block, decoding its proving result threw `Invalid discriminator value` in `jsonParseWithSchema` and stalled the epoch (surfaced as a cross-chain e2e timeout up-stack). The union member is added alongside the request type in this PR — its natural home, since this is where the type is introduced. A stdlib round-trip regression test (`proving-job-source.test.ts`) serializes a message-only block-root result and asserts it decodes back with `type === BLOCK_ROOT_MSGS_ONLY_ROLLUP`. Replaces #24612.
1 parent 4d90677 commit b9a15d2

37 files changed

Lines changed: 773 additions & 26 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ members = [
4747
"crates/rollup-block-root-first-single-tx",
4848
"crates/rollup-block-root-first-single-tx-simulated",
4949
"crates/rollup-block-root-first-empty-tx",
50+
"crates/rollup-block-root-msgs-only",
5051
"crates/rollup-block-merge",
5152
"crates/rollup-checkpoint-root",
5253
"crates/rollup-checkpoint-root-simulated",

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::utils::pad_end;
22
use types::{
33
constants::{
4-
HIDING_KERNEL_TO_PUBLIC_VK_INDEX, MEGA_KERNEL_VK_LENGTH_IN_FIELDS, PARITY_BASE_VK_INDEX,
5-
PARITY_ROOT_VK_INDEX, PRIVATE_KERNEL_INIT_2_VK_INDEX, PRIVATE_KERNEL_INIT_3_VK_INDEX,
4+
BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX, HIDING_KERNEL_TO_PUBLIC_VK_INDEX,
5+
MEGA_KERNEL_VK_LENGTH_IN_FIELDS, PARITY_BASE_VK_INDEX, PARITY_ROOT_VK_INDEX,
6+
PRIVATE_KERNEL_INIT_2_VK_INDEX, PRIVATE_KERNEL_INIT_3_VK_INDEX,
67
PRIVATE_KERNEL_INIT_4_VK_INDEX, PRIVATE_KERNEL_INIT_5_VK_INDEX,
78
PRIVATE_KERNEL_INNER_2_VK_INDEX, PRIVATE_KERNEL_INNER_3_VK_INDEX,
89
PRIVATE_KERNEL_INNER_4_VK_INDEX, PRIVATE_KERNEL_INNER_5_VK_INDEX,
@@ -69,6 +70,10 @@ pub global VK_MERKLE_TREE: MerkleTree<VK_TREE_WIDTH> = {
6970
leaves[PRIVATE_KERNEL_INNER_5_VK_INDEX] =
7071
generate_fake_chonk_vk_for_index(PRIVATE_KERNEL_INNER_5_VK_INDEX).hash;
7172

73+
// The message-only block root lives past the reset-variant range, so it's not covered by the rollup-honk loop below.
74+
leaves[BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX] =
75+
generate_fake_rollup_honk_vk_for_index(BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX).hash;
76+
7277
// Rollup Honk
7378
for i in HIDING_KERNEL_TO_PUBLIC_VK_INDEX + 1..PRIVATE_KERNEL_RESET_VK_INDEX {
7479
leaves[i] = generate_fake_rollup_honk_vk_for_index(i).hash;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "rollup_block_root_msgs_only"
3+
type = "bin"
4+
authors = [""]
5+
compiler_version = ">=0.18.0"
6+
7+
[dependencies]
8+
rollup_lib = { path = "../rollup-lib" }
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use rollup_lib::block_root::{
2+
block_root_msgs_only_rollup, BlockRollupPublicInputs, BlockRootMsgsOnlyRollupPrivateInputs,
3+
};
4+
5+
fn main(inputs: BlockRootMsgsOnlyRollupPrivateInputs) -> pub BlockRollupPublicInputs {
6+
block_root_msgs_only_rollup::execute(inputs)
7+
}

noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/block_merge/block_merge_rollup.nr

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,23 @@ use crate::{
88
use types::{
99
constants::{
1010
BLOCK_MERGE_ROLLUP_VK_INDEX, BLOCK_ROOT_EMPTY_TX_FIRST_ROLLUP_VK_INDEX,
11-
BLOCK_ROOT_FIRST_ROLLUP_VK_INDEX, BLOCK_ROOT_ROLLUP_VK_INDEX,
12-
BLOCK_ROOT_SINGLE_TX_FIRST_ROLLUP_VK_INDEX, BLOCK_ROOT_SINGLE_TX_ROLLUP_VK_INDEX,
11+
BLOCK_ROOT_FIRST_ROLLUP_VK_INDEX, BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX,
12+
BLOCK_ROOT_ROLLUP_VK_INDEX, BLOCK_ROOT_SINGLE_TX_FIRST_ROLLUP_VK_INDEX,
13+
BLOCK_ROOT_SINGLE_TX_ROLLUP_VK_INDEX,
1314
},
1415
proof::proof_data::RollupHonkProofData,
1516
};
1617

1718
// Note: see `rollup_structure_tests.nr` for valid combinations of left and right vks.
18-
global ALLOWED_RIGHT_ROLLUP_VK_INDICES: [u32; 3] =
19-
[BLOCK_ROOT_ROLLUP_VK_INDEX, BLOCK_ROOT_SINGLE_TX_ROLLUP_VK_INDEX, BLOCK_MERGE_ROLLUP_VK_INDEX];
19+
// The message-only block root is a non-first variant, so it appears alongside the other non-first block roots.
20+
global ALLOWED_RIGHT_ROLLUP_VK_INDICES: [u32; 4] = [
21+
BLOCK_ROOT_ROLLUP_VK_INDEX,
22+
BLOCK_ROOT_SINGLE_TX_ROLLUP_VK_INDEX,
23+
BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX,
24+
BLOCK_MERGE_ROLLUP_VK_INDEX,
25+
];
2026

21-
global ALLOWED_LEFT_ROLLUP_VK_INDICES: [u32; 6] = ALLOWED_RIGHT_ROLLUP_VK_INDICES.concat([
27+
global ALLOWED_LEFT_ROLLUP_VK_INDICES: [u32; 7] = ALLOWED_RIGHT_ROLLUP_VK_INDICES.concat([
2228
// The first block roots may only appear as the left child of the block merge rollup.
2329
// However, this doesn't prevent having 2 first block roots in the same checkpoint. We rely on the checks in
2430
// `validate_consecutive_block_rollups` and `checkpoint_root_inputs_validator` to enforce this.

noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/block_merge/tests/mod.nr

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod child_proof_vk_tests;
22
mod consecutive_block_rollups_tests;
3+
mod msgs_only_tests;
34
mod rollup_structure_tests;
45

56
use crate::{
@@ -13,8 +14,9 @@ use crate::{
1314
use types::{
1415
constants::{
1516
BLOCK_MERGE_ROLLUP_VK_INDEX, BLOCK_ROOT_EMPTY_TX_FIRST_ROLLUP_VK_INDEX,
16-
BLOCK_ROOT_FIRST_ROLLUP_VK_INDEX, BLOCK_ROOT_ROLLUP_VK_INDEX,
17-
BLOCK_ROOT_SINGLE_TX_FIRST_ROLLUP_VK_INDEX, BLOCK_ROOT_SINGLE_TX_ROLLUP_VK_INDEX,
17+
BLOCK_ROOT_FIRST_ROLLUP_VK_INDEX, BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX,
18+
BLOCK_ROOT_ROLLUP_VK_INDEX, BLOCK_ROOT_SINGLE_TX_FIRST_ROLLUP_VK_INDEX,
19+
BLOCK_ROOT_SINGLE_TX_ROLLUP_VK_INDEX,
1820
},
1921
hash::accumulate_sha256,
2022
};
@@ -96,7 +98,8 @@ impl TestBuilder {
9698
| (vk_index == BLOCK_ROOT_SINGLE_TX_FIRST_ROLLUP_VK_INDEX)
9799
| (vk_index == BLOCK_ROOT_EMPTY_TX_FIRST_ROLLUP_VK_INDEX)
98100
| (vk_index == BLOCK_ROOT_ROLLUP_VK_INDEX)
99-
| (vk_index == BLOCK_ROOT_SINGLE_TX_ROLLUP_VK_INDEX),
101+
| (vk_index == BLOCK_ROOT_SINGLE_TX_ROLLUP_VK_INDEX)
102+
| (vk_index == BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX),
100103
);
101104
}
102105
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use crate::{
2+
abis::BlockRollupPublicInputs,
3+
block_merge::block_merge_rollup::{self, BlockMergeRollupPrivateInputs},
4+
tests::RollupFixtureBuilder,
5+
};
6+
use types::constants::{
7+
BLOCK_MERGE_ROLLUP_VK_INDEX, BLOCK_ROOT_FIRST_ROLLUP_VK_INDEX,
8+
BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX, BLOCK_ROOT_ROLLUP_VK_INDEX,
9+
};
10+
11+
// Merges two consecutive single-block rollups into one.
12+
fn merge(
13+
left: BlockRollupPublicInputs,
14+
left_vk_index: u32,
15+
right: BlockRollupPublicInputs,
16+
right_vk_index: u32,
17+
) -> BlockRollupPublicInputs {
18+
block_merge_rollup::execute(BlockMergeRollupPrivateInputs {
19+
previous_rollups: [
20+
RollupFixtureBuilder::make_proof_data(left, left_vk_index),
21+
RollupFixtureBuilder::make_proof_data(right, right_vk_index),
22+
],
23+
})
24+
}
25+
26+
// The roadmap's done-when: a checkpoint made of [first block, message-only block, normal block] proves. The
27+
// message-only block sits in the middle, so the merge circuits must accept it as a non-first child and thread the state,
28+
// archive and sponges through it.
29+
#[test]
30+
fn checkpoint_with_mid_checkpoint_msgs_only_block() {
31+
let fixture_builder = RollupFixtureBuilder::new();
32+
let start_block_number = fixture_builder.start_block_number;
33+
34+
// The consecutive single-block fixtures chain naturally by block number (archives, states and sponges line up).
35+
let first = fixture_builder.get_block_rollup_public_inputs(start_block_number);
36+
let msgs_only = fixture_builder.get_block_rollup_public_inputs(start_block_number + 1);
37+
let normal = fixture_builder.get_block_rollup_public_inputs(start_block_number + 2);
38+
39+
assert(first.is_first_block);
40+
assert(!msgs_only.is_first_block);
41+
assert(!normal.is_first_block);
42+
43+
// ((first, msgs_only), normal)
44+
let left = merge(
45+
first,
46+
BLOCK_ROOT_FIRST_ROLLUP_VK_INDEX,
47+
msgs_only,
48+
BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX,
49+
);
50+
let merged = merge(left, BLOCK_MERGE_ROLLUP_VK_INDEX, normal, BLOCK_ROOT_ROLLUP_VK_INDEX);
51+
52+
assert_eq(merged.num_blocks(), 3);
53+
// `is_first_block` propagates from the leftmost (first) block only.
54+
assert(merged.is_first_block);
55+
assert_eq(merged.previous_archive, first.previous_archive);
56+
assert_eq(merged.new_archive, normal.new_archive);
57+
assert_eq(merged.start_msg_sponge, first.start_msg_sponge);
58+
assert_eq(merged.end_msg_sponge, normal.end_msg_sponge);
59+
}
60+
61+
// A message-only block is a valid right (non-first) child of a block merge.
62+
#[test]
63+
fn msgs_only_block_accepted_as_right_child() {
64+
let fixture_builder = RollupFixtureBuilder::new();
65+
let start_block_number = fixture_builder.start_block_number;
66+
67+
let first = fixture_builder.get_block_rollup_public_inputs(start_block_number);
68+
let msgs_only = fixture_builder.get_block_rollup_public_inputs(start_block_number + 1);
69+
70+
let merged = merge(
71+
first,
72+
BLOCK_ROOT_FIRST_ROLLUP_VK_INDEX,
73+
msgs_only,
74+
BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX,
75+
);
76+
77+
assert_eq(merged.num_blocks(), 2);
78+
assert(merged.is_first_block);
79+
}
80+
81+
// The message-only block's `start_msg_sponge` is a free input; the merge continuity check must catch it if it does not
82+
// follow on from the previous block's `end_msg_sponge`.
83+
#[test(should_fail_with = "Mismatched message sponge: expected right.start_msg_sponge to match left.end_msg_sponge")]
84+
fn msgs_only_block_bad_start_msg_sponge_fails() {
85+
let fixture_builder = RollupFixtureBuilder::new();
86+
let start_block_number = fixture_builder.start_block_number;
87+
88+
let first = fixture_builder.get_block_rollup_public_inputs(start_block_number);
89+
let mut msgs_only = fixture_builder.get_block_rollup_public_inputs(start_block_number + 1);
90+
91+
// Break the sponge continuity with the previous (first) block.
92+
msgs_only.start_msg_sponge.num_absorbed += 1;
93+
94+
let _ = merge(
95+
first,
96+
BLOCK_ROOT_FIRST_ROLLUP_VK_INDEX,
97+
msgs_only,
98+
BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX,
99+
);
100+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use crate::{
2+
abis::{BlockRollupPublicInputs, L1ToL2MessageSponge},
3+
block_root::components::BlockRollupPublicInputsComposer,
4+
};
5+
use types::{
6+
abis::{
7+
append_only_tree_snapshot::AppendOnlyTreeSnapshot,
8+
checkpoint_constant_data::CheckpointConstantData, state_reference::StateReference,
9+
},
10+
blob_data::SpongeBlob,
11+
constants::{ARCHIVE_HEIGHT, L1_TO_L2_MSG_TREE_HEIGHT, MAX_L1_TO_L2_MSGS_PER_BLOCK},
12+
};
13+
14+
pub struct BlockRootMsgsOnlyRollupPrivateInputs {
15+
pub(crate) previous_archive: AppendOnlyTreeSnapshot,
16+
pub(crate) previous_state: StateReference,
17+
// The previous block is in the same checkpoint as this block, but this block has no txs, so there are no tx
18+
// constants to carry them. The checkpoint constants are given as a free value here and pinned by the checkpoint
19+
// root's previous-header check via the merge continuity of the states below.
20+
pub(crate) constants: CheckpointConstantData,
21+
// The timestamp of this block. It's given as a free value here, but will be checked against the previous block's
22+
// timestamp in the block merge or checkpoint root.
23+
pub(crate) timestamp: u64,
24+
// Sponge blob inherited from the previous block. Checked against the previous block's `end_sponge_blob` in the
25+
// block merge or checkpoint root circuit.
26+
pub(crate) start_sponge_blob: SpongeBlob,
27+
// Message sponge inherited from the previous block. Checked against the previous block's `end_msg_sponge` in the
28+
// block merge or checkpoint root circuit.
29+
pub(crate) start_msg_sponge: L1ToL2MessageSponge,
30+
31+
// L1-to-L2 messages inserted by this block, padded with zeros beyond `num_msgs`.
32+
pub(crate) l1_to_l2_messages: [Field; MAX_L1_TO_L2_MSGS_PER_BLOCK],
33+
// Number of real (non-padding) leaves in `l1_to_l2_messages`.
34+
pub(crate) num_msgs: u32,
35+
// Frontier hint for appending the bundle to the l1-to-l2 message tree (validated against `previous_state`).
36+
pub(crate) l1_to_l2_message_frontier_hint: [Field; L1_TO_L2_MSG_TREE_HEIGHT],
37+
// Hint for inserting the new block hash to the last archive.
38+
pub(crate) new_archive_sibling_path: [Field; ARCHIVE_HEIGHT],
39+
}
40+
41+
/// The Block Root Msgs Only Rollup circuit creates a non-first, transaction-less block that inserts an L1-to-L2 message
42+
/// bundle. It lets a proposer keep draining the Inbox into a checkpoint when the tx pool is empty.
43+
///
44+
/// Unlike the first-empty variant, this block sits in the middle of a checkpoint: it inherits the sponge blob and
45+
/// message sponge from the previous block (rather than starting them from empty) and sets `is_first_block = false`. It
46+
/// is deliberately unable to be the leftmost block of a checkpoint: the checkpoint root asserts the leftmost rollup's
47+
/// `is_first_block` is true, so a checkpoint made only of this variant cannot prove.
48+
///
49+
/// This circuit:
50+
/// - Requires the bundle to be non-empty (`num_msgs > 0`); an empty non-first block carries no reason to exist and
51+
/// would otherwise be a provable filler block
52+
/// - Appends the block's L1-to-L2 message bundle to the L1-to-L2 message tree and absorbs it into the message sponge
53+
/// - Threads the (non-empty) start sponge blob through unchanged, since there are no tx effects
54+
/// - Computes the block header hash and inserts it into the archive tree
55+
///
56+
/// The output feeds into a Block Merge circuit if more blocks need to be combined, or directly into a Checkpoint Root
57+
/// circuit.
58+
///
59+
/// VkIndex: BLOCK_ROOT_MSGS_ONLY_ROLLUP_VK_INDEX
60+
pub fn execute(inputs: BlockRootMsgsOnlyRollupPrivateInputs) -> BlockRollupPublicInputs {
61+
// A message-only block exists solely to insert L1-to-L2 messages, so it must carry at least one. This prevents a
62+
// provable, fully-empty non-first filler block.
63+
assert(inputs.num_msgs != 0, "A message-only block must insert at least one L1-to-L2 message");
64+
65+
BlockRollupPublicInputsComposer::new_from_no_rollups_with_start_sponge_blob(
66+
inputs.previous_archive,
67+
inputs.previous_state,
68+
inputs.constants,
69+
inputs.timestamp,
70+
inputs.start_sponge_blob,
71+
)
72+
.with_message_bundle(
73+
false,
74+
inputs.previous_state.l1_to_l2_message_tree,
75+
inputs.start_msg_sponge,
76+
inputs.l1_to_l2_messages,
77+
inputs.num_msgs,
78+
inputs.l1_to_l2_message_frontier_hint,
79+
)
80+
.finish(inputs.new_archive_sibling_path)
81+
}

noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/block_root/components/block_rollup_public_inputs_composer.nr

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,36 @@ impl BlockRollupPublicInputsComposer {
4646
constants: CheckpointConstantData,
4747
timestamp: u64,
4848
) -> Self {
49-
let empty_sponge_blob = SpongeBlob::init();
49+
// The first block of a checkpoint starts from an empty sponge blob.
50+
Self::new_from_no_rollups_with_start_sponge_blob(
51+
previous_archive,
52+
previous_state,
53+
constants,
54+
timestamp,
55+
SpongeBlob::init(),
56+
)
57+
}
5058

59+
/// Same as `new_from_no_rollups` but for a non-first block, which inherits a (non-empty) sponge blob from the
60+
/// previous block instead of starting from empty. The `start_sponge_blob` is threaded unchanged as the end sponge
61+
/// blob (before this block's end data is absorbed in `finish`), since a block with no txs adds no tx effects. It is
62+
/// pinned against the previous block's `end_sponge_blob` at the block merge or checkpoint root.
63+
pub fn new_from_no_rollups_with_start_sponge_blob(
64+
previous_archive: AppendOnlyTreeSnapshot,
65+
previous_state: StateReference,
66+
constants: CheckpointConstantData,
67+
timestamp: u64,
68+
start_sponge_blob: SpongeBlob,
69+
) -> Self {
5170
Self {
5271
constants,
5372
previous_archive,
5473
previous_l1_to_l2: previous_state.l1_to_l2_message_tree,
5574
// The state remains the same since there are no tx effects in this block.
5675
start_tree_snapshots: previous_state.partial,
5776
end_tree_snapshots: previous_state.partial,
58-
// Since it's the first block in a checkpoint, the start sponge blob is empty.
59-
start_sponge_blob: empty_sponge_blob,
60-
end_sponge_blob: empty_sponge_blob,
77+
start_sponge_blob,
78+
end_sponge_blob: start_sponge_blob,
6179
timestamp,
6280
// The followings are 0 since there are no tx effects in this block.
6381
out_hash: 0,

noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/block_root/mod.nr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ pub mod block_root_single_tx_first_rollup;
44
pub mod block_root_empty_tx_first_rollup;
55
pub mod block_root_rollup;
66
pub mod block_root_single_tx_rollup;
7+
pub mod block_root_msgs_only_rollup;
78
mod tests;
89

910
// Re-exports
1011
pub use crate::abis::BlockRollupPublicInputs;
1112
pub use block_root_empty_tx_first_rollup::BlockRootEmptyTxFirstRollupPrivateInputs;
1213
pub use block_root_first_rollup::BlockRootFirstRollupPrivateInputs;
14+
pub use block_root_msgs_only_rollup::BlockRootMsgsOnlyRollupPrivateInputs;
1315
pub use block_root_rollup::BlockRootRollupPrivateInputs;
1416
pub use block_root_single_tx_first_rollup::BlockRootSingleTxFirstRollupPrivateInputs;
1517
pub use block_root_single_tx_rollup::BlockRootSingleTxRollupPrivateInputs;

0 commit comments

Comments
 (0)