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