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}