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        #[cfg(feature = "std")]
74        debug::print_debug_info(_process, _options);
75        Ok(())
76    }
77
78    /// Handles the trace emitted from the VM.
79    fn on_trace(&mut self, _process: ProcessState, _trace_id: u32) -> Result<(), ExecutionError> {
80        #[cfg(feature = "std")]
81        std::println!(
82            "Trace with id {} emitted at step {} in context {}",
83            _trace_id,
84            _process.clk(),
85            _process.ctx()
86        );
87        Ok(())
88    }
89
90    /// Handles the failure of the assertion instruction.
91    fn on_assert_failed(&mut self, _process: ProcessState, _err_code: Felt) {}
92}
93
94impl<H> Host for &mut H
95where
96    H: Host,
97{
98    type AdviceProvider = H::AdviceProvider;
99
100    fn advice_provider(&self) -> &Self::AdviceProvider {
101        H::advice_provider(self)
102    }
103
104    fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider {
105        H::advice_provider_mut(self)
106    }
107
108    fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>> {
109        H::get_mast_forest(self, node_digest)
110    }
111
112    fn on_debug(
113        &mut self,
114        process: ProcessState,
115        options: &DebugOptions,
116    ) -> Result<(), ExecutionError> {
117        H::on_debug(self, process, options)
118    }
119
120    fn on_event(
121        &mut self,
122        process: ProcessState,
123        event_id: u32,
124        err_ctx: &ErrorContext<'_, impl MastNodeExt>,
125    ) -> Result<(), ExecutionError> {
126        H::on_event(self, process, event_id, err_ctx)
127    }
128
129    fn on_trace(&mut self, process: ProcessState, trace_id: u32) -> Result<(), ExecutionError> {
130        H::on_trace(self, process, trace_id)
131    }
132
133    fn on_assert_failed(&mut self, process: ProcessState, err_code: Felt) {
134        H::on_assert_failed(self, process, err_code)
135    }
136}
137
138// DEFAULT HOST IMPLEMENTATION
139// ================================================================================================
140
141/// A default [Host] implementation that provides the essential functionality required by the VM.
142pub struct DefaultHost<A> {
143    adv_provider: A,
144    store: MemMastForestStore,
145}
146
147impl<A: Clone> Clone for DefaultHost<A> {
148    fn clone(&self) -> Self {
149        Self {
150            adv_provider: self.adv_provider.clone(),
151            store: self.store.clone(),
152        }
153    }
154}
155
156impl Default for DefaultHost<MemAdviceProvider> {
157    fn default() -> Self {
158        Self {
159            adv_provider: MemAdviceProvider::default(),
160            store: MemMastForestStore::default(),
161        }
162    }
163}
164
165impl<A: AdviceProvider> DefaultHost<A> {
166    pub fn new(adv_provider: A) -> Self {
167        Self {
168            adv_provider,
169            store: MemMastForestStore::default(),
170        }
171    }
172
173    pub fn load_mast_forest(&mut self, mast_forest: Arc<MastForest>) -> Result<(), ExecutionError> {
174        // Load the MAST's advice data into the advice provider.
175
176        for (digest, values) in mast_forest.advice_map().iter() {
177            if let Some(stored_values) = self.advice_provider().get_mapped_values(digest) {
178                if stored_values != values {
179                    return Err(ExecutionError::AdviceMapKeyAlreadyPresent {
180                        key: digest.into(),
181                        prev_values: stored_values.to_vec(),
182                        new_values: values.clone(),
183                    });
184                }
185            } else {
186                self.advice_provider_mut().insert_into_map(digest.into(), values.clone());
187            }
188        }
189
190        self.store.insert(mast_forest);
191        Ok(())
192    }
193
194    #[cfg(any(test, feature = "testing"))]
195    pub fn advice_provider(&self) -> &A {
196        &self.adv_provider
197    }
198
199    #[cfg(any(test, feature = "testing"))]
200    pub fn advice_provider_mut(&mut self) -> &mut A {
201        &mut self.adv_provider
202    }
203
204    pub fn into_inner(self) -> A {
205        self.adv_provider
206    }
207}
208
209impl<A: AdviceProvider> Host for DefaultHost<A> {
210    type AdviceProvider = A;
211
212    fn advice_provider(&self) -> &Self::AdviceProvider {
213        &self.adv_provider
214    }
215
216    fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider {
217        &mut self.adv_provider
218    }
219
220    fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>> {
221        self.store.get(node_digest)
222    }
223
224    fn on_event(
225        &mut self,
226        _process: ProcessState,
227        _event_id: u32,
228        _err_ctx: &ErrorContext<'_, impl MastNodeExt>,
229    ) -> Result<(), ExecutionError> {
230        #[cfg(feature = "std")]
231        std::println!(
232            "Event with id {} emitted at step {} in context {}",
233            _event_id,
234            _process.clk(),
235            _process.ctx()
236        );
237        Ok(())
238    }
239}