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 an interface by which the VM can interact with the host.
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 Host {
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 // Note: we don't use the `async` keyword in get_mast_forest and on_event, since we need to
78 // specify the `+ Send` bound to the returned Future, and `async` doesn't allow us to do that.
79
80 /// Returns MAST forest corresponding to the specified digest, or None if the MAST forest for
81 /// this digest could not be found in this host.
82 fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend<Option<Arc<MastForest>>>;
83
84 /// Handles the event emitted from the VM and provides advice mutations to be applied to
85 /// the advice provider.
86 ///
87 /// The event ID is available at the top of the stack (position 0) when this handler is called.
88 /// This allows the handler to access both the event ID and any additional context data that
89 /// may have been pushed onto the stack prior to the emit operation.
90 ///
91 /// ## Implementation notes
92 /// - Extract the event ID via `EventId::from_felt(process.get_stack_item(0))`
93 /// - Return errors without event names or IDs - the caller will enrich them via
94 /// [`Host::resolve_event()`]
95 /// - System events (IDs 0-255) are handled by the VM before calling this method
96 fn on_event(
97 &mut self,
98 process: &ProcessorState<'_>,
99 ) -> impl FutureMaybeSend<Result<Vec<AdviceMutation>, EventError>>;
100
101 // PROVIDED METHODS
102 // --------------------------------------------------------------------------------------------
103
104 /// Handles the debug request from the VM.
105 fn on_debug(
106 &mut self,
107 process: &ProcessorState,
108 options: &DebugOptions,
109 ) -> Result<(), DebugError> {
110 let mut handler = debug::DefaultDebugHandler::default();
111 handler.on_debug(process, options)
112 }
113
114 /// Handles the trace emitted from the VM.
115 fn on_trace(&mut self, process: &ProcessorState, trace_id: u32) -> Result<(), TraceError> {
116 let mut handler = debug::DefaultDebugHandler::default();
117 handler.on_trace(process, trace_id)
118 }
119
120 /// Returns the [`EventName`] registered for the provided [`EventId`], if any.
121 ///
122 /// Hosts that maintain an event registry can override this method to surface human-readable
123 /// names for diagnostics. The default implementation returns `None`.
124 fn resolve_event(&self, _event_id: EventId) -> Option<&EventName> {
125 None
126 }
127}
128
129/// Alias for a `Future`
130///
131/// Unless the compilation target family is `wasm`, we add `Send` to the required bounds. For
132/// `wasm` compilation targets there is no `Send` bound.
133///
134/// We also provide a blank implementation of this trait for all features.
135#[cfg(target_family = "wasm")]
136pub trait FutureMaybeSend<O>: Future<Output = O> {}
137
138#[cfg(target_family = "wasm")]
139impl<T, O> FutureMaybeSend<O> for T where T: Future<Output = O> {}
140
141/// Alias for a `Future`
142///
143/// Unless the compilation target family is `wasm`, we add `Send` to the required bounds. For
144/// `wasm` compilation targets there is no `Send` bound.
145///
146/// We also provide a blank implementation of this trait for all features.
147#[cfg(not(target_family = "wasm"))]
148pub trait FutureMaybeSend<O>: Future<Output = O> + Send {}
149
150#[cfg(not(target_family = "wasm"))]
151impl<T, O> FutureMaybeSend<O> for T where T: Future<Output = O> + Send {}