1#![no_std]
2
3#[macro_use]
4extern crate alloc;
5
6#[cfg(feature = "std")]
7extern crate std;
8
9use alloc::vec::Vec;
10use core::{
11 fmt::{self, Display, LowerHex},
12 ops::ControlFlow,
13};
14
15mod continuation_stack;
16mod debug;
17mod errors;
18mod execution;
19mod execution_options;
20mod fast;
21mod host;
22mod processor;
23mod tracer;
24
25use crate::{
26 advice::{AdviceInputs, AdviceProvider},
27 continuation_stack::ContinuationStack,
28 errors::MapExecErr,
29 processor::{Processor, SystemInterface},
30 trace::{ExecutionTrace, RowIndex},
31};
32
33#[cfg(any(test, feature = "testing"))]
34mod test_utils;
35#[cfg(any(test, feature = "testing"))]
36pub use test_utils::{ProcessorStateSnapshot, TestHost, TraceCollector};
37
38#[cfg(test)]
39mod tests;
40
41pub use continuation_stack::Continuation;
45pub use errors::{AceError, ExecutionError, HostError, MemoryError};
46pub use execution_options::{ExecutionOptions, ExecutionOptionsError};
47pub use fast::{BreakReason, ExecutionOutput, FastProcessor, ResumeContext};
48pub use host::{
49 FutureMaybeSend, Host, MastForestStore, MemMastForestStore,
50 debug::DefaultDebugHandler,
51 default::{DefaultHost, HostLibrary},
52 handlers::{DebugError, DebugHandler, TraceError},
53};
54pub use miden_core::{
55 EMPTY_WORD, Felt, ONE, WORD_SIZE, Word, ZERO, crypto, field, mast, precompile,
56 program::{
57 InputError, Kernel, MIN_STACK_DEPTH, Program, ProgramInfo, StackInputs, StackOutputs,
58 },
59 serde, utils,
60};
61
62pub mod advice {
63 pub use miden_core::advice::{AdviceInputs, AdviceMap, AdviceStackBuilder};
64
65 pub use super::host::{
66 AdviceMutation,
67 advice::{AdviceError, AdviceProvider},
68 };
69}
70
71pub mod event {
72 pub use miden_core::events::*;
73
74 pub use crate::host::handlers::{
75 EventError, EventHandler, EventHandlerRegistry, NoopEventHandler,
76 };
77}
78
79pub mod operation {
80 pub use miden_core::operations::*;
81
82 pub use crate::errors::OperationError;
83}
84
85pub mod trace;
86
87#[tracing::instrument("execute_program", skip_all)]
101pub async fn execute(
102 program: &Program,
103 stack_inputs: StackInputs,
104 advice_inputs: AdviceInputs,
105 host: &mut impl Host,
106 options: ExecutionOptions,
107) -> Result<ExecutionTrace, ExecutionError> {
108 let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options);
109 let (execution_output, trace_generation_context) =
110 processor.execute_for_trace(program, host).await?;
111
112 let trace = trace::build_trace(execution_output, trace_generation_context, program.to_info())?;
113
114 assert_eq!(&program.hash(), trace.program_hash(), "inconsistent program hash");
115 Ok(trace)
116}
117
118#[cfg(not(target_arch = "wasm32"))]
127#[tracing::instrument("execute_program_sync", skip_all)]
128pub fn execute_sync(
129 program: &Program,
130 stack_inputs: StackInputs,
131 advice_inputs: AdviceInputs,
132 host: &mut impl Host,
133 options: ExecutionOptions,
134) -> Result<ExecutionTrace, ExecutionError> {
135 match tokio::runtime::Handle::try_current() {
136 Ok(_handle) => {
137 panic!(
140 "Cannot call execute_sync from within a Tokio runtime. \
141 Use the async execute() method instead."
142 )
143 },
144 Err(_) => {
145 let rt = tokio::runtime::Builder::new_current_thread().build().unwrap();
147 rt.block_on(execute(program, stack_inputs, advice_inputs, host, options))
148 },
149 }
150}
151
152#[derive(Debug)]
160pub struct ProcessorState<'a> {
161 processor: &'a FastProcessor,
162}
163
164impl<'a> ProcessorState<'a> {
165 #[inline(always)]
167 pub fn advice_provider(&self) -> &AdviceProvider {
168 self.processor.advice_provider()
169 }
170
171 #[inline(always)]
173 pub fn execution_options(&self) -> &ExecutionOptions {
174 self.processor.execution_options()
175 }
176
177 #[inline(always)]
179 pub fn clock(&self) -> RowIndex {
180 self.processor.clock()
181 }
182
183 #[inline(always)]
185 pub fn ctx(&self) -> ContextId {
186 self.processor.ctx()
187 }
188
189 #[inline(always)]
193 pub fn get_stack_item(&self, pos: usize) -> Felt {
194 self.processor.stack_get_safe(pos)
195 }
196
197 #[inline(always)]
209 pub fn get_stack_word(&self, start_idx: usize) -> Word {
210 self.processor.stack_get_word_safe(start_idx)
211 }
212
213 #[inline(always)]
216 pub fn get_stack_state(&self) -> Vec<Felt> {
217 self.processor.stack().iter().rev().copied().collect()
218 }
219
220 #[inline(always)]
223 pub fn get_mem_value(&self, ctx: ContextId, addr: u32) -> Option<Felt> {
224 self.processor.memory().read_element_impl(ctx, addr)
225 }
226
227 #[inline(always)]
232 pub fn get_mem_word(&self, ctx: ContextId, addr: u32) -> Result<Option<Word>, MemoryError> {
233 self.processor.memory().read_word_impl(ctx, addr)
234 }
235
236 pub fn get_mem_addr_range(
239 &self,
240 start_idx: usize,
241 end_idx: usize,
242 ) -> Result<core::ops::Range<u32>, MemoryError> {
243 let start_addr = self.get_stack_item(start_idx).as_canonical_u64();
244 let end_addr = self.get_stack_item(end_idx).as_canonical_u64();
245
246 if start_addr > u32::MAX as u64 {
247 return Err(MemoryError::AddressOutOfBounds { addr: start_addr });
248 }
249 if end_addr > u32::MAX as u64 {
250 return Err(MemoryError::AddressOutOfBounds { addr: end_addr });
251 }
252
253 if start_addr > end_addr {
254 return Err(MemoryError::InvalidMemoryRange { start_addr, end_addr });
255 }
256
257 Ok(start_addr as u32..end_addr as u32)
258 }
259
260 #[inline(always)]
266 pub fn get_mem_state(&self, ctx: ContextId) -> Vec<(MemoryAddress, Felt)> {
267 self.processor.memory().get_memory_state(ctx)
268 }
269}
270
271pub trait Stopper {
281 type Processor;
282
283 fn should_stop(
298 &self,
299 processor: &Self::Processor,
300 continuation_stack: &ContinuationStack,
301 continuation_after_stop: impl FnOnce() -> Option<continuation_stack::Continuation>,
302 ) -> ControlFlow<BreakReason>;
303}
304
305#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
310pub struct ContextId(u32);
311
312impl ContextId {
313 pub fn root() -> Self {
315 Self(0)
316 }
317
318 pub fn is_root(&self) -> bool {
320 self.0 == 0
321 }
322}
323
324impl From<RowIndex> for ContextId {
325 fn from(value: RowIndex) -> Self {
326 Self(value.as_u32())
327 }
328}
329
330impl From<u32> for ContextId {
331 fn from(value: u32) -> Self {
332 Self(value)
333 }
334}
335
336impl From<ContextId> for u32 {
337 fn from(context_id: ContextId) -> Self {
338 context_id.0
339 }
340}
341
342impl From<ContextId> for u64 {
343 fn from(context_id: ContextId) -> Self {
344 context_id.0.into()
345 }
346}
347
348impl From<ContextId> for Felt {
349 fn from(context_id: ContextId) -> Self {
350 Felt::from_u32(context_id.0)
351 }
352}
353
354impl Display for ContextId {
355 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356 write!(f, "{}", self.0)
357 }
358}
359
360#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
364pub struct MemoryAddress(u32);
365
366impl From<u32> for MemoryAddress {
367 fn from(addr: u32) -> Self {
368 MemoryAddress(addr)
369 }
370}
371
372impl From<MemoryAddress> for u32 {
373 fn from(value: MemoryAddress) -> Self {
374 value.0
375 }
376}
377
378impl Display for MemoryAddress {
379 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
380 Display::fmt(&self.0, f)
381 }
382}
383
384impl LowerHex for MemoryAddress {
385 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
386 LowerHex::fmt(&self.0, f)
387 }
388}
389
390impl core::ops::Add<MemoryAddress> for MemoryAddress {
391 type Output = Self;
392
393 fn add(self, rhs: MemoryAddress) -> Self::Output {
394 MemoryAddress(self.0 + rhs.0)
395 }
396}
397
398impl core::ops::Add<u32> for MemoryAddress {
399 type Output = Self;
400
401 fn add(self, rhs: u32) -> Self::Output {
402 MemoryAddress(self.0 + rhs)
403 }
404}