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