miden_processor/host/
mod.rs

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