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::{
30 deferred::{Digest, Node, PrecompileError},
31 mast::ExecutableMastForest,
32};
33
34use crate::{
35 advice::{AdviceInputs, AdviceProvider},
36 continuation_stack::ContinuationStack,
37 errors::{MapExecErr, MapExecErrNoCtx},
38 processor::{Processor, SystemInterface},
39 trace::RowIndex,
40};
41
42#[cfg(any(test, feature = "testing"))]
43mod test_utils;
44#[cfg(any(test, feature = "testing"))]
45pub use test_utils::{ProcessorStateSnapshot, TestHost};
46
47#[cfg(test)]
48mod tests;
49
50pub use continuation_stack::Continuation;
54pub use errors::{
55 AceError, ExecutionError, HostError, MemoryError, PackageSourceDebugContext,
56 advice_error_with_package_source_context, event_error_with_package_source_context,
57 procedure_not_found_with_package_source_context,
58};
59pub use execution_options::{ExecutionOptions, ExecutionOptionsError};
60pub use fast::{BreakReason, ExecutionOutput, FastProcessor, ResumeContext};
61pub use host::{
62 BaseHost, FutureMaybeSend, Host, LoadedMastForest, MastForestStore, MemMastForestStore,
63 SyncHost,
64 debug::{StdoutWriter, format_value, write_interval, write_stack},
65 default::{DefaultHost, HostLibrary},
66};
67pub use miden_core::{
68 EMPTY_WORD, Felt, ONE, WORD_SIZE, Word, ZERO, crypto, field, mast,
69 program::{
70 InputError, KernelDescriptor, MIN_STACK_DEPTH, Program, ProgramInfo, StackInputs,
71 StackOutputs,
72 },
73 serde, utils,
74};
75pub use trace::{TraceBuildInputs, TraceGenerationContext};
76
77pub mod advice {
78 pub use miden_core::advice::{AdviceInputs, AdviceMap, AdviceStack};
79
80 pub use super::host::{
81 AdviceMutation,
82 advice::{AdviceError, AdviceProvider, MAX_ADVICE_STACK_SIZE},
83 };
84}
85
86pub mod event {
87 pub use miden_core::events::*;
88
89 pub use crate::host::handlers::{
90 EventError, EventHandler, EventHandlerRegistry, NoopEventHandler, TraceError, TraceHandler,
91 TraceHandlerRegistry,
92 };
93}
94
95pub mod operation {
96 pub use miden_core::operations::*;
97
98 pub use crate::errors::{BinaryValueErrorContext, OperationError};
99}
100
101pub mod trace;
102
103#[tracing::instrument("execute_program", skip_all)]
115pub async fn execute(
116 program: &Program,
117 stack_inputs: StackInputs,
118 advice_inputs: AdviceInputs,
119 host: &mut impl Host,
120 options: ExecutionOptions,
121) -> Result<ExecutionOutput, ExecutionError> {
122 let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options)
123 .map_exec_err_no_ctx()?;
124 processor.execute(program, host).await
125}
126
127#[cfg(not(target_family = "wasm"))]
136#[tracing::instrument("execute_program_sync", skip_all)]
137pub fn execute_sync(
138 program: &Program,
139 stack_inputs: StackInputs,
140 advice_inputs: AdviceInputs,
141 host: &mut impl SyncHost,
142 options: ExecutionOptions,
143) -> Result<ExecutionOutput, ExecutionError> {
144 let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options)
145 .map_exec_err_no_ctx()?;
146 processor.execute_sync(program, host)
147}
148
149#[derive(Debug)]
157pub struct ProcessorState<'a> {
158 processor: &'a FastProcessor,
159}
160
161impl<'a> ProcessorState<'a> {
162 #[inline(always)]
164 pub fn advice_provider(&self) -> &AdviceProvider {
165 self.processor.advice_provider()
166 }
167
168 #[inline(always)]
170 pub fn execution_options(&self) -> &ExecutionOptions {
171 self.processor.execution_options()
172 }
173
174 #[inline(always)]
176 pub fn clock(&self) -> RowIndex {
177 self.processor.clock()
178 }
179
180 #[inline(always)]
182 pub fn ctx(&self) -> ContextId {
183 self.processor.ctx()
184 }
185
186 #[inline(always)]
190 pub fn get_stack_item(&self, pos: usize) -> Felt {
191 self.processor.stack_get_safe(pos)
192 }
193
194 #[inline(always)]
206 pub fn get_stack_word(&self, start_idx: usize) -> Word {
207 self.processor.stack_get_word_safe(start_idx)
208 }
209
210 #[inline(always)]
213 pub fn get_stack_state(&self) -> Vec<Felt> {
214 self.processor.stack().iter().rev().copied().collect()
215 }
216
217 #[inline(always)]
220 pub fn get_mem_value(&self, ctx: ContextId, addr: u32) -> Option<Felt> {
221 self.processor.memory().read_element_impl(ctx, addr)
222 }
223
224 #[inline(always)]
229 pub fn get_mem_word(&self, ctx: ContextId, addr: u32) -> Result<Option<Word>, MemoryError> {
230 self.processor.memory().read_word_impl(ctx, addr)
231 }
232
233 pub fn get_mem_addr_range(
238 &self,
239 start_idx: usize,
240 end_idx: usize,
241 ) -> Result<core::ops::Range<u32>, MemoryError> {
242 let start_addr = self.get_stack_item(start_idx).as_canonical_u64();
243 let end_addr = self.get_stack_item(end_idx).as_canonical_u64();
244
245 if start_addr > u32::MAX as u64 {
246 return Err(MemoryError::AddressOutOfBounds { addr: start_addr });
247 }
248 if end_addr > u32::MAX as u64 {
249 return Err(MemoryError::AddressOutOfBounds { addr: end_addr });
250 }
251
252 if start_addr > end_addr {
253 return Err(MemoryError::InvalidMemoryRange { start_addr, end_addr });
254 }
255
256 Ok(start_addr as u32..end_addr as u32)
257 }
258
259 #[inline(always)]
265 pub fn get_mem_state(&self, ctx: ContextId) -> Vec<(MemoryAddress, Felt)> {
266 self.processor.memory().get_memory_state(ctx)
267 }
268
269 #[inline(always)]
274 pub fn get_canonical_deferred_digest(&self, digest: Digest) -> Option<Digest> {
275 self.processor.deferred_state().get_canonical_digest(digest)
276 }
277
278 #[inline(always)]
283 pub fn get_canonical_deferred_node(&self, digest: Digest) -> Option<(Digest, &Node)> {
284 self.processor.deferred_state().get_canonical_node(digest)
285 }
286
287 #[inline(always)]
294 pub fn require_canonical_deferred_node(
295 &self,
296 digest: Digest,
297 ) -> Result<(Digest, &Node), PrecompileError> {
298 self.processor.deferred_state().require_canonical_node(digest)
299 }
300}
301
302pub trait Stopper {
312 type Processor;
313
314 type Forest: ExecutableMastForest + Clone;
318
319 fn should_stop(
334 &self,
335 processor: &Self::Processor,
336 continuation_stack: &ContinuationStack<Self::Forest>,
337 continuation_after_stop: impl FnOnce() -> Option<(
338 Continuation<Self::Forest>,
339 Option<DebugSourceNodeId>,
340 )>,
341 ) -> ControlFlow<BreakReason<Self::Forest>>;
342}
343
344#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
349pub struct ContextId(u32);
350
351impl ContextId {
352 pub fn root() -> Self {
354 Self(0)
355 }
356
357 pub fn is_root(&self) -> bool {
359 self.0 == 0
360 }
361}
362
363impl From<RowIndex> for ContextId {
364 fn from(value: RowIndex) -> Self {
365 Self(value.as_u32())
366 }
367}
368
369impl From<u32> for ContextId {
370 fn from(value: u32) -> Self {
371 Self(value)
372 }
373}
374
375impl From<ContextId> for u32 {
376 fn from(context_id: ContextId) -> Self {
377 context_id.0
378 }
379}
380
381impl From<ContextId> for u64 {
382 fn from(context_id: ContextId) -> Self {
383 context_id.0.into()
384 }
385}
386
387impl From<ContextId> for Felt {
388 fn from(context_id: ContextId) -> Self {
389 Felt::from_u32(context_id.0)
390 }
391}
392
393impl Display for ContextId {
394 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395 write!(f, "{}", self.0)
396 }
397}
398
399#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
403pub struct MemoryAddress(u32);
404
405impl From<u32> for MemoryAddress {
406 fn from(addr: u32) -> Self {
407 MemoryAddress(addr)
408 }
409}
410
411impl From<MemoryAddress> for u32 {
412 fn from(value: MemoryAddress) -> Self {
413 value.0
414 }
415}
416
417impl Display for MemoryAddress {
418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419 Display::fmt(&self.0, f)
420 }
421}
422
423impl LowerHex for MemoryAddress {
424 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
425 LowerHex::fmt(&self.0, f)
426 }
427}
428
429impl core::ops::Add<MemoryAddress> for MemoryAddress {
430 type Output = Self;
431
432 fn add(self, rhs: MemoryAddress) -> Self::Output {
433 MemoryAddress(self.0 + rhs.0)
434 }
435}
436
437impl core::ops::Add<u32> for MemoryAddress {
438 type Output = Self;
439
440 fn add(self, rhs: u32) -> Self::Output {
441 MemoryAddress(self.0 + rhs)
442 }
443}
444
445#[track_caller]
457fn option_map_break_reason<F, T>(
458 opt: Option<T>,
459 err_msg: &'static str,
460) -> ControlFlow<BreakReason<F>, T> {
461 match opt {
462 Some(value) => ControlFlow::Continue(value),
463 None => ControlFlow::Break(BreakReason::Err(ExecutionError::Internal(err_msg))),
464 }
465}