Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
217 changes: 217 additions & 0 deletions clarity/src/vm/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> {
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<StackTrace>),
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<SqliteError>),
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<SerdeJSONErr>),
AttemptToFetchInTransientContext,
BadNameValue(&'static str, String),
UnknownBlockHeaderHash(BlockHeaderHash),
BadBlockHash(Vec<u8>),
UnwrapFailure,
DefunctPoxContract,
PoxAlreadyLocked,
MetadataAlreadySet,
}

#[derive(Debug, PartialEq)]
pub enum ShortReturnType {
ExpectedValue(Value),
AssertionFailed(Value),
}

pub type InterpreterResult<R> = Result<R, Error>;

impl<T> PartialEq<IncomparableError<T>> for IncomparableError<T> {
fn eq(&self, _other: &IncomparableError<T>) -> bool {
false
}
}

impl PartialEq<Error> 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<ParseError> 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<CostErrors> 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<RuntimeErrorType> for Error {
fn from(err: RuntimeErrorType) -> Self {
Error::Runtime(err, None)
}
}

impl From<CheckErrors> 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<ShortReturnType> for Error {
fn from(err: ShortReturnType) -> Self {
Error::ShortReturn(err)
}
}

impl From<InterpreterError> for Error {
fn from(err: InterpreterError) -> Self {
Error::Interpreter(err)
}
}

#[cfg(test)]
impl From<Error> for () {
fn from(err: Error) -> Self {}
}

impl From<ShortReturnType> for Value {
fn from(val: ShortReturnType) -> Self {
match val {
ShortReturnType::ExpectedValue(v) => v,
ShortReturnType::AssertionFailed(v) => v,
}
}
}


#[cfg(test)]
mod test {

Expand Down
8 changes: 8 additions & 0 deletions stacks-signer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down