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 {}