Skip to content

Commit 85caa18

Browse files
feat: implement Clone for TransactionContextBuilder (#2979)
* feat: implement Clone for TransactionContextBuilder * chore: add unwrap_unauthorized_err
1 parent 2ef8056 commit 85caa18

6 files changed

Lines changed: 380 additions & 443 deletions

File tree

crates/miden-testing/src/tx_context/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ use crate::MockChain;
6767
/// # Ok(())
6868
/// # }
6969
/// ```
70+
#[derive(Clone)]
7071
pub struct TransactionContextBuilder {
7172
source_manager: Arc<dyn SourceManagerSync>,
7273
account: Account,

crates/miden-testing/tests/auth/guarded_multisig.rs

Lines changed: 78 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -199,16 +199,18 @@ async fn test_guarded_multisig_signature_required(
199199
let mut mock_chain = mock_chain_builder.build().unwrap();
200200

201201
let salt = Word::from([Felt::new_unchecked(777); 4]);
202-
let tx_context_init = mock_chain
202+
let tx_context_builder = mock_chain
203203
.build_tx_context(multisig_account.id(), &[input_note.id()], &[])?
204-
.extend_expected_output_notes(vec![RawOutputNote::Full(output_note.clone())])
205-
.auth_args(salt)
206-
.build()?;
204+
.extend_expected_output_notes(vec![RawOutputNote::Full(output_note)])
205+
.auth_args(salt);
207206

208-
let tx_summary = match tx_context_init.execute().await.unwrap_err() {
209-
TransactionExecutorError::Unauthorized(tx_effects) => tx_effects,
210-
error => anyhow::bail!("expected abort with tx effects: {error}"),
211-
};
207+
let tx_summary = tx_context_builder
208+
.clone()
209+
.build()?
210+
.execute()
211+
.await
212+
.unwrap_err()
213+
.unwrap_unauthorized_err();
212214
let msg = tx_summary.as_ref().to_commitment();
213215
let tx_summary_signing = SigningInputs::TransactionSummary(tx_summary);
214216

@@ -220,12 +222,10 @@ async fn test_guarded_multisig_signature_required(
220222
.await?;
221223

222224
// Missing guardian signature must fail.
223-
let without_guardian_result = mock_chain
224-
.build_tx_context(multisig_account.id(), &[input_note.id()], &[])?
225-
.extend_expected_output_notes(vec![RawOutputNote::Full(output_note.clone())])
225+
let without_guardian_result = tx_context_builder
226+
.clone()
226227
.add_signature(public_keys[0].to_commitment(), msg, sig_1.clone())
227228
.add_signature(public_keys[1].to_commitment(), msg, sig_2.clone())
228-
.auth_args(salt)
229229
.build()?
230230
.execute()
231231
.await;
@@ -239,13 +239,10 @@ async fn test_guarded_multisig_signature_required(
239239
.await?;
240240

241241
// With guardian signature the transaction should succeed.
242-
let tx_context_execute = mock_chain
243-
.build_tx_context(multisig_account.id(), &[input_note.id()], &[])?
244-
.extend_expected_output_notes(vec![RawOutputNote::Full(output_note)])
242+
let tx_context_execute = tx_context_builder
245243
.add_signature(public_keys[0].to_commitment(), msg, sig_1)
246244
.add_signature(public_keys[1].to_commitment(), msg, sig_2)
247245
.add_signature(guardian_public_key.to_commitment(), msg, guardian_signature)
248-
.auth_args(salt)
249246
.build()?
250247
.execute()
251248
.await?;
@@ -312,16 +309,18 @@ async fn test_guarded_multisig_update_guardian_public_key(
312309
))?;
313310

314311
let update_salt = Word::from([Felt::new_unchecked(991); 4]);
315-
let tx_context_init = mock_chain
312+
let tx_context_builder = mock_chain
316313
.build_tx_context(multisig_account.id(), &[], &[])?
317-
.tx_script(update_guardian_script.clone())
318-
.auth_args(update_salt)
319-
.build()?;
314+
.tx_script(update_guardian_script)
315+
.auth_args(update_salt);
320316

321-
let tx_summary = match tx_context_init.execute().await.unwrap_err() {
322-
TransactionExecutorError::Unauthorized(tx_effects) => tx_effects,
323-
error => anyhow::bail!("expected abort with tx effects: {error}"),
324-
};
317+
let tx_summary = tx_context_builder
318+
.clone()
319+
.build()?
320+
.execute()
321+
.await
322+
.unwrap_err()
323+
.unwrap_unauthorized_err();
325324

326325
let update_msg = tx_summary.as_ref().to_commitment();
327326
let tx_summary_signing = SigningInputs::TransactionSummary(tx_summary);
@@ -333,12 +332,9 @@ async fn test_guarded_multisig_update_guardian_public_key(
333332
.await?;
334333

335334
// Guardian key rotation intentionally skips guardian signature for this update tx.
336-
let update_guardian_tx = mock_chain
337-
.build_tx_context(multisig_account.id(), &[], &[])?
338-
.tx_script(update_guardian_script)
335+
let update_guardian_tx = tx_context_builder
339336
.add_signature(public_keys[0].to_commitment(), update_msg, sig_1)
340337
.add_signature(public_keys[1].to_commitment(), update_msg, sig_2)
341-
.auth_args(update_salt)
342338
.build()?
343339
.execute()
344340
.await?;
@@ -364,15 +360,15 @@ async fn test_guarded_multisig_update_guardian_public_key(
364360
// Build one tx summary after key update. Old GUARDIAN must fail and new GUARDIAN must pass on
365361
// this same transaction.
366362
let next_salt = Word::from([Felt::new_unchecked(992); 4]);
367-
let tx_context_init_next = mock_chain
363+
let tx_context_builder_next = mock_chain
368364
.build_tx_context(updated_multisig_account.id(), &[], &[])?
369-
.auth_args(next_salt)
370-
.build()?;
365+
.auth_args(next_salt);
371366

372-
let tx_summary_next = match tx_context_init_next.execute().await.unwrap_err() {
373-
TransactionExecutorError::Unauthorized(tx_effects) => tx_effects,
374-
error => anyhow::bail!("expected abort with tx effects: {error}"),
375-
};
367+
let tx_summary_next =
368+
match tx_context_builder_next.clone().build()?.execute().await.unwrap_err() {
369+
TransactionExecutorError::Unauthorized(tx_effects) => tx_effects,
370+
error => anyhow::bail!("expected abort with tx effects: {error}"),
371+
};
376372
let next_msg = tx_summary_next.as_ref().to_commitment();
377373
let tx_summary_next_signing = SigningInputs::TransactionSummary(tx_summary_next);
378374

@@ -390,12 +386,11 @@ async fn test_guarded_multisig_update_guardian_public_key(
390386
.await?;
391387

392388
// Old guardian signature must fail after key update.
393-
let with_old_guardian_result = mock_chain
394-
.build_tx_context(updated_multisig_account.id(), &[], &[])?
389+
let with_old_guardian_result = tx_context_builder_next
390+
.clone()
395391
.add_signature(public_keys[0].to_commitment(), next_msg, next_sig_1.clone())
396392
.add_signature(public_keys[1].to_commitment(), next_msg, next_sig_2.clone())
397393
.add_signature(old_guardian_public_key.to_commitment(), next_msg, old_guardian_sig_next)
398-
.auth_args(next_salt)
399394
.build()?
400395
.execute()
401396
.await;
@@ -405,12 +400,10 @@ async fn test_guarded_multisig_update_guardian_public_key(
405400
));
406401

407402
// New guardian signature must pass.
408-
mock_chain
409-
.build_tx_context(updated_multisig_account.id(), &[], &[])?
403+
tx_context_builder_next
410404
.add_signature(public_keys[0].to_commitment(), next_msg, next_sig_1)
411405
.add_signature(public_keys[1].to_commitment(), next_msg, next_sig_2)
412406
.add_signature(new_guardian_public_key.to_commitment(), next_msg, new_guardian_sig_next)
413-
.auth_args(next_salt)
414407
.build()?
415408
.execute()
416409
.await?;
@@ -470,16 +463,18 @@ async fn test_guarded_multisig_update_guardian_public_key_must_be_called_alone(
470463
let mock_chain = mock_chain_builder.build().unwrap();
471464

472465
let salt = Word::from([Felt::new_unchecked(993); 4]);
473-
let tx_context_init = mock_chain
466+
let tx_context_builder = mock_chain
474467
.build_tx_context(multisig_account.id(), &[receive_asset_note.id()], &[])?
475-
.tx_script(update_guardian_script.clone())
476-
.auth_args(salt)
477-
.build()?;
468+
.tx_script(update_guardian_script)
469+
.auth_args(salt);
478470

479-
let tx_summary = match tx_context_init.execute().await.unwrap_err() {
480-
TransactionExecutorError::Unauthorized(tx_effects) => tx_effects,
481-
error => anyhow::bail!("expected abort with tx effects: {error}"),
482-
};
471+
let tx_summary = tx_context_builder
472+
.clone()
473+
.build()?
474+
.execute()
475+
.await
476+
.unwrap_err()
477+
.unwrap_unauthorized_err();
483478

484479
let msg = tx_summary.as_ref().to_commitment();
485480
let tx_summary_signing = SigningInputs::TransactionSummary(tx_summary);
@@ -490,12 +485,10 @@ async fn test_guarded_multisig_update_guardian_public_key_must_be_called_alone(
490485
.get_signature(public_keys[1].to_commitment(), &tx_summary_signing)
491486
.await?;
492487

493-
let without_guardian_result = mock_chain
494-
.build_tx_context(multisig_account.id(), &[receive_asset_note.id()], &[])?
495-
.tx_script(update_guardian_script.clone())
488+
let without_guardian_result = tx_context_builder
489+
.clone()
496490
.add_signature(public_keys[0].to_commitment(), msg, sig_1.clone())
497491
.add_signature(public_keys[1].to_commitment(), msg, sig_2.clone())
498-
.auth_args(salt)
499492
.build()?
500493
.execute()
501494
.await;
@@ -508,13 +501,10 @@ async fn test_guarded_multisig_update_guardian_public_key_must_be_called_alone(
508501
.get_signature(old_guardian_public_key.to_commitment(), &tx_summary_signing)
509502
.await?;
510503

511-
let with_guardian_result = mock_chain
512-
.build_tx_context(multisig_account.id(), &[receive_asset_note.id()], &[])?
513-
.tx_script(update_guardian_script)
504+
let with_guardian_result = tx_context_builder
514505
.add_signature(public_keys[0].to_commitment(), msg, sig_1)
515506
.add_signature(public_keys[1].to_commitment(), msg, sig_2)
516507
.add_signature(old_guardian_public_key.to_commitment(), msg, old_guardian_signature)
517-
.auth_args(salt)
518508
.build()?
519509
.execute()
520510
.await;
@@ -553,18 +543,20 @@ async fn test_guarded_multisig_update_guardian_public_key_must_be_called_alone(
553543
.unwrap();
554544

555545
let salt = Word::from([Felt::new_unchecked(994); 4]);
556-
let tx_context_init = mock_chain
546+
let tx_context_builder = mock_chain
557547
.build_tx_context(multisig_account.id(), &[], &[])?
558-
.tx_script(update_guardian_with_output_script.clone())
559-
.add_note_script(note_script.clone())
560-
.extend_expected_output_notes(vec![RawOutputNote::Full(output_note.clone())])
561-
.auth_args(salt)
562-
.build()?;
563-
564-
let tx_summary = match tx_context_init.execute().await.unwrap_err() {
565-
TransactionExecutorError::Unauthorized(tx_effects) => tx_effects,
566-
error => anyhow::bail!("expected abort with tx effects: {error}"),
567-
};
548+
.tx_script(update_guardian_with_output_script)
549+
.add_note_script(note_script)
550+
.extend_expected_output_notes(vec![RawOutputNote::Full(output_note)])
551+
.auth_args(salt);
552+
553+
let tx_summary = tx_context_builder
554+
.clone()
555+
.build()?
556+
.execute()
557+
.await
558+
.unwrap_err()
559+
.unwrap_unauthorized_err();
568560

569561
let msg = tx_summary.as_ref().to_commitment();
570562
let tx_summary_signing = SigningInputs::TransactionSummary(tx_summary);
@@ -575,14 +567,9 @@ async fn test_guarded_multisig_update_guardian_public_key_must_be_called_alone(
575567
.get_signature(public_keys[1].to_commitment(), &tx_summary_signing)
576568
.await?;
577569

578-
let result = mock_chain
579-
.build_tx_context(multisig_account.id(), &[], &[])?
580-
.tx_script(update_guardian_with_output_script)
581-
.add_note_script(note_script)
582-
.extend_expected_output_notes(vec![RawOutputNote::Full(output_note)])
570+
let result = tx_context_builder
583571
.add_signature(public_keys[0].to_commitment(), msg, sig_1)
584572
.add_signature(public_keys[1].to_commitment(), msg, sig_2)
585-
.auth_args(salt)
586573
.build()?
587574
.execute()
588575
.await;
@@ -690,17 +677,21 @@ async fn test_guarded_multisig_update_guardian_enforces_no_notes(
690677
let salt = Word::from([Felt::new_unchecked(995); 4]);
691678

692679
// Dry-run to obtain the tx summary the signers must sign.
693-
let mut init_ctx = mock_chain
680+
let mut tx_context_builder = mock_chain
694681
.build_tx_context(multisig_account.id(), &input_ids, &[])?
695-
.tx_script(update_guardian_script.clone())
682+
.tx_script(update_guardian_script)
696683
.auth_args(salt);
697-
if let Some(ref out) = output_note {
698-
init_ctx = init_ctx.extend_expected_output_notes(vec![RawOutputNote::Full(out.clone())]);
684+
if let Some(out) = output_note {
685+
tx_context_builder =
686+
tx_context_builder.extend_expected_output_notes(vec![RawOutputNote::Full(out)]);
699687
}
700-
let tx_summary = match init_ctx.build()?.execute().await.unwrap_err() {
701-
TransactionExecutorError::Unauthorized(tx_effects) => tx_effects,
702-
error => anyhow::bail!("expected dry-run abort with tx effects: {error}"),
703-
};
688+
let tx_summary = tx_context_builder
689+
.clone()
690+
.build()?
691+
.execute()
692+
.await
693+
.unwrap_err()
694+
.unwrap_unauthorized_err();
704695

705696
let msg = tx_summary.as_ref().to_commitment();
706697
let signing = SigningInputs::TransactionSummary(tx_summary);
@@ -714,18 +705,13 @@ async fn test_guarded_multisig_update_guardian_enforces_no_notes(
714705
.get_signature(old_guardian_public_key.to_commitment(), &signing)
715706
.await?;
716707

717-
let mut signed_ctx = mock_chain
718-
.build_tx_context(multisig_account.id(), &input_ids, &[])?
719-
.tx_script(update_guardian_script)
720-
.auth_args(salt)
708+
let result = tx_context_builder
721709
.add_signature(public_keys[0].to_commitment(), msg, sig_1)
722710
.add_signature(public_keys[1].to_commitment(), msg, sig_2)
723-
.add_signature(old_guardian_public_key.to_commitment(), msg, guardian_sig);
724-
if let Some(ref out) = output_note {
725-
signed_ctx =
726-
signed_ctx.extend_expected_output_notes(vec![RawOutputNote::Full(out.clone())]);
727-
}
728-
let result = signed_ctx.build()?.execute().await;
711+
.add_signature(old_guardian_public_key.to_commitment(), msg, guardian_sig)
712+
.build()?
713+
.execute()
714+
.await;
729715

730716
// Input check fires first, output check fires only when no input notes are present.
731717
match (include_input_note, include_output_note) {

0 commit comments

Comments
 (0)