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