use crate::{
asm::{self, Word},
Stack,
};
use core::fmt;
use thiserror::Error;
pub type CheckResult<T> = Result<T, CheckError>;
#[derive(Debug, Error)]
pub enum CheckError {
#[error("errors occurred while executing one or more constraints: {0}")]
ConstraintErrors(#[from] ConstraintErrors),
#[error("one or more constraints were unsatisfied: {0}")]
ConstraintsUnsatisfied(#[from] ConstraintsUnsatisfied),
}
#[derive(Debug, Error)]
pub struct ConstraintErrors(pub Vec<(usize, ConstraintError)>);
#[derive(Debug, Error)]
pub struct ConstraintsUnsatisfied(pub Vec<usize>);
pub type ConstraintResult<T> = Result<T, ConstraintError>;
#[derive(Debug, Error)]
pub enum ConstraintError {
#[error(
"invalid constraint evaluation result\n \
expected: [0] (false) or [1] (true)\n \
found: {0:?}"
)]
InvalidEvaluation(Stack),
#[error("operation at index {0} failed: {1}")]
Op(usize, OpError),
}
pub type OpResult<T> = Result<T, OpError>;
#[derive(Debug, Error)]
pub enum OpError {
#[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("temporary operation error: {0}")]
Temporary(#[from] TemporaryError),
#[error("bytecode error: {0}")]
FromBytes(#[from] asm::FromBytesError),
#[error("PC counter overflowed")]
PcOverflow,
#[error("decoding error: {0}")]
Decode(#[from] DecodeError),
#[error("encoding error: {0}")]
Encode(#[from] EncodeError),
}
#[derive(Debug, Error)]
pub enum AccessError {
#[error("decision variable slot out of bounds: {0}")]
DecisionSlotIxOutOfBounds(Word),
#[error("decision variable slot index out of bounds")]
DecisionIndexOutOfBounds,
#[error("the length of a decision variable slot is too large: {0}")]
DecisionLengthTooLarge(usize),
#[error("decision var value_ix out of bounds: {0}..{1}")]
DecisionValueRangeOutOfBounds(Word, Word),
#[error("solution data index out of bounds")]
SolutionDataOutOfBounds,
#[error("pub var data range was out of bounds")]
PubVarDataOutOfBounds,
#[error("pub var key out of bounds")]
PubVarKeyOutOfBounds,
#[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("pathway index out of bounds: {0}")]
PathwayOutOfBounds(Word),
#[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 `pathway_ix` argument for `PubVar` operation")]
PubVarPathwayIx,
#[error("missing `key` argument for `PubVar` operation")]
PubVarKey,
#[error("missing `key_len` argument for `PubVar` operation")]
PubVarKeyLen,
#[error("missing `value_ix` argument for `PubVar` operation")]
PubVarValueIx,
#[error("missing `value_len` argument for `PubVar` operation")]
PubVarValueLen,
#[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 `DecisionVar` operation")]
DecVarLen,
#[error("missing `value_ix` argument for `DecisionVar` operation")]
DecVarValueIx,
#[error("missing `slot_ix` argument for `DecisionVar` operation")]
DecVarSlotIx,
#[error("missing `pathway_ix` argument for `PushPubVarKeys` operation")]
PushPubVarKeysPathwayIx,
}
#[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 TemporaryResult<T> = Result<T, TemporaryError>;
#[derive(Debug, Error)]
pub enum TemporaryError {
#[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 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 fmt::Display for ConstraintErrors {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("the constraints at the following indices failed: \n")?;
for (ix, err) in &self.0 {
f.write_str(&format!(" {ix}: {err}\n"))?;
}
Ok(())
}
}
impl fmt::Display for ConstraintsUnsatisfied {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("the constraints at the following indices returned false: \n")?;
for ix in &self.0 {
f.write_str(&format!(" {ix}\n"))?;
}
Ok(())
}
}
impl From<core::convert::Infallible> for OpError {
fn from(err: core::convert::Infallible) -> Self {
match err {}
}
}
impl From<MissingAccessArgError> for OpError {
fn from(err: MissingAccessArgError) -> Self {
AccessError::MissingArg(err).into()
}
}