@@ -70,9 +70,13 @@ impl TransactionBatch {
7070 // CONSTRUCTORS
7171 // --------------------------------------------------------------------------------------------
7272
73- /// Returns a new [TransactionBatch] instantiated from the provided vector of proven
74- /// transactions. If a map of unauthenticated notes found in the store is provided, it is used
75- /// for transforming unauthenticated notes into authenticated notes.
73+ /// Returns a new [TransactionBatch] built from the provided transactions. If a map of
74+ /// unauthenticated notes found in the store is provided, it is used for transforming
75+ /// unauthenticated notes into authenticated notes.
76+ ///
77+ /// The tx input takes an `IntoIterator` of a reference, which effectively allows for cheap
78+ /// cloning of the iterator. Or put differently, we want something similar to `impl
79+ /// Iterator<Item = ProvenTransaction> + Clone` which this provides.
7680 ///
7781 /// # Errors
7882 ///
@@ -81,17 +85,21 @@ impl TransactionBatch {
8185 /// in the batch.
8286 /// - Hashes for corresponding input notes and output notes don't match.
8387 #[ instrument( target = "miden-block-producer" , name = "new_batch" , skip_all, err) ]
84- pub fn new (
85- txs : Vec < ProvenTransaction > ,
88+ pub fn new < ' a , I > (
89+ txs : impl IntoIterator < Item = & ' a ProvenTransaction , IntoIter = I > ,
8690 found_unauthenticated_notes : NoteAuthenticationInfo ,
87- ) -> Result < Self , BuildBatchError > {
88- let id = Self :: compute_id ( & txs) ;
91+ ) -> Result < Self , BuildBatchError >
92+ where
93+ I : Iterator < Item = & ' a ProvenTransaction > + Clone ,
94+ {
95+ let tx_iter = txs. into_iter ( ) ;
96+ let id = Self :: compute_id ( tx_iter. clone ( ) ) ;
8997
9098 // Populate batch output notes and updated accounts.
91- let mut output_notes = OutputNoteTracker :: new ( & txs ) ?;
99+ let mut output_notes = OutputNoteTracker :: new ( tx_iter . clone ( ) ) ?;
92100 let mut updated_accounts = BTreeMap :: < AccountId , AccountUpdate > :: new ( ) ;
93101 let mut unauthenticated_input_notes = BTreeSet :: new ( ) ;
94- for tx in & txs {
102+ for tx in tx_iter . clone ( ) {
95103 // Merge account updates so that state transitions A->B->C become A->C.
96104 match updated_accounts. entry ( tx. account_id ( ) ) {
97105 Entry :: Vacant ( vacant) => {
@@ -121,26 +129,28 @@ impl TransactionBatch {
121129 // note `x` (i.e., have a circular dependency between transactions), but this is not
122130 // a problem.
123131 let mut input_notes = vec ! [ ] ;
124- for input_note in txs. iter ( ) . flat_map ( |tx| tx. input_notes ( ) . iter ( ) ) {
125- // Header is presented only for unauthenticated input notes.
126- let input_note = match input_note. header ( ) {
127- Some ( input_note_header) => {
128- if output_notes. remove_note ( input_note_header) ? {
129- continue ;
130- }
131-
132- // If an unauthenticated note was found in the store, transform it to an
133- // authenticated one (i.e. erase additional note details
134- // except the nullifier)
135- if found_unauthenticated_notes. contains_note ( & input_note_header. id ( ) ) {
136- InputNoteCommitment :: from ( input_note. nullifier ( ) )
137- } else {
138- input_note. clone ( )
139- }
140- } ,
141- None => input_note. clone ( ) ,
142- } ;
143- input_notes. push ( input_note)
132+ for tx in tx_iter {
133+ for input_note in tx. input_notes ( ) . iter ( ) {
134+ // Header is presented only for unauthenticated input notes.
135+ let input_note = match input_note. header ( ) {
136+ Some ( input_note_header) => {
137+ if output_notes. remove_note ( input_note_header) ? {
138+ continue ;
139+ }
140+
141+ // If an unauthenticated note was found in the store, transform it to an
142+ // authenticated one (i.e. erase additional note details
143+ // except the nullifier)
144+ if found_unauthenticated_notes. contains_note ( & input_note_header. id ( ) ) {
145+ InputNoteCommitment :: from ( input_note. nullifier ( ) )
146+ } else {
147+ input_note. clone ( )
148+ }
149+ } ,
150+ None => input_note. clone ( ) ,
151+ } ;
152+ input_notes. push ( input_note)
153+ }
144154 }
145155
146156 let output_notes = output_notes. into_notes ( ) ;
@@ -208,8 +218,8 @@ impl TransactionBatch {
208218 // HELPER FUNCTIONS
209219 // --------------------------------------------------------------------------------------------
210220
211- fn compute_id ( txs : & [ ProvenTransaction ] ) -> BatchId {
212- let mut buf = Vec :: with_capacity ( 32 * txs. len ( ) ) ;
221+ fn compute_id < ' a > ( txs : impl Iterator < Item = & ' a ProvenTransaction > ) -> BatchId {
222+ let mut buf = Vec :: with_capacity ( 32 * txs. size_hint ( ) . 0 ) ;
213223 for tx in txs {
214224 buf. extend_from_slice ( & tx. id ( ) . as_bytes ( ) ) ;
215225 }
@@ -224,7 +234,7 @@ struct OutputNoteTracker {
224234}
225235
226236impl OutputNoteTracker {
227- fn new ( txs : & [ ProvenTransaction ] ) -> Result < Self , BuildBatchError > {
237+ fn new < ' a > ( txs : impl Iterator < Item = & ' a ProvenTransaction > ) -> Result < Self , BuildBatchError > {
228238 let mut output_notes = vec ! [ ] ;
229239 let mut output_note_index = BTreeMap :: new ( ) ;
230240 for tx in txs {
@@ -283,7 +293,7 @@ mod tests {
283293 fn output_note_tracker_duplicate_output_notes ( ) {
284294 let mut txs = mock_proven_txs ( ) ;
285295
286- let result = OutputNoteTracker :: new ( & txs) ;
296+ let result = OutputNoteTracker :: new ( txs. iter ( ) ) ;
287297 assert ! (
288298 result. is_ok( ) ,
289299 "Creation of output note tracker was not expected to fail: {result:?}"
@@ -297,7 +307,7 @@ mod tests {
297307 vec ! [ duplicate_output_note. clone( ) , mock_output_note( 8 ) , mock_output_note( 4 ) ] ,
298308 ) ) ;
299309
300- match OutputNoteTracker :: new ( & txs) {
310+ match OutputNoteTracker :: new ( txs. iter ( ) ) {
301311 Err ( BuildBatchError :: DuplicateOutputNote ( note_id) ) => {
302312 assert_eq ! ( note_id, duplicate_output_note. id( ) )
303313 } ,
@@ -308,7 +318,7 @@ mod tests {
308318 #[ test]
309319 fn output_note_tracker_remove_in_place_consumed_note ( ) {
310320 let txs = mock_proven_txs ( ) ;
311- let mut tracker = OutputNoteTracker :: new ( & txs) . unwrap ( ) ;
321+ let mut tracker = OutputNoteTracker :: new ( txs. iter ( ) ) . unwrap ( ) ;
312322
313323 let note_to_remove = mock_note ( 4 ) ;
314324
@@ -333,7 +343,7 @@ mod tests {
333343 let mut txs = mock_proven_txs ( ) ;
334344 let duplicate_note = mock_note ( 5 ) ;
335345 txs. push ( mock_proven_tx ( 4 , vec ! [ duplicate_note. clone( ) ] , vec ! [ mock_output_note( 9 ) ] ) ) ;
336- match TransactionBatch :: new ( txs, Default :: default ( ) ) {
346+ match TransactionBatch :: new ( & txs, Default :: default ( ) ) {
337347 Err ( BuildBatchError :: DuplicateUnauthenticatedNote ( note_id) ) => {
338348 assert_eq ! ( note_id, duplicate_note. id( ) )
339349 } ,
@@ -351,7 +361,7 @@ mod tests {
351361 vec ! [ mock_output_note( 9 ) , mock_output_note( 10 ) ] ,
352362 ) ) ;
353363
354- let batch = TransactionBatch :: new ( txs, Default :: default ( ) ) . unwrap ( ) ;
364+ let batch = TransactionBatch :: new ( & txs, Default :: default ( ) ) . unwrap ( ) ;
355365
356366 // One of the unauthenticated notes must be removed from the batch due to the consumption
357367 // of the corresponding output note
@@ -395,7 +405,7 @@ mod tests {
395405 note_proofs : found_unauthenticated_notes,
396406 block_proofs : Default :: default ( ) ,
397407 } ;
398- let batch = TransactionBatch :: new ( txs, found_unauthenticated_notes) . unwrap ( ) ;
408+ let batch = TransactionBatch :: new ( & txs, found_unauthenticated_notes) . unwrap ( ) ;
399409
400410 let expected_input_notes =
401411 vec ! [ mock_unauthenticated_note_commitment( 1 ) , mock_note( 5 ) . nullifier( ) . into( ) ] ;
0 commit comments