Skip to content

Commit 41bc4ab

Browse files
committed
feat(fast-inbox): same-block L1-to-L2 message consumption for non-first blocks (A-1432)
## What Makes every block's `BlockConstantData.l1_to_l2_tree_snapshot` the **post-bundle** snapshot for that block — first block or not — so a public/AVM tx in block N can read the L1-to-L2 messages block N inserts (same-block consumption), instead of only from block N+1. Previously the non-first tx-carrying variants (`block_root`, `block_root_single_tx`) read their start snapshot from `constants.l1_to_l2_tree_snapshot` and never asserted the post-bundle root, giving next-block visibility for mid-checkpoint insertions. Now they: - take the start L1-to-L2 snapshot as a **witness input** (`previous_l1_to_l2`), pinned by block-merge continuity (`right.start_state == left.end_state`) to the previous block's end state — the checkpoint root forces the leftmost block to be a first-block variant, so every non-first block has a left neighbour pinning its start; - append their bundle and assert `validate_l1_to_l2_tree_snapshot_in_constants(constants, new_l1_to_l2)`, exactly like the first-block variants. The tx-less variants (`block_root_empty_tx_first`, `block_root_msgs_only`) carry no tx constants to read against and already witness their start snapshot, so they are unchanged. ## Soundness The witnessed start snapshot cannot be forged: block-merge / checkpoint-root continuity asserts `right.start_state == left.end_state`, and the checkpoint root asserts the leftmost block is a first-block variant (whose start is pinned to the previous checkpoint). The start is therefore anchored, and the new assert pins the tx-constants snapshot to the computed post-bundle root. The start is **not** derived from "constants minus the bundle" (not expressible). ## Bit-identical pre-flip (public inputs) Non-first bundles are empty today, so `new_l1_to_l2 == start == today's constants value`; the new assert passes with unchanged values and the block-root **public inputs / state are unchanged**. The circuit constraints, private-input ABI, proof, and VK do change (hence the regen below). This is a restructure-now / flip-minimal change. ## Flip follow-on (not in this PR) The recursive pinning of the witnessed `previous_l1_to_l2` is already exercised by `block_merge::tests::consecutive_block_rollups_tests::non_consecutive_l1_to_l2_message_tree_snapshots` (a right block whose `start_state.l1_to_l2_message_tree` — i.e. this witness — doesn't match the left block's end is rejected on continuity). One flip requirement this change surfaces: today the prover gives every non-first block the checkpoint's post-first-block snapshot as its `previousL1ToL2` (`block-proving-state.ts`), which is correct only while non-first bundles are empty. Once non-first blocks insert their own bundles (A-1384), the prover must instead feed block N+1 the end snapshot of block N plus the matching frontier hint. Flagged for the flip plan (A-1384). ## Tests Adds negative nargo tests: a non-first block (two-tx and single-tx) whose `constants.l1_to_l2_tree_snapshot` differs from its post-bundle root must fail. Red/green verified locally — with the new asserts removed the four negative tests report "Test passed when it should have failed"; restored, they pass. `rollup_lib` block_root suite green (63 tests), block_merge (45), checkpoint_root structure tests (17). ## TS wiring Mirrors the new `previous_l1_to_l2` field through `stdlib` (`BlockRootRollupPrivateInputs` / `BlockRootSingleTxRollupPrivateInputs` serialization + factory), the Noir ABI conversion (`server.ts`), and the prover-client block-root input builders (`block-proving-state.ts`), which pass the block's `lastL1ToL2MessageTreeSnapshot` (for non-first blocks, the checkpoint's post-first-block snapshot). `stdlib` builds and its serialization test passes. ## Artifact regen (rides CI / mainframe) This changes the `block_root` and `block_root_single_tx` circuit ABIs, so it invalidates their VKs, the checkpoint-root/block-root `Prover.toml` sample inputs, and the generated `noir-protocol-circuits-types/src/types/index.ts`. These are **not** regenerated locally (`bb write_vk` OOMs on large circuits on dev boxes; the generated `index.ts` also depends on recompiled circuit artifacts). They ride the seeded-S3-cache mainframe/CI flow, consistent with the rest of the Fast Inbox stack. ## Stack Stacked on `spl/a-1427-inbox-parity`; the L1 PRs (#24771, #24773) are rebased on top of this. Part of the Fast Inbox stack (umbrella #24774). Fixes A-1432 Replaces #24781.
1 parent 6ae3afd commit 41bc4ab

