miden_testing/
mock_host.rs

1use alloc::boxed::Box;
2use alloc::collections::BTreeSet;
3use alloc::rc::Rc;
4use alloc::sync::Arc;
5use alloc::vec::Vec;
6
7use miden_lib::transaction::{TransactionEvent, TransactionEventError};
8use miden_objects::account::{AccountHeader, AccountVaultDelta};
9use miden_objects::assembly::debuginfo::SourceManagerSync;
10use miden_objects::assembly::{DefaultSourceManager, SourceManager};
11use miden_objects::{Felt, Word};
12use miden_processor::{
13    AdviceInputs,
14    AdviceMutation,
15    BaseHost,
16    ContextId,
17    EventError,
18    MastForest,
19    MastForestStore,
20    ProcessState,
21    SyncHost,
22};
23use miden_tx::{AccountProcedureIndexMap, LinkMap, TransactionMastStore};
24
25// MOCK HOST
26// ================================================================================================
27
28/// This is very similar to the TransactionHost in miden-tx. The differences include:
29/// - We do not track account delta here.
30/// - There is special handling of EMPTY_DIGEST in account procedure index map.
31/// - This host uses `MemAdviceProvider` which is instantiated from the passed in advice inputs.
32pub struct MockHost {
33    acct_procedure_index_map: AccountProcedureIndexMap,
34    mast_store: Rc<TransactionMastStore>,
35    source_manager: Arc<dyn SourceManagerSync>,
36}
37
38impl MockHost {
39    /// Returns a new [`MockHost`] instance with the provided [`AdviceInputs`].
40    pub fn new(
41        account: AccountHeader,
42        advice_inputs: &AdviceInputs,
43        mast_store: Rc<TransactionMastStore>,
44        mut foreign_code_commitments: BTreeSet<Word>,
45    ) -> Self {
46        foreign_code_commitments.insert(account.code_commitment());
47        let account_procedure_index_map =
48            AccountProcedureIndexMap::new(foreign_code_commitments, advice_inputs)
49                .expect("account procedure index map should be valid");
50
51        Self {
52            acct_procedure_index_map: account_procedure_index_map,
53            mast_store,
54            source_manager: Arc::new(DefaultSourceManager::default()),
55        }
56    }
57
58    /// Sets the provided [`SourceManagerSync`] on the host.
59    pub fn with_source_manager(mut self, source_manager: Arc<dyn SourceManagerSync>) -> Self {
60        self.source_manager = source_manager;
61        self
62    }
63
64    /// Consumes `self` and returns the advice provider and account vault delta.
65    pub fn into_parts(self) -> AccountVaultDelta {
66        AccountVaultDelta::default()
67    }
68
69    // EVENT HANDLERS
70    // --------------------------------------------------------------------------------------------
71
72    fn on_push_account_procedure_index(
73        &mut self,
74        process: &ProcessState,
75    ) -> Result<Vec<AdviceMutation>, EventError> {
76        let proc_idx = self.acct_procedure_index_map.get_proc_index(process).map_err(Box::new)?;
77        Ok(vec![AdviceMutation::extend_stack([Felt::from(proc_idx)])])
78    }
79}
80
81impl BaseHost for MockHost {
82    fn get_mast_forest(&self, node_digest: &Word) -> Option<Arc<MastForest>> {
83        self.mast_store.get(node_digest)
84    }
85
86    fn get_label_and_source_file(
87        &self,
88        location: &miden_objects::assembly::debuginfo::Location,
89    ) -> (
90        miden_objects::assembly::debuginfo::SourceSpan,
91        Option<Arc<miden_objects::assembly::SourceFile>>,
92    ) {
93        let maybe_file = self.source_manager.get_by_uri(location.uri());
94        let span = self.source_manager.location_to_span(location.clone()).unwrap_or_default();
95        (span, maybe_file)
96    }
97}
98
99impl SyncHost for MockHost {
100    fn on_event(
101        &mut self,
102        process: &ProcessState,
103        event_id: u32,
104    ) -> Result<Vec<AdviceMutation>, EventError> {
105        let event = TransactionEvent::try_from(event_id).map_err(Box::new)?;
106
107        if process.ctx() != ContextId::root() {
108            return Err(Box::new(TransactionEventError::NotRootContext(event_id)));
109        }
110
111        let advice_mutations = match event {
112            TransactionEvent::AccountPushProcedureIndex => {
113                self.on_push_account_procedure_index(process)
114            },
115            TransactionEvent::LinkMapSetEvent => LinkMap::handle_set_event(process),
116            TransactionEvent::LinkMapGetEvent => LinkMap::handle_get_event(process),
117            _ => Ok(Vec::new()),
118        }?;
119
120        Ok(advice_mutations)
121    }
122}