miden_tx/prover/mast_store.rs
1use alloc::{collections::BTreeMap, sync::Arc};
2
3use miden_lib::{MidenLib, StdLibrary, transaction::TransactionKernel, utils::sync::RwLock};
4use miden_objects::{
5 Digest,
6 account::AccountCode,
7 assembly::mast::MastForest,
8 transaction::{InputNote, InputNotes, TransactionArgs},
9};
10use vm_processor::MastForestStore;
11
12// TRANSACTION MAST STORE
13// ================================================================================================
14
15/// A store for the code available during transaction execution.
16///
17/// Transaction MAST store contains a map between procedure MAST roots and [MastForest]s containing
18/// MASTs for these procedures. The VM will request [MastForest]s from the store when it encounters
19/// a procedure which it doesn't have the code for. Thus, to execute a program which makes
20/// references to external procedures, the store must be loaded with [MastForest]s containing these
21/// procedures.
22pub struct TransactionMastStore {
23 mast_forests: RwLock<BTreeMap<Digest, Arc<MastForest>>>,
24}
25
26#[allow(clippy::new_without_default)]
27impl TransactionMastStore {
28 /// Returns a new [TransactionMastStore] instantiated with the default libraries.
29 ///
30 /// The default libraries include:
31 /// - Miden standard library (miden-stdlib).
32 /// - Miden rollup library (miden-lib).
33 /// - Transaction kernel.
34 pub fn new() -> Self {
35 let mast_forests = RwLock::new(BTreeMap::new());
36 let store = Self { mast_forests };
37
38 // load transaction kernel MAST forest
39 let kernels_forest = TransactionKernel::kernel().mast_forest().clone();
40 store.insert(kernels_forest);
41
42 // load miden-stdlib MAST forest
43 let miden_stdlib_forest = StdLibrary::default().mast_forest().clone();
44 store.insert(miden_stdlib_forest);
45
46 // load miden lib MAST forest
47 let miden_lib_forest = MidenLib::default().mast_forest().clone();
48 store.insert(miden_lib_forest);
49
50 store
51 }
52
53 /// Loads code required for executing a transaction with the specified inputs and args into
54 /// this store.
55 ///
56 /// The loaded code includes:
57 /// - Account code for the account specified from the provided [AccountCode].
58 /// - Note scripts for all input notes in the provided [InputNotes].
59 /// - Transaction script (if any) from the specified [TransactionArgs].
60 pub fn load_transaction_code(
61 &self,
62 account_code: &AccountCode,
63 input_notes: &InputNotes<InputNote>,
64 tx_args: &TransactionArgs,
65 ) {
66 // load account code
67 self.load_account_code(account_code);
68
69 // load note script MAST into the MAST store
70 for note in input_notes {
71 self.insert(note.note().script().mast().clone());
72 }
73
74 // add extra account codes
75 for foreign_account in tx_args.foreign_account_inputs() {
76 self.load_account_code(foreign_account.code());
77 }
78
79 // load tx script MAST into the MAST store
80 if let Some(tx_script) = tx_args.tx_script() {
81 self.insert(tx_script.mast().clone());
82 }
83 }
84
85 /// Registers all procedures of the provided [MastForest] with this store.
86 pub fn insert(&self, mast_forest: Arc<MastForest>) {
87 let mut mast_forests = self.mast_forests.write();
88
89 // only register procedures that are local to this forest
90 for proc_digest in mast_forest.local_procedure_digests() {
91 mast_forests.insert(proc_digest, mast_forest.clone());
92 }
93 }
94
95 /// Loads the provided account code into this store.
96 fn load_account_code(&self, code: &AccountCode) {
97 self.insert(code.mast().clone());
98 }
99}
100
101// MAST FOREST STORE IMPLEMENTATION
102// ================================================================================================
103
104impl MastForestStore for TransactionMastStore {
105 fn get(&self, procedure_root: &Digest) -> Option<Arc<MastForest>> {
106 self.mast_forests.read().get(procedure_root).cloned()
107 }
108}