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