11import { MAX_L2_TO_L1_MSGS_PER_TX } from '@aztec/constants' ;
22import { EpochNumber } from '@aztec/foundation/branded-types' ;
3- import { padArrayEnd } from '@aztec/foundation/collection' ;
3+ import { padArrayEnd , sum } from '@aztec/foundation/collection' ;
44import { Fr } from '@aztec/foundation/curves/bn254' ;
55import { EthAddress } from '@aztec/foundation/eth-address' ;
66import { createLogger } from '@aztec/foundation/log' ;
@@ -225,7 +225,8 @@ describe('prover/orchestrator/checkpoint-sub-tree', () => {
225225 // carries none (txs only), and the last block carries a bundle with zero txs (a message-only block, proven by
226226 // the msgs-only block root). The sub-tree must append each block's own slice at compact indices with
227227 // contiguous, non-overlapping per-block snapshots, and thread the message sponge across the blocks (AZIP-22
228- // Fast Inbox).
228+ // Fast Inbox). The sub-tree result surfaces post-merge top-level nodes (at most two, for the binary
229+ // checkpoint root), not one output per block.
229230 const l1ToL2MessagesPerBlock = [ [ new Fr ( 1001 ) , new Fr ( 1002 ) ] , [ ] , [ new Fr ( 1003 ) , new Fr ( 1004 ) , new Fr ( 1005 ) ] ] ;
230231 const numBlocks = l1ToL2MessagesPerBlock . length ;
231232 const { constants, blocks, l1ToL2Messages, previousBlockHeader } = await context . makeCheckpointWithMessagesPerBlock (
@@ -261,15 +262,19 @@ describe('prover/orchestrator/checkpoint-sub-tree', () => {
261262 }
262263
263264 const result = await resultPromise ;
264- expect ( result . blockProofOutputs ) . toHaveLength ( numBlocks ) ;
265+ // Three block roots reduce to two top-level outputs: a block-merge over blocks 0-1 and block 2's msgs-only
266+ // root. Merge public inputs span their range: is_first_block propagates from the left child, the start
267+ // sponge/state come from the left child and the end sponge/state from the right.
268+ const expectedOutputBlockRanges = [ [ 0 , 1 ] , [ 2 ] ] ;
269+ expect ( result . blockProofOutputs ) . toHaveLength ( expectedOutputBlockRanges . length ) ;
265270
266- // Order the block outputs by block number (the archive tree grows by exactly one leaf per block).
271+ // Order the outputs by position in the checkpoint (the archive tree grows by one leaf per block).
267272 const ordered = [ ...result . blockProofOutputs ] . sort (
268273 ( a , b ) => a . inputs . previousArchive . nextAvailableLeafIndex - b . inputs . previousArchive . nextAvailableLeafIndex ,
269274 ) ;
270275
271- // Walk the blocks in order, asserting the L1-to-L2 message tree partitions cleanly into per-block slices,
272- // with each block 's start snapshot equal to the previous block 's end snapshot (the "threaded" per-block
276+ // Walk the outputs in order, asserting the L1-to-L2 message tree partitions cleanly into per-output slices,
277+ // with each output 's start snapshot equal to the previous output 's end snapshot (the "threaded" per-block
273278 // L1-to-L2 tree state).
274279 const baseLeaf = ordered [ 0 ] . inputs . startState . l1ToL2MessageTree . nextAvailableLeafIndex ;
275280 let expectedStartLeaf = baseLeaf ;
@@ -279,21 +284,24 @@ describe('prover/orchestrator/checkpoint-sub-tree', () => {
279284 const expectedSponge = L1ToL2MessageSponge . empty ( ) ;
280285 for ( const [ i , output ] of ordered . entries ( ) ) {
281286 const inputs = output . inputs ;
287+ const blockIndexes = expectedOutputBlockRanges [ i ] ;
282288 const startLeaf = inputs . startState . l1ToL2MessageTree . nextAvailableLeafIndex ;
283289 const endLeaf = inputs . endState . l1ToL2MessageTree . nextAvailableLeafIndex ;
284- const sliceLen = l1ToL2MessagesPerBlock [ i ] . length ;
290+ const sliceLen = sum ( blockIndexes . map ( b => l1ToL2MessagesPerBlock [ b ] . length ) ) ;
285291
286- // Only the checkpoint's first block flags isFirstBlock.
287- expect ( inputs . isFirstBlock ) . toBe ( i === 0 ) ;
288- // Contiguous, non-overlapping slices: this block starts where the previous one ended (no gap/overlap).
292+ // Only the output covering the checkpoint's first block flags isFirstBlock.
293+ expect ( inputs . isFirstBlock ) . toBe ( blockIndexes . includes ( 0 ) ) ;
294+ // Contiguous, non-overlapping slices: this output starts where the previous one ended (no gap/overlap).
289295 expect ( startLeaf ) . toBe ( expectedStartLeaf ) ;
290- // Block slice = [prevBlockLeafCount, blockLeafCount): the tree grows by exactly this block's bundle size .
296+ // The tree grows by exactly the covered blocks' bundle sizes .
291297 expect ( endLeaf - startLeaf ) . toBe ( sliceLen ) ;
292298 expectedStartLeaf = endLeaf ;
293299
294- // Sponge continuity: this block starts from the previous block 's end sponge and absorbs its own slice .
300+ // Sponge continuity: this output starts from the previous one 's end sponge and absorbs its blocks' slices .
295301 expect ( inputs . startMsgSponge . toBuffer ( ) ) . toEqual ( expectedSponge . toBuffer ( ) ) ;
296- await expectedSponge . absorb ( l1ToL2MessagesPerBlock [ i ] ) ;
302+ for ( const blockIndex of blockIndexes ) {
303+ await expectedSponge . absorb ( l1ToL2MessagesPerBlock [ blockIndex ] ) ;
304+ }
297305 expect ( inputs . endMsgSponge . toBuffer ( ) ) . toEqual ( expectedSponge . toBuffer ( ) ) ;
298306 }
299307
0 commit comments