@@ -35,6 +35,11 @@ use types::{
3535 traits ::{Deserialize , Empty , Hash },
3636};
3737
38+ // The fixture pre-fills l1-to-l2 leaves into a single subtree of 2^3 = 8 leaves, which bounds how far into the tree a
39+ // block's bundle can be made to start. The bundle append itself is not aligned to that subtree.
40+ global PRE_EXISTING_L1_TO_L2_SUBTREE_HEIGHT : u32 = 3 ;
41+ global PRE_EXISTING_L1_TO_L2_LEAF_COUNT : u32 = 8 ;
42+
3843pub struct RollupFixtureBuilder {
3944 // Epoch constants.
4045 pub chain_id : Field ,
@@ -181,23 +186,51 @@ impl RollupFixtureBuilder {
181186 }
182187
183188 /// Builds a per-block L1-to-L2 message bundle appended to an empty tree, returning
184- /// `(previous_snapshot, leaves, num_msgs, frontier_hint, new_snapshot)`. The empty tree has an all-zero frontier,
185- /// and the resulting `new_snapshot` is exactly what the block root circuit recomputes from the same inputs.
189+ /// `(previous_snapshot, leaves, frontier_hint, new_snapshot)`. The resulting `new_snapshot` is exactly what the
190+ /// block root circuit recomputes from the same inputs.
186191 pub fn build_l1_to_l2_message_bundle (
192+ self ,
193+ num_msgs : u32 ,
194+ ) -> (AppendOnlyTreeSnapshot , [Field ; MAX_L1_TO_L2_MSGS_PER_BLOCK ], [Field ; L1_TO_L2_MSG_TREE_HEIGHT ], AppendOnlyTreeSnapshot ) {
195+ self .build_l1_to_l2_message_bundle_at_index (num_msgs , 0 )
196+ }
197+
198+ /// Same as `build_l1_to_l2_message_bundle`, but appending into a tree that already holds `start_index` leaves —
199+ /// the compact, unaligned append every block after the very first one performs. The pre-existing leaves sit in a
200+ /// single subtree of `PRE_EXISTING_L1_TO_L2_LEAF_COUNT` leaves, so `start_index` must stay below that. The frontier
201+ /// hint is the tree's sibling path at `start_index`, which is how a tree database answers for it: the pending left
202+ /// sibling at every level where the index is a right child, and the zero-subtree root everywhere else.
203+ pub fn build_l1_to_l2_message_bundle_at_index (
187204 _self : Self ,
188205 num_msgs : u32 ,
206+ start_index : u32 ,
189207 ) -> (AppendOnlyTreeSnapshot , [Field ; MAX_L1_TO_L2_MSGS_PER_BLOCK ], [Field ; L1_TO_L2_MSG_TREE_HEIGHT ], AppendOnlyTreeSnapshot ) {
208+ assert (
209+ start_index < PRE_EXISTING_L1_TO_L2_LEAF_COUNT ,
210+ "The fixture cannot pre-fill that many l1-to-l2 leaves" ,
211+ );
212+
213+ let mut pre_existing = [0 ; PRE_EXISTING_L1_TO_L2_LEAF_COUNT ];
214+ for i in 0 ..PRE_EXISTING_L1_TO_L2_LEAF_COUNT {
215+ if i < start_index {
216+ pre_existing [i ] = (i + 1 ) as Field * 7 ;
217+ }
218+ }
219+ let tree = SingleSubtreeMerkleTree ::<PRE_EXISTING_L1_TO_L2_LEAF_COUNT , PRE_EXISTING_L1_TO_L2_SUBTREE_HEIGHT , L1_TO_L2_MSG_TREE_HEIGHT >::new (
220+ pre_existing ,
221+ );
222+
190223 let mut leaves = [0 ; MAX_L1_TO_L2_MSGS_PER_BLOCK ];
191224 for i in 0 ..MAX_L1_TO_L2_MSGS_PER_BLOCK {
192225 if i < num_msgs {
193226 leaves [i ] = (i + 1 ) as Field * 100 ;
194227 }
195228 }
196229 let previous = AppendOnlyTreeSnapshot {
197- root : compute_empty_tree_root ::< L1_TO_L2_MSG_TREE_HEIGHT > (),
198- next_available_leaf_index : 0 ,
230+ root : tree . get_root (),
231+ next_available_leaf_index : start_index as Field ,
199232 };
200- let frontier_hint = [ 0 ; L1_TO_L2_MSG_TREE_HEIGHT ] ;
233+ let frontier_hint = tree . get_sibling_path ( start_index as Field ) ;
201234 let new = append_leaves_to_snapshot ::<L1_TO_L2_MSG_TREE_HEIGHT , MAX_L1_TO_L2_MSGS_PER_BLOCK >(
202235 previous ,
203236 leaves ,
0 commit comments