miden_testing/
mock_host.rs

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