Skip to content

Commit 28c20d0

Browse files
feat(block-producer): remove deep clone of tx data (#570)
This was previously added in #544 but was mistakenly dropped by a rebase.
1 parent aaaef51 commit 28c20d0

5 files changed

Lines changed: 69 additions & 72 deletions

File tree

crates/block-producer/src/batch_builder/batch.rs

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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

226236
impl 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()];

crates/block-producer/src/batch_builder/mod.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -243,13 +243,7 @@ impl WorkerPool {
243243
info!(target: COMPONENT, num_txs, "Building a transaction batch");
244244
debug!(target: COMPONENT, txs = %format_array(txs.iter().map(|tx| tx.id().to_hex())));
245245

246-
// TODO: This is a deep clone which can be avoided by change batch building to using
247-
// refs or arcs.
248-
let txs = txs
249-
.iter()
250-
.map(AuthenticatedTransaction::raw_proven_transaction)
251-
.cloned()
252-
.collect();
246+
let txs = txs.iter().map(AuthenticatedTransaction::raw_proven_transaction);
253247
// TODO: Found unauthenticated notes are no longer required.. potentially?
254248
let batch = TransactionBatch::new(txs, Default::default())?;
255249

crates/block-producer/src/block_builder/prover/tests.rs

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ fn block_witness_validation_inconsistent_account_ids() {
6969
)
7070
.build();
7171

72-
TransactionBatch::new(vec![tx], Default::default()).unwrap()
72+
TransactionBatch::new([&tx], Default::default()).unwrap()
7373
};
7474

7575
let batch_2 = {
@@ -80,7 +80,7 @@ fn block_witness_validation_inconsistent_account_ids() {
8080
)
8181
.build();
8282

83-
TransactionBatch::new(vec![tx], Default::default()).unwrap()
83+
TransactionBatch::new([&tx], Default::default()).unwrap()
8484
};
8585

