miden_testing/tx_context/
context.rs1#[cfg(any(feature = "async", target_family = "wasm"))]
2use alloc::boxed::Box;
3use alloc::{collections::BTreeSet, rc::Rc, sync::Arc, vec::Vec};
4
5use miden_lib::transaction::TransactionKernel;
6use miden_objects::{
7 account::{Account, AccountId},
8 assembly::{Assembler, SourceManager},
9 block::{BlockHeader, BlockNumber},
10 note::Note,
11 transaction::{
12 ExecutedTransaction, InputNote, InputNotes, PartialBlockchain, TransactionArgs,
13 TransactionInputs,
14 },
15};
16use miden_tx::{
17 DataStore, DataStoreError, TransactionExecutor, TransactionExecutorError, TransactionMastStore,
18 auth::{BasicAuthenticator, TransactionAuthenticator},
19};
20use rand_chacha::ChaCha20Rng;
21use vm_processor::{
22 AdviceInputs, Digest, ExecutionError, MastForest, MastForestStore, Process, Word,
23};
24use winter_maybe_async::*;
25
26use crate::{MockHost, executor::CodeExecutor, tx_context::builder::MockAuthenticator};
27
28pub struct TransactionContext {
36 pub(super) expected_output_notes: Vec<Note>,
37 pub(super) tx_args: TransactionArgs,
38 pub(super) tx_inputs: TransactionInputs,
39 pub(super) mast_store: TransactionMastStore,
40 pub(super) advice_inputs: AdviceInputs,
41 pub(super) authenticator: Option<MockAuthenticator>,
42 pub(super) source_manager: Arc<dyn SourceManager>,
43}
44
45impl TransactionContext {
46 pub fn execute_code_with_assembler(
57 &self,
58 code: &str,
59 assembler: Assembler,
60 ) -> Result<Process, ExecutionError> {
61 let (stack_inputs, mut advice_inputs) = TransactionKernel::prepare_inputs(
62 &self.tx_inputs,
63 &self.tx_args,
64 Some(self.advice_inputs.clone()),
65 )
66 .unwrap();
67 advice_inputs.extend(self.advice_inputs.clone());
68
69 let test_lib = TransactionKernel::kernel_as_library();
70
71 let source_manager = assembler.source_manager();
72 let program = assembler
73 .with_debug_mode(true)
74 .assemble_program(code)
75 .expect("compilation of the provided code failed");
76
77 let mast_store = Rc::new(TransactionMastStore::new());
78
79 mast_store.insert(program.mast_forest().clone());
80 mast_store.insert(test_lib.mast_forest().clone());
81 mast_store.load_transaction_code(self.account().code(), self.input_notes(), &self.tx_args);
82
83 CodeExecutor::new(MockHost::new(
84 self.tx_inputs.account().into(),
85 advice_inputs,
86 mast_store,
87 self.tx_args.foreign_account_code_commitments(),
88 ))
89 .stack_inputs(stack_inputs)
90 .execute_program(program, source_manager)
91 }
92
93 pub fn execute_code(&self, code: &str) -> Result<Process, ExecutionError> {
97 let assembler = TransactionKernel::testing_assembler();
98 self.execute_code_with_assembler(code, assembler)
99 }
100
101 #[allow(clippy::arc_with_non_send_sync)]
103 #[maybe_async]
104 pub fn execute(self) -> Result<ExecutedTransaction, TransactionExecutorError> {
105 let account_id = self.account().id();
106 let block_num = self.tx_inputs().block_header().block_num();
107 let notes = self.tx_inputs().input_notes().clone();
108 let tx_args = self.tx_args().clone();
109
110 let authenticator = self
111 .authenticator()
112 .cloned()
113 .map(|auth| Arc::new(auth) as Arc<dyn TransactionAuthenticator>);
114
115 let source_manager = Arc::clone(&self.source_manager);
116 let tx_executor = TransactionExecutor::new(Arc::new(self), authenticator).with_debug_mode();
117
118 maybe_await!(tx_executor.execute_transaction(
119 account_id,
120 block_num,
121 notes,
122 tx_args,
123 source_manager
124 ))
125 }
126
127 pub fn account(&self) -> &Account {
128 self.tx_inputs.account()
129 }
130
131 pub fn expected_output_notes(&self) -> &[Note] {
132 &self.expected_output_notes
133 }
134
135 pub fn tx_args(&self) -> &TransactionArgs {
136 &self.tx_args
137 }
138
139 pub fn input_notes(&self) -> &InputNotes<InputNote> {
140 self.tx_inputs.input_notes()
141 }
142
143 pub fn set_tx_args(&mut self, tx_args: TransactionArgs) {
144 self.tx_args = tx_args;
145 }
146
147 pub fn tx_inputs(&self) -> &TransactionInputs {
148 &self.tx_inputs
149 }
150
151 pub fn authenticator(&self) -> Option<&BasicAuthenticator<ChaCha20Rng>> {
152 self.authenticator.as_ref()
153 }
154
155 pub fn source_manager(&self) -> Arc<dyn SourceManager> {
157 Arc::clone(&self.source_manager)
158 }
159}
160
161#[maybe_async_trait]
162impl DataStore for TransactionContext {
163 #[maybe_async]
164 fn get_transaction_inputs(
165 &self,
166 account_id: AccountId,
167 _ref_blocks: BTreeSet<BlockNumber>,
168 ) -> Result<(Account, Option<Word>, BlockHeader, PartialBlockchain), DataStoreError> {
169 assert_eq!(account_id, self.account().id());
170 let (account, seed, header, mmr, _) = self.tx_inputs.clone().into_parts();
171
172 Ok((account, seed, header, mmr))
173 }
174}
175
176impl MastForestStore for TransactionContext {
177 fn get(&self, procedure_hash: &Digest) -> Option<Arc<MastForest>> {
178 self.mast_store.get(procedure_hash)
179 }
180}