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