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