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