Skip to main content

miden_processor/host/
mod.rs

1use alloc::{sync::Arc, vec::Vec};
2use core::future::Future;
3
4use miden_core::{
5    Felt, Word,
6    advice::AdviceMap,
7    crypto::merkle::InnerNodeInfo,
8    events::{EventId, EventName},
9    mast::MastForest,
10    operations::DebugOptions,
11    precompile::PrecompileRequest,
12};
13use miden_debug_types::{Location, SourceFile, SourceSpan};
14
15use crate::{DebugError, ProcessorState, TraceError};
16
17pub(super) mod advice;
18
19pub mod debug;
20
21pub mod default;
22
23pub mod handlers;
24use handlers::{DebugHandler, EventError};
25
26mod mast_forest_store;
27pub use mast_forest_store::{MastForestStore, MemMastForestStore};
28
29// ADVICE MAP MUTATIONS
30// ================================================================================================
31
32/// Any possible way an event can modify the advice provider.
33#[derive(Debug, PartialEq, Eq)]
34pub enum AdviceMutation {
35    ExtendStack { values: Vec<Felt> },
36    ExtendMap { other: AdviceMap },
37    ExtendMerkleStore { infos: Vec<InnerNodeInfo> },
38    ExtendPrecompileRequests { data: Vec<PrecompileRequest> },
39}
40
41impl AdviceMutation {
42    pub fn extend_stack(iter: impl IntoIterator<Item = Felt>) -> Self {
43        Self::ExtendStack { values: Vec::from_iter(iter) }
44    }
45
46    pub fn extend_map(other: AdviceMap) -> Self {
47        Self::ExtendMap { other }
48    }
49
50    pub fn extend_merkle_store(infos: impl IntoIterator<Item = InnerNodeInfo>) -> Self {
51        Self::ExtendMerkleStore { infos: Vec::from_iter(infos) }
52    }
53
54    pub fn extend_precompile_requests(data: impl IntoIterator<Item = PrecompileRequest>) -> Self {
55        Self::ExtendPrecompileRequests { data: Vec::from_iter(data) }
56    }
57}
58// HOST TRAIT
59// ================================================================================================
60
61/// Defines the host functionality shared by both sync and async execution.
62///
63/// There are three main categories of interactions between the VM and the host:
64/// 1. getting a library's MAST forest,
65/// 2. handling VM events (which can mutate the process' advice provider), and
66/// 3. handling debug and trace events.
67pub trait BaseHost {
68    // REQUIRED METHODS
69    // --------------------------------------------------------------------------------------------
70
71    /// Returns the [`SourceSpan`] and optional [`SourceFile`] for the provided location.
72    fn get_label_and_source_file(
73        &self,
74        location: &Location,
75    ) -> (SourceSpan, Option<Arc<SourceFile>>);
76
77    // PROVIDED METHODS
78    // --------------------------------------------------------------------------------------------
79
80    /// Handles the debug request from the VM.
81    fn on_debug(
82        &mut self,
83        process: &ProcessorState,
84        options: &DebugOptions,
85    ) -> Result<(), DebugError> {
86        let mut handler = debug::DefaultDebugHandler::default();
87        handler.on_debug(process, options)
88    }
89
90    /// Handles the trace emitted from the VM.
91    fn on_trace(&mut self, process: &ProcessorState, trace_id: u32) -> Result<(), TraceError> {
92        let mut handler = debug::DefaultDebugHandler::default();
93        handler.on_trace(process, trace_id)
94    }
95
96    /// Returns the [`EventName`] registered for the provided [`EventId`], if any.
97    ///
98    /// Hosts that maintain an event registry can override this method to surface human-readable
99    /// names for diagnostics. The default implementation returns `None`.
100    fn resolve_event(&self, _event_id: EventId) -> Option<&EventName> {
101        None
102    }
103}
104
105/// Defines a synchronous interface by which the VM can interact with the host during execution.
106pub trait SyncHost: BaseHost {
107    /// Returns MAST forest corresponding to the specified digest, or None if the MAST forest for
108    /// this digest could not be found in this host.
109    fn get_mast_forest(&self, node_digest: &Word) -> Option<Arc<MastForest>>;
110
111    /// Handles the event emitted from the VM and provides advice mutations to be applied to
112    /// the advice provider.
113    ///
114    /// The event ID is available at the top of the stack (position 0) when this handler is called.
115    /// This allows the handler to access both the event ID and any additional context data that
116    /// may have been pushed onto the stack prior to the emit operation.
117    ///
118    /// ## Implementation notes
119    /// - Extract the event ID via `EventId::from_felt(process.get_stack_item(0))`
120    /// - Return errors without event names or IDs - the caller will enrich them via
121    ///   [`BaseHost::resolve_event()`]
122    /// - System events (IDs 0-255) are handled by the VM before calling this method
123    fn on_event(&mut self, process: &ProcessorState<'_>)
124    -> Result<Vec<AdviceMutation>, EventError>;
125}
126
127/// Defines an async interface by which the VM can interact with the host during execution.
128///
129/// This mirrors the historic async host surface while allowing the sync-first core to depend on
130/// [`BaseHost`].
131pub trait Host: BaseHost {
132    // REQUIRED METHODS
133    // --------------------------------------------------------------------------------------------
134
135    /// Returns MAST forest corresponding to the specified digest, or None if the MAST forest for
136    /// this digest could not be found in this host.
137    fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend<Option<Arc<MastForest>>>;
138
139    /// Handles the event emitted from the VM and provides advice mutations to be applied to
140    /// the advice provider.
141    ///
142    /// The event ID is available at the top of the stack (position 0) when this handler is called.
143    /// This allows the handler to access both the event ID and any additional context data that
144    /// may have been pushed onto the stack prior to the emit operation.
145    ///
146    /// ## Implementation notes
147    /// - Extract the event ID via `EventId::from_felt(process.get_stack_item(0))`
148    /// - Return errors without event names or IDs - the caller will enrich them via
149    ///   [`BaseHost::resolve_event()`]
150    /// - System events (IDs 0-255) are handled by the VM before calling this method
151    fn on_event(
152        &mut self,
153        process: &ProcessorState<'_>,
154    ) -> impl FutureMaybeSend<Result<Vec<AdviceMutation>, EventError>>;
155}
156
157impl<T> Host for T
158where
159    T: SyncHost,
160{
161    fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend<Option<Arc<MastForest>>> {
162        let result = SyncHost::get_mast_forest(self, node_digest);
163        async move { result }
164    }
165
166    fn on_event(
167        &mut self,
168        process: &ProcessorState<'_>,
169    ) -> impl FutureMaybeSend<Result<Vec<AdviceMutation>, EventError>> {
170        let result = SyncHost::on_event(self, process);
171        async move { result }
172    }
173}
174
175/// Alias for a `Future`
176///
177/// Unless the compilation target family is `wasm`, we add `Send` to the required bounds. For
178/// `wasm` compilation targets there is no `Send` bound.
179#[cfg(target_family = "wasm")]
180pub trait FutureMaybeSend<O>: Future<Output = O> {}
181
182#[cfg(target_family = "wasm")]
183impl<T, O> FutureMaybeSend<O> for T where T: Future<Output = O> {}
184
185/// Alias for a `Future`
186///
187/// Unless the compilation target family is `wasm`, we add `Send` to the required bounds. For
188/// `wasm` compilation targets there is no `Send` bound.
189#[cfg(not(target_family = "wasm"))]
190pub trait FutureMaybeSend<O>: Future<Output = O> + Send {}
191
192#[cfg(not(target_family = "wasm"))]
193impl<T, O> FutureMaybeSend<O> for T where T: Future<Output = O> + Send {}