essential_vm/
error.rs

1//! The types of errors that might occur throughout execution.
2
3#[doc(inline)]
4use crate::{
5    asm::{self, Word},
6    Gas,
7};
8use core::convert::Infallible;
9use thiserror::Error;
10
11/// Shorthand for a `Result` where the error type is a `ExecError`.
12pub type ExecResult<T, E> = Result<T, ExecError<E>>;
13
14/// Shorthand for a `Result` where the error type is a `EvalSyncError`.
15pub type EvalResult<T, E> = Result<T, EvalError<E>>;
16
17/// Shorthand for a `Result` where the error type is an `OpError`.
18pub type OpResult<T, E = Infallible> = Result<T, OpError<E>>;
19
20/// Execution failed at the operation at the given index.
21#[derive(Debug, Error)]
22#[error("operation at index {0} failed: {1}")]
23pub struct ExecError<E>(pub usize, pub OpError<E>);
24
25/// Errors that might occur during synchronous evaluation.
26#[derive(Debug, Error)]
27pub enum EvalError<E> {
28    /// An error occurred during execution.
29    #[error("{0}")]
30    Exec(#[from] ExecError<E>),
31    /// Evaluation should have resulted with a `0` (false) or `1` (true) at the
32    /// top of the stack, but did not.
33    #[error(
34        "invalid constraint evaluation result\n  \
35        expected: [0] (false) or [1] (true)\n  \
36        found:    {0:?}"
37    )]
38    InvalidEvaluation(crate::Stack),
39}
40
41/// An individual operation failed during execution.
42#[derive(Debug, Error)]
43pub enum OpError<E = Infallible> {
44    /// An error occurred during an `Access` operation.
45    #[error("access operation error: {0}")]
46    Access(#[from] AccessError),
47    /// An error occurred during an `Alu` operation.
48    #[error("ALU operation error: {0}")]
49    Alu(#[from] AluError),
50    /// An error occurred during a `Crypto` operation.
51    #[error("crypto operation error: {0}")]
52    Crypto(#[from] CryptoError),
53    /// An error occurred during a `Stack` operation.
54    #[error("stack operation error: {0}")]
55    Stack(#[from] StackError),
56    /// An error occurred during a `Repeat` operation.
57    #[error("repeat operation error: {0}")]
58    Repeat(#[from] RepeatError),
59    /// An error occurred during a `TotalControlFlow` operation.
60    #[error("total control flow operation error: {0}")]
61    TotalControlFlow(#[from] TotalControlFlowError),
62    /// An error occurred during a `Memory` operation.
63    #[error("memory operation error: {0}")]
64    Memory(#[from] MemoryError),
65    /// An error occurred during a `ParentMemory` operation.
66    #[error("parent memory operation error: {0}")]
67    ParentMemory(#[from] ParentMemoryError),
68    /// Pc counter overflowed.
69    #[error("PC counter overflowed")]
70    PcOverflow,
71    /// An error occurred while decoding some data.
72    #[error("decoding error: {0}")]
73    Decode(#[from] DecodeError),
74    /// An error occurred while encoding some data.
75    #[error("encoding error: {0}")]
76    Encode(#[from] EncodeError),
77    /// An error occurred during a `StateRead` operation.
78    #[error("state read operation error: {0}")]
79    StateRead(E),
80    /// An error occurred during a `Compute` operation.
81    #[error("compute operation error: {0}")]
82    Compute(#[from] ComputeError<E>),
83    /// An error occurred while parsing an operation from bytes.
84    #[error("bytecode error: {0}")]
85    FromBytes(#[from] asm::FromBytesError),
86    /// The total gas limit was exceeded.
87    #[error("{0}")]
88    OutOfGas(#[from] OutOfGasError),
89}
90
91/// The gas cost of performing an operation would exceed the gas limit.
92#[derive(Debug, Error)]
93#[error(
94    "operation cost would exceed gas limit\n  \
95    spent: {spent} gas\n  \
96    op cost: {op_gas} gas\n  \
97    limit: {limit} gas"
98)]
99pub struct OutOfGasError {
100    /// Total spent prior to the operation that would exceed the limit.
101    pub spent: Gas,
102    /// The gas required for the operation that failed.
103    pub op_gas: Gas,
104    /// The total gas limit that would be exceeded.
105    pub limit: Gas,
106}
107
108/// A error occurred while reading state read arguments
109#[derive(Debug, Error)]
110pub enum StateReadArgError {
111    /// A memory access related error occurred.
112    #[error("memory error: {0}")]
113    Memory(#[from] MemoryError),
114    /// An error occurred during a `Stack` operation.
115    #[error("stack operation error: {0}")]
116    Stack(#[from] StackError),
117}
118
119/// Errors occuring during `TotalControlFlow` operation.
120#[derive(Debug, Error)]
121pub enum ControlFlowError {
122    /// A `JumpIf` operation encountered an invalid condition.
123    ///
124    /// Condition values must be 0 (false) or 1 (true).
125    #[error("invalid condition value {0}, expected 0 (false) or 1 (true)")]
126    InvalidJumpIfCondition(Word),
127}
128
129/// Access operation error.
130#[derive(Debug, Error)]
131pub enum AccessError {
132    /// A predicate data slot was out of bounds.
133    #[error("predicate data slot out of bounds: {0}")]
134    PredicateDataSlotIxOutOfBounds(Word),
135    /// A predicate data value length was too large.
136    #[error("the length of a predicate data value is too large: {0}")]
137    PredicateDataValueTooLarge(usize),
138    /// A predicate data index was out of bounds.
139    #[error("predicate data value_ix out of bounds: {0}..{1}")]
140    PredicateDataValueRangeOutOfBounds(Word, Word),
141    /// A state slot index was out of bounds.
142    #[error("state slot_ix out of bounds: {0}")]
143    StateSlotIxOutOfBounds(Word),
144    /// A state slot index was out of bounds.
145    #[error("state value_ix out of bounds: {0}..{1}")]
146    StateValueRangeOutOfBounds(Word, Word),
147    /// A state slot delta value was invalid. Must be `0` (pre) or `1` (post).
148    #[error("invalid state slot delta: expected `0` or `1`, found {0}")]
149    InvalidStateSlotDelta(Word),
150    /// The total length of the set of state mutations was too large.
151    #[error("the total length of the set of state mutations was too large: {0}")]
152    StateMutationsLengthTooLarge(usize),
153    /// The state slot value was too large.
154    #[error("the state slot value was too large: {0}")]
155    StateValueTooLarge(usize),
156    /// Key length was out of bounds.
157    #[error("key length out of bounds: {0}")]
158    KeyLengthOutOfBounds(Word),
159    /// The access range was invalid
160    #[error("invalid access range")]
161    InvalidAccessRange,
162    /// The length of the slots was too large large to fit in a `Word`.
163    #[error("the length of the slots was too large: {0}")]
164    SlotsLengthTooLarge(usize),
165    /// The `which_slots` argument was invalid.
166    #[error("invalid `which_slots` argument: {0}")]
167    InvalidSlotType(Word),
168    /// Missing argument error.
169    #[error("missing `Access` argument: {0}")]
170    MissingArg(#[from] MissingAccessArgError),
171}
172
173/// Missing argument error.
174#[derive(Debug, Error)]
175pub enum MissingAccessArgError {
176    /// Missing `delta` argument for `State` operation.
177    #[error("missing `delta` argument for `State` operation")]
178    StateDelta,
179    /// Missing `len` argument for `State` operation.
180    #[error("missing `len` argument for `State` operation")]
181    StateLen,
182    /// Missing `value_ix` argument for `State` operation.
183    #[error("missing `value_ix` argument for `State` operation")]
184    StateValueIx,
185    /// Missing `slot_ix` argument for `State` operation.
186    #[error("missing `slot_ix` argument for `State` operation")]
187    StateSlotIx,
188    /// Missing `len` argument for `PredicateData` operation.
189    #[error("missing `len` argument for `PredicateData` operation")]
190    PredDataLen,
191    /// Missing `value_ix` argument for `PredicateData` operation.
192    #[error("missing `value_ix` argument for `PredicateData` operation")]
193    PredDataValueIx,
194    /// Missing `slot_ix` argument for `PredicateData` operation.
195    #[error("missing `slot_ix` argument for `PredicateData` operation")]
196    PredDataSlotIx,
197}
198
199/// ALU operation error.
200#[derive(Debug, Error)]
201pub enum AluError {
202    /// An ALU operation overflowed a `Word` value.
203    #[error("word overflow")]
204    Overflow,
205    /// An ALU operation underflowed a `Word` value.
206    #[error("word underflow")]
207    Underflow,
208    /// An ALU operation (either Div or Mod) attempted to divide by zero.
209    #[error("attempted to divide by zero")]
210    DivideByZero,
211}
212
213/// Crypto operation error.
214#[derive(Debug, Error)]
215pub enum CryptoError {
216    /// Failed to verify a ED25519 signature.
217    #[error("failed to verify ed25519 signature: {0}")]
218    Ed25519(#[from] ed25519_dalek::ed25519::Error),
219    /// Failed to recover a SECP256k1 public key.
220    #[error("failed to recover secp256k1 public key: {0}")]
221    Secp256k1(#[from] secp256k1::Error),
222    /// Failed to parse SECP256k1 recovery id
223    #[error("failed to parse secp256k1 recovery id")]
224    Secp256k1RecoveryId,
225}
226
227/// Shorthand for a `Result` where the error type is a `StackError`.
228pub type StackResult<T> = Result<T, StackError>;
229
230/// Stack operation error.
231#[derive(Debug, Error)]
232pub enum StackError {
233    /// Attempted to pop a word from an empty stack.
234    #[error("attempted to pop an empty stack")]
235    Empty,
236    /// An index into the stack was out of bounds.
237    #[error("indexed stack out of bounds")]
238    IndexOutOfBounds,
239    /// The stack size exceeded the size limit.
240    #[error("the {}-word stack size limit was exceeded", crate::Stack::SIZE_LIMIT)]
241    Overflow,
242    /// The condition for Select or SelectRange is not `0` (false) or `1` (true).
243    #[error(
244        "invalid condition\n  \
245        expected: [0] (false) or [1] (true)\n  \
246        found:    {0}"
247    )]
248    InvalidCondition(Word),
249    /// There was an error while calling a `len words` function.
250    #[error(transparent)]
251    LenWords(#[from] LenWordsError),
252}
253
254/// A `len words` error.
255#[derive(Debug, Error)]
256pub enum LenWordsError {
257    /// A `len words` function was called with a missing length.
258    #[error("missing length argument for `len words` operation")]
259    MissingLength,
260    /// A `len words` function was called with an invalid length.
261    #[error("invalid length argument for `len words` operation: {0}")]
262    InvalidLength(Word),
263    /// A `len words` function was called with an out-of-bounds length.
264    #[error("length argument for `len words` operation out of bounds: {0}")]
265    OutOfBounds(Word),
266    /// The additional length was too large for the `len words` function.
267    #[error("additional length too large for `len words` operation: {0} + {1}")]
268    AdditionalOutOfBounds(usize, usize),
269}
270
271/// Shorthand for a `Result` where the error type is a `RepeatError`.
272pub type RepeatResult<T> = Result<T, RepeatError>;
273
274/// Repeat operation error.
275#[derive(Debug, Error)]
276pub enum RepeatError {
277    /// Repeat end hit with no corresponding repeat start on the stack
278    #[error("attempted to repeat to empty stack")]
279    Empty,
280    /// Repeat counter called when stack is empty
281    #[error("attempted to access repeat counter with empty stack")]
282    NoCounter,
283    /// Repeat counter called with an invalid count direction
284    #[error("The count direction must be 0 or 1")]
285    InvalidCountDirection,
286    /// The repeat stack size exceeded the size limit.
287    #[error("the {}-word stack size limit was exceeded", crate::Stack::SIZE_LIMIT)]
288    Overflow,
289}
290
291/// Shorthand for a `Result` where the error type is a `TotalControlFlowError`.
292pub type TotalControlFlowResult<T> = Result<T, TotalControlFlowError>;
293
294/// Total control flow operation error.
295#[derive(Debug, Error)]
296pub enum TotalControlFlowError {
297    /// Attempted to jump forward if with an invalid condition
298    #[error("jump forward if requires a boolean condition")]
299    InvalidJumpForwardIfCondition,
300    /// Attempted to jump forward if to the same location
301    #[error("jump forward if requires to jump at least one instruction")]
302    JumpedToSelf,
303    /// Attempted to halt if with an invalid condition
304    #[error("halt if requires a boolean condition")]
305    InvalidHaltIfCondition,
306    /// Attempted to panic if with an invalid condition
307    #[error("panic if requires a boolean condition")]
308    InvalidPanicIfCondition,
309    /// The `PanicIf` operation was called with a `true` argument
310    #[error("program panicked with `PanicIf` operation. The stack at the time of panic: {0:?}")]
311    Panic(Vec<Word>),
312}
313
314/// Shorthand for a `Result` where the error type is a `MemoryError`.
315pub type MemoryResult<T> = Result<T, MemoryError>;
316
317/// Memory operation error.
318#[derive(Debug, Error)]
319pub enum MemoryError {
320    /// Attempted to pop a word from an empty memory.
321    #[error("attempted to pop an empty memory")]
322    Empty,
323    /// Index into memory was out of bounds.
324    #[error("indexed memory out of bounds")]
325    IndexOutOfBounds,
326    /// The memory size exceeded the size limit.
327    #[error("the {}-word stack size limit was exceeded", crate::Memory::SIZE_LIMIT)]
328    Overflow,
329}
330
331/// Parent memory operation error.
332#[derive(Debug, Error)]
333pub enum ParentMemoryError {
334    /// Attempted to access parent memory outside of a `Compute` context.
335    #[error("Attempted to access parent memory outside of a `Compute` context")]
336    NoParent,
337    /// A memory access error occurred.
338    #[error("A memory access error occurred: {0}")]
339    Memory(#[from] MemoryError),
340}
341
342/// Shorthand for a `Result` where the error type is a `ComputeError`.
343pub type ComputeResult<T, E> = Result<T, ComputeError<E>>;
344
345/// Compute operation error.
346#[derive(Debug, Error)]
347pub enum ComputeError<E> {
348    /// Maximum compute recursion depth reached.
349    #[error("cannot exceed compute depth: {0}")]
350    DepthReached(usize),
351    /// An error occurred during a `Stack` operation.
352    #[error("stack operation error: {0}")]
353    Stack(#[from] StackError),
354    /// A memory access related error occurred.
355    #[error("memory error: {0}")]
356    Memory(#[from] MemoryError),
357    /// An error occurred during execution.
358    #[error("execution error")]
359    Exec(Box<ExecError<E>>),
360    /// Compute breadth is not greater than or equal to 1.
361    #[error("compute breadth is not at least 1: {0}")]
362    InvalidBreadth(Word),
363}
364
365/// Decode error.
366#[derive(Debug, Error)]
367pub enum DecodeError {
368    /// Decoding a set failed.
369    #[error("failed to decode set: {0:?}")]
370    Set(Vec<Word>),
371    /// Decoding item failed because it was too large.
372    #[error("item length too large: {0}")]
373    ItemLengthTooLarge(usize),
374}
375
376/// Encode error.
377#[derive(Debug, Error)]
378pub enum EncodeError {
379    /// Encoding item failed because it was too large.
380    #[error("item length too large: {0}")]
381    ItemLengthTooLarge(usize),
382}
383
384impl<E> From<core::convert::Infallible> for OpError<E> {
385    fn from(err: core::convert::Infallible) -> Self {
386        match err {}
387    }
388}
389
390impl<E> From<StateReadArgError> for OpError<E> {
391    fn from(err: StateReadArgError) -> Self {
392        match err {
393            StateReadArgError::Memory(e) => OpError::Memory(e),
394            StateReadArgError::Stack(e) => OpError::Stack(e),
395        }
396    }
397}
398
399impl<E> OpError<E> {
400    /// Convert an op error that doesn't contain a state read a generic op error.
401    pub fn from_infallible(value: OpError<Infallible>) -> Self {
402        match value {
403            OpError::Access(access_error) => OpError::Access(access_error),
404            OpError::Alu(alu_error) => OpError::Alu(alu_error),
405            OpError::Crypto(crypto_error) => OpError::Crypto(crypto_error),
406            OpError::Stack(stack_error) => OpError::Stack(stack_error),
407            OpError::Repeat(repeat_error) => OpError::Repeat(repeat_error),
408            OpError::TotalControlFlow(total_control_flow_error) => {
409                OpError::TotalControlFlow(total_control_flow_error)
410            }
411            OpError::Memory(memory_error) => OpError::Memory(memory_error),
412            OpError::ParentMemory(memory_error) => OpError::ParentMemory(memory_error),
413            OpError::PcOverflow => OpError::PcOverflow,
414            OpError::Decode(decode_error) => OpError::Decode(decode_error),
415            OpError::Encode(encode_error) => OpError::Encode(encode_error),
416            OpError::StateRead(_) => unreachable!(),
417            OpError::FromBytes(from_bytes_error) => OpError::FromBytes(from_bytes_error),
418            OpError::OutOfGas(out_of_gas_error) => OpError::OutOfGas(out_of_gas_error),
419            OpError::Compute(_) => unreachable!(),
420        }
421    }
422}