diff --git a/CHANGELOG.md b/CHANGELOG.md index da077c5051..902ef3aa2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE ### Added +- Add `stackerdb_timeout_secs` to miner config for limiting duration of StackerDB HTTP requests. - Renamed `clarity-serialization` to `clarity-types`. - Add `stackerdb_timeout_secs` to miner config for limiting duration of StackerDB HTTP requests. - When determining a global transaction replay set, the state evaluator now uses a longest-common-prefix algorithm to find a replay set in the case where a single replay set has less than 70% of signer weight. diff --git a/clarity/src/vm/errors.rs b/clarity/src/vm/errors.rs index 764ac466e5..6406cdae9f 100644 --- a/clarity/src/vm/errors.rs +++ b/clarity/src/vm/errors.rs @@ -24,6 +24,223 @@ pub use crate::vm::analysis::errors::{ SyntaxBindingError, SyntaxBindingErrorType, }; +use crate::vm::ast::errors::ParseError; +use crate::vm::contexts::StackTrace; +use crate::vm::costs::CostErrors; +use crate::vm::types::Value; +use crate::vm::SymbolicExpression; + +#[derive(Debug)] +pub struct IncomparableError { + pub err: T, +} + +#[derive(Debug)] +#[allow(clippy::large_enum_variant)] +pub enum Error { + /// UncheckedErrors are errors that *should* be caught by the + /// TypeChecker and other check passes. Test executions may + /// trigger these errors. + Unchecked(CheckErrors), + Interpreter(InterpreterError), + Runtime(RuntimeErrorType, Option), + ShortReturn(ShortReturnType), +} + +/// InterpreterErrors are errors that *should never* occur. +/// Test executions may trigger these errors. +#[derive(Debug, PartialEq)] +pub enum InterpreterError { + BadSender(Value), + BadSymbolicRepresentation(String), + InterpreterError(String), + UninitializedPersistedVariable, + FailedToConstructAssetTable, + FailedToConstructEventBatch, + #[cfg(feature = "rusqlite")] + SqliteError(IncomparableError), + BadFileName, + FailedToCreateDataDirectory, + MarfFailure(String), + FailureConstructingTupleWithType, + FailureConstructingListWithType, + InsufficientBalance, + CostContractLoadFailure, + DBError(String), + Expect(String), +} + +/// RuntimeErrors are errors that smart contracts are expected +/// to be able to trigger during execution (e.g., arithmetic errors) +#[derive(Debug, PartialEq)] +pub enum RuntimeErrorType { + Arithmetic(String), + ArithmeticOverflow, + ArithmeticUnderflow, + SupplyOverflow(u128, u128), + SupplyUnderflow(u128, u128), + DivisionByZero, + // error in parsing types + ParseError(String), + // error in parsing the AST + ASTError(ParseError), + MaxStackDepthReached, + MaxContextDepthReached, + ListDimensionTooHigh, + BadTypeConstruction, + ValueTooLarge, + BadBlockHeight(String), + TransferNonPositiveAmount, + NoSuchToken, + NotImplemented, + NoCallerInContext, + NoSenderInContext, + NonPositiveTokenSupply, + JSONParseError(IncomparableError), + AttemptToFetchInTransientContext, + BadNameValue(&'static str, String), + UnknownBlockHeaderHash(BlockHeaderHash), + BadBlockHash(Vec), + UnwrapFailure, + DefunctPoxContract, + PoxAlreadyLocked, + MetadataAlreadySet, +} + +#[derive(Debug, PartialEq)] +pub enum ShortReturnType { + ExpectedValue(Value), + AssertionFailed(Value), +} + +pub type InterpreterResult = Result; + +impl PartialEq> for IncomparableError { + fn eq(&self, _other: &IncomparableError) -> bool { + false + } +} + +impl PartialEq for Error { + fn eq(&self, other: &Error) -> bool { + match (self, other) { + (Error::Runtime(x, _), Error::Runtime(y, _)) => x == y, + (Error::Unchecked(x), Error::Unchecked(y)) => x == y, + (Error::ShortReturn(x), Error::ShortReturn(y)) => x == y, + (Error::Interpreter(x), Error::Interpreter(y)) => x == y, + _ => false, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::Runtime(ref err, ref stack) => { + write!(f, "{err}")?; + if let Some(ref stack_trace) = stack { + if !stack_trace.is_empty() { + writeln!(f, "\n Stack Trace: ")?; + for item in stack_trace.iter() { + writeln!(f, "{item}")?; + } + } + } + Ok(()) + } + _ => write!(f, "{self:?}"), + } + } +} + +impl fmt::Display for RuntimeErrorType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } +} + +impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + None + } +} + +impl error::Error for RuntimeErrorType { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + None + } +} + +impl From for Error { + fn from(err: ParseError) -> Self { + match &err.err { + ParseErrors::InterpreterFailure => Error::from(InterpreterError::Expect( + "Unexpected interpreter failure during parsing".into(), + )), + _ => Error::from(RuntimeErrorType::ASTError(err)), + } + } +} + +impl From for Error { + fn from(err: CostErrors) -> Self { + match err { + CostErrors::InterpreterFailure => Error::from(InterpreterError::Expect( + "Interpreter failure during cost calculation".into(), + )), + CostErrors::Expect(s) => Error::from(InterpreterError::Expect(format!( + "Interpreter failure during cost calculation: {s}" + ))), + other_err => Error::from(CheckErrors::from(other_err)), + } + } +} + +impl From for Error { + fn from(err: RuntimeErrorType) -> Self { + Error::Runtime(err, None) + } +} + +impl From for Error { + fn from(err: CheckErrors) -> Self { + Error::Unchecked(err) + } +} + +impl From<(CheckErrors, &SymbolicExpression)> for Error { + fn from(err: (CheckErrors, &SymbolicExpression)) -> Self { + Error::Unchecked(err.0) + } +} + +impl From for Error { + fn from(err: ShortReturnType) -> Self { + Error::ShortReturn(err) + } +} + +impl From for Error { + fn from(err: InterpreterError) -> Self { + Error::Interpreter(err) + } +} + +#[cfg(test)] +impl From for () { + fn from(err: Error) -> Self {} +} + +impl From for Value { + fn from(val: ShortReturnType) -> Self { + match val { + ShortReturnType::ExpectedValue(v) => v, + ShortReturnType::AssertionFailed(v) => v, + } + } +} + + #[cfg(test)] mod test { diff --git a/stacks-signer/CHANGELOG.md b/stacks-signer/CHANGELOG.md index c332710cc2..95948ef15d 100644 --- a/stacks-signer/CHANGELOG.md +++ b/stacks-signer/CHANGELOG.md @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to the versioning scheme outlined in the [README.md](README.md). + +## [3.2.0.0.1.1] + +### Added + +- Introduced `stackerdb_timeout_secs`: config option to set the maximum time (in seconds) the signer will wait for StackerDB HTTP requests to complete. + + ## Unreleased ### Added