1#![allow(unused_assignments)]
3
4use alloc::{string::String, sync::Arc, vec::Vec};
5
6use miden_air::RowIndex;
7use miden_core::{
8 EventId, EventName, Felt, QuadFelt, Word,
9 mast::{DecoratorId, MastForest, MastNodeErrorContext, MastNodeId},
10 stack::MIN_STACK_DEPTH,
11 utils::to_hex,
12};
13use miden_debug_types::{SourceFile, SourceSpan};
14use miden_utils_diagnostics::{Diagnostic, miette};
15use winter_prover::ProverError;
16
17use crate::{
18 AssertError, BaseHost, DebugError, EventError, MemoryError, TraceError,
19 host::advice::AdviceError,
20};
21
22#[derive(Debug, thiserror::Error, Diagnostic)]
26pub enum ExecutionError {
27 #[error("advice provider error at clock cycle {clk}")]
28 #[diagnostic()]
29 AdviceError {
30 #[label]
31 label: SourceSpan,
32 #[source_code]
33 source_file: Option<Arc<SourceFile>>,
34 clk: RowIndex,
35 #[source]
36 #[diagnostic_source]
37 err: AdviceError,
38 },
39 #[error("external node with mast root {0} resolved to an external node")]
40 CircularExternalNode(Word),
41 #[error("exceeded the allowed number of max cycles {0}")]
42 CycleLimitExceeded(u32),
43 #[error("decorator id {decorator_id} does not exist in MAST forest")]
44 DecoratorNotFoundInForest { decorator_id: DecoratorId },
45 #[error("debug handler error at clock cycle {clk}: {err}")]
46 DebugHandlerError {
47 clk: RowIndex,
48 #[source]
49 err: DebugError,
50 },
51 #[error("trace handler error at clock cycle {clk} for trace ID {trace_id}: {err}")]
52 TraceHandlerError {
53 clk: RowIndex,
54 trace_id: u32,
55 #[source]
56 err: TraceError,
57 },
58 #[error("division by zero at clock cycle {clk}")]
59 #[diagnostic()]
60 DivideByZero {
61 #[label]
62 label: SourceSpan,
63 #[source_code]
64 source_file: Option<Arc<SourceFile>>,
65 clk: RowIndex,
66 },
67 #[error("failed to execute the dynamic code block provided by the stack with root {hex}; the block could not be found",
68 hex = .digest.to_hex()
69 )]
70 #[diagnostic()]
71 DynamicNodeNotFound {
72 #[label]
73 label: SourceSpan,
74 #[source_code]
75 source_file: Option<Arc<SourceFile>>,
76 digest: Word,
77 },
78 #[error("error during processing of event {}", match event_name {
79 Some(name) => format!("'{}' (ID: {})", name, event_id),
80 None => format!("with ID: {}", event_id),
81 })]
82 #[diagnostic()]
83 EventError {
84 #[label]
85 label: SourceSpan,
86 #[source_code]
87 source_file: Option<Arc<SourceFile>>,
88 event_id: EventId,
89 event_name: Option<EventName>,
90 #[source]
91 error: EventError,
92 },
93 #[error("attempted to add event handler for '{event}' (already registered)")]
94 DuplicateEventHandler { event: EventName },
95 #[error("attempted to add event handler for '{event}' (reserved system event)")]
96 ReservedEventNamespace { event: EventName },
97 #[error("assertion failed at clock cycle {clk} with error {}{}",
98 match err_msg {
99 Some(msg) => format!("message: {msg}"),
100 None => format!("code: {err_code}"),
101 },
102 match err {
103 Some(err) => format!(" (host error: {err})"),
104 None => String::new(),
105 }
106 )]
107 #[diagnostic()]
108 FailedAssertion {
109 #[label]
110 label: SourceSpan,
111 #[source_code]
112 source_file: Option<Arc<SourceFile>>,
113 clk: RowIndex,
114 err_code: Felt,
115 err_msg: Option<Arc<str>>,
116 #[source]
117 err: Option<AssertError>,
118 },
119 #[error("failed to execute the program for internal reason: {0}")]
120 FailedToExecuteProgram(&'static str),
121 #[error("FRI domain segment value cannot exceed 3, but was {0}")]
122 InvalidFriDomainSegment(u64),
123 #[error("degree-respecting projection is inconsistent: expected {0} but was {1}")]
124 InvalidFriLayerFolding(QuadFelt, QuadFelt),
125 #[error(
126 "when returning from a call or dyncall, stack depth must be {MIN_STACK_DEPTH}, but was {depth}"
127 )]
128 #[diagnostic()]
129 InvalidStackDepthOnReturn {
130 #[label("when returning from this call site")]
131 label: SourceSpan,
132 #[source_code]
133 source_file: Option<Arc<SourceFile>>,
134 depth: usize,
135 },
136 #[error("attempted to calculate integer logarithm with zero argument at clock cycle {clk}")]
137 #[diagnostic()]
138 LogArgumentZero {
139 #[label]
140 label: SourceSpan,
141 #[source_code]
142 source_file: Option<Arc<SourceFile>>,
143 clk: RowIndex,
144 },
145 #[error("malformed signature key: {key_type}")]
146 #[diagnostic(help("the secret key associated with the provided public key is malformed"))]
147 MalformedSignatureKey {
148 #[label]
149 label: SourceSpan,
150 #[source_code]
151 source_file: Option<Arc<SourceFile>>,
152 key_type: &'static str,
153 },
154 #[error(
155 "MAST forest in host indexed by procedure root {root_digest} doesn't contain that root"
156 )]
157 MalformedMastForestInHost {
158 #[label]
159 label: SourceSpan,
160 #[source_code]
161 source_file: Option<Arc<SourceFile>>,
162 root_digest: Word,
163 },
164 #[error("node id {node_id} does not exist in MAST forest")]
165 MastNodeNotFoundInForest { node_id: MastNodeId },
166 #[error(transparent)]
167 #[diagnostic(transparent)]
168 MemoryError(MemoryError),
169 #[error("no MAST forest contains the procedure with root digest {root_digest}")]
170 NoMastForestWithProcedure {
171 #[label]
172 label: SourceSpan,
173 #[source_code]
174 source_file: Option<Arc<SourceFile>>,
175 root_digest: Word,
176 },
177 #[error("merkle path verification failed for value {value} at index {index} in the Merkle tree with root {root} (error {err})",
178 value = to_hex(value.as_bytes()),
179 root = to_hex(root.as_bytes()),
180 err = match err_msg {
181 Some(msg) => format!("message: {msg}"),
182 None => format!("code: {err_code}"),
183 }
184 )]
185 MerklePathVerificationFailed {
186 #[label]
187 label: SourceSpan,
188 #[source_code]
189 source_file: Option<Arc<SourceFile>>,
190 value: Word,
191 index: Felt,
192 root: Word,
193 err_code: Felt,
194 err_msg: Option<Arc<str>>,
195 },
196 #[error("if statement expected a binary value on top of the stack, but got {value}")]
197 #[diagnostic()]
198 NotBinaryValueIf {
199 #[label]
200 label: SourceSpan,
201 #[source_code]
202 source_file: Option<Arc<SourceFile>>,
203 value: Felt,
204 },
205 #[error("operation expected a binary value, but got {value}")]
206 #[diagnostic()]
207 NotBinaryValueOp {
208 #[label]
209 label: SourceSpan,
210 #[source_code]
211 source_file: Option<Arc<SourceFile>>,
212 value: Felt,
213 },
214 #[error("loop condition must be a binary value, but got {value}")]
215 #[diagnostic(help(
216 "this could happen either when first entering the loop, or any subsequent iteration"
217 ))]
218 NotBinaryValueLoop {
219 #[label]
220 label: SourceSpan,
221 #[source_code]
222 source_file: Option<Arc<SourceFile>>,
223 value: Felt,
224 },
225 #[error("operation expected u32 values, but got values: {values:?} (error code: {err_code})")]
226 NotU32Values {
227 #[label]
228 label: SourceSpan,
229 #[source_code]
230 source_file: Option<Arc<SourceFile>>,
231 values: Vec<Felt>,
232 err_code: Felt,
233 },
234 #[error(
235 "Operand stack input is {input} but it is expected to fit in a u32 at clock cycle {clk}"
236 )]
237 #[diagnostic()]
238 NotU32StackValue {
239 #[label]
240 label: SourceSpan,
241 #[source_code]
242 source_file: Option<Arc<SourceFile>>,
243 clk: RowIndex,
244 input: u64,
245 },
246 #[error("stack should have at most {MIN_STACK_DEPTH} elements at the end of program execution, but had {} elements", MIN_STACK_DEPTH + .0)]
247 OutputStackOverflow(usize),
248 #[error("a program has already been executed in this process")]
249 ProgramAlreadyExecuted,
250 #[error("proof generation failed")]
251 ProverError(#[source] ProverError),
252 #[error("smt node {node_hex} not found", node_hex = to_hex(node.as_bytes()))]
253 SmtNodeNotFound {
254 #[label]
255 label: SourceSpan,
256 #[source_code]
257 source_file: Option<Arc<SourceFile>>,
258 node: Word,
259 },
260 #[error("expected pre-image length of node {node_hex} to be a multiple of 8 but was {preimage_len}",
261 node_hex = to_hex(node.as_bytes()),
262 )]
263 SmtNodePreImageNotValid {
264 #[label]
265 label: SourceSpan,
266 #[source_code]
267 source_file: Option<Arc<SourceFile>>,
268 node: Word,
269 preimage_len: usize,
270 },
271 #[error("syscall failed: procedure with root {hex} was not found in the kernel",
272 hex = to_hex(proc_root.as_bytes())
273 )]
274 SyscallTargetNotInKernel {
275 #[label]
276 label: SourceSpan,
277 #[source_code]
278 source_file: Option<Arc<SourceFile>>,
279 proc_root: Word,
280 },
281 #[error("failed to execute arithmetic circuit evaluation operation: {error}")]
282 #[diagnostic()]
283 AceChipError {
284 #[label("this call failed")]
285 label: SourceSpan,
286 #[source_code]
287 source_file: Option<Arc<SourceFile>>,
288 error: AceError,
289 },
290 #[error("execution yielded unexpected precompiles")]
291 UnexpectedPrecompiles,
292 #[error(
293 "invalid crypto operation: Merkle path length {path_len} does not match expected depth {depth} at clock cycle {clk}"
294 )]
295 #[diagnostic()]
296 InvalidCryptoInput {
297 #[label]
298 label: SourceSpan,
299 #[source_code]
300 source_file: Option<Arc<SourceFile>>,
301 clk: RowIndex,
302 path_len: usize,
303 depth: Felt,
304 },
305}
306
307impl ExecutionError {
308 pub fn advice_error(
309 err: AdviceError,
310 clk: RowIndex,
311 err_ctx: &impl ErrorContext,
312 ) -> ExecutionError {
313 let (label, source_file) = err_ctx.label_and_source_file();
314 ExecutionError::AdviceError { label, source_file, err, clk }
315 }
316
317 pub fn divide_by_zero(clk: RowIndex, err_ctx: &impl ErrorContext) -> Self {
318 let (label, source_file) = err_ctx.label_and_source_file();
319 Self::DivideByZero { clk, label, source_file }
320 }
321
322 pub fn input_not_u32(clk: RowIndex, input: u64, err_ctx: &impl ErrorContext) -> Self {
323 let (label, source_file) = err_ctx.label_and_source_file();
324 Self::NotU32StackValue { clk, input, label, source_file }
325 }
326
327 pub fn dynamic_node_not_found(digest: Word, err_ctx: &impl ErrorContext) -> Self {
328 let (label, source_file) = err_ctx.label_and_source_file();
329
330 Self::DynamicNodeNotFound { label, source_file, digest }
331 }
332
333 pub fn event_error(
334 error: EventError,
335 event_id: EventId,
336 event_name: Option<EventName>,
337 err_ctx: &impl ErrorContext,
338 ) -> Self {
339 let (label, source_file) = err_ctx.label_and_source_file();
340
341 Self::EventError {
342 label,
343 source_file,
344 event_id,
345 event_name,
346 error,
347 }
348 }
349
350 pub fn failed_assertion(
351 clk: RowIndex,
352 err_code: Felt,
353 err_msg: Option<Arc<str>>,
354 err: Option<AssertError>,
355 err_ctx: &impl ErrorContext,
356 ) -> Self {
357 let (label, source_file) = err_ctx.label_and_source_file();
358
359 Self::FailedAssertion {
360 label,
361 source_file,
362 clk,
363 err_code,
364 err_msg,
365 err,
366 }
367 }
368
369 pub fn invalid_stack_depth_on_return(depth: usize, err_ctx: &impl ErrorContext) -> Self {
370 let (label, source_file) = err_ctx.label_and_source_file();
371 Self::InvalidStackDepthOnReturn { label, source_file, depth }
372 }
373
374 pub fn log_argument_zero(clk: RowIndex, err_ctx: &impl ErrorContext) -> Self {
375 let (label, source_file) = err_ctx.label_and_source_file();
376 Self::LogArgumentZero { label, source_file, clk }
377 }
378
379 pub fn malfored_mast_forest_in_host(root_digest: Word, err_ctx: &impl ErrorContext) -> Self {
380 let (label, source_file) = err_ctx.label_and_source_file();
381 Self::MalformedMastForestInHost { label, source_file, root_digest }
382 }
383
384 pub fn malformed_signature_key(key_type: &'static str, err_ctx: &impl ErrorContext) -> Self {
385 let (label, source_file) = err_ctx.label_and_source_file();
386 Self::MalformedSignatureKey { label, source_file, key_type }
387 }
388
389 pub fn merkle_path_verification_failed(
390 value: Word,
391 index: Felt,
392 root: Word,
393 err_code: Felt,
394 err_msg: Option<Arc<str>>,
395 err_ctx: &impl ErrorContext,
396 ) -> Self {
397 let (label, source_file) = err_ctx.label_and_source_file();
398
399 Self::MerklePathVerificationFailed {
400 label,
401 source_file,
402 value,
403 index,
404 root,
405 err_code,
406 err_msg,
407 }
408 }
409
410 pub fn no_mast_forest_with_procedure(root_digest: Word, err_ctx: &impl ErrorContext) -> Self {
411 let (label, source_file) = err_ctx.label_and_source_file();
412 Self::NoMastForestWithProcedure { label, source_file, root_digest }
413 }
414
415 pub fn not_binary_value_if(value: Felt, err_ctx: &impl ErrorContext) -> Self {
416 let (label, source_file) = err_ctx.label_and_source_file();
417 Self::NotBinaryValueIf { label, source_file, value }
418 }
419
420 pub fn not_binary_value_op(value: Felt, err_ctx: &impl ErrorContext) -> Self {
421 let (label, source_file) = err_ctx.label_and_source_file();
422 Self::NotBinaryValueOp { label, source_file, value }
423 }
424
425 pub fn not_binary_value_loop(value: Felt, err_ctx: &impl ErrorContext) -> Self {
426 let (label, source_file) = err_ctx.label_and_source_file();
427 Self::NotBinaryValueLoop { label, source_file, value }
428 }
429
430 pub fn not_u32_value(value: Felt, err_code: Felt, err_ctx: &impl ErrorContext) -> Self {
431 let (label, source_file) = err_ctx.label_and_source_file();
432 Self::NotU32Values {
433 label,
434 source_file,
435 values: vec![value],
436 err_code,
437 }
438 }
439
440 pub fn not_u32_values(values: Vec<Felt>, err_code: Felt, err_ctx: &impl ErrorContext) -> Self {
441 let (label, source_file) = err_ctx.label_and_source_file();
442 Self::NotU32Values { label, source_file, values, err_code }
443 }
444
445 pub fn smt_node_not_found(node: Word, err_ctx: &impl ErrorContext) -> Self {
446 let (label, source_file) = err_ctx.label_and_source_file();
447 Self::SmtNodeNotFound { label, source_file, node }
448 }
449
450 pub fn smt_node_preimage_not_valid(
451 node: Word,
452 preimage_len: usize,
453 err_ctx: &impl ErrorContext,
454 ) -> Self {
455 let (label, source_file) = err_ctx.label_and_source_file();
456 Self::SmtNodePreImageNotValid { label, source_file, node, preimage_len }
457 }
458
459 pub fn syscall_target_not_in_kernel(proc_root: Word, err_ctx: &impl ErrorContext) -> Self {
460 let (label, source_file) = err_ctx.label_and_source_file();
461 Self::SyscallTargetNotInKernel { label, source_file, proc_root }
462 }
463
464 pub fn failed_arithmetic_evaluation(err_ctx: &impl ErrorContext, error: AceError) -> Self {
465 let (label, source_file) = err_ctx.label_and_source_file();
466 Self::AceChipError { label, source_file, error }
467 }
468
469 pub fn invalid_crypto_input(
470 clk: RowIndex,
471 path_len: usize,
472 depth: Felt,
473 err_ctx: &impl ErrorContext,
474 ) -> Self {
475 let (label, source_file) = err_ctx.label_and_source_file();
476 Self::InvalidCryptoInput { label, source_file, clk, path_len, depth }
477 }
478}
479
480impl AsRef<dyn Diagnostic> for ExecutionError {
481 fn as_ref(&self) -> &(dyn Diagnostic + 'static) {
482 self
483 }
484}
485
486#[derive(Debug, thiserror::Error)]
490pub enum AceError {
491 #[error("num of variables should be word aligned and non-zero but was {0}")]
492 NumVarIsNotWordAlignedOrIsEmpty(u64),
493 #[error("num of evaluation gates should be word aligned and non-zero but was {0}")]
494 NumEvalIsNotWordAlignedOrIsEmpty(u64),
495 #[error("circuit does not evaluate to zero")]
496 CircuitNotEvaluateZero,
497 #[error("failed to read from memory")]
498 FailedMemoryRead,
499 #[error("failed to decode instruction")]
500 FailedDecodeInstruction,
501 #[error("failed to read from the wiring bus")]
502 FailedWireBusRead,
503 #[error("num of wires must be less than 2^30 but was {0}")]
504 TooManyWires(u64),
505}
506
507#[cfg(not(feature = "no_err_ctx"))]
521#[macro_export]
522macro_rules! err_ctx {
523 ($mast_forest:expr, $node:expr, $host:expr) => {
524 $crate::errors::ErrorContextImpl::new($mast_forest, $node, $host)
525 };
526 ($mast_forest:expr, $node:expr, $host:expr, $op_idx:expr) => {
527 $crate::errors::ErrorContextImpl::new_with_op_idx($mast_forest, $node, $host, $op_idx)
528 };
529}
530
531#[cfg(feature = "no_err_ctx")]
542#[macro_export]
543macro_rules! err_ctx {
544 ($mast_forest:expr, $node:expr, $host:expr) => {{ () }};
545 ($mast_forest:expr, $node:expr, $host:expr, $op_idx:expr) => {{ () }};
546}
547
548pub trait ErrorContext {
553 fn label_and_source_file(&self) -> (SourceSpan, Option<Arc<SourceFile>>);
557}
558
559pub struct ErrorContextImpl {
561 label: SourceSpan,
562 source_file: Option<Arc<SourceFile>>,
563}
564
565impl ErrorContextImpl {
566 pub fn new(
567 mast_forest: &MastForest,
568 node: &impl MastNodeErrorContext,
569 host: &impl BaseHost,
570 ) -> Self {
571 let (label, source_file) =
572 Self::precalc_label_and_source_file(None, mast_forest, node, host);
573 Self { label, source_file }
574 }
575
576 pub fn new_with_op_idx(
577 mast_forest: &MastForest,
578 node: &impl MastNodeErrorContext,
579 host: &impl BaseHost,
580 op_idx: usize,
581 ) -> Self {
582 let op_idx = op_idx.into();
583 let (label, source_file) =
584 Self::precalc_label_and_source_file(op_idx, mast_forest, node, host);
585 Self { label, source_file }
586 }
587
588 fn precalc_label_and_source_file(
589 op_idx: Option<usize>,
590 mast_forest: &MastForest,
591 node: &impl MastNodeErrorContext,
592 host: &impl BaseHost,
593 ) -> (SourceSpan, Option<Arc<SourceFile>>) {
594 node.get_assembly_op(mast_forest, op_idx)
595 .and_then(|assembly_op| assembly_op.location())
596 .map_or_else(
597 || (SourceSpan::UNKNOWN, None),
598 |location| host.get_label_and_source_file(location),
599 )
600 }
601}
602
603impl ErrorContext for ErrorContextImpl {
604 fn label_and_source_file(&self) -> (SourceSpan, Option<Arc<SourceFile>>) {
605 (self.label, self.source_file.clone())
606 }
607}
608
609impl ErrorContext for () {
610 fn label_and_source_file(&self) -> (SourceSpan, Option<Arc<SourceFile>>) {
611 (SourceSpan::UNKNOWN, None)
612 }
613}
614
615#[cfg(test)]
619mod error_assertions {
620 use super::*;
621
622 fn _assert_error_is_send_sync_static<E: core::error::Error + Send + Sync + 'static>(_: E) {}
624
625 fn _assert_execution_error_bounds(err: ExecutionError) {
626 _assert_error_is_send_sync_static(err);
627 }
628}