8686
vec![batch_1, batch_2]
@@ -132,7 +132,7 @@ fn block_witness_validation_inconsistent_account_hashes() {
132132

133133
let batches = {
134134
let batch_1 = TransactionBatch::new(
135-
vec![MockProvenTxBuilder::with_account(
135+
[&MockProvenTxBuilder::with_account(
136136
account_id_1,
137137
account_1_hash_batches,
138138
Digest::default(),
@@ -142,7 +142,7 @@ fn block_witness_validation_inconsistent_account_hashes() {
142142
)
143143
.unwrap();
144144
let batch_2 = TransactionBatch::new(
145-
vec![MockProvenTxBuilder::with_account(
145+
[&MockProvenTxBuilder::with_account(
146146
account_id_2,
147147
Digest::default(),
148148
Digest::default(),
@@ -233,12 +233,8 @@ fn block_witness_multiple_batches_per_account() {
233233
};
234234

235235
let batches = {
236-
let batch_1 =
237-
TransactionBatch::new(vec![x_txs[0].clone(), y_txs[1].clone()], Default::default())
238-
.unwrap();
239-
let batch_2 =
240-
TransactionBatch::new(vec![y_txs[0].clone(), x_txs[1].clone()], Default::default())
241-
.unwrap();
236+
let batch_1 = TransactionBatch::new([&x_txs[0], &y_txs[1]], Default::default()).unwrap();
237+
let batch_2 = TransactionBatch::new([&y_txs[0], &x_txs[1]], Default::default()).unwrap();
242238

243239
vec![batch_1, batch_2]
244240
};
@@ -334,8 +330,8 @@ async fn compute_account_root_success() {
334330
})
335331
.collect();
336332

337-
let batch_1 = TransactionBatch::new(txs[..2].to_vec(), Default::default()).unwrap();
338-
let batch_2 = TransactionBatch::new(txs[2..].to_vec(), Default::default()).unwrap();
333+
let batch_1 = TransactionBatch::new(&txs[..2], Default::default()).unwrap();
334+
let batch_2 = TransactionBatch::new(&txs[2..], Default::default()).unwrap();
339335

340336
vec![batch_1, batch_2]
341337
};
@@ -552,8 +548,8 @@ async fn compute_note_root_success() {
552548
})
553549
.collect();
554550

555-
let batch_1 = TransactionBatch::new(txs[..2].to_vec(), Default::default()).unwrap();
556-
let batch_2 = TransactionBatch::new(txs[2..].to_vec(), Default::default()).unwrap();
551+
let batch_1 = TransactionBatch::new(&txs[..2], Default::default()).unwrap();
552+
let batch_2 = TransactionBatch::new(&txs[2..], Default::default()).unwrap();
557553

558554
vec![batch_1, batch_2]
559555
};
@@ -609,13 +605,13 @@ fn block_witness_validation_inconsistent_nullifiers() {
609605
let batch_1 = {
610606
let tx = MockProvenTxBuilder::with_account_index(0).nullifiers_range(0..1).build();
611607

612-
TransactionBatch::new(vec![tx], Default::default()).unwrap()
608+
TransactionBatch::new([&tx], Default::default()).unwrap()
613609
};
614610

615611
let batch_2 = {
616612
let tx = MockProvenTxBuilder::with_account_index(1).nullifiers_range(1..2).build();
617613

618-
TransactionBatch::new(vec![tx], Default::default()).unwrap()
614+
TransactionBatch::new([&tx], Default::default()).unwrap()
619615
};
620616

621617
vec![batch_1, batch_2]
@@ -688,13 +684,13 @@ async fn compute_nullifier_root_empty_success() {
688684
let batch_1 = {
689685
let tx = MockProvenTxBuilder::with_account_index(0).build();
690686

691-
TransactionBatch::new(vec![tx], Default::default()).unwrap()
687+
TransactionBatch::new([&tx], Default::default()).unwrap()
692688
};
693689

694690
let batch_2 = {
695691
let tx = MockProvenTxBuilder::with_account_index(1).build();
696692

697-
TransactionBatch::new(vec![tx], Default::default()).unwrap()
693+
TransactionBatch::new([&tx], Default::default()).unwrap()
698694
};
699695

700696
vec![batch_1, batch_2]
@@ -742,13 +738,13 @@ async fn compute_nullifier_root_success() {
742738
let batch_1 = {
743739
let tx = MockProvenTxBuilder::with_account_index(0).nullifiers_range(0..1).build();
744740

745-
TransactionBatch::new(vec![tx], Default::default()).unwrap()
741+
TransactionBatch::new([&tx], Default::default()).unwrap()
746742
};
747743

748744
let batch_2 = {
749745
let tx = MockProvenTxBuilder::with_account_index(1).nullifiers_range(1..2).build();
750746

751-
TransactionBatch::new(vec![tx], Default::default()).unwrap()
747+
TransactionBatch::new([&tx], Default::default()).unwrap()
752748
};
753749

754750
vec![batch_1, batch_2]

crates/block-producer/src/mempool/mod.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,8 @@ mod tests {
416416
uut.batch_failed(child_batch_a);
417417
assert_eq!(uut, reference);
418418

419-
let proof = TransactionBatch::new(
420-
vec![txs[2].raw_proven_transaction().clone()],
421-
Default::default(),
422-
)
423-
.unwrap();
419+
let proof =
420+
TransactionBatch::new([txs[2].raw_proven_transaction()], Default::default()).unwrap();
424421
uut.batch_proved(child_batch_b, proof);
425422
assert_eq!(uut, reference);
426423
}

crates/block-producer/src/test_utils/batch.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl TransactionBatchConstructor for TransactionBatch {
2424
})
2525
.collect();
2626

27-
Self::new(txs, Default::default()).unwrap()
27+
Self::new(&txs, Default::default()).unwrap()
2828
}
2929

3030
fn from_txs(starting_account_index: u32, num_txs_in_batch: u64) -> Self {
@@ -36,6 +36,6 @@ impl TransactionBatchConstructor for TransactionBatch {
3636
})
3737
.collect();
3838

39-
Self::new(txs, Default::default()).unwrap()
39+
Self::new(&txs, Default::default()).unwrap()
4040
}
4141
}

0 commit comments

Comments
 (0)