Skip to content
Closed
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
95 changes: 54 additions & 41 deletions clarity/src/vm/clarity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,26 @@ use crate::vm::events::StacksTransactionEvent;
use crate::vm::types::{BuffData, PrincipalData, QualifiedContractIdentifier};
use crate::vm::{analysis, ast, ClarityVersion, ContractContext, SymbolicExpression, Value};

/// Top-level error type for Clarity contract processing, encompassing errors from parsing,
/// type-checking, runtime evaluation, and transaction execution.
#[derive(Debug)]
pub enum Error {
pub enum ClarityError {
/// Error during static type-checking or semantic analysis.
/// The `StaticCheckError` wraps the specific type-checking error, including diagnostic details.
StaticCheck(StaticCheckError),
/// Error during lexical or syntactic parsing.
/// The `ParseError` wraps the specific parsing error, such as invalid syntax or tokens.
Parse(ParseError),
/// Error during runtime evaluation in the virtual machine.
/// The `VmExecutionError` wraps the specific error, such as runtime errors or dynamic type-checking errors.
Interpreter(InterpreterError),
/// Transaction is malformed or invalid due to blockchain-level issues.
/// The `String` wraps a human-readable description of the issue, such as incorrect format or invalid signatures.
BadTransaction(String),
/// Transaction exceeds the allocated cost budget during execution.
/// The first `ExecutionCost` represents the total consumed cost, and the second represents the budget limit.
CostError(ExecutionCost, ExecutionCost),
/// Transaction aborted by a callback (e.g., post-condition check or custom logic).
AbortedByCallback {
/// What the output value of the transaction would have been.
/// This will be a Some for contract-calls, and None for contract initialization txs.
Expand All @@ -33,85 +46,85 @@ pub enum Error {
},
}

impl fmt::Display for Error {
impl fmt::Display for ClarityError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::CostError(ref a, ref b) => {
ClarityError::CostError(ref a, ref b) => {
write!(f, "Cost Error: {a} cost exceeded budget of {b} cost")
}
Error::StaticCheck(ref e) => fmt::Display::fmt(e, f),
Error::Parse(ref e) => fmt::Display::fmt(e, f),
Error::AbortedByCallback { reason, .. } => {
ClarityError::StaticCheck(ref e) => fmt::Display::fmt(e, f),
ClarityError::Parse(ref e) => fmt::Display::fmt(e, f),
ClarityError::AbortedByCallback { reason, .. } => {
write!(f, "Post condition aborted transaction: {reason}")
}
Error::Interpreter(ref e) => fmt::Display::fmt(e, f),
Error::BadTransaction(ref s) => fmt::Display::fmt(s, f),
ClarityError::Interpreter(ref e) => fmt::Display::fmt(e, f),
ClarityError::BadTransaction(ref s) => fmt::Display::fmt(s, f),
}
}
}

impl std::error::Error for Error {
impl std::error::Error for ClarityError {
fn cause(&self) -> Option<&dyn std::error::Error> {
match *self {
Error::CostError(ref _a, ref _b) => None,
Error::AbortedByCallback { .. } => None,
Error::StaticCheck(ref e) => Some(e),
Error::Parse(ref e) => Some(e),
Error::Interpreter(ref e) => Some(e),
Error::BadTransaction(ref _s) => None,
ClarityError::CostError(ref _a, ref _b) => None,
ClarityError::AbortedByCallback { .. } => None,
ClarityError::StaticCheck(ref e) => Some(e),
ClarityError::Parse(ref e) => Some(e),
ClarityError::Interpreter(ref e) => Some(e),
ClarityError::BadTransaction(ref _s) => None,
}
}
}

impl From<StaticCheckError> for Error {
impl From<StaticCheckError> for ClarityError {
fn from(e: StaticCheckError) -> Self {
match *e.err {
CheckErrorKind::CostOverflow => {
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
}
CheckErrorKind::CostBalanceExceeded(a, b) => Error::CostError(a, b),
CheckErrorKind::CostBalanceExceeded(a, b) => ClarityError::CostError(a, b),
CheckErrorKind::MemoryBalanceExceeded(_a, _b) => {
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
}
CheckErrorKind::ExecutionTimeExpired => {
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
}
_ => Error::StaticCheck(e),
_ => ClarityError::StaticCheck(e),
}
}
}

impl From<InterpreterError> for Error {
impl From<InterpreterError> for ClarityError {
fn from(e: InterpreterError) -> Self {
match &e {
InterpreterError::Unchecked(CheckErrorKind::CostBalanceExceeded(a, b)) => {
Error::CostError(a.clone(), b.clone())
ClarityError::CostError(a.clone(), b.clone())
}
InterpreterError::Unchecked(CheckErrorKind::CostOverflow) => {
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
}
InterpreterError::Unchecked(CheckErrorKind::ExecutionTimeExpired) => {
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
}
_ => Error::Interpreter(e),
_ => ClarityError::Interpreter(e),
}
}
}

impl From<ParseError> for Error {
impl From<ParseError> for ClarityError {
fn from(e: ParseError) -> Self {
match *e.err {
ParseErrors::CostOverflow => {
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
}
ParseErrors::CostBalanceExceeded(a, b) => Error::CostError(a, b),
ParseErrors::CostBalanceExceeded(a, b) => ClarityError::CostError(a, b),
ParseErrors::MemoryBalanceExceeded(_a, _b) => {
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
}
ParseErrors::ExecutionTimeExpired => {
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
}
_ => Error::Parse(e),
_ => ClarityError::Parse(e),
}
}
}
Expand Down Expand Up @@ -210,7 +223,7 @@ pub trait TransactionConnection: ClarityConnection {
clarity_version: ClarityVersion,
contract_content: &str,
ast_rules: ASTRules,
) -> Result<(ContractAST, ContractAnalysis), Error> {
) -> Result<(ContractAST, ContractAnalysis), ClarityError> {
let epoch_id = self.get_epoch();

self.with_analysis_db(|db, mut cost_track| {
Expand Down Expand Up @@ -289,12 +302,12 @@ pub trait TransactionConnection: ClarityConnection {
to: &PrincipalData,
amount: u128,
memo: &BuffData,
) -> Result<(Value, AssetMap, Vec<StacksTransactionEvent>), Error> {
) -> Result<(Value, AssetMap, Vec<StacksTransactionEvent>), ClarityError> {
self.with_abort_callback(
|vm_env| {
vm_env
.stx_transfer(from, to, amount, memo)
.map_err(Error::from)
.map_err(ClarityError::from)
},
|_, _| None,
)
Expand All @@ -316,7 +329,7 @@ pub trait TransactionConnection: ClarityConnection {
args: &[Value],
abort_call_back: F,
max_execution_time: Option<std::time::Duration>,
) -> Result<(Value, AssetMap, Vec<StacksTransactionEvent>), Error>
) -> Result<(Value, AssetMap, Vec<StacksTransactionEvent>), ClarityError>
where
F: FnOnce(&AssetMap, &mut ClarityDatabase) -> Option<String>,
{
Expand All @@ -340,13 +353,13 @@ pub trait TransactionConnection: ClarityConnection {
public_function,
&expr_args,
)
.map_err(Error::from)
.map_err(ClarityError::from)
},
abort_call_back,
)
.and_then(|(value, assets_modified, tx_events, reason)| {
if let Some(reason) = reason {
Err(Error::AbortedByCallback {
Err(ClarityError::AbortedByCallback {
output: Some(Box::new(value)),
assets_modified: Box::new(assets_modified),
tx_events,
Expand All @@ -373,7 +386,7 @@ pub trait TransactionConnection: ClarityConnection {
sponsor: Option<PrincipalData>,
abort_call_back: F,
max_execution_time: Option<std::time::Duration>,
) -> Result<(AssetMap, Vec<StacksTransactionEvent>), Error>
) -> Result<(AssetMap, Vec<StacksTransactionEvent>), ClarityError>
where
F: FnOnce(&AssetMap, &mut ClarityDatabase) -> Option<String>,
{
Expand All @@ -392,12 +405,12 @@ pub trait TransactionConnection: ClarityConnection {
contract_str,
sponsor,
)
.map_err(Error::from)
.map_err(ClarityError::from)
},
abort_call_back,
)?;
if let Some(reason) = reason {
Err(Error::AbortedByCallback {
Err(ClarityError::AbortedByCallback {
output: None,
assets_modified: Box::new(assets_modified),
tx_events,
Expand Down
2 changes: 1 addition & 1 deletion stackslib/src/chainstate/stacks/boot/contract_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use crate::chainstate::stacks::boot::{
use crate::chainstate::stacks::index::ClarityMarfTrieId;
use crate::chainstate::stacks::{C32_ADDRESS_VERSION_TESTNET_SINGLESIG, *};
use crate::clarity_vm::clarity::{
ClarityBlockConnection, ClarityMarfStore, ClarityMarfStoreTransaction, Error as ClarityError,
ClarityBlockConnection, ClarityError, ClarityMarfStore, ClarityMarfStoreTransaction,
WritableMarfStore,
};
use crate::clarity_vm::database::marf::MarfedKV;
Expand Down
2 changes: 1 addition & 1 deletion stackslib/src/chainstate/stacks/boot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use std::sync::LazyLock;
use clarity::types::Address;
use clarity::vm::analysis::CheckErrorKind;
use clarity::vm::ast::ASTRules;
use clarity::vm::clarity::{Error as ClarityError, TransactionConnection};
use clarity::vm::clarity::{ClarityError, TransactionConnection};
use clarity::vm::costs::LimitedCostTracker;
use clarity::vm::database::{ClarityDatabase, NULL_BURN_STATE_DB, NULL_HEADER_DB};
use clarity::vm::errors::Error as VmError;
Expand Down
4 changes: 2 additions & 2 deletions stackslib/src/chainstate/stacks/db/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl StacksChainState {
.with_clarity_db_readonly(|ref mut db| match db.get_contract(contract_id) {
Ok(c) => Ok(Some(c)),
Err(clarity_vm_error::Unchecked(CheckErrorKind::NoSuchContract(_))) => Ok(None),
Err(e) => Err(clarity_error::Interpreter(e)),
Err(e) => Err(ClarityError::Interpreter(e)),
})
.map_err(Error::ClarityError)
}
Expand All @@ -50,7 +50,7 @@ impl StacksChainState {
Err(clarity_vm_error::Unchecked(CheckErrorKind::NoSuchDataVariable(_))) => {
Ok(None)
}
Err(e) => Err(clarity_error::Interpreter(e)),
Err(e) => Err(ClarityError::Interpreter(e)),
}
})
.map_err(Error::ClarityError)
Expand Down
10 changes: 5 additions & 5 deletions stackslib/src/chainstate/stacks/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ use crate::chainstate::stacks::{
C32_ADDRESS_VERSION_TESTNET_SINGLESIG, *,
};
use crate::clarity_vm::clarity::{
ClarityBlockConnection, ClarityConnection, ClarityInstance, ClarityReadOnlyConnection,
Error as clarity_error, PreCommitClarityBlock,
ClarityBlockConnection, ClarityConnection, ClarityError, ClarityInstance,
ClarityReadOnlyConnection, PreCommitClarityBlock,
};
use crate::clarity_vm::database::marf::MarfedKV;
use crate::clarity_vm::database::HeadersDBConn;
Expand Down Expand Up @@ -545,7 +545,7 @@ impl<'a, 'b> ClarityTx<'a, 'b> {
pub fn commit_mined_block(
self,
block_hash: &StacksBlockId,
) -> Result<ExecutionCost, clarity_error> {
) -> Result<ExecutionCost, ClarityError> {
Ok(self.block.commit_mined_block(block_hash)?.get_total())
}

Expand Down Expand Up @@ -1977,7 +1977,7 @@ impl StacksChainState {
parent_id_bhh: &StacksBlockId,
contract: &QualifiedContractIdentifier,
code: &str,
) -> Result<Value, clarity_error> {
) -> Result<Value, ClarityError> {
self.clarity_state.eval_read_only(
parent_id_bhh,
&HeadersDBConn(StacksDBConn::new(&self.state_index, ())),
Expand All @@ -1998,7 +1998,7 @@ impl StacksChainState {
contract: &QualifiedContractIdentifier,
function: &str,
args: &[Value],
) -> Result<Value, clarity_error> {
) -> Result<Value, ClarityError> {
let headers_db = HeadersDBConn(StacksDBConn::new(&self.state_index, ()));
let mut conn = self.clarity_state.read_only_connection_checked(
parent_id_bhh,
Expand Down
Loading
Loading