31 files changed

Lines changed: 260 additions & 139 deletions

noir-projects/fnd/noir-protocol-circuits/crates/rollup-block-root-single-tx/Prover.toml

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ l1_to_l2_message_frontier_hint = [
3939
]
4040
new_archive_sibling_path = [
4141
"0x0000000000000000000000000000000000000000000000000000000000000000",
42-
"0x2fdbd1b87ca82784e3c3d2871efa66b2a61337fcb13897a786c67fbafb377149",
42+
"0x2f559d93de6d3e8a6289d45995351f749463bcee0ee677456f8ee19347c27114",
4343
"0x14e4b977b2203b70e6ee1c2456eb7114d090fe4b907f631eecd0919fed432e7d",
4444
"0x30105bad22ddcc508b739b7c9ad87a561c569ff5cb0098a853c1c4ac21b7a037",
4545
"0x1e20ad4181460cbfdc74ca773502c59b890f184efe300ebad895956d318422da",
@@ -561,12 +561,12 @@ new_archive_sibling_path = [
561561
accumulated_mana_used = "0x0000000000000000000000000000000000000000000000000000000000000000"
562562

563563
[inputs.previous_rollup.public_inputs.constants]
564-
vk_tree_root = "0x0a178ec6fe216bfa6e2d25089ce97f9ff6b5c5701d2bce2a1fdf11e6dc351e3c"
564+
vk_tree_root = "0x1d51e7bb66dda198c072b182a8e4809fc6614d677c914af2afa9c5376f16f06d"
565565
protocol_contracts_hash = "0x0727efc9473643b7abbe3c57df72d68e86b244b99cae71b17553c0f937ea433b"
566566
prover_id = "0x0000000000000000000000000000000000000000000000000000000000000000"
567567

568568
[inputs.previous_rollup.public_inputs.constants.last_archive]
569-
root = "0x2d84822e545f3f6e16012e854f9327cee518281ec5f6925ae461d64328e692ee"
569+
root = "0x0c2eb70ed9c405d7895991207fcf58411017ab8481fba43c23b8d01f9ee6d826"
570570
next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000002"
571571

572572
[inputs.previous_rollup.public_inputs.constants.l1_to_l2_tree_snapshot]
@@ -624,10 +624,10 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
624624
"0x18d6aae3ab4a271abd590cb98267825b70de1e9e5c339356e94ea5fc7feba64b"
625625
]
626626
state = [
627-
"0x2f7854ba50d6143cd7c2d0aab9074594e7443021752b672f532fb28036bdf464",
628-
"0x2d6155d605fc85dbd2c44a9dc2d61848c1a1abe0536b44e4482c9ac6024a77d5",
629-
"0x236c352e3ae68c93a62504965bc9e8778e07c0cd338fe798a2c88b9fdb4ceae7",
630-
"0x032fc1b246541ca6be41be6375543d448d6b21e06b2cb16d26c42bc97deafdfc"
627+
"0x1e20e5a8cee556f890f804b4c34dfa9d0c0691184ef311d07a3360c7a3ed0abb",
628+
"0x2f58f461552b8e4a5eb0e2390a113ced8ed4fbe200eae42042548cc471aa8302",
629+
"0x0f289d4b3c928a76f3d6b02eb37d55a0bc9f5efe83f048e9bb6087c97ecd2629",
630+
"0x030aab4986f4fd9cf6184c20046212db4094a9884e02d5fd5cb39b8c3fa73119"
631631
]
632632
cache_size = "0x0000000000000000000000000000000000000000000000000000000000000003"
633633
squeeze_mode = false
@@ -642,10 +642,10 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
642642
"0x00000000000000000000000000000000000000000000000000000000b7e5c34c"
643643
]
644644
state = [
645-
"0x2dc74882aa099ff2d05d3ee7a9f8bfdddbbdedba13a6a544b7a97b6f834bd1d6",
646-
"0x2002908e197ef2363618c1ada3e9533d21bc4f30c720c5d5957a90ddbbf42748",
647-
"0x1bc50bd10705cd3e35a0ddf12d2d20342247e2d9f66bd2ef3f8c87afab432a9f",
648-
"0x099fa9fa9487c303774e42ca2c7897603abf9ca25584364229ef9593af312d96"
645+
"0x03a9c278ef420de34c98d3ed9353652c050aa787564e29869ba130c93aeeb58c",
646+
"0x04840897fb96b980247599b309da2659be7d79a529b8e120a3de7d0ce81a18c4",
647+
"0x261c3adfec1a9c39f94e54687fc959511aa357d07907d7eb60b6c1ede39dc9f8",
648+
"0x22aeae6b14550f3d8954f9f9098c4255a25eabe1d0e5e6c662a8917c3d1a0e00"
649649
]
650650
cache_size = "0x0000000000000000000000000000000000000000000000000000000000000002"
651651
squeeze_mode = false
@@ -655,7 +655,7 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
655655
sibling_path = [
656656
"0x10b6730f1d1e9c6bf8d7c4b42b64b40d2603e3ae6ddbd464c3d8fcfb9e06e6d4",
657657
"0x014ffec160e37b6cb713c1a4e6e7058964dde1733e6734520ed72f72fd262919",
658-
"0x196cbe2980734bc5d21b53464a1d00c06dad0febdec75822d79d6933dff40579",
658+
"0x14bb1983f28c88ab603e0fe7e46b743829816df364ec385e2245072c3dad3e1e",
659659
"0x0787c8cc4cfb80390c27cdc17cb24ae198faad7989508690070b3cf40a2ae4fd",
660660
"0x134e9973b03d62389ee6021d35e61158807c7da3c3e6a052d365f53ab1ac214d",
661661
"0x118d25fdd2c4cc96d5af69bd85930dd49d101d463e3f5ee9f2cc9236384b5d41",
@@ -1812,6 +1812,10 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
18121812
num_msgs = "0x0000000000000000000000000000000000000000000000000000000000000000"
18131813
num_real_msgs = "0x0000000000000000000000000000000000000000000000000000000000000000"
18141814

1815+
[inputs.previous_l1_to_l2]
1816+
root = "0x18d6aae3ab4a271abd590cb98267825b70de1e9e5c339356e94ea5fc7feba64b"
1817+
next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000400"
1818+
18151819
[inputs.start_msg_sponge]
18161820
num_absorbed = "0x0000000000000000000000000000000000000000000000000000000000000400"
18171821

noir-projects/fnd/noir-protocol-circuits/crates/rollup-block-root/Prover.toml

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ l1_to_l2_message_frontier_hint = [
3939
]
4040
new_archive_sibling_path = [
4141
"0x0000000000000000000000000000000000000000000000000000000000000000",
42-
"0x111f90dfe6a42b72a65046b7a1203d1249f522b498f11feda2da45ec757fed25",
42+
"0x284d753011a1544ea66ccc1024bcc2aef83468522f0151d20454f31a06424e77",
4343
"0x14e4b977b2203b70e6ee1c2456eb7114d090fe4b907f631eecd0919fed432e7d",
4444
"0x30105bad22ddcc508b739b7c9ad87a561c569ff5cb0098a853c1c4ac21b7a037",
4545
"0x1e20ad4181460cbfdc74ca773502c59b890f184efe300ebad895956d318422da",
@@ -561,12 +561,12 @@ new_archive_sibling_path = [
561561
accumulated_mana_used = "0x000000000000000000000000000000000000000000000000000000000006b6c0"
562562

563563
[inputs.previous_rollups.public_inputs.constants]
564-
vk_tree_root = "0x0a178ec6fe216bfa6e2d25089ce97f9ff6b5c5701d2bce2a1fdf11e6dc351e3c"
564+
vk_tree_root = "0x1d51e7bb66dda198c072b182a8e4809fc6614d677c914af2afa9c5376f16f06d"
565565
protocol_contracts_hash = "0x0727efc9473643b7abbe3c57df72d68e86b244b99cae71b17553c0f937ea433b"
566566
prover_id = "0x0000000000000000000000000000000000000000000000000000000000000000"
567567

568568
[inputs.previous_rollups.public_inputs.constants.last_archive]
569-
root = "0x09eab2d41c2ecafb0668fbada15342c670b7102c777e8fe01688205370be35dd"
569+
root = "0x22fb435f1b17b06f994e96f8b9092935bb52d7ff089f9da911deb76fb11eafd0"
570570
next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000002"
571571

572572
[inputs.previous_rollups.public_inputs.constants.l1_to_l2_tree_snapshot]
@@ -624,10 +624,10 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
624624
"0x1e1c597744057b88e39a9780ed087c39b1fc42864e05ef03a59ebd9e96b70b00"
625625
]
626626
state = [
627-
"0x1340f2f29cb8306ff70bcc4ae858857833524119183778ecc6ad42461cffd2ec",
628-
"0x0ded042d3f2742a39c12f49fea7578be6ca12907c913496a96aac8a4beab7da7",
629-
"0x07fce0817fe38521b58a9910cc882430a755bfe4141eb684f9e13bb55ea08d59",
630-
"0x2c426510a61e082128e8b428a5af495ed7351f768d421f3af48442dde4997151"
627+
"0x2a5cf7199bc1a5f8871b4fea5c6f99f5dba43db93b819ca26d2fa8dbbdc1f82c",
628+
"0x011cf649f43e718babd7d68caa9d36ccebf49e536e764b6674fc8ca18e8a4ada",
629+
"0x17d68b99d3347b9908ca791c2a098777db49c111ac24b850a48e36fd0329b4e4",
630+
"0x038347b13467b09e427b9f4154c2d36b1cd02bd1b08d8ea406687512f0b16a79"
631631
]
632632
cache_size = "0x0000000000000000000000000000000000000000000000000000000000000002"
633633
squeeze_mode = false
@@ -642,10 +642,10 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
642642
"0x00000000000000000000000000000000000000000000000000000000b7f9d44d"
643643
]
644644
state = [
645-
"0x1f28dcf22870bc323df6d045183ab4e620f63c728f91adb34989c7f0fa15014e",
646-
"0x11f9c62ca437d779c42395acdfa9aa365198c2c31c659401d9f436e898895308",
647-
"0x22b47289bb74cee917c189d8d045521b296102ee2cd45d4a78df74c2d5fa0f7b",
648-
"0x234bafa32c222e8d0eb62eaede11e3bfa20b4287f68b880c744abe51ac88ab6d"
645+
"0x2d2cd78abcdb723be782846e1ad64ae3ab9aa2260689da6ae7475677befc11c2",
646+
"0x0250e73c2089d502af086b4d31fc90a61b62f71901e93588a19421c1e54417db",
647+
"0x1225c74c7caef02691c6f3a18a18ed4ce10675ec8286339594bef2cee3bcdf01",
648+
"0x0b9145803dfcf3b0958502feb867fdbb62eb5726361b0971f704ffe19719c0af"
649649
]
650650
cache_size = "0x0000000000000000000000000000000000000000000000000000000000000001"
651651
squeeze_mode = false
@@ -656,7 +656,7 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
656656
"0x1fc39d0a428c8536dbca551ea79848acf67d89d090fd8c643c7d90f2e8f32340",
657657
"0x12ce5a49a1ceca53ada7bee003f929bbd65abaa74e8072a81f304c2c96c44e31",
658658
"0x2dd71474f7775d87b6c2986ace5f654686583f0970d7400b1ccf8096dad131b5",
659-
"0x0aca02f69b05a42958d30ced7da19a9e135e0c83b75e72ae5f7e2bec714a418f",
659+
"0x1bd9ea476112f37bb5ce44ce3c3f0d2e62e20993253269166a016eda81ac1007",
660660
"0x134e9973b03d62389ee6021d35e61158807c7da3c3e6a052d365f53ab1ac214d",
661661
"0x118d25fdd2c4cc96d5af69bd85930dd49d101d463e3f5ee9f2cc9236384b5d41",
662662
"0x19dc50e83dfaeddfc1eb7b19cfcf39ef4b5608eecfaf54180697ea982b7bebbd"
@@ -1273,12 +1273,12 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
12731273
accumulated_mana_used = "0x0000000000000000000000000000000000000000000000000000000000000000"
12741274

12751275
[inputs.previous_rollups.public_inputs.constants]
1276-
vk_tree_root = "0x0a178ec6fe216bfa6e2d25089ce97f9ff6b5c5701d2bce2a1fdf11e6dc351e3c"
1276+
vk_tree_root = "0x1d51e7bb66dda198c072b182a8e4809fc6614d677c914af2afa9c5376f16f06d"
12771277
protocol_contracts_hash = "0x0727efc9473643b7abbe3c57df72d68e86b244b99cae71b17553c0f937ea433b"
12781278
prover_id = "0x0000000000000000000000000000000000000000000000000000000000000000"
12791279

12801280
[inputs.previous_rollups.public_inputs.constants.last_archive]
1281-
root = "0x09eab2d41c2ecafb0668fbada15342c670b7102c777e8fe01688205370be35dd"
1281+
root = "0x22fb435f1b17b06f994e96f8b9092935bb52d7ff089f9da911deb76fb11eafd0"
12821282
next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000002"
12831283

12841284
[inputs.previous_rollups.public_inputs.constants.l1_to_l2_tree_snapshot]
@@ -1336,10 +1336,10 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
13361336
"0x00000000000000000000000000000000000000000000000000000000b7f9d44d"
13371337
]
13381338
state = [
1339-
"0x1f28dcf22870bc323df6d045183ab4e620f63c728f91adb34989c7f0fa15014e",
1340-
"0x11f9c62ca437d779c42395acdfa9aa365198c2c31c659401d9f436e898895308",
1341-
"0x22b47289bb74cee917c189d8d045521b296102ee2cd45d4a78df74c2d5fa0f7b",
1342-
"0x234bafa32c222e8d0eb62eaede11e3bfa20b4287f68b880c744abe51ac88ab6d"
1339+
"0x2d2cd78abcdb723be782846e1ad64ae3ab9aa2260689da6ae7475677befc11c2",
1340+
"0x0250e73c2089d502af086b4d31fc90a61b62f71901e93588a19421c1e54417db",
1341+
"0x1225c74c7caef02691c6f3a18a18ed4ce10675ec8286339594bef2cee3bcdf01",
1342+
"0x0b9145803dfcf3b0958502feb867fdbb62eb5726361b0971f704ffe19719c0af"
13431343
]
13441344
cache_size = "0x0000000000000000000000000000000000000000000000000000000000000001"
13451345
squeeze_mode = false
@@ -1354,10 +1354,10 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
13541354
"0x00000000000000000000000000000000000000000000000000000000b80de34e"
13551355
]
13561356
state = [
1357-
"0x134946855417bcc442f889686f1d56a235ef003975c044d0247a83233b410758",
1358-
"0x1b72a1748313dbe8d809b3fcbafc90c42245820ec62b0dad170882743ff5229f",
1359-
"0x0c028e173991130ade8d45c7ca581aba2786fafd52c6204542bedbd83554d15e",
1360-
"0x1d53b7e7cf226e419d853dc8cfc46ecd424838a883d07356d2a1fa811e38c34e"
1357+
"0x081ffd41f516611101fabed22dbbba6e6bf5ac0eff43aa020fb8407fe66471be",
1358+
"0x07e1027927852cc3291b4d5b979823dfacab903c13b5bd3f2590388210b608ed",
1359+
"0x17c059bfe7dca4a328bf27482e1c7d33887c0ff69b69f2be89eb754266e263ed",
1360+
"0x1e85bde3c04a4baa1d2d6e1237d10ced927e777bbd7fa7c31fce28cdd79b92ca"
13611361
]
13621362
cache_size = "0x0000000000000000000000000000000000000000000000000000000000000003"
13631363
squeeze_mode = false
@@ -1367,7 +1367,7 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
13671367
sibling_path = [
13681368
"0x10b6730f1d1e9c6bf8d7c4b42b64b40d2603e3ae6ddbd464c3d8fcfb9e06e6d4",
13691369
"0x014ffec160e37b6cb713c1a4e6e7058964dde1733e6734520ed72f72fd262919",
1370-
"0x196cbe2980734bc5d21b53464a1d00c06dad0febdec75822d79d6933dff40579",
1370+
"0x14bb1983f28c88ab603e0fe7e46b743829816df364ec385e2245072c3dad3e1e",
13711371
"0x0787c8cc4cfb80390c27cdc17cb24ae198faad7989508690070b3cf40a2ae4fd",
13721372
"0x134e9973b03d62389ee6021d35e61158807c7da3c3e6a052d365f53ab1ac214d",
13731373
"0x118d25fdd2c4cc96d5af69bd85930dd49d101d463e3f5ee9f2cc9236384b5d41",
@@ -2524,6 +2524,10 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000
25242524
num_msgs = "0x0000000000000000000000000000000000000000000000000000000000000000"
25252525
num_real_msgs = "0x0000000000000000000000000000000000000000000000000000000000000000"
25262526

2527+
[inputs.previous_l1_to_l2]
2528+
root = "0x18d6aae3ab4a271abd590cb98267825b70de1e9e5c339356e94ea5fc7feba64b"
2529+
next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000400"
2530+
25272531
[inputs.start_msg_sponge]
25282532
num_absorbed = "0x0000000000000000000000000000000000000000000000000000000000000400"
25292533

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// TODO: Move to types/src/abis/rollup/
2-
// `l1_to_l2_message_sponge` is declared first because the serde `#[derive(...)]` macro requires a field type's module
3-
// to be declared before any struct that embeds it (see the ordering note in `types/src/lib.nr`).
2+
// `l1_to_l2_message_sponge` is declared first because the `#[derive(Serialize, Deserialize)]` macros require a field
3+
// type's module to be declared before any struct that embeds it (see the ordering note in `types/src/lib.nr`).
44
mod l1_to_l2_message_sponge;
55
mod l1_to_l2_message_bundle;
66
mod public_chonk_verifier_public_inputs;

noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/abis/root_rollup_public_inputs.nr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ pub struct RootRollupPublicInputs {
1818
// The out hash of the first checkpoint in the epoch is inserted at index 0, the second at index 1, and so on.
1919
pub out_hash: Field,
2020
// Inbox rolling-hash chain segment consumed across the epoch: the chain value before the first checkpoint's
21-
// messages and after the last checkpoint's. Continuity within the range is enforced by the checkpoint merges;
22-
// L1 passes both through to proof verification without validating them until the Fast Inbox flip.
21+
// messages and after the last checkpoint's. Continuity within the range is enforced by the checkpoint merges.
2322
pub previous_inbox_rolling_hash: Field,
2423
pub end_inbox_rolling_hash: Field,
2524
// Checkpoint header hashes for each checkpoint in this epoch.

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ fn assert_prev_block_rollups_follow_on_from_each_other(
4242
"Mismatched timestamps: expected right.timestamp to match left.timestamp",
4343
);
4444

45-
// TODO: Consider extracting into its own function:
46-
4745
// `is_first_block` originates from the first block root only, and is propagated through all merge steps via the
4846
// left rollup only (see merge_block_rollups.nr). We prevent the right rollup from carrying it, so it's impossible
4947
// for any block but the first to propagate `is_first_block == true` up to the checkpoint root.

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

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
use crate::{
22
abis::{BlockRollupPublicInputs, L1ToL2MessageBundle, L1ToL2MessageSponge, TxRollupPublicInputs},
3-
block_root::components::{BlockRollupPublicInputsComposer, validate_previous_rollups},
3+
block_root::components::{
4+
BlockRollupPublicInputsComposer, validate_l1_to_l2_tree_snapshot_in_constants,
5+
validate_previous_rollups,
6+
},
47
};
58
use types::{
9+
abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot,
610
constants::{
711
ARCHIVE_HEIGHT, L1_TO_L2_MSG_TREE_HEIGHT, PRIVATE_TX_BASE_ROLLUP_VK_INDEX,
812
PUBLIC_TX_BASE_ROLLUP_VK_INDEX, TX_MERGE_ROLLUP_VK_INDEX,
@@ -17,11 +21,15 @@ pub struct BlockRootRollupPrivateInputs {
1721
pub(crate) previous_rollups: [RollupHonkProofData<TxRollupPublicInputs>; 2],
1822
// L1-to-L2 message bundle inserted by this block.
1923
pub(crate) message_bundle: L1ToL2MessageBundle,
24+
// The l1-to-l2 tree snapshot this block builds on (the previous block's post-insertion snapshot). It is a witnessed
25+
// value, pinned by block-merge continuity (`right.start_state == left.end_state`) to the previous block's end
26+
// state; since the checkpoint root forces the leftmost block to be a first-block variant, every non-first block
27+
// has a left neighbour that pins it.
28+
pub(crate) previous_l1_to_l2: AppendOnlyTreeSnapshot,
2029
// Message sponge inherited from the previous block. Checked against the previous block's `end_msg_sponge` in the
2130
// block merge or checkpoint root circuit.
2231
pub(crate) start_msg_sponge: L1ToL2MessageSponge,
23-
// Frontier hint for appending the bundle to the l1-to-l2 message tree (validated against the tree snapshot in the
24-
// constants, which is where the l1-to-l2 tree stands for this non-first block).
32+
// Frontier hint for appending the bundle to the l1-to-l2 message tree (validated against `previous_l1_to_l2`).
2533
pub(crate) l1_to_l2_message_frontier_hint: [Field; L1_TO_L2_MSG_TREE_HEIGHT],
2634
// Hint for inserting the new block hash to the last archive.
2735
pub(crate) new_archive_sibling_path: [Field; ARCHIVE_HEIGHT],
@@ -43,18 +51,29 @@ pub struct BlockRootRollupPrivateInputs {
4351
///
4452
/// VkIndex: BLOCK_ROOT_ROLLUP_VK_INDEX
4553
pub fn execute(inputs: BlockRootRollupPrivateInputs) -> BlockRollupPublicInputs {
46-
validate_previous_rollups(inputs.previous_rollups, ALLOWED_PREVIOUS_VK_INDICES);
47-
4854
let previous_rollups = inputs.previous_rollups.map(|rollup| rollup.public_inputs);
49-
// Non-first blocks build on the l1-to-l2 tree snapshot carried in the checkpoint constants.
50-
let previous_l1_to_l2 = previous_rollups[0].constants.l1_to_l2_tree_snapshot;
51-
BlockRollupPublicInputsComposer::new_from_two_rollups(previous_rollups)
55+
// Non-first blocks build on a witnessed start snapshot (pinned by block-merge continuity to the previous block's
56+
// end state) rather than the constants value, so this block can append its own bundle and still assert the tx
57+
// constants carry the post-bundle snapshot.
58+
let mut composer = BlockRollupPublicInputsComposer::new_from_two_rollups(previous_rollups);
59+
let new_l1_to_l2 = composer
5260
.with_message_bundle(
5361
false,
54-
previous_l1_to_l2,
62+
inputs.previous_l1_to_l2,
5563
inputs.start_msg_sponge,
5664
inputs.message_bundle,
5765
inputs.l1_to_l2_message_frontier_hint,
5866
)
59-
.finish(inputs.new_archive_sibling_path)
67+
.get_new_l1_to_l2();
68+
69+
validate_previous_rollups(inputs.previous_rollups, ALLOWED_PREVIOUS_VK_INDICES);
70+
71+
// The tx constants pin the l1-to-l2 snapshot the AVM validates message reads against; asserting it equals this
72+
// block's post-bundle root lets this block's txs read the messages this block inserts (same-block consumption).
73+
validate_l1_to_l2_tree_snapshot_in_constants(
74+
inputs.previous_rollups[0].public_inputs.constants,
75+
new_l1_to_l2,
76+
);
77+
78+
composer.finish(inputs.new_archive_sibling_path)
6079
}

0 commit comments

Comments
 (0)