1#![no_std]
2#![cfg_attr(test, allow(clippy::needless_range_loop))]
5
6#[macro_use]
7extern crate alloc;
8
9#[cfg(feature = "std")]
10extern crate std;
11
12use alloc::vec::Vec;
13use core::{
14 fmt::{self, Display, LowerHex},
15 ops::ControlFlow,
16};
17
18use miden_mast_package::debug_info::DebugSourceNodeId;
19
20mod continuation_stack;
21mod errors;
22mod execution;
23mod execution_options;
24mod fast;
25mod host;
26mod processor;
27mod tracer;
28
29use miden_core::mast::ExecutableMastForest;
30
31use crate::{
32 advice::{AdviceInputs, AdviceProvider},
33 continuation_stack::ContinuationStack,
34 errors::{MapExecErr, MapExecErrNoCtx},
35 processor::{Processor, SystemInterface},
36 trace::RowIndex,
37};
38
39#[cfg(any(test, feature = "testing"))]
40mod test_utils;
41#[cfg(any(test, feature = "testing"))]
42pub use test_utils::{ProcessorStateSnapshot, TestHost};
43
44#[cfg(test)]
45mod tests;
46
47pub use continuation_stack::Continuation;
51pub use errors::{
52 AceError, ExecutionError, HostError, MemoryError, PackageSourceDebugContext,
53 advice_error_with_package_source_context, event_error_with_package_source_context,
54 procedure_not_found_with_package_source_context,
55};
56pub use execution_options::{ExecutionOptions, ExecutionOptionsError};
57pub use fast::{BreakReason, ExecutionOutput, FastProcessor, ResumeContext};
58pub use host::{
59 BaseHost, FutureMaybeSend, Host, LoadedMastForest, MastForestStore, MemMastForestStore,
60 SyncHost,
61 debug::{StdoutWriter, format_value, write_interval, write_stack},
62 default::{DefaultHost, HostLibrary},
63};
64pub use miden_core::{
65 EMPTY_WORD, Felt, ONE, WORD_SIZE, Word, ZERO, crypto, field, mast, precompile,
66 program::{
67 InputError, Kernel, MIN_STACK_DEPTH, Program, ProgramInfo, StackInputs, StackOutputs,
68 },
69 serde, utils,
70};
71pub use trace::{TraceBuildInputs, TraceGenerationContext};
72
73pub mod advice {
74 pub use miden_core::advice::{AdviceInputs, AdviceMap, AdviceStackBuilder};
75
76 pub use super::host::{
77 AdviceMutation,
78 advice::{AdviceError, AdviceProvider, MAX_ADVICE_STACK_SIZE},
79 };
80}
81
82pub mod event {
83 pub use miden_core::events::*;
84
85 pub use crate::host::handlers::{
86 EventError, EventHandler, EventHandlerRegistry, NoopEventHandler,
87 };
88}
89
90pub mod operation {
91 pub use miden_core::operations::*;
92
93 pub use crate::errors::{BinaryValueErrorContext, OperationError};
94}
95
96pub mod trace;
97
98#[tracing::instrument("execute_program", skip_all)]
110pub async fn execute(
111 program: &Program,
112 stack_inputs: StackInputs,
113 advice_inputs: AdviceInputs,
114 host: &mut impl Host,
115 options: ExecutionOptions,
116) -> Result<ExecutionOutput, ExecutionError> {
117 let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options)
118 .map_exec_err_no_ctx()?;
119 processor.execute(program, host).await
120}
121
122#[cfg(not(target_family = "wasm"))]
131#[tracing::instrument("execute_program_sync", skip_all)]
132pub fn execute_sync(
133 program: &Program,
134 stack_inputs: StackInputs,
135 advice_inputs: AdviceInputs,
136 host: &mut impl SyncHost,
137 options: ExecutionOptions,
138) -> Result<ExecutionOutput, ExecutionError> {
139 let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options)
140 .map_exec_err_no_ctx()?;
141 processor.execute_sync(program, host)
142}
143
144#[derive(Debug)]
152pub struct ProcessorState<'a> {
153 processor: &'a FastProcessor,
154}
155
156impl<'a> ProcessorState<'a> {
157 #[inline(always)]
159 pub fn advice_provider(&self) -> &AdviceProvider {
160 self.processor.advice_provider()
161 }
162
163 #[inline(always)]
165 pub fn execution_options(&self) -> &ExecutionOptions {
166 self.processor.execution_options()
167 }
168
169 #[inline(always)]
171 pub fn clock(&self) -> RowIndex {
172 self.processor.clock()
173 }
174
175 #[inline(always)]
177 pub fn ctx(&self) -> ContextId {
178 self.processor.ctx()
179 }
180
181 #[inline(always)]
185 pub fn get_stack_item(&self, pos: usize) -> Felt {
186 self.processor.stack_get_safe(pos)
187 }
188
189 #[inline(always)]
201 pub fn get_stack_word(&self, start_idx: usize) -> Word {
202 self.processor.stack_get_word_safe(start_idx)
203 }
204
205 #[inline(always)]
208 pub fn get_stack_state(&self) -> Vec<Felt> {
209 self.processor.stack().iter().rev().copied().collect()
210 }
211
212 #[inline(always)]
215 pub fn get_mem_value(&self, ctx: ContextId, addr: u32) -> Option<Felt> {
216 self.processor.memory().read_element_impl(ctx, addr)
217 }
218
219 #[inline(always)]
224 pub fn get_mem_word(&self, ctx: ContextId, addr: u32) -> Result<Option<Word>, MemoryError> {
225 self.processor.memory().read_word_impl(ctx, addr)
226 }
227
228 pub fn get_mem_addr_range(
233 &self,
234 start_idx: usize,
235 end_idx: usize,
236 ) -> Result<core::ops::Range<u32>, MemoryError> {
237 let start_addr = self.get_stack_item(start_idx).as_canonical_u64();
238 let end_addr = self.get_stack_item(end_idx).as_canonical_u64();
239
240 if start_addr > u32::MAX as u64 {
241 return Err(MemoryError::AddressOutOfBounds { addr: start_addr });
242 }
243 if end_addr > u32::MAX as u64 {
244 return Err(MemoryError::AddressOutOfBounds { addr: end_addr });
245 }
246
247 if start_addr > end_addr {
248 return Err(MemoryError::InvalidMemoryRange { start_addr, end_addr });
249 }
250
251 Ok(start_addr as u32..end_addr as u32)
252 }
253
254 #[inline(always)]
260 pub fn get_mem_state(&self, ctx: ContextId) -> Vec<(MemoryAddress, Felt)> {
261 self.processor.memory().get_memory_state(ctx)
262 }
263}
264
265pub trait Stopper {
275 type Processor;
276
277 type Forest: ExecutableMastForest + Clone;
281
282 fn should_stop(
297 &self,
298 processor: &Self::Processor,
299 continuation_stack: &ContinuationStack<Self::Forest>,
300 continuation_after_stop: impl FnOnce() -> Option<(
301 Continuation<Self::Forest>,
302 Option<DebugSourceNodeId>,
303 )>,
304 ) -> ControlFlow<BreakReason<Self::Forest>>;
305}
306
307#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
312pub struct ContextId(u32);
313
314impl ContextId {
315 pub fn root() -> Self {
317 Self(0)
318 }
319
320 pub fn is_root(&self) -> bool {
322 self.0 == 0
323 }
324}
325
326impl From<RowIndex> for ContextId {
327 fn from(value: RowIndex) -> Self {
328 Self(value.as_u32())
329 }
330}
331
332impl From<u32> for ContextId {
333 fn from(value: u32) -> Self {
334 Self(value)
335 }
336}
337
338impl From<ContextId> for u32 {
339 fn from(context_id: ContextId) -> Self {
340 context_id.0
341 }
342}
343
344impl From<ContextId> for u64 {
345 fn from(context_id: ContextId) -> Self {
346 context_id.0.into()
347 }
348}
349
350impl From<ContextId> for Felt {
351 fn from(context_id: ContextId) -> Self {
352 Felt::from_u32(context_id.0)
353 }
354}
355
356impl Display for ContextId {
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358 write!(f, "{}", self.0)
359 }
360}
361
362#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
366pub struct MemoryAddress(u32);
367
368impl From<u32> for MemoryAddress {
369 fn from(addr: u32) -> Self {
370 MemoryAddress(addr)
371 }
372}
373
374impl From<MemoryAddress> for u32 {
375 fn from(value: MemoryAddress) -> Self {
376 value.0
377 }
378}
379
380impl Display for MemoryAddress {
381 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
382 Display::fmt(&self.0, f)
383 }
384}
385
386impl LowerHex for MemoryAddress {
387 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388 LowerHex::fmt(&self.0, f)
389 }
390}
391
392impl core::ops::Add<MemoryAddress> for MemoryAddress {
393 type Output = Self;
394
395 fn add(self, rhs: MemoryAddress) -> Self::Output {
396 MemoryAddress(self.0 + rhs.0)
397 }
398}
399
400impl core::ops::Add<u32> for MemoryAddress {
401 type Output = Self;
402
403 fn add(self, rhs: u32) -> Self::Output {
404 MemoryAddress(self.0 + rhs)
405 }
406}
407
408#[track_caller]
420fn option_map_break_reason<F, T>(
421 opt: Option<T>,
422 err_msg: &'static str,
423) -> ControlFlow<BreakReason<F>, T> {
424 match opt {
425 Some(value) => ControlFlow::Continue(value),
426 None => ControlFlow::Break(BreakReason::Err(ExecutionError::Internal(err_msg))),
427 }
428}