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
86impl<T: BaseHost + ?Sized> BaseHost for &mut T {
87    fn get_label_and_source_file(
88        &self,
89        location: &Location,
90    ) -> (SourceSpan, Option<Arc<SourceFile>>) {
91        (**self).get_label_and_source_file(location)
92    }
93
94    fn resolve_event(&self, event_id: EventId) -> Option<&EventName> {
95        (**self).resolve_event(event_id)
96    }
97}
98
99/// Defines a synchronous interface by which the VM can interact with the host during execution.
100pub trait SyncHost: BaseHost {
101    /// Returns MAST forest corresponding to the specified digest, or None if the MAST forest for
102    /// this digest could not be found in this host.
103    fn get_mast_forest(&self, node_digest: &Word) -> Option<LoadedMastForest>;
104
105    /// Handles the event emitted from the VM and provides advice mutations to be applied to
106    /// the advice provider.
107    ///
108    /// The event ID is available at the top of the stack (position 0) when this handler is called.
109    /// This allows the handler to access both the event ID and any additional context data that
110    /// may have been pushed onto the stack prior to the emit operation.
111    ///
112    /// ## Implementation notes
113    /// - Extract the event ID via `EventId::from_felt(process.get_stack_item(0))`
114    /// - Return errors without event names or IDs - the caller will enrich them via
115    ///   [`BaseHost::resolve_event()`]
116    /// - System events (IDs 0-255) are handled by the VM before calling this method
117    fn on_event(&mut self, process: &ProcessorState<'_>)
118    -> Result<Vec<AdviceMutation>, EventError>;
119}
120
121/// Defines an async interface by which the VM can interact with the host during execution.
122///
123/// This mirrors the historic async host surface while allowing the sync-first core to depend on
124/// [`BaseHost`].
125pub trait Host: BaseHost {
126    // REQUIRED METHODS
127    // --------------------------------------------------------------------------------------------
128
129    /// Returns MAST forest corresponding to the specified digest, or None if the MAST forest for
130    /// this digest could not be found in this host.
131    fn get_mast_forest(&self, node_digest: &Word)
132    -> impl FutureMaybeSend<Option<LoadedMastForest>>;
133
134    /// Handles the event emitted from the VM and provides advice mutations to be applied to
135    /// the advice provider.
136    ///
137    /// The event ID is available at the top of the stack (position 0) when this handler is called.
138    /// This allows the handler to access both the event ID and any additional context data that
139    /// may have been pushed onto the stack prior to the emit operation.
140    ///
141    /// ## Implementation notes
142    /// - Extract the event ID via `EventId::from_felt(process.get_stack_item(0))`
143    /// - Return errors without event names or IDs - the caller will enrich them via
144    ///   [`BaseHost::resolve_event()`]
145    /// - System events (IDs 0-255) are handled by the VM before calling this method
146    fn on_event(
147        &mut self,
148        process: &ProcessorState<'_>,
149    ) -> impl FutureMaybeSend<Result<Vec<AdviceMutation>, EventError>>;
150}
151
152impl<T> Host for T
153where
154    T: SyncHost,
155{
156    fn get_mast_forest(
157        &self,
158        node_digest: &Word,
159    ) -> impl FutureMaybeSend<Option<LoadedMastForest>> {
160        let result = SyncHost::get_mast_forest(self, node_digest);
161        async move { result }
162    }
163
164    fn on_event(
165        &mut self,
166        process: &ProcessorState<'_>,
167    ) -> impl FutureMaybeSend<Result<Vec<AdviceMutation>, EventError>> {
168        let result = SyncHost::on_event(self, process);
169        async move { result }
170    }
171}
172
173/// Alias for a `Future`
174///
175/// Unless the compilation target family is `wasm`, we add `Send` to the required bounds. For
176/// `wasm` compilation targets there is no `Send` bound.
177#[cfg(target_family = "wasm")]
178pub trait FutureMaybeSend<O>: Future<Output = O> {}
179
180#[cfg(target_family = "wasm")]
181impl<T, O> FutureMaybeSend<O> for T where T: Future<Output = O> {}
182
183/// Alias for a `Future`
184///
185/// Unless the compilation target family is `wasm`, we add `Send` to the required bounds. For
186/// `wasm` compilation targets there is no `Send` bound.
187#[cfg(not(target_family = "wasm"))]
188pub trait FutureMaybeSend<O>: Future<Output = O> + Send {}
189
190#[cfg(not(target_family = "wasm"))]
191impl<T, O> FutureMaybeSend<O> for T where T: Future<Output = O> + Send {}