1use alloc::string::String;
2use alloc::vec::Vec;
3
4use miden_lib::testing::note::NoteBuilder;
5use miden_lib::transaction::{TransactionKernel, memory};
6use miden_objects::account::AccountId;
7use miden_objects::asset::Asset;
8use miden_objects::note::Note;
9use miden_objects::testing::storage::prepare_assets;
10use miden_processor::Felt;
11use rand::SeedableRng;
12use rand::rngs::SmallRng;
13
14#[macro_export]
18macro_rules! assert_execution_error {
19 ($execution_result:expr, $expected_err:expr) => {
20 match $execution_result {
21 Err(miden_processor::ExecutionError::FailedAssertion { label: _, source_file: _, clk: _, err_code, err_msg }) => {
22 if let Some(ref msg) = err_msg {
23 assert_eq!(msg.as_ref(), $expected_err.message(), "error messages did not match");
24 }
25
26 assert_eq!(
27 err_code, $expected_err.code(),
28 "Execution failed on assertion with an unexpected error (Actual code: {}, msg: {}, Expected code: {}).",
29 err_code, err_msg.as_ref().map(|string| string.as_ref()).unwrap_or("<no message>"), $expected_err,
30 );
31 },
32 Ok(_) => panic!("Execution was unexpectedly successful"),
33 Err(err) => panic!("Execution error was not as expected: {err}"),
34 }
35 };
36}
37
38#[macro_export]
39macro_rules! assert_transaction_executor_error {
40 ($execution_result:expr, $expected_err:expr) => {
41 match $execution_result {
42 Err(miden_tx::TransactionExecutorError::TransactionProgramExecutionFailed(
43 miden_processor::ExecutionError::FailedAssertion {
44 label: _,
45 source_file: _,
46 clk: _,
47 err_code,
48 err_msg,
49 },
50 )) => {
51 if let Some(ref msg) = err_msg {
52 assert_eq!(msg.as_ref(), $expected_err.message(), "error messages did not match");
53 }
54
55 assert_eq!(
56 err_code, $expected_err.code(),
57 "Execution failed on assertion with an unexpected error (Actual code: {}, msg: {}, Expected: {}).",
58 err_code, err_msg.as_ref().map(|string| string.as_ref()).unwrap_or("<no message>"), $expected_err);
59 },
60 Ok(_) => panic!("Execution was unexpectedly successful"),
61 Err(err) => panic!("Execution error was not as expected: {err}"),
62 }
63 };
64}
65
66pub fn input_note_data_ptr(note_idx: u32) -> memory::MemoryAddress {
70 memory::INPUT_NOTE_DATA_SECTION_OFFSET + note_idx * memory::NOTE_MEM_SIZE
71}
72
73pub fn create_p2any_note(sender: AccountId, assets: &[Asset]) -> Note {
83 let mut code_body = String::new();
84 for i in 0..assets.len() {
85 if i == 0 {
86 code_body.push_str(
88 "
89 # add first asset
90
91 padw dup.4 mem_loadw
92 padw swapw padw padw swapdw
93 call.wallet::receive_asset
94 dropw movup.12
95 # => [dest_ptr, pad(12)]
96 ",
97 );
98 } else {
99 code_body.push_str(
100 "
101 # add next asset
102
103 add.4 dup movdn.13
104 padw movup.4 mem_loadw
105 call.wallet::receive_asset
106 dropw movup.12
107 # => [dest_ptr, pad(12)]",
108 );
109 }
110 }
111 code_body.push_str("dropw dropw dropw dropw");
112
113 let code = format!(
114 "
115 use.mock::account
116 use.miden::note
117 use.miden::contracts::wallets::basic->wallet
118
119 begin
120 # fetch pointer & number of assets
121 push.0 exec.note::get_assets # [num_assets, dest_ptr]
122
123 # runtime-check we got the expected count
124 push.{num_assets} assert_eq # [dest_ptr]
125
126 {code_body}
127 dropw dropw dropw dropw
128 end
129 ",
130 num_assets = assets.len(),
131 );
132
133 NoteBuilder::new(sender, SmallRng::from_seed([0; 32]))
134 .add_assets(assets.iter().copied())
135 .code(code)
136 .dynamically_linked_libraries(TransactionKernel::mock_libraries())
137 .build()
138 .expect("generated note script should compile")
139}
140
141pub fn create_spawn_note(sender_id: AccountId, output_notes: Vec<&Note>) -> anyhow::Result<Note> {
146 let note_code = note_script_that_creates_notes(output_notes);
147
148 let note = NoteBuilder::new(sender_id, SmallRng::from_os_rng())
149 .code(note_code)
150 .dynamically_linked_libraries(TransactionKernel::mock_libraries())
151 .build()?;
152
153 Ok(note)
154}
155
156fn note_script_that_creates_notes(output_notes: Vec<&Note>) -> String {
158 let mut out = String::from("use.miden::tx\nuse.mock::account\n\nbegin\n");
159
160 for (idx, note) in output_notes.iter().enumerate() {
161 if idx == 0 {
162 out.push_str("padw padw\n");
163 } else {
164 out.push_str("dropw dropw dropw\n");
165 }
166 let assets_str = prepare_assets(note.assets());
167 out.push_str(&format!(
168 " push.{recipient}
169 push.{hint}
170 push.{note_type}
171 push.{aux}
172 push.{tag}
173 call.tx::create_note\n",
174 recipient = note.recipient().digest(),
175 hint = Felt::from(note.metadata().execution_hint()),
176 note_type = note.metadata().note_type() as u8,
177 aux = note.metadata().aux(),
178 tag = note.metadata().tag(),
179 ));
180
181 for asset in assets_str {
182 out.push_str(&format!(
183 " push.{asset}
184 call.tx::add_asset_to_note\n",
185 ));
186 }
187 }
188
189 out.push_str("repeat.5 dropw end\nend");
190 out
191}