miden_processor/host/
mod.rs

1use alloc::sync::Arc;
2
3use vm_core::{DebugOptions, crypto::hash::RpoDigest, mast::MastForest};
4
5use super::{ExecutionError, ProcessState};
6use crate::{KvMap, MemAdviceProvider};
7
8pub(super) mod advice;
9use advice::AdviceProvider;
10
11#[cfg(feature = "std")]
12mod debug;
13
14mod mast_forest_store;
15pub use mast_forest_store::{MastForestStore, MemMastForestStore};
16
17// HOST TRAIT
18// ================================================================================================
19
20/// Defines an interface by which the VM can interact with the host.
21///
22/// There are four main categories of interactions between the VM and the host:
23/// 1. accessing the advice provider,
24/// 2. getting a library's MAST forest,
25/// 3. handling advice events (which internally mutates the advice provider), and
26/// 4. handling debug and trace events.
27pub trait Host {
28    type AdviceProvider: AdviceProvider;
29
30    // REQUIRED METHODS
31    // --------------------------------------------------------------------------------------------
32
33    /// Returns a reference to the advice provider.
34    fn advice_provider(&self) -> &Self::AdviceProvider;
35
36    /// Returns a mutable reference to the advice provider.
37    fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider;
38
39    /// Returns MAST forest corresponding to the specified digest, or None if the MAST forest for
40    /// this digest could not be found in this [Host].
41    fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>>;
42
43    // PROVIDED METHODS
44    // --------------------------------------------------------------------------------------------
45
46    /// Handles the event emitted from the VM.
47    fn on_event(&mut self, _process: ProcessState, _event_id: u32) -> Result<(), ExecutionError> {
48        #[cfg(feature = "std")]
49        std::println!(
50            "Event with id {} emitted at step {} in context {}",
51            _event_id,
52            _process.clk(),
53            _process.ctx()
54        );
55        Ok(())
56    }
57
58    /// Handles the debug request from the VM.
59    fn on_debug(
60        &mut self,
61        _process: ProcessState,
62        _options: &DebugOptions,
63    ) -> Result<(), ExecutionError> {
64        #[cfg(feature = "std")]
65        debug::print_debug_info(_process, _options);
66        Ok(())
67    }
68
69    /// Handles the trace emitted from the VM.
70    fn on_trace(&mut self, _process: ProcessState, _trace_id: u32) -> Result<(), ExecutionError> {
71        #[cfg(feature = "std")]
72        std::println!(
73            "Trace with id {} emitted at step {} in context {}",
74            _trace_id,
75            _process.clk(),
76            _process.ctx()
77        );
78        Ok(())
79    }
80
81    /// Handles the failure of the assertion instruction.
82    fn on_assert_failed(&mut self, process: ProcessState, err_code: u32) -> ExecutionError {
83        ExecutionError::FailedAssertion {
84            clk: process.clk(),
85            err_code,
86            err_msg: None,
87        }
88    }
89}
90
91impl<H> Host for &mut H
92where
93    H: Host,
94{
95    type AdviceProvider = H::AdviceProvider;
96
97    fn advice_provider(&self) -> &Self::AdviceProvider {
98        H::advice_provider(self)
99    }
100
101    fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider {
102        H::advice_provider_mut(self)
103    }
104
105    fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>> {
106        H::get_mast_forest(self, node_digest)
107    }
108
109    fn on_debug(
110        &mut self,
111        process: ProcessState,
112        options: &DebugOptions,
113    ) -> Result<(), ExecutionError> {
114        H::on_debug(self, process, options)
115    }
116
117    fn on_event(&mut self, process: ProcessState, event_id: u32) -> Result<(), ExecutionError> {
118        H::on_event(self, process, event_id)
119    }
120
121    fn on_trace(&mut self, process: ProcessState, trace_id: u32) -> Result<(), ExecutionError> {
122        H::on_trace(self, process, trace_id)
123    }
124
125    fn on_assert_failed(&mut self, process: ProcessState, err_code: u32) -> ExecutionError {
126        H::on_assert_failed(self, process, err_code)
127    }
128}
129
130// DEFAULT HOST IMPLEMENTATION
131// ================================================================================================
132
133/// A default [Host] implementation that provides the essential functionality required by the VM.
134pub struct DefaultHost<A> {
135    adv_provider: A,
136    store: MemMastForestStore,
137}
138
139impl<A: Clone> Clone for DefaultHost<A> {
140    fn clone(&self) -> Self {
141        Self {
142            adv_provider: self.adv_provider.clone(),
143            store: self.store.clone(),
144        }
145    }
146}
147
148impl Default for DefaultHost<MemAdviceProvider> {
149    fn default() -> Self {
150        Self {
151            adv_provider: MemAdviceProvider::default(),
152            store: MemMastForestStore::default(),
153        }
154    }
155}
156
157impl<A: AdviceProvider> DefaultHost<A> {
158    pub fn new(adv_provider: A) -> Self {
159        Self {
160            adv_provider,
161            store: MemMastForestStore::default(),
162        }
163    }
164
165    pub fn load_mast_forest(&mut self, mast_forest: Arc<MastForest>) -> Result<(), ExecutionError> {
166        // Load the MAST's advice data into the advice provider.
167
168        for (digest, values) in mast_forest.advice_map().iter() {
169            if let Some(stored_values) = self.advice_provider().get_mapped_values(digest) {
170                if stored_values != values {
171                    return Err(ExecutionError::AdviceMapKeyAlreadyPresent(digest.into()));
172                }
173            } else {
174                self.advice_provider_mut().insert_into_map(digest.into(), values.clone());
175            }
176        }
177
178        self.store.insert(mast_forest);
179        Ok(())
180    }
181
182    #[cfg(any(test, feature = "testing"))]
183    pub fn advice_provider(&self) -> &A {
184        &self.adv_provider
185    }
186
187    #[cfg(any(test, feature = "testing"))]
188    pub fn advice_provider_mut(&mut self) -> &mut A {
189        &mut self.adv_provider
190    }
191
192    pub fn into_inner(self) -> A {
193        self.adv_provider
194    }
195}
196
197impl<A: AdviceProvider> Host for DefaultHost<A> {
198    type AdviceProvider = A;
199
200    fn advice_provider(&self) -> &Self::AdviceProvider {
201        &self.adv_provider
202    }
203
204    fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider {
205        &mut self.adv_provider
206    }
207
208    fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>> {
209        self.store.get(node_digest)
210    }
211
212    fn on_event(&mut self, _process: ProcessState, _event_id: u32) -> Result<(), ExecutionError> {
213        #[cfg(feature = "std")]
214        std::println!(
215            "Event with id {} emitted at step {} in context {}",
216            _event_id,
217            _process.clk(),
218            _process.ctx()
219        );
220        Ok(())
221    }
222}