#[doc(inline)]
use crate::{
asm::{self, Word},
Gas,
};
use core::convert::Infallible;
use thiserror::Error;
pub type ExecResult<T, E> = Result<T, ExecError<E>>;
pub type EvalResult<T, E> = Result<T, EvalError<E>>;
pub type OpResult<T, E = Infallible> = Result<T, OpError<E>>;
#[derive(Debug, Error)]
#[error("operation at index {0} failed: {1}")]
pub struct ExecError<E>(pub usize, pub OpError<E>);
#[derive(Debug, Error)]
pub enum EvalError<E> {
#[error("{0}")]
Exec(#[from] ExecError<E>),
#[error(
"invalid constraint evaluation result\n \
expected: [0] (false) or [1] (true)\n \
found: {0:?}"
)]
InvalidEvaluation(crate::Stack),
}
#[derive(Debug, Error)]
pub enum OpError<E = Infallible> {
#[error("access operation error: {0}")]
Access(#[from] AccessError),
#[error("ALU operation error: {0}")]
Alu(#[from] AluError),
#[error("crypto operation error: {0}")]
Crypto(#[from] CryptoError),
#[error("stack operation error: {0}")]
Stack(#[from] StackError),
#[error("repeat operation error: {0}")]
Repeat(#[from] RepeatError),
#[error("total control flow operation error: {0}")]
TotalControlFlow(#[from] TotalControlFlowError),
#[error("memory operation error: {0}")]
Memory(#[from] MemoryError),
#[error("parent memory operation error: {0}")]
ParentMemory(#[from] ParentMemoryError),
#[error("PC counter overflowed")]
PcOverflow,
#[error("decoding error: {0}")]
Decode(#[from] DecodeError),
#[error("encoding error: {0}")]
Encode(#[from] EncodeError),
#[error("state read operation error: {0}")]
StateRead(E),
#[error("compute operation error: {0}")]
Compute(#[from] ComputeError<E>),
#[error("bytecode error: {0}")]
FromBytes(#[from] asm::FromBytesError),
#[error("{0}")]
OutOfGas(#[from] OutOfGasError),
}
#[derive(Debug, Error)]
#[error(
"operation cost would exceed gas limit\n \
spent: {spent} gas\n \
op cost: {op_gas} gas\n \
limit: {limit} gas"
)]
pub struct OutOfGasError {
pub spent: Gas,
pub op_gas: Gas,
pub limit: Gas,
}
#[derive(Debug, Error)]
pub enum StateReadArgError {
#[error("memory error: {0}")]
Memory(#[from] MemoryError),
#[error("stack operation error: {0}")]
Stack(#[from] StackError),
}
#[derive(Debug, Error)]
pub enum ControlFlowError {
#[error("invalid condition value {0}, expected 0 (false) or 1 (true)")]
InvalidJumpIfCondition(Word),
}
#[derive(Debug, Error)]
pub enum AccessError {
#[error("predicate data slot out of bounds: {0}")]
PredicateDataSlotIxOutOfBounds(Word),
#[error("the length of a predicate data value is too large: {0}")]
PredicateDataValueTooLarge(usize),
#[error("predicate data value_ix out of bounds: {0}..{1}")]
PredicateDataValueRangeOutOfBounds(Word, Word),
#[error("state slot_ix out of bounds: {0}")]
StateSlotIxOutOfBounds(Word),
#[error("state value_ix out of bounds: {0}..{1}")]
StateValueRangeOutOfBounds(Word, Word),
#[error("invalid state slot delta: expected `0` or `1`, found {0}")]
InvalidStateSlotDelta(Word),
#[error("the total length of the set of state mutations was too large: {0}")]
StateMutationsLengthTooLarge(usize),
#[error("the state slot value was too large: {0}")]
StateValueTooLarge(usize),
#[error("key length out of bounds: {0}")]
KeyLengthOutOfBounds(Word),
#[error("invalid access range")]
InvalidAccessRange,
#[error("the length of the slots was too large: {0}")]
SlotsLengthTooLarge(usize),
#[error("invalid `which_slots` argument: {0}")]
InvalidSlotType(Word),
#[error("missing `Access` argument: {0}")]
MissingArg(#[from] MissingAccessArgError),
}
#[derive(Debug, Error)]
pub enum MissingAccessArgError {
#[error("missing `delta` argument for `State` operation")]
StateDelta,
#[error("missing `len` argument for `State` operation")]
StateLen,
#[error("missing `value_ix` argument for `State` operation")]
StateValueIx,
#[error("missing `slot_ix` argument for `State` operation")]
StateSlotIx,
#[error("missing `len` argument for `PredicateData` operation")]
PredDataLen,
#[error("missing `value_ix` argument for `PredicateData` operation")]
PredDataValueIx,
#[error("missing `slot_ix` argument for `PredicateData` operation")]
PredDataSlotIx,
}
#[derive(Debug, Error)]
pub enum AluError {
#[error("word overflow")]
Overflow,
#[error("word underflow")]
Underflow,
#[error("attempted to divide by zero")]
DivideByZero,
}
#[derive(Debug, Error)]
pub enum CryptoError {
#[error("failed to verify ed25519 signature: {0}")]
Ed25519(#[from] ed25519_dalek::ed25519::Error),
#[error("failed to recover secp256k1 public key: {0}")]
Secp256k1(#[from] secp256k1::Error),
#[error("failed to parse secp256k1 recovery id")]
Secp256k1RecoveryId,
}
pub type StackResult<T> = Result<T, StackError>;
#[derive(Debug, Error)]
pub enum StackError {
#[error("attempted to pop an empty stack")]
Empty,
#[error("indexed stack out of bounds")]
IndexOutOfBounds,
#[error("the {}-word stack size limit was exceeded", crate::Stack::SIZE_LIMIT)]
Overflow,
#[error(
"invalid condition\n \
expected: [0] (false) or [1] (true)\n \
found: {0}"
)]
InvalidCondition(Word),
#[error(transparent)]
LenWords(#[from] LenWordsError),
}
#[derive(Debug, Error)]
pub enum LenWordsError {
#[error("missing length argument for `len words` operation")]
MissingLength,
#[error("invalid length argument for `len words` operation: {0}")]
InvalidLength(Word),
#[error("length argument for `len words` operation out of bounds: {0}")]
OutOfBounds(Word),
#[error("additional length too large for `len words` operation: {0} + {1}")]
AdditionalOutOfBounds(usize, usize),
}
pub type RepeatResult<T> = Result<T, RepeatError>;
#[derive(Debug, Error)]
pub enum RepeatError {
#[error("attempted to repeat to empty stack")]
Empty,
#[error("attempted to access repeat counter with empty stack")]
NoCounter,
#[error("The count direction must be 0 or 1")]
InvalidCountDirection,
#[error("the {}-word stack size limit was exceeded", crate::Stack::SIZE_LIMIT)]
Overflow,
}
pub type TotalControlFlowResult<T> = Result<T, TotalControlFlowError>;
#[derive(Debug, Error)]
pub enum TotalControlFlowError {
#[error("jump forward if requires a boolean condition")]
InvalidJumpForwardIfCondition,
#[error("jump forward if requires to jump at least one instruction")]
JumpedToSelf,
#[error("halt if requires a boolean condition")]
InvalidHaltIfCondition,
#[error("panic if requires a boolean condition")]
InvalidPanicIfCondition,
#[error("program panicked with `PanicIf` operation. The stack at the time of panic: {0:?}")]
Panic(Vec<Word>),
}
pub type MemoryResult<T> = Result<T, MemoryError>;
#[derive(Debug, Error)]
pub enum MemoryError {
#[error("attempted to pop an empty memory")]
Empty,
#[error("indexed memory out of bounds")]
IndexOutOfBounds,
#[error("the {}-word stack size limit was exceeded", crate::Memory::SIZE_LIMIT)]
Overflow,
}
#[derive(Debug, Error)]
pub enum ParentMemoryError {
#[error("Attempted to access parent memory outside of a `Compute` context")]
NoParent,
#[error("A memory access error occurred: {0}")]
Memory(#[from] MemoryError),
}
pub type ComputeResult<T, E> = Result<T, ComputeError<E>>;
#[derive(Debug, Error)]
pub enum ComputeError<E> {
#[error("cannot exceed compute depth: {0}")]
DepthReached(usize),
#[error("stack operation error: {0}")]
Stack(#[from] StackError),
#[error("memory error: {0}")]
Memory(#[from] MemoryError),
#[error("execution error")]
Exec(Box<ExecError<E>>),
#[error("compute breadth is not at least 1: {0}")]
InvalidBreadth(Word),
}
#[derive(Debug, Error)]
pub enum DecodeError {
#[error("failed to decode set: {0:?}")]
Set(Vec<Word>),
#[error("item length too large: {0}")]
ItemLengthTooLarge(usize),
}
#[derive(Debug, Error)]
pub enum EncodeError {
#[error("item length too large: {0}")]
ItemLengthTooLarge(usize),
}
impl<E> From<core::convert::Infallible> for OpError<E> {
fn from(err: core::convert::Infallible) -> Self {
match err {}
}
}
impl<E> From<StateReadArgError> for OpError<E> {
fn from(err: StateReadArgError) -> Self {
match err {
StateReadArgError::Memory(e) => OpError::Memory(e),
StateReadArgError::Stack(e) => OpError::Stack(e),
}
}
}
impl<E> OpError<E> {
pub fn from_infallible(value: OpError<Infallible>) -> Self {
match value {
OpError::Access(access_error) => OpError::Access(access_error),
OpError::Alu(alu_error) => OpError::Alu(alu_error),
OpError::Crypto(crypto_error) => OpError::Crypto(crypto_error),
OpError::Stack(stack_error) => OpError::Stack(stack_error),
OpError::Repeat(repeat_error) => OpError::Repeat(repeat_error),
OpError::TotalControlFlow(total_control_flow_error) => {
OpError::TotalControlFlow(total_control_flow_error)
}
OpError::Memory(memory_error) => OpError::Memory(memory_error),
OpError::ParentMemory(memory_error) => OpError::ParentMemory(memory_error),
OpError::PcOverflow => OpError::PcOverflow,
OpError::Decode(decode_error) => OpError::Decode(decode_error),
OpError::Encode(encode_error) => OpError::Encode(encode_error),
OpError::StateRead(_) => unreachable!(),
OpError::FromBytes(from_bytes_error) => OpError::FromBytes(from_bytes_error),
OpError::OutOfGas(out_of_gas_error) => OpError::OutOfGas(out_of_gas_error),
OpError::Compute(_) => unreachable!(),
}
}
}