1use alloc::{boxed::Box, string::String};
2use core::error::Error;
3
4use miden_air::RowIndex;
5use vm_core::{
6 mast::{DecoratorId, MastNodeId},
7 stack::MIN_STACK_DEPTH,
8 utils::to_hex,
9};
10use winter_prover::{ProverError, math::FieldElement};
11
12use super::{
13 Digest, Felt, QuadFelt, Word,
14 crypto::MerkleError,
15 system::{FMP_MAX, FMP_MIN},
16};
17use crate::ContextId;
18
19#[derive(Debug, thiserror::Error)]
23pub enum ExecutionError {
24 #[error("value for key {} not present in the advice map", to_hex(Felt::elements_as_bytes(.0)))]
25 AdviceMapKeyNotFound(Word),
26 #[error("value for key {} already present in the advice map", to_hex(Felt::elements_as_bytes(.0)))]
27 AdviceMapKeyAlreadyPresent(Word),
28 #[error("advice stack read failed at step {0}")]
29 AdviceStackReadFailed(RowIndex),
30 #[error("illegal use of instruction {0} while inside a syscall")]
31 CallInSyscall(&'static str),
32 #[error("instruction `caller` used outside of kernel context")]
33 CallerNotInSyscall,
34 #[error("external node with mast root {0} resolved to an external node")]
35 CircularExternalNode(Digest),
36 #[error("exceeded the allowed number of max cycles {0}")]
37 CycleLimitExceeded(u32),
38 #[error("decorator id {decorator_id} does not exist in MAST forest")]
39 DecoratorNotFoundInForest { decorator_id: DecoratorId },
40 #[error("division by zero at clock cycle {0}")]
41 DivideByZero(RowIndex),
42 #[error("failed to execute the dynamic code block provided by the stack with root {hex}; the block could not be found",
43 hex = to_hex(.0.as_bytes())
44 )]
45 DynamicNodeNotFound(Digest),
46 #[error("error during processing of event in on_event handler")]
47 EventError(#[source] Box<dyn Error + Send + Sync + 'static>),
48 #[error("failed to execute Ext2Intt operation: {0}")]
49 Ext2InttError(Ext2InttError),
50 #[error("assertion failed at clock cycle {clk} with error code {err_code}{}",
51 match err_msg {
52 Some(msg) => format!(": {msg}"),
53 None => "".into()
54 }
55 )]
56 FailedAssertion {
57 clk: RowIndex,
58 err_code: u32,
59 err_msg: Option<String>,
60 },
61 #[error(
62 "memory address {addr} in context {ctx} was read and written, or written twice, in the same clock cycle {clk}"
63 )]
64 IllegalMemoryAccess { ctx: ContextId, addr: u32, clk: Felt },
65 #[error(
66 "Updating FMP register from {0} to {1} failed because {1} is outside of {FMP_MIN}..{FMP_MAX}"
67 )]
68 InvalidFmpValue(Felt, Felt),
69 #[error("FRI domain segment value cannot exceed 3, but was {0}")]
70 InvalidFriDomainSegment(u64),
71 #[error("degree-respecting projection is inconsistent: expected {0} but was {1}")]
72 InvalidFriLayerFolding(QuadFelt, QuadFelt),
73 #[error(
74 "memory range start address cannot exceed end address, but was ({start_addr}, {end_addr})"
75 )]
76 InvalidMemoryRange { start_addr: u64, end_addr: u64 },
77 #[error("when returning from a call, stack depth must be {MIN_STACK_DEPTH}, but was {0}")]
78 InvalidStackDepthOnReturn(usize),
79 #[error(
80 "provided merkle tree {depth} is out of bounds and cannot be represented as an unsigned 8-bit integer"
81 )]
82 InvalidMerkleTreeDepth { depth: Felt },
83 #[error("provided node index {value} is out of bounds for a merkle tree node at depth {depth}")]
84 InvalidMerkleTreeNodeIndex { depth: Felt, value: Felt },
85 #[error("attempted to calculate integer logarithm with zero argument at clock cycle {0}")]
86 LogArgumentZero(RowIndex),
87 #[error("malformed signature key: {0}")]
88 MalformedSignatureKey(&'static str),
89 #[error(
90 "MAST forest in host indexed by procedure root {root_digest} doesn't contain that root"
91 )]
92 MalformedMastForestInHost { root_digest: Digest },
93 #[error("node id {node_id} does not exist in MAST forest")]
94 MastNodeNotFoundInForest { node_id: MastNodeId },
95 #[error("no MAST forest contains the procedure with root digest {root_digest}")]
96 NoMastForestWithProcedure { root_digest: Digest },
97 #[error("memory address cannot exceed 2^32 but was {0}")]
98 MemoryAddressOutOfBounds(u64),
99 #[error(
100 "word memory access at address {addr} in context {ctx} is unaligned at clock cycle {clk}"
101 )]
102 MemoryUnalignedWordAccess { addr: u32, ctx: ContextId, clk: Felt },
103 #[error("word access at memory address {addr} in context {ctx} is unaligned")]
106 MemoryUnalignedWordAccessNoClk { addr: u32, ctx: ContextId },
107 #[error("merkle path verification failed for value {value} at index {index} in the Merkle tree with root {root} (error code: {err_code})",
108 value = to_hex(Felt::elements_as_bytes(value)),
109 root = to_hex(root.as_bytes()),
110 )]
111 MerklePathVerificationFailed {
112 value: Word,
113 index: Felt,
114 root: Digest,
115 err_code: u32,
116 },
117 #[error("advice provider Merkle store backend lookup failed")]
118 MerkleStoreLookupFailed(#[source] MerkleError),
119 #[error("advice provider Merkle store backend merge failed")]
120 MerkleStoreMergeFailed(#[source] MerkleError),
121 #[error("advice provider Merkle store backend update failed")]
122 MerkleStoreUpdateFailed(#[source] MerkleError),
123 #[error("an operation expected a binary value, but received {0}")]
124 NotBinaryValue(Felt),
125 #[error("an operation expected a u32 value, but received {0} (error code: {1})")]
126 NotU32Value(Felt, Felt),
127 #[error("stack should have at most {MIN_STACK_DEPTH} elements at the end of program execution, but had {} elements", MIN_STACK_DEPTH + .0)]
128 OutputStackOverflow(usize),
129 #[error("a program has already been executed in this process")]
130 ProgramAlreadyExecuted,
131 #[error("proof generation failed")]
132 ProverError(#[source] ProverError),
133 #[error("smt node {node_hex} not found", node_hex = to_hex(Felt::elements_as_bytes(.0)))]
134 SmtNodeNotFound(Word),
135 #[error("expected pre-image length of node {node_hex} to be a multiple of 8 but was {preimage_len}",
136 node_hex = to_hex(Felt::elements_as_bytes(.0)),
137 preimage_len = .1
138 )]
139 SmtNodePreImageNotValid(Word, usize),
140 #[error("syscall failed: procedure with root {hex} was not found in the kernel",
141 hex = to_hex(.0.as_bytes())
142 )]
143 SyscallTargetNotInKernel(Digest),
144}
145
146impl From<Ext2InttError> for ExecutionError {
147 fn from(value: Ext2InttError) -> Self {
148 Self::Ext2InttError(value)
149 }
150}
151
152#[derive(Debug, thiserror::Error)]
156pub enum Ext2InttError {
157 #[error("input domain size must be a power of two, but was {0}")]
158 DomainSizeNotPowerOf2(u64),
159 #[error("input domain size ({0} elements) is too small")]
160 DomainSizeTooSmall(u64),
161 #[error("address of the last input must be smaller than 2^32, but was {0}")]
162 InputEndAddressTooBig(u64),
163 #[error("input size must be smaller than 2^32, but was {0}")]
164 InputSizeTooBig(u64),
165 #[error("address of the first input must be smaller than 2^32, but was {0}")]
166 InputStartAddressTooBig(u64),
167 #[error("address of the first input is not word aligned: {0}")]
168 InputStartNotWordAligned(u64),
169 #[error("output size ({0}) cannot be greater than the input size ({1})")]
170 OutputSizeTooBig(usize, usize),
171 #[error("output size must be greater than 0")]
172 OutputSizeIsZero,
173 #[error("uninitialized memory at address {0}")]
174 UninitializedMemoryAddress(u32),
175}
176
177#[cfg(test)]
178mod error_assertions {
179 use super::*;
180
181 fn _assert_error_is_send_sync_static<E: core::error::Error + Send + Sync + 'static>(_: E) {}
183
184 fn _assert_execution_error_bounds(err: ExecutionError) {
185 _assert_error_is_send_sync_static(err);
186 }
187}