From e92b92ed30c96eed6a6835854b141bb2cc72b35f Mon Sep 17 00:00:00 2001 From: Jacinta Ferrant Date: Wed, 17 Sep 2025 15:58:53 -0700 Subject: [PATCH 1/4] Rename vm::errors::Error to VmExecutionError Signed-off-by: Jacinta Ferrant --- clarity-types/src/errors/mod.rs | 79 ++++++++++--------- clarity-types/src/lib.rs | 2 +- clarity-types/src/tests/types/mod.rs | 56 ++++++------- .../src/tests/types/serialization.rs | 6 +- clarity/src/vm/ast/mod.rs | 3 +- clarity/src/vm/callables.rs | 6 +- clarity/src/vm/clarity.rs | 20 ++--- clarity/src/vm/contexts.rs | 42 +++++----- clarity/src/vm/costs/cost_functions.rs | 6 +- clarity/src/vm/costs/mod.rs | 3 +- clarity/src/vm/coverage.rs | 2 +- clarity/src/vm/database/clarity_db.rs | 11 ++- clarity/src/vm/database/structures.rs | 79 ++++++++++--------- clarity/src/vm/docs/contracts.rs | 2 +- clarity/src/vm/errors.rs | 4 +- clarity/src/vm/functions/assets.rs | 20 ++--- clarity/src/vm/functions/mod.rs | 6 +- clarity/src/vm/mod.rs | 12 +-- clarity/src/vm/tests/assets.rs | 12 +-- clarity/src/vm/tests/contracts.rs | 14 ++-- clarity/src/vm/tests/datamaps.rs | 17 ++-- clarity/src/vm/tests/defines.rs | 29 ++++--- clarity/src/vm/tests/sequences.rs | 18 ++--- clarity/src/vm/tests/simple_apply_eval.rs | 34 ++++---- clarity/src/vm/tests/traits.rs | 14 ++-- clarity/src/vm/tests/variables.rs | 20 +++-- clarity/src/vm/types/serialization.rs | 4 +- clarity/src/vm/version.rs | 6 +- pox-locking/src/events.rs | 8 +- pox-locking/src/events_24.rs | 6 +- pox-locking/src/lib.rs | 16 ++-- pox-locking/src/pox_1.rs | 8 +- pox-locking/src/pox_2.rs | 18 ++--- pox-locking/src/pox_3.rs | 18 ++--- pox-locking/src/pox_4.rs | 18 ++--- stacks-signer/src/client/mod.rs | 4 +- stackslib/src/blockstack_cli.rs | 8 +- stackslib/src/chainstate/coordinator/tests.rs | 4 +- .../chainstate/stacks/boot/contract_tests.rs | 4 +- stackslib/src/chainstate/stacks/boot/mod.rs | 6 +- stackslib/src/chainstate/stacks/db/blocks.rs | 28 +++---- .../src/chainstate/stacks/db/contracts.rs | 6 +- .../src/chainstate/stacks/db/transactions.rs | 36 ++++----- stackslib/src/chainstate/stacks/miner.rs | 4 +- stackslib/src/chainstate/stacks/mod.rs | 6 +- stackslib/src/clarity_cli.rs | 36 +++++---- stackslib/src/clarity_vm/clarity.rs | 6 +- stackslib/src/clarity_vm/special.rs | 4 +- stackslib/src/clarity_vm/tests/contracts.rs | 6 +- stackslib/src/clarity_vm/tests/costs.rs | 4 +- stackslib/src/clarity_vm/tests/forking.rs | 6 +- .../src/clarity_vm/tests/large_contract.rs | 8 +- .../src/clarity_vm/tests/simple_tests.rs | 4 +- stackslib/src/net/api/callreadonly.rs | 2 +- stackslib/src/net/api/fastcallreadonly.rs | 2 +- stackslib/src/net/mod.rs | 6 +- 56 files changed, 421 insertions(+), 388 deletions(-) diff --git a/clarity-types/src/errors/mod.rs b/clarity-types/src/errors/mod.rs index 58b42b8a99d..8037ed7f7b5 100644 --- a/clarity-types/src/errors/mod.rs +++ b/clarity-types/src/errors/mod.rs @@ -39,7 +39,7 @@ pub struct IncomparableError { } #[derive(Debug)] -pub enum Error { +pub enum VmExecutionError { /// UncheckedErrors are errors that *should* be caught by the /// TypeChecker and other check passes. Test executions may /// trigger these errors. @@ -109,7 +109,7 @@ pub enum ShortReturnType { AssertionFailed(Box), } -pub type InterpreterResult = Result; +pub type InterpreterResult = Result; impl PartialEq> for IncomparableError { fn eq(&self, _other: &IncomparableError) -> bool { @@ -117,22 +117,22 @@ impl PartialEq> for IncomparableError { } } -impl PartialEq for Error { - fn eq(&self, other: &Error) -> bool { +impl PartialEq for VmExecutionError { + fn eq(&self, other: &VmExecutionError) -> 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, + (VmExecutionError::Runtime(x, _), VmExecutionError::Runtime(y, _)) => x == y, + (VmExecutionError::Unchecked(x), VmExecutionError::Unchecked(y)) => x == y, + (VmExecutionError::ShortReturn(x), VmExecutionError::ShortReturn(y)) => x == y, + (VmExecutionError::Interpreter(x), VmExecutionError::Interpreter(y)) => x == y, _ => false, } } } -impl fmt::Display for Error { +impl fmt::Display for VmExecutionError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Error::Runtime(err, stack) => { + VmExecutionError::Runtime(err, stack) => { write!(f, "{err}")?; if let Some(stack_trace) = stack { writeln!(f, "\n Stack Trace: ")?; @@ -153,7 +153,7 @@ impl fmt::Display for RuntimeErrorType { } } -impl error::Error for Error { +impl error::Error for VmExecutionError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { None } @@ -165,64 +165,64 @@ impl error::Error for RuntimeErrorType { } } -impl From for Error { +impl From for VmExecutionError { fn from(err: ParseError) -> Self { match *err.err { - ParseErrors::InterpreterFailure => Error::from(InterpreterError::Expect( + ParseErrors::InterpreterFailure => VmExecutionError::from(InterpreterError::Expect( "Unexpected interpreter failure during parsing".into(), )), - _ => Error::from(RuntimeErrorType::ASTError(Box::new(err))), + _ => VmExecutionError::from(RuntimeErrorType::ASTError(Box::new(err))), } } } -impl From for Error { +impl From for VmExecutionError { fn from(err: CostErrors) -> Self { match err { - CostErrors::InterpreterFailure => Error::from(InterpreterError::Expect( + CostErrors::InterpreterFailure => VmExecutionError::from(InterpreterError::Expect( "Interpreter failure during cost calculation".into(), )), - CostErrors::Expect(s) => Error::from(InterpreterError::Expect(format!( + CostErrors::Expect(s) => VmExecutionError::from(InterpreterError::Expect(format!( "Interpreter failure during cost calculation: {s}" ))), - other_err => Error::from(CheckErrors::from(other_err)), + other_err => VmExecutionError::from(CheckErrors::from(other_err)), } } } -impl From for Error { +impl From for VmExecutionError { fn from(err: RuntimeErrorType) -> Self { - Error::Runtime(err, None) + VmExecutionError::Runtime(err, None) } } -impl From for Error { +impl From for VmExecutionError { fn from(err: CheckErrors) -> Self { - Error::Unchecked(err) + VmExecutionError::Unchecked(err) } } -impl From<(CheckErrors, &SymbolicExpression)> for Error { +impl From<(CheckErrors, &SymbolicExpression)> for VmExecutionError { fn from(err: (CheckErrors, &SymbolicExpression)) -> Self { - Error::Unchecked(err.0) + VmExecutionError::Unchecked(err.0) } } -impl From for Error { +impl From for VmExecutionError { fn from(err: ShortReturnType) -> Self { - Error::ShortReturn(err) + VmExecutionError::ShortReturn(err) } } -impl From for Error { +impl From for VmExecutionError { fn from(err: InterpreterError) -> Self { - Error::Interpreter(err) + VmExecutionError::Interpreter(err) } } #[cfg(any(test, feature = "testing"))] -impl From for () { - fn from(_err: Error) -> Self {} +impl From for () { + fn from(_err: VmExecutionError) -> Self {} } impl From for Value { @@ -241,16 +241,23 @@ mod test { #[test] fn equality() { assert_eq!( - Error::ShortReturn(ShortReturnType::ExpectedValue(Box::new(Value::Bool(true)))), - Error::ShortReturn(ShortReturnType::ExpectedValue(Box::new(Value::Bool(true)))) + VmExecutionError::ShortReturn(ShortReturnType::ExpectedValue(Box::new(Value::Bool( + true + )))), + VmExecutionError::ShortReturn(ShortReturnType::ExpectedValue(Box::new(Value::Bool( + true + )))) ); assert_eq!( - Error::Interpreter(InterpreterError::InterpreterError("".to_string())), - Error::Interpreter(InterpreterError::InterpreterError("".to_string())) + VmExecutionError::Interpreter(InterpreterError::InterpreterError("".to_string())), + VmExecutionError::Interpreter(InterpreterError::InterpreterError("".to_string())) ); assert!( - Error::ShortReturn(ShortReturnType::ExpectedValue(Box::new(Value::Bool(true)))) - != Error::Interpreter(InterpreterError::InterpreterError("".to_string())) + VmExecutionError::ShortReturn(ShortReturnType::ExpectedValue(Box::new(Value::Bool( + true + )))) != VmExecutionError::Interpreter(InterpreterError::InterpreterError( + "".to_string() + )) ); } } diff --git a/clarity-types/src/lib.rs b/clarity-types/src/lib.rs index de51f539156..68cc269b47f 100644 --- a/clarity-types/src/lib.rs +++ b/clarity-types/src/lib.rs @@ -31,7 +31,7 @@ pub mod representations; pub mod token; pub mod types; -pub use errors::Error; +pub use errors::VmExecutionError; pub use representations::{ClarityName, ContractName}; pub use types::Value; diff --git a/clarity-types/src/tests/types/mod.rs b/clarity-types/src/tests/types/mod.rs index 8c8d861c7ce..c7c72972728 100644 --- a/clarity-types/src/tests/types/mod.rs +++ b/clarity-types/src/tests/types/mod.rs @@ -18,7 +18,7 @@ mod signatures; use rstest::rstest; use stacks_common::types::StacksEpochId; -use crate::Error; +use crate::VmExecutionError; use crate::errors::{CheckErrors, InterpreterError, RuntimeErrorType}; use crate::types::{ ASCIIData, BuffData, CharType, ListTypeData, MAX_VALUE_SIZE, PrincipalData, @@ -255,7 +255,7 @@ fn test_qualified_contract_identifier_local_returns_runtime_error() { let err = QualifiedContractIdentifier::local("1nvalid-name") .expect_err("Unexpected qualified contract identifier"); assert_eq!( - Error::from(RuntimeErrorType::BadNameValue( + VmExecutionError::from(RuntimeErrorType::BadNameValue( "ContractName", "1nvalid-name".into() )), @@ -279,7 +279,7 @@ fn test_principal_data_parse_standard_principal_returns_runtime_error( ) { let err = PrincipalData::parse_standard_principal(input).expect_err("Unexpected principal data"); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } #[rstest] @@ -295,7 +295,7 @@ fn test_qualified_contract_identifier_parse_returns_interpreter_error( ) { let err = QualifiedContractIdentifier::parse(input) .expect_err("Unexpected qualified contract identifier"); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } #[rstest] @@ -312,7 +312,7 @@ fn test_trait_identifier_parse_returns_runtime_error( #[case] input: &str, #[case] expected_err: RuntimeErrorType, ) { - let expected_err = Error::from(expected_err); + let expected_err = VmExecutionError::from(expected_err); let err = TraitIdentifier::parse(input).expect_err("Unexpected trait identifier"); assert_eq!(expected_err, err); @@ -333,7 +333,7 @@ fn test_trait_identifier_parse_fully_qualified_returns_runtime_error( ) { let err = TraitIdentifier::parse_fully_qualified(input).expect_err("Unexpected trait identifier"); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } /// The returned InterpreterError is consensus-critical. @@ -343,7 +343,7 @@ fn test_standard_principal_data_new_returns_interpreter_error_consensus_critical let err = result.expect_err("Unexpected principal data"); assert_eq!( - Error::from(InterpreterError::Expect("Unexpected principal data".into())), + VmExecutionError::from(InterpreterError::Expect("Unexpected principal data".into())), err.into(), ); } @@ -354,7 +354,7 @@ fn test_sequence_data_element_at_returns_interpreter_error_consensus_critical() let buff = SequenceData::String(CharType::ASCII(ASCIIData { data: vec![1] })); let err = buff.element_at(0).unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(InterpreterError::Expect( "BUG: failed to initialize single-byte ASCII buffer".into() )), err @@ -366,7 +366,7 @@ fn test_sequence_data_element_at_returns_interpreter_error_consensus_critical() fn test_ascii_data_to_value_returns_interpreter_error_consensus_critical() { let err = ASCIIData::to_value(&1).unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(InterpreterError::Expect( "ERROR: Invalid ASCII string successfully constructed".into() )), err @@ -378,7 +378,7 @@ fn test_ascii_data_to_value_returns_interpreter_error_consensus_critical() { fn test_utf8_data_to_value_returns_interpreter_error_consensus_critical() { let err = UTF8Data::to_value(&vec![0xED, 0xA0, 0x80]).unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(InterpreterError::Expect( "ERROR: Invalid UTF8 string successfully constructed".into() )), err @@ -397,7 +397,7 @@ fn test_tuple_data_from_data_typed_returns_interpreter_error_consensus_critical( ) .unwrap_err(); assert_eq!( - Error::from(InterpreterError::FailureConstructingTupleWithType), + VmExecutionError::from(InterpreterError::FailureConstructingTupleWithType), err ); } @@ -410,7 +410,7 @@ fn test_value_expect_ascii_returns_interpreter_error( #[case] expected_err: InterpreterError, ) { let err = value.expect_ascii().unwrap_err(); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } /// The returned InterpreterError is consensus-critical. @@ -418,7 +418,7 @@ fn test_value_expect_ascii_returns_interpreter_error( fn test_value_expect_u128_returns_interpreter_error_consensus_critical() { let err = Value::none().expect_u128().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected u128".to_string())), + VmExecutionError::from(InterpreterError::Expect("Expected u128".to_string())), err ); } @@ -427,7 +427,7 @@ fn test_value_expect_u128_returns_interpreter_error_consensus_critical() { fn test_value_expect_i128_returns_interpreter_error() { let err = Value::none().expect_i128().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected i128".to_string())), + VmExecutionError::from(InterpreterError::Expect("Expected i128".to_string())), err ); } @@ -440,14 +440,14 @@ fn test_value_expect_buff_returns_interpreter_error( #[case] expected_err: InterpreterError, ) { let err = value.expect_buff(1).unwrap_err(); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } #[test] fn test_value_expect_tuple_returns_interpreter_error() { let err = Value::none().expect_tuple().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected tuple".to_string())), + VmExecutionError::from(InterpreterError::Expect("Expected tuple".to_string())), err ); } @@ -456,7 +456,7 @@ fn test_value_expect_tuple_returns_interpreter_error() { fn test_value_expect_list_returns_interpreter_error() { let err = Value::none().expect_list().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected list".to_string())), + VmExecutionError::from(InterpreterError::Expect("Expected list".to_string())), err ); } @@ -465,7 +465,7 @@ fn test_value_expect_list_returns_interpreter_error() { fn test_value_expect_buff_padded_returns_interpreter_error() { let err = Value::none().expect_buff_padded(10, 0).unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected buff".to_string())), + VmExecutionError::from(InterpreterError::Expect("Expected buff".to_string())), err ); } @@ -474,7 +474,7 @@ fn test_value_expect_buff_padded_returns_interpreter_error() { fn test_value_expect_bool_returns_interpreter_error() { let err = Value::none().expect_bool().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected bool".to_string())), + VmExecutionError::from(InterpreterError::Expect("Expected bool".to_string())), err ); } @@ -484,7 +484,7 @@ fn test_value_expect_bool_returns_interpreter_error() { fn test_value_expect_optional_returns_interpreter_error_consensus_critical() { let err = Value::okay_true().expect_optional().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected optional".to_string())), + VmExecutionError::from(InterpreterError::Expect("Expected optional".to_string())), err ); } @@ -494,7 +494,7 @@ fn test_value_expect_optional_returns_interpreter_error_consensus_critical() { fn test_value_expect_principal_returns_interpreter_error_consensus_critical() { let err = Value::none().expect_principal().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected principal".to_string())), + VmExecutionError::from(InterpreterError::Expect("Expected principal".to_string())), err ); } @@ -504,7 +504,7 @@ fn test_value_expect_principal_returns_interpreter_error_consensus_critical() { fn test_value_expect_callable_returns_interpreter_error_consensus_critical() { let err = Value::none().expect_callable().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected callable".to_string())), + VmExecutionError::from(InterpreterError::Expect("Expected callable".to_string())), err ); } @@ -513,7 +513,7 @@ fn test_value_expect_callable_returns_interpreter_error_consensus_critical() { fn test_value_expect_result_returns_interpreter_error() { let err = Value::none().expect_result().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected response".to_string())), + VmExecutionError::from(InterpreterError::Expect("Expected response".to_string())), err ); } @@ -526,7 +526,7 @@ fn test_value_expect_result_ok_returns_interpreter_error( #[case] expected_err: InterpreterError, ) { let err = value.expect_result_ok().unwrap_err(); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } #[rstest] @@ -537,7 +537,7 @@ fn test_value_expect_result_err_returns_interpreter_error( #[case] expected_err: InterpreterError, ) { let err = value.expect_result_err().unwrap_err(); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } /// The returned InterpreterError is consensus-critical. @@ -549,7 +549,7 @@ fn test_buff_data_len_returns_interpreter_error_consensus_critical() { .len() .unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(InterpreterError::Expect( "Data length should be valid".into() )), err @@ -564,7 +564,7 @@ fn test_ascii_data_len_returns_interpreter_error() { .len() .unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(InterpreterError::Expect( "Data length should be valid".into() )), err @@ -579,7 +579,7 @@ fn test_utf8_data_len_returns_interpreter_error() { .len() .unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(InterpreterError::Expect( "Data length should be valid".into() )), err diff --git a/clarity-types/src/tests/types/serialization.rs b/clarity-types/src/tests/types/serialization.rs index 679befd351c..e1bee07b2fe 100644 --- a/clarity-types/src/tests/types/serialization.rs +++ b/clarity-types/src/tests/types/serialization.rs @@ -14,7 +14,7 @@ // along with this program. If not, see . use std::io::Write; -use crate::Error; +use crate::VmExecutionError; use crate::errors::{CheckErrors, InterpreterError}; use crate::types::serialization::SerializationError; use crate::types::{ @@ -424,7 +424,7 @@ fn test_serialize_to_vec_returns_interpreter_error_consensus_critical() { }))); let err = value.serialize_to_vec().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(InterpreterError::Expect( "IOError filling byte buffer.".into() )), err.into() @@ -439,7 +439,7 @@ fn test_serialize_to_hex_returns_interpreter_error_consensus_critical() { }))); let err = value.serialize_to_hex().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(InterpreterError::Expect( "IOError filling byte buffer.".into() )), err.into() diff --git a/clarity/src/vm/ast/mod.rs b/clarity/src/vm/ast/mod.rs index ccb78536411..2ab93d70cf5 100644 --- a/clarity/src/vm/ast/mod.rs +++ b/clarity/src/vm/ast/mod.rs @@ -49,7 +49,8 @@ pub fn parse( source_code: &str, version: ClarityVersion, epoch: StacksEpochId, -) -> Result, crate::vm::errors::Error> { +) -> Result, crate::vm::errors::VmExecutionError> +{ let ast = build_ast(contract_identifier, source_code, &mut (), version, epoch)?; Ok(ast.expressions) } diff --git a/clarity/src/vm/callables.rs b/clarity/src/vm/callables.rs index b697b3a0959..ee9659bfec6 100644 --- a/clarity/src/vm/callables.rs +++ b/clarity/src/vm/callables.rs @@ -28,7 +28,7 @@ use crate::vm::analysis::errors::CheckErrors; use crate::vm::contexts::ContractContext; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; -use crate::vm::errors::{check_argument_count, Error, InterpreterResult as Result}; +use crate::vm::errors::{check_argument_count, InterpreterResult as Result, VmExecutionError}; use crate::vm::representations::SymbolicExpression; use crate::vm::types::{ CallableData, ListData, ListTypeData, OptionalData, PrincipalData, ResponseData, SequenceData, @@ -116,7 +116,7 @@ pub fn cost_input_sized_vararg(args: &[Value]) -> Result { .map_err(|e| CostErrors::Expect(format!("{e:?}")))? as u64) .cost_overflow_add(sum) }) - .map_err(Error::from) + .map_err(VmExecutionError::from) } impl DefinedFunction { @@ -294,7 +294,7 @@ impl DefinedFunction { match result { Ok(r) => Ok(r), Err(e) => match e { - Error::ShortReturn(v) => Ok(v.into()), + VmExecutionError::ShortReturn(v) => Ok(v.into()), _ => Err(e), }, } diff --git a/clarity/src/vm/clarity.rs b/clarity/src/vm/clarity.rs index 979d815268c..1d3ec45ebc5 100644 --- a/clarity/src/vm/clarity.rs +++ b/clarity/src/vm/clarity.rs @@ -8,7 +8,7 @@ use crate::vm::ast::{ASTRules, ContractAST}; use crate::vm::contexts::{AssetMap, Environment, OwnedEnvironment}; use crate::vm::costs::{ExecutionCost, LimitedCostTracker}; use crate::vm::database::ClarityDatabase; -use crate::vm::errors::Error as InterpreterError; +use crate::vm::errors::VmExecutionError; use crate::vm::events::StacksTransactionEvent; use crate::vm::types::{BuffData, PrincipalData, QualifiedContractIdentifier}; use crate::vm::{analysis, ast, ClarityVersion, ContractContext, SymbolicExpression, Value}; @@ -17,7 +17,7 @@ use crate::vm::{analysis, ast, ClarityVersion, ContractContext, SymbolicExpressi pub enum Error { Analysis(CheckError), Parse(ParseError), - Interpreter(InterpreterError), + Interpreter(VmExecutionError), BadTransaction(String), CostError(ExecutionCost, ExecutionCost), AbortedByCallback { @@ -81,16 +81,16 @@ impl From for Error { } } -impl From for Error { - fn from(e: InterpreterError) -> Self { +impl From for Error { + fn from(e: VmExecutionError) -> Self { match &e { - InterpreterError::Unchecked(CheckErrors::CostBalanceExceeded(a, b)) => { + VmExecutionError::Unchecked(CheckErrors::CostBalanceExceeded(a, b)) => { Error::CostError(a.clone(), b.clone()) } - InterpreterError::Unchecked(CheckErrors::CostOverflow) => { + VmExecutionError::Unchecked(CheckErrors::CostOverflow) => { Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) } - InterpreterError::Unchecked(CheckErrors::ExecutionTimeExpired) => { + VmExecutionError::Unchecked(CheckErrors::ExecutionTimeExpired) => { Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) } _ => Error::Interpreter(e), @@ -143,9 +143,9 @@ pub trait ClarityConnection { sponsor: Option, cost_track: LimitedCostTracker, to_do: F, - ) -> Result + ) -> Result where - F: FnOnce(&mut Environment) -> Result, + F: FnOnce(&mut Environment) -> Result, { let epoch_id = self.get_epoch(); let clarity_version = ClarityVersion::default_for_epoch(epoch_id); @@ -192,7 +192,7 @@ pub trait TransactionConnection: ClarityConnection { where A: FnOnce(&AssetMap, &mut ClarityDatabase) -> Option, F: FnOnce(&mut OwnedEnvironment) -> Result<(R, AssetMap, Vec), E>, - E: From; + E: From; /// Do something with the analysis database and cost tracker /// instance of this transaction connection. This is a low-level diff --git a/clarity/src/vm/contexts.rs b/clarity/src/vm/contexts.rs index 355a0e9d537..c319360438e 100644 --- a/clarity/src/vm/contexts.rs +++ b/clarity/src/vm/contexts.rs @@ -21,6 +21,7 @@ use std::time::{Duration, Instant}; pub use clarity_types::errors::StackTrace; use clarity_types::representations::ClarityName; +use clarity_types::VmExecutionError; use serde::Serialize; use serde_json::json; use stacks_common::types::chainstate::StacksBlockId; @@ -605,7 +606,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { f: F, ) -> std::result::Result<(A, AssetMap, Vec), E> where - E: From, + E: From, F: FnOnce(&mut Environment) -> std::result::Result, { assert!(self.context.is_top_level()); @@ -730,29 +731,24 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { #[cfg(any(test, feature = "testing"))] pub fn stx_faucet(&mut self, recipient: &PrincipalData, amount: u128) { - self.execute_in_env::<_, _, crate::vm::errors::Error>( - recipient.clone(), - None, - None, - |env| { - let mut snapshot = env - .global_context - .database - .get_stx_balance_snapshot(recipient) - .unwrap(); + self.execute_in_env::<_, _, VmExecutionError>(recipient.clone(), None, None, |env| { + let mut snapshot = env + .global_context + .database + .get_stx_balance_snapshot(recipient) + .unwrap(); - snapshot.credit(amount).unwrap(); - snapshot.save().unwrap(); + snapshot.credit(amount).unwrap(); + snapshot.save().unwrap(); - env.global_context - .database - .increment_ustx_liquid_supply(amount) - .unwrap(); + env.global_context + .database + .increment_ustx_liquid_supply(amount) + .unwrap(); - let res: std::result::Result<(), crate::vm::errors::Error> = Ok(()); - res - }, - ) + let res: std::result::Result<(), VmExecutionError> = Ok(()); + res + }) .unwrap(); } @@ -1368,7 +1364,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { pub fn run_as_transaction(&mut self, f: F) -> std::result::Result where F: FnOnce(&mut Self) -> std::result::Result, - E: From, + E: From, { self.global_context.begin(); let result = f(self); @@ -1649,7 +1645,7 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { f: F, ) -> std::result::Result where - E: From, + E: From, F: FnOnce(&mut Environment) -> std::result::Result, { self.begin(); diff --git a/clarity/src/vm/costs/cost_functions.rs b/clarity/src/vm/costs/cost_functions.rs index 6abbaec5556..729ee4b1f4c 100644 --- a/clarity/src/vm/costs/cost_functions.rs +++ b/clarity/src/vm/costs/cost_functions.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use clarity_types::VmExecutionError; + use super::ExecutionCost; use crate::vm::errors::{InterpreterResult, RuntimeErrorType}; @@ -169,7 +171,7 @@ pub fn linear(n: u64, a: u64, b: u64) -> u64 { } pub fn logn(n: u64, a: u64, b: u64) -> InterpreterResult { if n < 1 { - return Err(crate::vm::errors::Error::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::Arithmetic("log2 must be passed a positive integer".to_string()), Some(vec![]), )); @@ -179,7 +181,7 @@ pub fn logn(n: u64, a: u64, b: u64) -> InterpreterResult { } pub fn nlogn(n: u64, a: u64, b: u64) -> InterpreterResult { if n < 1 { - return Err(crate::vm::errors::Error::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::Arithmetic("log2 must be passed a positive integer".to_string()), Some(vec![]), )); diff --git a/clarity/src/vm/costs/mod.rs b/clarity/src/vm/costs/mod.rs index 669f6f483dc..475ee3b9083 100644 --- a/clarity/src/vm/costs/mod.rs +++ b/clarity/src/vm/costs/mod.rs @@ -19,6 +19,7 @@ use std::{cmp, fmt}; pub use clarity_types::errors::CostErrors; pub use clarity_types::execution_cost::{CostOverflowingMath, ExecutionCost}; +use clarity_types::VmExecutionError; use costs_1::Costs1; use costs_2::Costs2; use costs_2_testnet::Costs2Testnet; @@ -215,7 +216,7 @@ impl DefaultVersion { }; r.map_err(|e| { let e = match e { - crate::vm::errors::Error::Runtime(RuntimeErrorType::NotImplemented, _) => { + VmExecutionError::Runtime(RuntimeErrorType::NotImplemented, _) => { CheckErrors::UndefinedFunction(cost_function_ref.function_name.clone()).into() } other => other, diff --git a/clarity/src/vm/coverage.rs b/clarity/src/vm/coverage.rs index 15f41b6693a..afbf45a87aa 100644 --- a/clarity/src/vm/coverage.rs +++ b/clarity/src/vm/coverage.rs @@ -241,7 +241,7 @@ impl EvalHook for CoverageReporter { _env: &mut crate::vm::Environment, _context: &crate::vm::LocalContext, _expr: &SymbolicExpression, - _res: &core::result::Result, + _res: &core::result::Result, ) { } diff --git a/clarity/src/vm/database/clarity_db.rs b/clarity/src/vm/database/clarity_db.rs index a895b00ddb3..ea9b2c3e201 100644 --- a/clarity/src/vm/database/clarity_db.rs +++ b/clarity/src/vm/database/clarity_db.rs @@ -38,7 +38,7 @@ use crate::vm::database::structures::{ }; use crate::vm::database::{ClarityBackingStore, RollbackWrapper}; use crate::vm::errors::{ - CheckErrors, Error, InterpreterError, InterpreterResult as Result, RuntimeErrorType, + CheckErrors, InterpreterError, InterpreterResult as Result, RuntimeErrorType, VmExecutionError, }; use crate::vm::representations::ClarityName; use crate::vm::types::serialization::NONE_SERIALIZATION_LEN; @@ -693,7 +693,10 @@ impl<'a> ClarityDatabase<'a> { data: &str, ) -> Result<()> { if self.store.has_metadata_entry(contract_identifier, key) { - Err(Error::Runtime(RuntimeErrorType::MetadataAlreadySet, None)) + Err(VmExecutionError::Runtime( + RuntimeErrorType::MetadataAlreadySet, + None, + )) } else { Ok(self.store.insert_metadata(contract_identifier, key, data)?) } @@ -984,7 +987,7 @@ impl<'a> ClarityDatabase<'a> { /// transactions in the block. pub fn set_tenure_height(&mut self, height: u32) -> Result<()> { if self.get_clarity_epoch_version()? < StacksEpochId::Epoch30 { - return Err(Error::Interpreter(InterpreterError::Expect( + return Err(VmExecutionError::Interpreter(InterpreterError::Expect( "Setting tenure height in Clarity state is not supported before epoch 3.0".into(), ))); } @@ -1485,7 +1488,7 @@ impl ClarityDatabase<'_> { // will throw NoSuchFoo errors instead of NoSuchContract errors. fn map_no_contract_as_none(res: Result>) -> Result> { res.or_else(|e| match e { - Error::Unchecked(CheckErrors::NoSuchContract(_)) => Ok(None), + VmExecutionError::Unchecked(CheckErrors::NoSuchContract(_)) => Ok(None), x => Err(x), }) } diff --git a/clarity/src/vm/database/structures.rs b/clarity/src/vm/database/structures.rs index c4fec9f382e..05de5ae862e 100644 --- a/clarity/src/vm/database/structures.rs +++ b/clarity/src/vm/database/structures.rs @@ -22,7 +22,7 @@ use stacks_common::util::hash::{hex_bytes, to_hex}; use crate::vm::analysis::ContractAnalysis; use crate::vm::contracts::Contract; use crate::vm::database::ClarityDatabase; -use crate::vm::errors::{Error, InterpreterError, RuntimeErrorType}; +use crate::vm::errors::{InterpreterError, RuntimeErrorType, VmExecutionError}; use crate::vm::types::{PrincipalData, TypeSignature}; pub trait ClaritySerializable { @@ -30,7 +30,7 @@ pub trait ClaritySerializable { } pub trait ClarityDeserializable { - fn deserialize(json: &str) -> Result; + fn deserialize(json: &str) -> Result; } impl ClaritySerializable for String { @@ -40,7 +40,7 @@ impl ClaritySerializable for String { } impl ClarityDeserializable for String { - fn deserialize(serialized: &str) -> Result { + fn deserialize(serialized: &str) -> Result { Ok(serialized.into()) } } @@ -54,7 +54,7 @@ macro_rules! clarity_serializable { } impl ClarityDeserializable<$Name> for $Name { #[cfg(not(target_family = "wasm"))] - fn deserialize(json: &str) -> Result { + fn deserialize(json: &str) -> Result { let mut deserializer = serde_json::Deserializer::from_str(&json); // serde's default 128 depth limit can be exhausted // by a 64-stack-depth AST, so disable the recursion limit @@ -67,7 +67,7 @@ macro_rules! clarity_serializable { }) } #[cfg(target_family = "wasm")] - fn deserialize(json: &str) -> Result { + fn deserialize(json: &str) -> Result { serde_json::from_str(json).map_err(|_| { InterpreterError::Expect("Failed to deserialize vm.Value".into()).into() }) @@ -257,7 +257,7 @@ impl ClaritySerializable for STXBalance { } impl ClarityDeserializable for STXBalance { - fn deserialize(input: &str) -> Result { + fn deserialize(input: &str) -> Result { let bytes = hex_bytes(input).map_err(|_| { InterpreterError::Expect("STXBalance deserialization: failed decoding bytes.".into()) })?; @@ -374,12 +374,16 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { &self.balance } - pub fn save(self) -> Result<(), Error> { + pub fn save(self) -> Result<(), VmExecutionError> { let key = ClarityDatabase::make_key_for_account_balance(&self.principal); self.db_ref.put_data(&key, &self.balance) } - pub fn transfer_to(mut self, recipient: &PrincipalData, amount: u128) -> Result<(), Error> { + pub fn transfer_to( + mut self, + recipient: &PrincipalData, + amount: u128, + ) -> Result<(), VmExecutionError> { if !self.can_transfer(amount)? { return Err(InterpreterError::InsufficientBalance.into()); } @@ -392,7 +396,10 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { recipient_balance .checked_add_unlocked_amount(amount) - .ok_or(Error::Runtime(RuntimeErrorType::ArithmeticOverflow, None))?; + .ok_or(VmExecutionError::Runtime( + RuntimeErrorType::ArithmeticOverflow, + None, + ))?; self.debit(amount)?; self.db_ref.put_data(&recipient_key, &recipient_balance)?; @@ -400,7 +407,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { Ok(()) } - pub fn get_available_balance(&mut self) -> Result { + pub fn get_available_balance(&mut self) -> Result { let v1_unlock_height = self.db_ref.get_v1_unlock_height(); let v2_unlock_height = self.db_ref.get_v2_unlock_height()?; let v3_unlock_height = self.db_ref.get_v3_unlock_height()?; @@ -412,7 +419,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { ) } - pub fn canonical_balance_repr(&mut self) -> Result { + pub fn canonical_balance_repr(&mut self) -> Result { let v1_unlock_height = self.db_ref.get_v1_unlock_height(); let v2_unlock_height = self.db_ref.get_v2_unlock_height()?; let v3_unlock_height = self.db_ref.get_v3_unlock_height()?; @@ -427,7 +434,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { .0) } - pub fn has_locked_tokens(&mut self) -> Result { + pub fn has_locked_tokens(&mut self) -> Result { let v1_unlock_height = self.db_ref.get_v1_unlock_height(); let v2_unlock_height = self.db_ref.get_v2_unlock_height()?; let v3_unlock_height = self.db_ref.get_v3_unlock_height()?; @@ -439,7 +446,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { )) } - pub fn has_unlockable_tokens(&mut self) -> Result { + pub fn has_unlockable_tokens(&mut self) -> Result { let v1_unlock_height = self.db_ref.get_v1_unlock_height(); let v2_unlock_height = self.db_ref.get_v2_unlock_height()?; let v3_unlock_height = self.db_ref.get_v3_unlock_height()?; @@ -451,11 +458,11 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { )) } - pub fn can_transfer(&mut self, amount: u128) -> Result { + pub fn can_transfer(&mut self, amount: u128) -> Result { Ok(self.get_available_balance()? >= amount) } - pub fn debit(&mut self, amount: u128) -> Result<(), Error> { + pub fn debit(&mut self, amount: u128) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-debit"); @@ -464,7 +471,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { self.balance.debit_unlocked_amount(amount) } - pub fn credit(&mut self, amount: u128) -> Result<(), Error> { + pub fn credit(&mut self, amount: u128) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-credit"); @@ -484,7 +491,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { &mut self, amount_to_lock: u128, unlock_burn_height: u64, - ) -> Result<(), Error> { + ) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-token-lock"); @@ -530,7 +537,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Return true iff `self` represents a snapshot that has a lock /// created by PoX v2. - pub fn is_v2_locked(&mut self) -> Result { + pub fn is_v2_locked(&mut self) -> Result { match self.canonical_balance_repr()? { STXBalance::LockedPoxTwo { .. } => Ok(true), _ => Ok(false), @@ -539,7 +546,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Increase the account's current lock to `new_total_locked`. /// Panics if `self` was not locked by V2 PoX. - pub fn increase_lock_v2(&mut self, new_total_locked: u128) -> Result<(), Error> { + pub fn increase_lock_v2(&mut self, new_total_locked: u128) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -588,7 +595,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Extend this account's current lock to `unlock_burn_height`. /// After calling, this method will set the balance to a "LockedPoxTwo" balance, /// because this method is only invoked as a result of PoX2 interactions - pub fn extend_lock_v2(&mut self, unlock_burn_height: u64) -> Result<(), Error> { + pub fn extend_lock_v2(&mut self, unlock_burn_height: u64) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -625,7 +632,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { &mut self, amount_to_lock: u128, unlock_burn_height: u64, - ) -> Result<(), Error> { + ) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-token-lock"); @@ -678,7 +685,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { &mut self, amount_to_lock: u128, unlock_burn_height: u64, - ) -> Result<(), Error> { + ) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-token-lock"); @@ -728,7 +735,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Extend this account's current lock to `unlock_burn_height`. /// After calling, this method will set the balance to a "LockedPoxThree" balance, /// because this method is only invoked as a result of PoX3 interactions - pub fn extend_lock_v3(&mut self, unlock_burn_height: u64) -> Result<(), Error> { + pub fn extend_lock_v3(&mut self, unlock_burn_height: u64) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -760,7 +767,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Increase the account's current lock to `new_total_locked`. /// Panics if `self` was not locked by V3 PoX. - pub fn increase_lock_v3(&mut self, new_total_locked: u128) -> Result<(), Error> { + pub fn increase_lock_v3(&mut self, new_total_locked: u128) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -805,7 +812,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Return true iff `self` represents a snapshot that has a lock /// created by PoX v3. - pub fn is_v3_locked(&mut self) -> Result { + pub fn is_v3_locked(&mut self) -> Result { match self.canonical_balance_repr()? { STXBalance::LockedPoxThree { .. } => Ok(true), _ => Ok(false), @@ -821,7 +828,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { &mut self, amount_to_lock: u128, unlock_burn_height: u64, - ) -> Result<(), Error> { + ) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-token-lock"); @@ -860,7 +867,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Extend this account's current lock to `unlock_burn_height`. /// After calling, this method will set the balance to a "LockedPoxFour" balance, /// because this method is only invoked as a result of PoX3 interactions - pub fn extend_lock_v4(&mut self, unlock_burn_height: u64) -> Result<(), Error> { + pub fn extend_lock_v4(&mut self, unlock_burn_height: u64) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -886,7 +893,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Increase the account's current lock to `new_total_locked`. /// Panics if `self` was not locked by V3 PoX. - pub fn increase_lock_v4(&mut self, new_total_locked: u128) -> Result<(), Error> { + pub fn increase_lock_v4(&mut self, new_total_locked: u128) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -926,7 +933,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Return true iff `self` represents a snapshot that has a lock /// created by PoX v3. - pub fn is_v4_locked(&mut self) -> Result { + pub fn is_v4_locked(&mut self) -> Result { match self.canonical_balance_repr()? { STXBalance::LockedPoxFour { .. } => Ok(true), _ => Ok(false), @@ -937,7 +944,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// If this snapshot is locked, then alter the lock height to be /// the next burn block (i.e., `self.burn_block_height + 1`) - pub fn accelerate_unlock(&mut self) -> Result<(), Error> { + pub fn accelerate_unlock(&mut self) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-token-lock"); @@ -985,7 +992,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Unlock any tokens that are unlockable at the current /// burn block height, and return the amount newly unlocked - fn unlock_available_tokens_if_any(&mut self) -> Result { + fn unlock_available_tokens_if_any(&mut self) -> Result { let (new_balance, unlocked) = self.balance.canonical_repr_at_block( self.burn_block_height, self.db_ref.get_v1_unlock_height(), @@ -1102,7 +1109,7 @@ impl STXBalance { } } - fn debit_unlocked_amount(&mut self, delta: u128) -> Result<(), Error> { + fn debit_unlocked_amount(&mut self, delta: u128) -> Result<(), VmExecutionError> { match self { STXBalance::Unlocked { amount: amount_unlocked, @@ -1164,7 +1171,7 @@ impl STXBalance { v1_unlock_height: u32, v2_unlock_height: u32, v3_unlock_height: u32, - ) -> Result<(STXBalance, u128), Error> { + ) -> Result<(STXBalance, u128), VmExecutionError> { if self.has_unlockable_tokens_at_burn_block( burn_block_height, v1_unlock_height, @@ -1188,7 +1195,7 @@ impl STXBalance { v1_unlock_height: u32, v2_unlock_height: u32, v3_unlock_height: u32, - ) -> Result { + ) -> Result { if self.has_unlockable_tokens_at_burn_block( burn_block_height, v1_unlock_height, @@ -1257,7 +1264,7 @@ impl STXBalance { } } - pub fn get_total_balance(&self) -> Result { + pub fn get_total_balance(&self) -> Result { let (unlocked, locked) = match self { STXBalance::Unlocked { amount } => (*amount, 0), STXBalance::LockedPoxOne { @@ -1462,7 +1469,7 @@ impl STXBalance { v1_unlock_height: u32, v2_unlock_height: u32, v3_unlock_height: u32, - ) -> Result { + ) -> Result { Ok(self.get_available_balance_at_burn_block( burn_block_height, v1_unlock_height, diff --git a/clarity/src/vm/docs/contracts.rs b/clarity/src/vm/docs/contracts.rs index 2cb8b2c4033..2438ba67651 100644 --- a/clarity/src/vm/docs/contracts.rs +++ b/clarity/src/vm/docs/contracts.rs @@ -67,7 +67,7 @@ fn get_constant_value(var_name: &str, contract_content: &str) -> Value { .expect("BUG: failed to return constant value") } -fn doc_execute(program: &str) -> Result, vm::Error> { +fn doc_execute(program: &str) -> Result, vm::VmExecutionError> { let contract_id = QualifiedContractIdentifier::transient(); let mut contract_context = ContractContext::new(contract_id.clone(), ClarityVersion::Clarity2); let mut marf = MemoryBackingStore::new(); diff --git a/clarity/src/vm/errors.rs b/clarity/src/vm/errors.rs index 764ac466e5c..1a7740ce3d3 100644 --- a/clarity/src/vm/errors.rs +++ b/clarity/src/vm/errors.rs @@ -15,8 +15,8 @@ // along with this program. If not, see . pub use clarity_types::errors::{ - Error, IncomparableError, InterpreterError, InterpreterResult, RuntimeErrorType, - ShortReturnType, + IncomparableError, InterpreterError, InterpreterResult, RuntimeErrorType, ShortReturnType, + VmExecutionError, }; pub use crate::vm::analysis::errors::{ diff --git a/clarity/src/vm/functions/assets.rs b/clarity/src/vm/functions/assets.rs index 62763fa3fc0..a42b39bc341 100644 --- a/clarity/src/vm/functions/assets.rs +++ b/clarity/src/vm/functions/assets.rs @@ -20,8 +20,8 @@ use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{runtime_cost, CostTracker}; use crate::vm::database::STXBalance; use crate::vm::errors::{ - check_argument_count, CheckErrors, Error, InterpreterError, InterpreterResult as Result, - RuntimeErrorType, + check_argument_count, CheckErrors, InterpreterError, InterpreterResult as Result, + RuntimeErrorType, VmExecutionError, }; use crate::vm::representations::SymbolicExpression; use crate::vm::types::{ @@ -418,7 +418,7 @@ pub fn special_mint_asset_v200( &asset, expected_asset_type, ) { - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(()), + Err(VmExecutionError::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(()), Ok(_owner) => return clarity_ecode!(MintAssetErrorCodes::ALREADY_EXIST), Err(e) => Err(e), }?; @@ -492,7 +492,7 @@ pub fn special_mint_asset_v205( &asset, expected_asset_type, ) { - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(()), + Err(VmExecutionError::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(()), Ok(_owner) => return clarity_ecode!(MintAssetErrorCodes::ALREADY_EXIST), Err(e) => Err(e), }?; @@ -571,7 +571,7 @@ pub fn special_transfer_asset_v200( expected_asset_type, ) { Ok(owner) => Ok(owner), - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => { + Err(VmExecutionError::Runtime(RuntimeErrorType::NoSuchToken, _)) => { return clarity_ecode!(TransferAssetErrorCodes::DOES_NOT_EXIST) } Err(e) => Err(e), @@ -665,7 +665,7 @@ pub fn special_transfer_asset_v205( expected_asset_type, ) { Ok(owner) => Ok(owner), - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => { + Err(VmExecutionError::Runtime(RuntimeErrorType::NoSuchToken, _)) => { return clarity_ecode!(TransferAssetErrorCodes::DOES_NOT_EXIST) } Err(e) => Err(e), @@ -889,7 +889,7 @@ pub fn special_get_owner_v200( Ok(owner) => Ok(Value::some(Value::Principal(owner)).map_err(|_| { InterpreterError::Expect("Principal should always fit in optional.".into()) })?), - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(Value::none()), + Err(VmExecutionError::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(Value::none()), Err(e) => Err(e), } } @@ -936,7 +936,7 @@ pub fn special_get_owner_v205( Ok(owner) => Ok(Value::some(Value::Principal(owner)).map_err(|_| { InterpreterError::Expect("Principal should always fit in optional.".into()) })?), - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(Value::none()), + Err(VmExecutionError::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(Value::none()), Err(e) => Err(e), } } @@ -1068,7 +1068,7 @@ pub fn special_burn_asset_v200( &asset, expected_asset_type, ) { - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => { + Err(VmExecutionError::Runtime(RuntimeErrorType::NoSuchToken, _)) => { return clarity_ecode!(BurnAssetErrorCodes::DOES_NOT_EXIST) } Ok(owner) => Ok(owner), @@ -1156,7 +1156,7 @@ pub fn special_burn_asset_v205( &asset, expected_asset_type, ) { - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => { + Err(VmExecutionError::Runtime(RuntimeErrorType::NoSuchToken, _)) => { return clarity_ecode!(BurnAssetErrorCodes::DOES_NOT_EXIST) } Ok(owner) => Ok(owner), diff --git a/clarity/src/vm/functions/mod.rs b/clarity/src/vm/functions/mod.rs index f458c282e6c..d9b76f99355 100644 --- a/clarity/src/vm/functions/mod.rs +++ b/clarity/src/vm/functions/mod.rs @@ -20,8 +20,8 @@ use crate::vm::callables::{cost_input_sized_vararg, CallableType, NativeHandle}; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{constants as cost_constants, runtime_cost, CostTracker, MemoryConsumer}; use crate::vm::errors::{ - check_argument_count, check_arguments_at_least, CheckErrors, Error, - InterpreterResult as Result, ShortReturnType, SyntaxBindingError, SyntaxBindingErrorType, + check_argument_count, check_arguments_at_least, CheckErrors, InterpreterResult as Result, + ShortReturnType, SyntaxBindingError, SyntaxBindingErrorType, VmExecutionError, }; pub use crate::vm::functions::assets::stx_transfer_consolidated; use crate::vm::representations::{ClarityName, SymbolicExpression, SymbolicExpressionType}; @@ -749,7 +749,7 @@ fn special_let( let mut memory_use = 0; finally_drop_memory!( env, memory_use; { - handle_binding_list::<_, Error>(bindings, SyntaxBindingErrorType::Let, |binding_name, var_sexp| { + handle_binding_list::<_, VmExecutionError>(bindings, SyntaxBindingErrorType::Let, |binding_name, var_sexp| { if is_reserved(binding_name, env.contract_context.get_clarity_version()) || env.contract_context.lookup_function(binding_name).is_some() || inner_context.lookup_variable(binding_name).is_some() { diff --git a/clarity/src/vm/mod.rs b/clarity/src/vm/mod.rs index 781c7d4d7ba..18452fd2e49 100644 --- a/clarity/src/vm/mod.rs +++ b/clarity/src/vm/mod.rs @@ -73,7 +73,7 @@ use crate::vm::costs::{ // publish the non-generic StacksEpoch form for use throughout module pub use crate::vm::database::clarity_db::StacksEpoch; use crate::vm::errors::{ - CheckErrors, Error, InterpreterError, InterpreterResult as Result, RuntimeErrorType, + CheckErrors, InterpreterError, InterpreterResult as Result, RuntimeErrorType, VmExecutionError, }; use crate::vm::events::StacksTransactionEvent; use crate::vm::functions::define::DefineResult; @@ -155,7 +155,7 @@ pub trait EvalHook { _env: &mut Environment, _context: &LocalContext, _expr: &SymbolicExpression, - _res: &core::result::Result, + _res: &core::result::Result, ); // Called upon completion of the execution @@ -214,7 +214,7 @@ pub fn lookup_function(name: &str, env: &mut Environment) -> Result, env: &Environment) { - if let Err(Error::Runtime(_, ref mut stack_trace)) = result { + if let Err(VmExecutionError::Runtime(_, ref mut stack_trace)) = result { if stack_trace.is_none() { stack_trace.replace(env.call_stack.make_stack_trace()); } @@ -266,7 +266,7 @@ pub fn apply( Err(e) => { env.drop_memory(used_memory)?; env.call_stack.decr_apply_depth(); - return Err(Error::from(e)); + return Err(VmExecutionError::from(e)); } }; used_memory += arg_value.get_memory_use()?; @@ -278,7 +278,7 @@ pub fn apply( let mut resp = match function { CallableType::NativeFunction(_, function, cost_function) => { runtime_cost(cost_function.clone(), env, evaluated_args.len()) - .map_err(Error::from) + .map_err(VmExecutionError::from) .and_then(|_| function.apply(evaluated_args, env)) } CallableType::NativeFunction205(_, function, cost_function, cost_input_handle) => { @@ -288,7 +288,7 @@ pub fn apply( evaluated_args.len() as u64 }; runtime_cost(cost_function.clone(), env, cost_input) - .map_err(Error::from) + .map_err(VmExecutionError::from) .and_then(|_| function.apply(evaluated_args, env)) } CallableType::UserFunction(function) => function.apply(&evaluated_args, env), diff --git a/clarity/src/vm/tests/assets.rs b/clarity/src/vm/tests/assets.rs index 0cfeebfb274..c41cd85ef1a 100644 --- a/clarity/src/vm/tests/assets.rs +++ b/clarity/src/vm/tests/assets.rs @@ -17,7 +17,7 @@ use stacks_common::types::StacksEpochId; use crate::vm::contexts::{AssetMap, OwnedEnvironment}; -use crate::vm::errors::Error; +use crate::vm::errors::VmExecutionError; use crate::vm::events::StacksTransactionEvent; use crate::vm::representations::SymbolicExpression; use crate::vm::tests::{test_clarity_versions, test_epochs}; @@ -137,7 +137,7 @@ fn execute_transaction( contract_identifier: &QualifiedContractIdentifier, tx: &str, args: &[SymbolicExpression], -) -> Result<(Value, AssetMap, Vec), Error> { +) -> Result<(Value, AssetMap, Vec), VmExecutionError> { env.execute_transaction(issuer, None, contract_identifier.clone(), tx, args) } @@ -622,7 +622,7 @@ fn test_simple_token_system( assert!(matches!( err, - Error::Unchecked(CheckErrors::TypeValueError(_, _)) + VmExecutionError::Unchecked(CheckErrors::TypeValueError(_, _)) )); let (result, asset_map, _events) = execute_transaction( @@ -856,7 +856,7 @@ fn test_total_supply(epoch: StacksEpochId, mut env_factory: TopLevelMemoryEnviro .unwrap_err(); assert!(matches!( err, - Error::Unchecked(CheckErrors::TypeValueError(_, _)) + VmExecutionError::Unchecked(CheckErrors::TypeValueError(_, _)) )); let err = owned_env @@ -869,7 +869,7 @@ fn test_total_supply(epoch: StacksEpochId, mut env_factory: TopLevelMemoryEnviro .unwrap_err(); assert!(matches!( err, - Error::Unchecked(CheckErrors::TypeValueError(_, _)) + VmExecutionError::Unchecked(CheckErrors::TypeValueError(_, _)) )); owned_env @@ -921,7 +921,7 @@ fn test_total_supply(epoch: StacksEpochId, mut env_factory: TopLevelMemoryEnviro .unwrap_err(); println!("{err}"); assert!(match err { - Error::Runtime(RuntimeErrorType::SupplyOverflow(x, y), _) => (x, y) == (6, 5), + VmExecutionError::Runtime(RuntimeErrorType::SupplyOverflow(x, y), _) => (x, y) == (6, 5), _ => false, }); } diff --git a/clarity/src/vm/tests/contracts.rs b/clarity/src/vm/tests/contracts.rs index da9d4f37318..3cfdecf8236 100644 --- a/clarity/src/vm/tests/contracts.rs +++ b/clarity/src/vm/tests/contracts.rs @@ -27,7 +27,7 @@ use crate::vm::types::{PrincipalData, QualifiedContractIdentifier, StandardPrinc #[cfg(test)] use crate::vm::{ ast::{errors::ParseErrors, ASTRules}, - errors::{CheckErrors, Error, RuntimeErrorType}, + errors::{CheckErrors, RuntimeErrorType, VmExecutionError}, tests::{ env_factory, execute, is_committed, is_err_code_i128 as is_err_code, symbols_from_values, tl_env_factory, MemoryEnvironmentGenerator, TopLevelMemoryEnvironmentGenerator, @@ -972,7 +972,7 @@ fn test_factorial_contract(epoch: StacksEpochId, mut env_factory: MemoryEnvironm .unwrap_err(); assert!(matches!( err_result, - Error::Unchecked(CheckErrors::NoSuchPublicFunction(_, _)) + VmExecutionError::Unchecked(CheckErrors::NoSuchPublicFunction(_, _)) )); let err_result = env @@ -985,7 +985,7 @@ fn test_factorial_contract(epoch: StacksEpochId, mut env_factory: MemoryEnvironm .unwrap_err(); assert!(matches!( err_result, - Error::Unchecked(CheckErrors::TypeValueError(_, _)) + VmExecutionError::Unchecked(CheckErrors::TypeValueError(_, _)) )); } @@ -1008,7 +1008,7 @@ fn test_at_unknown_block( .unwrap_err(); eprintln!("{err}"); match err { - Error::Runtime(x, _) => assert_eq!( + VmExecutionError::Runtime(x, _) => assert_eq!( x, RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash::from( vec![2_u8; 32].as_slice() @@ -1180,7 +1180,7 @@ fn test_eval_with_non_existing_contract( ); assert_eq!( result.as_ref().unwrap_err(), - &Error::Unchecked(CheckErrors::NoSuchContract( + &VmExecutionError::Unchecked(CheckErrors::NoSuchContract( QualifiedContractIdentifier::local("absent") .unwrap() .to_string() @@ -1382,7 +1382,7 @@ fn test_contract_hash_type_check( .unwrap_err(); assert_eq!( err, - Error::Unchecked(CheckErrors::ExpectedContractPrincipalValue(Box::new( + VmExecutionError::Unchecked(CheckErrors::ExpectedContractPrincipalValue(Box::new( Value::UInt(123) ))) ); @@ -1440,6 +1440,6 @@ fn test_contract_hash_pre_clarity4( assert_eq!( err, - Error::Unchecked(CheckErrors::UndefinedFunction("contract-hash?".to_string())) + VmExecutionError::Unchecked(CheckErrors::UndefinedFunction("contract-hash?".to_string())) ); } diff --git a/clarity/src/vm/tests/datamaps.rs b/clarity/src/vm/tests/datamaps.rs index 83fef9ab764..6f2be1c01c5 100644 --- a/clarity/src/vm/tests/datamaps.rs +++ b/clarity/src/vm/tests/datamaps.rs @@ -19,9 +19,9 @@ use crate::vm::{ errors::{CheckErrors, ShortReturnType, SyntaxBindingError}, types::{ListData, SequenceData, TupleTypeSignature, TypeSignature}, }; -use crate::vm::{execute, ClarityName, Error}; +use crate::vm::{execute, ClarityName, VmExecutionError}; -fn assert_executes(expected: Result, input: &str) { +fn assert_executes(expected: Result, input: &str) { assert_eq!(expected.unwrap(), execute(input).unwrap().unwrap()); } @@ -495,7 +495,7 @@ fn lists_system_2() { matches!( execute(test), - Err(Error::Unchecked(CheckErrors::TypeError(_, _))) + Err(VmExecutionError::Unchecked(CheckErrors::TypeError(_, _))) ); } @@ -560,7 +560,10 @@ fn lists_system() { println!("{test:#?}"); assert!(matches!( test, - Err(Error::Unchecked(CheckErrors::TypeValueError(_, _))) + Err(VmExecutionError::Unchecked(CheckErrors::TypeValueError( + _, + _ + ))) )); } } @@ -623,7 +626,7 @@ fn tuples_system() { for test in type_error_tests.iter() { let expected_type_error = match execute(test) { - Err(Error::Unchecked(CheckErrors::TypeValueError(_, _))) => true, + Err(VmExecutionError::Unchecked(CheckErrors::TypeValueError(_, _))) => true, _ => { println!("{:?}", execute(test)); false @@ -643,7 +646,7 @@ fn bad_define_maps() { "(define-map lists { name: int } contents 5)", "(define-map lists { name: int } { contents: (list 5 0 int) })", ]; - let expected: Vec = vec![ + let expected: Vec = vec![ CheckErrors::BadSyntaxBinding(SyntaxBindingError::tuple_cons_invalid_length(0)).into(), CheckErrors::UnknownTypeName("contents".to_string()).into(), CheckErrors::ExpectedName.into(), @@ -769,7 +772,7 @@ fn test_non_tuple_map_get_set() { for test in type_error_tests.iter() { let expected_type_error = match execute(test) { - Err(Error::Unchecked(CheckErrors::TypeValueError(_, _))) => true, + Err(VmExecutionError::Unchecked(CheckErrors::TypeValueError(_, _))) => true, _ => { println!("{:?}", execute(test)); false diff --git a/clarity/src/vm/tests/defines.rs b/clarity/src/vm/tests/defines.rs index 2cd874f2c31..71639778abb 100644 --- a/clarity/src/vm/tests/defines.rs +++ b/clarity/src/vm/tests/defines.rs @@ -21,7 +21,7 @@ use rstest_reuse::{self, *}; #[cfg(test)] use stacks_common::types::StacksEpochId; -use crate::vm::errors::{CheckErrors, Error}; +use crate::vm::errors::{CheckErrors, VmExecutionError}; use crate::vm::tests::test_clarity_versions; #[cfg(test)] use crate::vm::{ @@ -32,8 +32,8 @@ use crate::vm::{ {execute, ClarityVersion}, }; -fn assert_eq_err(e1: CheckErrors, e2: Error) { - let e1: Error = e1.into(); +fn assert_eq_err(e1: CheckErrors, e2: VmExecutionError) { + let e1: VmExecutionError = e1.into(); assert_eq!(e1, e2) } @@ -67,7 +67,7 @@ fn test_accept_options(#[case] version: ClarityVersion, #[case] epoch: StacksEpo format!("{defun} (f (some 1))"), format!("{defun} (f (some true))"), ]; - let expectations: &[Result<_, Error>] = &[ + let expectations: &[Result<_, VmExecutionError>] = &[ Ok(Some(Value::Int(0))), Ok(Some(Value::Int(10))), Err(CheckErrors::TypeValueError( @@ -187,7 +187,10 @@ fn test_stack_depth() { assert_eq!(Ok(Some(Value::Int(64))), execute(&test0)); assert!(matches!( execute(&test1), - Err(Error::Runtime(RuntimeErrorType::MaxStackDepthReached, _)) + Err(VmExecutionError::Runtime( + RuntimeErrorType::MaxStackDepthReached, + _ + )) )) } @@ -474,18 +477,18 @@ fn test_define_trait_arg_count() { // These errors are hit in the trait resolver, before reaching the type-checker match execute(test0).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) + VmExecutionError::Runtime(RuntimeErrorType::ASTError(parse_err), _) if *parse_err.err == ParseErrors::DefineTraitBadSignature => {} e => panic!("{e:?}"), }; match execute(test1).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) + VmExecutionError::Runtime(RuntimeErrorType::ASTError(parse_err), _) if *parse_err.err == ParseErrors::DefineTraitBadSignature => {} e => panic!("{e}"), }; execute(test2).unwrap(); match execute(test3).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) + VmExecutionError::Runtime(RuntimeErrorType::ASTError(parse_err), _) if *parse_err.err == ParseErrors::DefineTraitBadSignature => {} e => panic!("{e}"), }; @@ -500,18 +503,18 @@ fn test_use_trait_arg_count() { // These errors are hit in the trait resolver, before reaching the type-checker match execute(test0).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) + VmExecutionError::Runtime(RuntimeErrorType::ASTError(parse_err), _) if *parse_err.err == ParseErrors::ImportTraitBadSignature => {} e => panic!("{e:?}"), }; match execute(test1).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) + VmExecutionError::Runtime(RuntimeErrorType::ASTError(parse_err), _) if *parse_err.err == ParseErrors::ImportTraitBadSignature => {} e => panic!("{e}"), }; execute(test2).unwrap(); match execute(test3).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) + VmExecutionError::Runtime(RuntimeErrorType::ASTError(parse_err), _) if *parse_err.err == ParseErrors::ImportTraitBadSignature => {} e => panic!("{e}"), }; @@ -525,13 +528,13 @@ fn test_impl_trait_arg_count() { // These errors are hit in the trait resolver, before reaching the type-checker match execute(test0).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) + VmExecutionError::Runtime(RuntimeErrorType::ASTError(parse_err), _) if *parse_err.err == ParseErrors::ImplTraitBadSignature => {} e => panic!("{e:?}"), }; execute(test1).unwrap(); match execute(test2).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) + VmExecutionError::Runtime(RuntimeErrorType::ASTError(parse_err), _) if *parse_err.err == ParseErrors::ImplTraitBadSignature => {} e => panic!("{e}"), }; diff --git a/clarity/src/vm/tests/sequences.rs b/clarity/src/vm/tests/sequences.rs index 3ea779b7d67..d6e84aaa7be 100644 --- a/clarity/src/vm/tests/sequences.rs +++ b/clarity/src/vm/tests/sequences.rs @@ -22,7 +22,7 @@ use stacks_common::types::StacksEpochId; use crate::vm::tests::test_clarity_versions; #[cfg(test)] use crate::vm::{ - errors::{CheckErrors, Error, RuntimeErrorType}, + errors::{CheckErrors, RuntimeErrorType, VmExecutionError}, execute, execute_v2, types::{ signatures::{ @@ -59,7 +59,7 @@ fn test_simple_list_admission() { ); let err = execute(&t3).unwrap_err(); assert!(match err { - Error::Unchecked(CheckErrors::TypeValueError(_, _)) => true, + VmExecutionError::Unchecked(CheckErrors::TypeValueError(_, _)) => true, _ => { eprintln!("Expected TypeError, but found: {err:?}"); false @@ -129,7 +129,7 @@ fn test_index_of() { for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { match execute(bad_test).unwrap_err() { - Error::Unchecked(check_error) => { + VmExecutionError::Unchecked(check_error) => { assert_eq!(&check_error, expected); } _ => unreachable!("Should have raised unchecked errors"), @@ -179,7 +179,7 @@ fn test_element_at() { for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { match execute(bad_test).unwrap_err() { - Error::Unchecked(check_error) => { + VmExecutionError::Unchecked(check_error) => { assert_eq!(&check_error, expected); } _ => unreachable!("Should have raised unchecked errors"), @@ -1205,23 +1205,23 @@ fn test_construct_bad_list(#[case] version: ClarityVersion, #[case] epoch: Stack #[test] fn test_eval_func_arg_panic() { let test1 = "(fold (lambda (x y) (* x y)) (list 1 2 3 4) 1)"; - let e: Error = CheckErrors::ExpectedName.into(); + let e: VmExecutionError = CheckErrors::ExpectedName.into(); assert_eq!(e, execute(test1).unwrap_err()); let test2 = "(map (lambda (x) (* x x)) (list 1 2 3 4))"; - let e: Error = CheckErrors::ExpectedName.into(); + let e: VmExecutionError = CheckErrors::ExpectedName.into(); assert_eq!(e, execute(test2).unwrap_err()); let test3 = "(map square (list 1 2 3 4) 2)"; - let e: Error = CheckErrors::UndefinedFunction("square".to_string()).into(); + let e: VmExecutionError = CheckErrors::UndefinedFunction("square".to_string()).into(); assert_eq!(e, execute(test3).unwrap_err()); let test4 = "(define-private (multiply-all (x int) (acc int)) (* x acc)) (fold multiply-all (list 1 2 3 4))"; - let e: Error = CheckErrors::IncorrectArgumentCount(3, 2).into(); + let e: VmExecutionError = CheckErrors::IncorrectArgumentCount(3, 2).into(); assert_eq!(e, execute(test4).unwrap_err()); let test5 = "(map + (list 1 2 3 4) 2)"; - let e: Error = CheckErrors::ExpectedSequence(Box::new(IntType)).into(); + let e: VmExecutionError = CheckErrors::ExpectedSequence(Box::new(IntType)).into(); assert_eq!(e, execute(test5).unwrap_err()); } diff --git a/clarity/src/vm/tests/simple_apply_eval.rs b/clarity/src/vm/tests/simple_apply_eval.rs index 53558e3548f..368ea21175f 100644 --- a/clarity/src/vm/tests/simple_apply_eval.rs +++ b/clarity/src/vm/tests/simple_apply_eval.rs @@ -31,7 +31,7 @@ use crate::vm::callables::DefinedFunction; use crate::vm::contexts::OwnedEnvironment; use crate::vm::costs::LimitedCostTracker; use crate::vm::database::MemoryBackingStore; -use crate::vm::errors::{CheckErrors, Error, RuntimeErrorType, ShortReturnType}; +use crate::vm::errors::{CheckErrors, RuntimeErrorType, ShortReturnType, VmExecutionError}; use crate::vm::tests::{execute, test_clarity_versions}; use crate::vm::types::signatures::*; use crate::vm::types::{ @@ -580,7 +580,7 @@ fn test_secp256k1_errors() { "(principal-of?)", ]; - let expectations: &[Error] = &[ + let expectations: &[VmExecutionError] = &[ CheckErrors::TypeValueError(Box::new(BUFF_32.clone()), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("de5b9eb9e7c5592930eb2e30a01369c36586d872082ed8181ee83d2a0ec20f").unwrap() })))).into(), CheckErrors::TypeValueError(Box::new(BUFF_65.clone()), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("8738487ebe69b93d8e51583be8eee50bb4213fc49c767d329632730cc193b873554428fc936ca3569afc15f1c9365f6591d6251a89fee9c9ac661116824d3a130100").unwrap() })))).into(), CheckErrors::IncorrectArgumentCount(2, 1).into(), @@ -877,7 +877,7 @@ fn test_sequence_comparisons_clarity1() { "(>= \"baa\" \"aaa\")", "(<= \"baa\" \"aaa\")", ]; - let error_expectations: &[Error] = &[ + let error_expectations: &[VmExecutionError] = &[ CheckErrors::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::Sequence(SequenceData::String(CharType::ASCII( @@ -988,7 +988,7 @@ fn test_sequence_comparisons_clarity2() { fn test_sequence_comparisons_mismatched_types() { // Tests that comparing objects of different types results in an error in Clarity1. let error_tests = ["(> 0 u1)", "(< 0 u1)"]; - let v1_error_expectations: &[Error] = &[ + let v1_error_expectations: &[VmExecutionError] = &[ CheckErrors::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::Int(0)), @@ -1009,7 +1009,7 @@ fn test_sequence_comparisons_mismatched_types() { assert_eq!(*expectation, vm_execute(program).unwrap_err()) }); - let v2_error_expectations: &[Error] = &[ + let v2_error_expectations: &[VmExecutionError] = &[ CheckErrors::UnionTypeValueError( vec![ TypeSignature::IntType, @@ -1043,7 +1043,7 @@ fn test_sequence_comparisons_mismatched_types() { // Tests that comparing objects of different types results in an error in Clarity2. let error_tests = ["(> \"baa\" u\"aaa\")", "(> \"baa\" 0x0001)"]; - let error_expectations: &[Error] = &[ + let error_expectations: &[VmExecutionError] = &[ CheckErrors::UnionTypeValueError( vec![ TypeSignature::IntType, @@ -1112,7 +1112,7 @@ fn test_simple_arithmetic_errors(#[case] version: ClarityVersion, #[case] epoch: "(is-eq (some 1) (some true))", ]; - let expectations: &[Error] = &[ + let expectations: &[VmExecutionError] = &[ CheckErrors::IncorrectArgumentCount(2, 1).into(), CheckErrors::TypeValueError( Box::new(TypeSignature::IntType), @@ -1167,7 +1167,7 @@ fn test_unsigned_arithmetic() { "(to-int (pow u2 u127))", ]; - let expectations: &[Error] = &[ + let expectations: &[VmExecutionError] = &[ RuntimeErrorType::ArithmeticUnderflow.into(), RuntimeErrorType::ArithmeticUnderflow.into(), CheckErrors::UnionTypeValueError( @@ -1206,7 +1206,7 @@ fn test_options_errors() { "(get field-0 1)", ]; - let expectations: &[Error] = &[ + let expectations: &[VmExecutionError] = &[ CheckErrors::IncorrectArgumentCount(1, 2).into(), CheckErrors::ExpectedOptionalValue(Box::new(Value::Bool(true))).into(), CheckErrors::IncorrectArgumentCount(1, 2).into(), @@ -1244,7 +1244,7 @@ fn test_stx_ops_errors() { "(stx-burn? 4 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR)", ]; - let expectations: &[Error] = &[ + let expectations: &[VmExecutionError] = &[ CheckErrors::IncorrectArgumentCount(3, 2).into(), CheckErrors::BadTransferSTXArguments.into(), CheckErrors::BadTransferSTXArguments.into(), @@ -1318,7 +1318,7 @@ fn test_bitwise() { "(bit-shift-left -64 u121)", // -170141183460469231731687303715884105728 ]; - let expectations: &[Result] = &[ + let expectations: &[Result] = &[ Ok(Value::Int(16)), // (bit-and 24 16) Ok(Value::UInt(16)), // (bit-and u24 u16) Ok(Value::Int(28)), // (bit-xor 24 4)y @@ -1423,7 +1423,7 @@ fn test_option_destructs() { "(try! 1)", ]; - let expectations: &[Result] = &[ + let expectations: &[Result] = &[ Ok(Value::Int(1)), Ok(Value::Int(1)), Err( @@ -1472,7 +1472,7 @@ fn test_hash_errors() { "(sha512/256 1 2)", ]; - let expectations: &[Error] = &[ + let expectations: &[VmExecutionError] = &[ CheckErrors::IncorrectArgumentCount(1, 2).into(), CheckErrors::IncorrectArgumentCount(1, 2).into(), CheckErrors::IncorrectArgumentCount(1, 2).into(), @@ -1573,7 +1573,7 @@ fn test_bad_lets() { "(let ((false 1)) false)", ]; - let expectations: &[Error] = &[ + let expectations: &[VmExecutionError] = &[ CheckErrors::NameAlreadyUsed("tx-sender".to_string()).into(), CheckErrors::NameAlreadyUsed("*".to_string()).into(), CheckErrors::NameAlreadyUsed("a".to_string()).into(), @@ -1674,11 +1674,11 @@ fn test_asserts_short_circuit() { "(begin (asserts! (is-eq 1 1) (err 0)) (asserts! (is-eq 2 1) (err 1)) (ok 2))", ]; - let expectations: &[Error] = &[ - Error::ShortReturn(ShortReturnType::AssertionFailed(Box::new( + let expectations: &[VmExecutionError] = &[ + VmExecutionError::ShortReturn(ShortReturnType::AssertionFailed(Box::new( Value::error(Value::Int(0)).unwrap(), ))), - Error::ShortReturn(ShortReturnType::AssertionFailed(Box::new( + VmExecutionError::ShortReturn(ShortReturnType::AssertionFailed(Box::new( Value::error(Value::Int(1)).unwrap(), ))), ]; diff --git a/clarity/src/vm/tests/traits.rs b/clarity/src/vm/tests/traits.rs index 09c95cdbcca..cc7f3e54f97 100644 --- a/clarity/src/vm/tests/traits.rs +++ b/clarity/src/vm/tests/traits.rs @@ -22,7 +22,7 @@ use crate::vm::tests::{test_clarity_versions, test_epochs}; #[cfg(test)] use crate::vm::{ ast::ASTRules, - errors::{CheckErrors, Error}, + errors::{CheckErrors, VmExecutionError}, tests::{env_factory, execute, symbols_from_values}, types::{PrincipalData, QualifiedContractIdentifier, Value}, version::ClarityVersion, @@ -251,7 +251,7 @@ fn test_dynamic_dispatch_intra_contract_call( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::CircularReference(_)) => {} + VmExecutionError::Unchecked(CheckErrors::CircularReference(_)) => {} _ => panic!("{err_result:?}"), } } @@ -582,7 +582,7 @@ fn test_dynamic_dispatch_mismatched_args( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::BadTraitImplementation(_, _)) => {} + VmExecutionError::Unchecked(CheckErrors::BadTraitImplementation(_, _)) => {} _ => panic!("{err_result:?}"), } } @@ -639,7 +639,7 @@ fn test_dynamic_dispatch_mismatched_returned( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::ReturnTypesMustMatch(_, _)) => {} + VmExecutionError::Unchecked(CheckErrors::ReturnTypesMustMatch(_, _)) => {} _ => panic!("{err_result:?}"), } } @@ -699,7 +699,7 @@ fn test_reentrant_dynamic_dispatch( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::CircularReference(_)) => {} + VmExecutionError::Unchecked(CheckErrors::CircularReference(_)) => {} _ => panic!("{err_result:?}"), } } @@ -756,7 +756,7 @@ fn test_readwrite_dynamic_dispatch( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::TraitBasedContractCallInReadOnly) => {} + VmExecutionError::Unchecked(CheckErrors::TraitBasedContractCallInReadOnly) => {} _ => panic!("{err_result:?}"), } } @@ -813,7 +813,7 @@ fn test_readwrite_violation_dynamic_dispatch( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::TraitBasedContractCallInReadOnly) => {} + VmExecutionError::Unchecked(CheckErrors::TraitBasedContractCallInReadOnly) => {} _ => panic!("{err_result:?}"), } } diff --git a/clarity/src/vm/tests/variables.rs b/clarity/src/vm/tests/variables.rs index f1a0f16e130..bd737abde7e 100644 --- a/clarity/src/vm/tests/variables.rs +++ b/clarity/src/vm/tests/variables.rs @@ -25,7 +25,7 @@ use crate::vm::{ analysis::type_checker::v2_1::tests::contracts::type_check_version, ast::{parse, ASTRules}, database::MemoryBackingStore, - errors::{CheckErrors, Error}, + errors::{CheckErrors, VmExecutionError}, tests::{tl_env_factory, TopLevelMemoryEnvironmentGenerator}, types::{PrincipalData, QualifiedContractIdentifier, Value}, ClarityVersion, ContractContext, @@ -81,7 +81,9 @@ fn test_block_height( if version >= ClarityVersion::Clarity3 { let err = eval_result.unwrap_err(); assert_eq!( - Error::Unchecked(CheckErrors::UndefinedVariable("block-height".to_string(),)), + VmExecutionError::Unchecked( + CheckErrors::UndefinedVariable("block-height".to_string(),) + ), err ); } else { @@ -139,7 +141,7 @@ fn test_stacks_block_height( if version < ClarityVersion::Clarity3 { let err = eval_result.unwrap_err(); assert_eq!( - Error::Unchecked(CheckErrors::UndefinedVariable( + VmExecutionError::Unchecked(CheckErrors::UndefinedVariable( "stacks-block-height".to_string(), )), err @@ -199,7 +201,9 @@ fn test_tenure_height( if version < ClarityVersion::Clarity3 { let err = eval_result.unwrap_err(); assert_eq!( - Error::Unchecked(CheckErrors::UndefinedVariable("tenure-height".to_string(),)), + VmExecutionError::Unchecked(CheckErrors::UndefinedVariable( + "tenure-height".to_string(), + )), err ); } else { @@ -273,7 +277,7 @@ fn expect_contract_error( for (when, err_condition, expected_error) in expected_errors { if *when == WhenError::Initialization && err_condition(version, epoch) { let err = init_result.unwrap_err(); - if let Error::Unchecked(inner_err) = &err { + if let VmExecutionError::Unchecked(inner_err) = &err { assert_eq!(expected_error, inner_err); } else { panic!("Expected an Unchecked error, but got a different error"); @@ -292,7 +296,7 @@ fn expect_contract_error( for (when, err_condition, expected_error) in expected_errors { if *when == WhenError::Runtime && err_condition(version, epoch) { let err = eval_result.unwrap_err(); - if let Error::Unchecked(inner_err) = &err { + if let VmExecutionError::Unchecked(inner_err) = &err { assert_eq!(expected_error, inner_err); } else { panic!("Expected an Unchecked error, but got a different error"); @@ -1161,7 +1165,7 @@ fn test_block_time( if version < ClarityVersion::Clarity4 { let err = eval_result.unwrap_err(); assert_eq!( - Error::Unchecked(CheckErrors::UndefinedVariable("block-time".to_string(),)), + VmExecutionError::Unchecked(CheckErrors::UndefinedVariable("block-time".to_string(),)), err ); } else { @@ -1287,7 +1291,7 @@ fn test_current_contract( if version < ClarityVersion::Clarity4 { let err = eval_result.unwrap_err(); assert_eq!( - Error::Unchecked(CheckErrors::UndefinedVariable( + VmExecutionError::Unchecked(CheckErrors::UndefinedVariable( "current-contract".to_string(), )), err diff --git a/clarity/src/vm/types/serialization.rs b/clarity/src/vm/types/serialization.rs index 16e62f24099..79d413f0da7 100644 --- a/clarity/src/vm/types/serialization.rs +++ b/clarity/src/vm/types/serialization.rs @@ -22,7 +22,7 @@ pub use clarity_types::types::serialization::{ use stacks_common::util::hash::{hex_bytes, to_hex}; use crate::vm::database::{ClarityDeserializable, ClaritySerializable}; -use crate::vm::errors::{Error as ClarityError, InterpreterError}; +use crate::vm::errors::{InterpreterError, VmExecutionError}; impl ClaritySerializable for u32 { fn serialize(&self) -> String { @@ -31,7 +31,7 @@ impl ClaritySerializable for u32 { } impl ClarityDeserializable for u32 { - fn deserialize(input: &str) -> Result { + fn deserialize(input: &str) -> Result { let bytes = hex_bytes(input).map_err(|_| { InterpreterError::Expect("u32 deserialization: failed decoding bytes.".into()) })?; diff --git a/clarity/src/vm/version.rs b/clarity/src/vm/version.rs index 41226cfad97..604cfce90d8 100644 --- a/clarity/src/vm/version.rs +++ b/clarity/src/vm/version.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use stacks_common::types::StacksEpochId; -use crate::vm::errors::{Error, RuntimeErrorType}; +use crate::vm::errors::{RuntimeErrorType, VmExecutionError}; #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, PartialOrd)] pub enum ClarityVersion { @@ -51,9 +51,9 @@ impl ClarityVersion { } impl FromStr for ClarityVersion { - type Err = Error; + type Err = VmExecutionError; - fn from_str(version: &str) -> Result { + fn from_str(version: &str) -> Result { let s = version.to_string().to_lowercase(); if s == "clarity1" { Ok(ClarityVersion::Clarity1) diff --git a/pox-locking/src/events.rs b/pox-locking/src/events.rs index 3a71083673e..986447b0d13 100644 --- a/pox-locking/src/events.rs +++ b/pox-locking/src/events.rs @@ -17,7 +17,7 @@ use clarity::vm::ast::ASTRules; use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::LimitedCostTracker; -use clarity::vm::errors::Error as ClarityError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier, ResponseData, TupleData}; use clarity::vm::Value; #[cfg(any(test, feature = "testing"))] @@ -566,7 +566,7 @@ pub fn synthesize_pox_event_info( function_name: &str, args: &[Value], response: &ResponseData, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // the first thing we do is check the current epoch. In Epochs <= 2.4, // synthesizing PoX events was an assessed cost, so event generation // must remain identical. @@ -611,7 +611,7 @@ fn inner_synthesize_pox_event_info( function_name: &str, args: &[Value], response: &ResponseData, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { let sender = match sender_opt { Some(sender) => sender, None => { @@ -690,7 +690,7 @@ fn inner_synthesize_pox_event_info( Ok(Value::Tuple(event_tuple)) }, ) - .map_err(|e: ClarityError| { + .map_err(|e: VmExecutionError| { error!("Failed to synthesize PoX event: {:?}", &e); e })?; diff --git a/pox-locking/src/events_24.rs b/pox-locking/src/events_24.rs index 40c10de9051..c8017d6f96e 100644 --- a/pox-locking/src/events_24.rs +++ b/pox-locking/src/events_24.rs @@ -16,7 +16,7 @@ use clarity::vm::ast::ASTRules; use clarity::vm::contexts::GlobalContext; -use clarity::vm::errors::Error as ClarityError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier, TupleData}; use clarity::vm::Value; #[cfg(any(test, feature = "testing"))] @@ -344,7 +344,7 @@ pub fn synthesize_pox_2_or_3_event_info( sender_opt: Option<&PrincipalData>, function_name: &str, args: &[Value], -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { let sender = match sender_opt { Some(sender) => sender, None => { @@ -422,7 +422,7 @@ pub fn synthesize_pox_2_or_3_event_info( Ok(Value::Tuple(event_tuple)) }, ) - .map_err(|e: ClarityError| { + .map_err(|e: VmExecutionError| { error!("Failed to synthesize PoX event: {:?}", &e); e })?; diff --git a/pox-locking/src/lib.rs b/pox-locking/src/lib.rs index 16c11c8af26..3b3ab9bb92d 100644 --- a/pox-locking/src/lib.rs +++ b/pox-locking/src/lib.rs @@ -26,7 +26,7 @@ //! invoked. If so, it updates the PoX lock. use clarity::boot_util::boot_code_id; use clarity::vm::contexts::GlobalContext; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeErrorType, VmExecutionError}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::Value; use stacks_common::types::StacksEpochId; @@ -48,11 +48,11 @@ pub enum LockingError { PoxExtendNotLocked, PoxIncreaseOnV1, PoxInvalidIncrease, - Clarity(ClarityError), + Clarity(VmExecutionError), } -impl From for LockingError { - fn from(e: ClarityError) -> LockingError { +impl From for LockingError { + fn from(e: VmExecutionError) -> LockingError { LockingError::Clarity(e) } } @@ -71,7 +71,7 @@ pub fn handle_contract_call_special_cases( function_name: &str, args: &[Value], result: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { if *contract_id == boot_code_id(POX_1_NAME, global_context.mainnet) { if !pox_1::is_read_only(function_name) && global_context.database.get_v1_unlock_height() @@ -86,7 +86,7 @@ pub fn handle_contract_call_special_cases( "function_name" => function_name, "contract_id" => %contract_id ); - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )); @@ -101,7 +101,7 @@ pub fn handle_contract_call_special_cases( "function_name" => function_name, "contract_id" => %contract_id ); - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )); @@ -124,7 +124,7 @@ pub fn handle_contract_call_special_cases( "function_name" => function_name, "contract_id" => %contract_id ); - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )); diff --git a/pox-locking/src/pox_1.rs b/pox-locking/src/pox_1.rs index 4cc7ffe0ea5..c55f134cee5 100644 --- a/pox-locking/src/pox_1.rs +++ b/pox-locking/src/pox_1.rs @@ -19,7 +19,7 @@ use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::cost_functions::ClarityCostFunction; use clarity::vm::costs::runtime_cost; use clarity::vm::database::ClarityDatabase; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeErrorType, VmExecutionError}; use clarity::vm::events::{STXEventType, STXLockEventData, StacksTransactionEvent}; use clarity::vm::types::PrincipalData; use clarity::vm::Value; @@ -131,7 +131,7 @@ pub fn handle_contract_call( _sender_opt: Option<&PrincipalData>, function_name: &str, value: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { if !(function_name == "stack-stx" || function_name == "delegate-stack-stx") { // only have work to do if the function is `stack-stx` or `delegate-stack-stx` return Ok(()); @@ -181,14 +181,14 @@ pub fn handle_contract_call( return Ok(()); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )); } Err(LockingError::PoxAlreadyLocked) => { // the caller tried to lock tokens into both pox-1 and pox-2 - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::PoxAlreadyLocked, None, )); diff --git a/pox-locking/src/pox_2.rs b/pox-locking/src/pox_2.rs index 1cbb1cd7724..5249fe726ca 100644 --- a/pox-locking/src/pox_2.rs +++ b/pox-locking/src/pox_2.rs @@ -19,7 +19,7 @@ use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::cost_functions::ClarityCostFunction; use clarity::vm::costs::runtime_cost; use clarity::vm::database::{ClarityDatabase, STXBalance}; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeErrorType, VmExecutionError}; use clarity::vm::events::{STXEventType, STXLockEventData, StacksTransactionEvent}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::{Environment, Value}; @@ -295,7 +295,7 @@ fn handle_stack_lockup_pox_v2( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { debug!( "Handle special-case contract-call to {:?} {} (which returned {:?})", "PoX-2 contract", function_name, value @@ -332,14 +332,14 @@ fn handle_stack_lockup_pox_v2( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )); } Err(LockingError::PoxAlreadyLocked) => { // the caller tried to lock tokens into both pox-1 and pox-2 - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::PoxAlreadyLocked, None, )); @@ -360,7 +360,7 @@ fn handle_stack_lockup_extension_pox_v2( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-2 contract has stored the extension information // and performed the extension checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -400,7 +400,7 @@ fn handle_stack_lockup_extension_pox_v2( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )); @@ -424,7 +424,7 @@ fn handle_stack_lockup_increase_pox_v2( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-2 contract has stored the increase information // and performed the increase checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -463,7 +463,7 @@ fn handle_stack_lockup_increase_pox_v2( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )); @@ -488,7 +488,7 @@ pub fn handle_contract_call( function_name: &str, args: &[Value], value: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { // Generate a synthetic print event for all functions that alter stacking state let print_event_opt = if let Value::Response(response) = value { if response.committed { diff --git a/pox-locking/src/pox_3.rs b/pox-locking/src/pox_3.rs index 265ec592088..4ee474edb22 100644 --- a/pox-locking/src/pox_3.rs +++ b/pox-locking/src/pox_3.rs @@ -19,7 +19,7 @@ use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::cost_functions::ClarityCostFunction; use clarity::vm::costs::runtime_cost; use clarity::vm::database::{ClarityDatabase, STXBalance}; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeErrorType, VmExecutionError}; use clarity::vm::events::{STXEventType, STXLockEventData, StacksTransactionEvent}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::{Environment, Value}; @@ -184,7 +184,7 @@ fn handle_stack_lockup_pox_v3( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { debug!( "Handle special-case contract-call to {:?} {} (which returned {:?})", boot_code_id(POX_3_NAME, global_context.mainnet), @@ -223,14 +223,14 @@ fn handle_stack_lockup_pox_v3( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )); } Err(LockingError::PoxAlreadyLocked) => { // the caller tried to lock tokens into multiple pox contracts - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::PoxAlreadyLocked, None, )); @@ -251,7 +251,7 @@ fn handle_stack_lockup_extension_pox_v3( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-3 contract has stored the extension information // and performed the extension checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -291,7 +291,7 @@ fn handle_stack_lockup_extension_pox_v3( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )); @@ -315,7 +315,7 @@ fn handle_stack_lockup_increase_pox_v3( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-3 contract has stored the increase information // and performed the increase checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -353,7 +353,7 @@ fn handle_stack_lockup_increase_pox_v3( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( + return Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )); @@ -378,7 +378,7 @@ pub fn handle_contract_call( function_name: &str, args: &[Value], value: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { // Generate a synthetic print event for all functions that alter stacking state let print_event_opt = if let Value::Response(response) = value { if response.committed { diff --git a/pox-locking/src/pox_4.rs b/pox-locking/src/pox_4.rs index 733d6d6c545..134cdfcc7e5 100644 --- a/pox-locking/src/pox_4.rs +++ b/pox-locking/src/pox_4.rs @@ -19,7 +19,7 @@ use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::cost_functions::ClarityCostFunction; use clarity::vm::costs::runtime_cost; use clarity::vm::database::{ClarityDatabase, STXBalance}; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeErrorType, VmExecutionError}; use clarity::vm::events::{STXEventType, STXLockEventData, StacksTransactionEvent}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::{Environment, Value}; @@ -154,7 +154,7 @@ fn handle_stack_lockup_pox_v4( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { debug!( "Handle special-case contract-call to {:?} {function_name} (which returned {value:?})", boot_code_id(POX_4_NAME, global_context.mainnet) @@ -190,13 +190,13 @@ fn handle_stack_lockup_pox_v4( })); Ok(Some(event)) } - Err(LockingError::DefunctPoxContract) => Err(ClarityError::Runtime( + Err(LockingError::DefunctPoxContract) => Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )), Err(LockingError::PoxAlreadyLocked) => { // the caller tried to lock tokens into multiple pox contracts - Err(ClarityError::Runtime( + Err(VmExecutionError::Runtime( RuntimeErrorType::PoxAlreadyLocked, None, )) @@ -215,7 +215,7 @@ fn handle_stack_lockup_extension_pox_v4( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-4 contract has stored the extension information // and performed the extension checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -252,7 +252,7 @@ fn handle_stack_lockup_extension_pox_v4( })); Ok(Some(event)) } - Err(LockingError::DefunctPoxContract) => Err(ClarityError::Runtime( + Err(LockingError::DefunctPoxContract) => Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )), @@ -271,7 +271,7 @@ fn handle_stack_lockup_increase_pox_v4( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-4 contract has stored the increase information // and performed the increase checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -308,7 +308,7 @@ fn handle_stack_lockup_increase_pox_v4( Ok(Some(event)) } - Err(LockingError::DefunctPoxContract) => Err(ClarityError::Runtime( + Err(LockingError::DefunctPoxContract) => Err(VmExecutionError::Runtime( RuntimeErrorType::DefunctPoxContract, None, )), @@ -329,7 +329,7 @@ pub fn handle_contract_call( function_name: &str, args: &[Value], value: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { // Generate a synthetic print event for all functions that alter stacking state let print_event_opt = if let Value::Response(response) = value { if response.committed { diff --git a/stacks-signer/src/client/mod.rs b/stacks-signer/src/client/mod.rs index e518ff4a7b8..50bd7bbe351 100644 --- a/stacks-signer/src/client/mod.rs +++ b/stacks-signer/src/client/mod.rs @@ -21,7 +21,7 @@ pub(crate) mod stacks_client; use std::time::Duration; -use clarity::vm::errors::Error as ClarityError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::serialization::SerializationError; use libsigner::RPCError; use libstackerdb::Error as StackerDBError; @@ -81,7 +81,7 @@ pub enum ClientError { NotConnected, /// Clarity interpreter error #[error("Clarity interpreter error: {0}")] - ClarityError(#[from] ClarityError), + ClarityError(#[from] VmExecutionError), /// Malformed reward set #[error("Malformed contract data: {0}")] MalformedContractData(String), diff --git a/stackslib/src/blockstack_cli.rs b/stackslib/src/blockstack_cli.rs index bcf23757e7c..93847ccd01d 100644 --- a/stackslib/src/blockstack_cli.rs +++ b/stackslib/src/blockstack_cli.rs @@ -42,7 +42,7 @@ use blockstack_lib::clarity_cli::vm_execute; use blockstack_lib::core::{CHAIN_ID_MAINNET, CHAIN_ID_TESTNET}; use blockstack_lib::net::Error as NetError; use blockstack_lib::util_lib::strings::StacksString; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeErrorType, VmExecutionError}; use clarity::vm::types::PrincipalData; use clarity::vm::{ClarityName, ClarityVersion, ContractName, Value}; use stacks_common::address::{b58, AddressHashMode}; @@ -190,7 +190,7 @@ block's sqlite database."; #[derive(Debug)] enum CliError { ClarityRuntimeError(RuntimeErrorType), - ClarityGeneralError(ClarityError), + ClarityGeneralError(VmExecutionError), Message(String), Usage, InvalidChainId(std::num::ParseIntError), @@ -230,8 +230,8 @@ impl From for CliError { } } -impl From for CliError { - fn from(value: ClarityError) -> Self { +impl From for CliError { + fn from(value: VmExecutionError) -> Self { CliError::ClarityGeneralError(value) } } diff --git a/stackslib/src/chainstate/coordinator/tests.rs b/stackslib/src/chainstate/coordinator/tests.rs index d948f08a55b..1ce3b3afbc1 100644 --- a/stackslib/src/chainstate/coordinator/tests.rs +++ b/stackslib/src/chainstate/coordinator/tests.rs @@ -23,7 +23,7 @@ use std::sync::Arc; use clarity::vm::clarity::TransactionConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; use clarity::vm::database::BurnStateDB; -use clarity::vm::errors::Error as InterpreterError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::Value; use lazy_static::lazy_static; @@ -4834,7 +4834,7 @@ fn get_total_stacked_info( parent_tip: &StacksBlockId, reward_cycle: u64, is_pox_2: bool, -) -> Result { +) -> Result { chainstate .with_read_only_clarity_tx(burn_dbconn, parent_tip, |conn| { conn.with_readonly_clarity_env( diff --git a/stackslib/src/chainstate/stacks/boot/contract_tests.rs b/stackslib/src/chainstate/stacks/boot/contract_tests.rs index 7514ba3632e..b29b0806c0d 100644 --- a/stackslib/src/chainstate/stacks/boot/contract_tests.rs +++ b/stackslib/src/chainstate/stacks/boot/contract_tests.rs @@ -7,7 +7,7 @@ use clarity::vm::ast::ASTRules; use clarity::vm::clarity::TransactionConnection; use clarity::vm::contexts::OwnedEnvironment; use clarity::vm::database::*; -use clarity::vm::errors::{CheckErrors, Error}; +use clarity::vm::errors::{CheckErrors, VmExecutionError}; use clarity::vm::test_util::{execute, symbols_from_values, TEST_BURN_STATE_DB, TEST_HEADER_DB}; use clarity::vm::types::{ OptionalData, PrincipalData, QualifiedContractIdentifier, ResponseData, StandardPrincipalData, @@ -1746,7 +1746,7 @@ fn simple_epoch21_test() { ClarityError::Interpreter(e) => { assert_eq!( e, - Error::Unchecked(CheckErrors::NameAlreadyUsed("stx-account".into())) + VmExecutionError::Unchecked(CheckErrors::NameAlreadyUsed("stx-account".into())) ); } e => panic!("Should have caused an Interpreter error: {:#?}", e), diff --git a/stackslib/src/chainstate/stacks/boot/mod.rs b/stackslib/src/chainstate/stacks/boot/mod.rs index 83afc46301e..d58526fc140 100644 --- a/stackslib/src/chainstate/stacks/boot/mod.rs +++ b/stackslib/src/chainstate/stacks/boot/mod.rs @@ -24,7 +24,7 @@ use clarity::vm::ast::ASTRules; use clarity::vm::clarity::{Error as 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; +use clarity::vm::errors::VmExecutionError; use clarity::vm::events::StacksTransactionEvent; use clarity::vm::representations::ContractName; use clarity::vm::types::{ @@ -366,7 +366,7 @@ impl StacksChainState { fn mark_pox_cycle_handled( db: &mut ClarityDatabase, cycle_number: u64, - ) -> Result<(), clarity::vm::errors::Error> { + ) -> Result<(), VmExecutionError> { let db_key = Self::handled_pox_cycle_start_key(cycle_number); db.put_data(&db_key, &POX_CYCLE_START_HANDLED_VALUE.to_string())?; Ok(()) @@ -1362,7 +1362,7 @@ impl StacksChainState { // Catch the epoch boundary edge case where burn height >= pox 3 activation height, but // there hasn't yet been a Stacks block. match result { - Err(Error::ClarityError(ClarityError::Interpreter(VmError::Unchecked( + Err(Error::ClarityError(ClarityError::Interpreter(VmExecutionError::Unchecked( CheckErrors::NoSuchContract(_), )))) => { warn!("Reward cycle attempted to calculate rewards before the PoX contract was instantiated"); diff --git a/stackslib/src/chainstate/stacks/db/blocks.rs b/stackslib/src/chainstate/stacks/db/blocks.rs index 061fba56bc3..84dff43b463 100644 --- a/stackslib/src/chainstate/stacks/db/blocks.rs +++ b/stackslib/src/chainstate/stacks/db/blocks.rs @@ -24,6 +24,7 @@ use clarity::vm::ast::ASTRules; use clarity::vm::clarity::TransactionConnection; use clarity::vm::costs::LimitedCostTracker; use clarity::vm::database::BurnStateDB; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{ BuffData, PrincipalData, QualifiedContractIdentifier, SequenceData, StacksAddressExtensions as ClarityStacksAddressExtensions, StandardPrincipalData, TupleData, @@ -307,8 +308,8 @@ impl From for MemPoolRejection { } } -impl From for MemPoolRejection { - fn from(e: clarity::vm::errors::Error) -> MemPoolRejection { +impl From for MemPoolRejection { + fn from(e: VmExecutionError) -> MemPoolRejection { MemPoolRejection::Other(e.to_string()) } } @@ -3929,7 +3930,7 @@ impl StacksChainState { ) -> Result<(bool, Vec), Error> { // is this stacks block the first of a new epoch? let (stacks_parent_epoch, sortition_epoch) = clarity_tx - .with_clarity_db_readonly::<_, Result<_, clarity::vm::errors::Error>>(|db| { + .with_clarity_db_readonly::<_, Result<_, VmExecutionError>>(|db| { Ok(( db.get_clarity_epoch_version()?, db.get_stacks_epoch(chain_tip_burn_header_height), @@ -6628,17 +6629,16 @@ impl StacksChainState { } let (block_height, v1_unlock_height, v2_unlock_height, v3_unlock_height) = - clarity_connection - .with_clarity_db_readonly::<_, Result<_, clarity::vm::errors::Error>>( - |ref mut db| { - Ok(( - db.get_current_burnchain_block_height()? as u64, - db.get_v1_unlock_height(), - db.get_v2_unlock_height()?, - db.get_v3_unlock_height()?, - )) - }, - )?; + clarity_connection.with_clarity_db_readonly::<_, Result<_, VmExecutionError>>( + |ref mut db| { + Ok(( + db.get_current_burnchain_block_height()? as u64, + db.get_v1_unlock_height(), + db.get_v2_unlock_height()?, + db.get_v3_unlock_height()?, + )) + }, + )?; // 6: the paying account must have enough funds if !payer.stx_balance.can_transfer_at_burn_block( diff --git a/stackslib/src/chainstate/stacks/db/contracts.rs b/stackslib/src/chainstate/stacks/db/contracts.rs index 11b2ee0d023..6569dbd9ebf 100644 --- a/stackslib/src/chainstate/stacks/db/contracts.rs +++ b/stackslib/src/chainstate/stacks/db/contracts.rs @@ -16,7 +16,7 @@ pub use clarity::vm::analysis::errors::CheckErrors; use clarity::vm::contracts::Contract; -use clarity::vm::errors::Error as clarity_vm_error; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{QualifiedContractIdentifier, Value}; use crate::chainstate::stacks::db::*; @@ -31,7 +31,7 @@ impl StacksChainState { clarity_tx .with_clarity_db_readonly(|ref mut db| match db.get_contract(contract_id) { Ok(c) => Ok(Some(c)), - Err(clarity_vm_error::Unchecked(CheckErrors::NoSuchContract(_))) => Ok(None), + Err(VmExecutionError::Unchecked(CheckErrors::NoSuchContract(_))) => Ok(None), Err(e) => Err(clarity_error::Interpreter(e)), }) .map_err(Error::ClarityError) @@ -47,7 +47,7 @@ impl StacksChainState { .with_clarity_db_readonly(|ref mut db| { match db.lookup_variable_unknown_descriptor(contract_id, data_var, &epoch) { Ok(c) => Ok(Some(c)), - Err(clarity_vm_error::Unchecked(CheckErrors::NoSuchDataVariable(_))) => { + Err(VmExecutionError::Unchecked(CheckErrors::NoSuchDataVariable(_))) => { Ok(None) } Err(e) => Err(clarity_error::Interpreter(e)), diff --git a/stackslib/src/chainstate/stacks/db/transactions.rs b/stackslib/src/chainstate/stacks/db/transactions.rs index 2deee7b6426..526af55cbb8 100644 --- a/stackslib/src/chainstate/stacks/db/transactions.rs +++ b/stackslib/src/chainstate/stacks/db/transactions.rs @@ -23,7 +23,7 @@ use clarity::vm::clarity::TransactionConnection; use clarity::vm::contexts::{AssetMap, AssetMapEntry, Environment}; use clarity::vm::costs::cost_functions::ClarityCostFunction; use clarity::vm::costs::{runtime_cost, CostTracker, ExecutionCost}; -use clarity::vm::errors::Error as InterpreterError; +use clarity::vm::errors::{InterpreterError, VmExecutionError}; use clarity::vm::representations::ClarityName; use clarity::vm::types::{ AssetIdentifier, BuffData, PrincipalData, QualifiedContractIdentifier, SequenceData, @@ -44,12 +44,12 @@ use crate::util_lib::strings::VecDisplay; struct HashableClarityValue(Value); impl TryFrom for HashableClarityValue { - type Error = InterpreterError; + type Error = VmExecutionError; fn try_from(value: Value) -> Result { // check that serialization _will_ be successful when hashed let _bytes = value.serialize_to_vec().map_err(|_| { - InterpreterError::Interpreter(clarity::vm::errors::InterpreterError::Expect( + VmExecutionError::Interpreter(InterpreterError::Expect( "Failed to serialize asset in NFT during post-condition checks".into(), )) })?; @@ -376,22 +376,22 @@ pub enum ClarityRuntimeTxError { pub fn handle_clarity_runtime_error(error: clarity_error) -> ClarityRuntimeTxError { match error { // runtime errors are okay - clarity_error::Interpreter(InterpreterError::Runtime(_, _)) => { + clarity_error::Interpreter(VmExecutionError::Runtime(_, _)) => { ClarityRuntimeTxError::Acceptable { error, err_type: "runtime error", } } - clarity_error::Interpreter(InterpreterError::ShortReturn(_)) => { + clarity_error::Interpreter(VmExecutionError::ShortReturn(_)) => { ClarityRuntimeTxError::Acceptable { error, err_type: "short return/panic", } } - clarity_error::Interpreter(InterpreterError::Unchecked(check_error)) => { + clarity_error::Interpreter(VmExecutionError::Unchecked(check_error)) => { if check_error.rejectable() { ClarityRuntimeTxError::Rejectable(clarity_error::Interpreter( - InterpreterError::Unchecked(check_error), + VmExecutionError::Unchecked(check_error), )) } else { ClarityRuntimeTxError::AnalysisError(check_error) @@ -633,7 +633,7 @@ impl StacksChainState { origin_account: &StacksAccount, asset_map: &AssetMap, txid: Txid, - ) -> Result, InterpreterError> { + ) -> Result, VmExecutionError> { let mut checked_fungible_assets: HashMap> = HashMap::new(); let mut checked_nonfungible_assets: HashMap< @@ -962,7 +962,7 @@ impl StacksChainState { env.add_memory(u64::from( TypeSignature::PrincipalType .size() - .map_err(InterpreterError::from)?, + .map_err(VmExecutionError::from)?, )) .map_err(|e| Error::from_cost_error(e, cost_before.clone(), env.global_context))?; @@ -1213,7 +1213,7 @@ impl StacksChainState { "function_args" => %VecDisplay(&contract_call.function_args), "error" => %check_error); return Err(Error::ClarityError(clarity_error::Interpreter( - InterpreterError::Unchecked(check_error), + VmExecutionError::Unchecked(check_error), ))); } } @@ -1455,7 +1455,7 @@ impl StacksChainState { "contract" => %contract_id, "error" => %check_error); return Err(Error::ClarityError(clarity_error::Interpreter( - InterpreterError::Unchecked(check_error), + VmExecutionError::Unchecked(check_error), ))); } } @@ -9814,7 +9814,7 @@ pub mod test { ASTRules::PrecheckSize, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(clarity_error::Interpreter(VmExecutionError::Unchecked( _check_error, ))) = err { @@ -9871,7 +9871,7 @@ pub mod test { ASTRules::PrecheckSize, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(clarity_error::Interpreter(VmExecutionError::Unchecked( _check_error, ))) = err { @@ -9926,7 +9926,7 @@ pub mod test { ASTRules::PrecheckSize, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(clarity_error::Interpreter(VmExecutionError::Unchecked( _check_error, ))) = err { @@ -9982,7 +9982,7 @@ pub mod test { ASTRules::PrecheckSize, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(clarity_error::Interpreter(VmExecutionError::Unchecked( _check_error, ))) = err { @@ -10506,7 +10506,7 @@ pub mod test { ASTRules::PrecheckSize, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(clarity_error::Interpreter(VmExecutionError::Unchecked( check_error, ))) = err { @@ -10980,7 +10980,7 @@ pub mod test { ASTRules::PrecheckSize, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(clarity_error::Interpreter(VmExecutionError::Unchecked( check_error, ))) = err { @@ -11095,7 +11095,7 @@ pub mod test { ASTRules::PrecheckSize, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(clarity_error::Interpreter(VmExecutionError::Unchecked( check_error, ))) = err { diff --git a/stackslib/src/chainstate/stacks/miner.rs b/stackslib/src/chainstate/stacks/miner.rs index a6837e5c4f0..8675075746b 100644 --- a/stackslib/src/chainstate/stacks/miner.rs +++ b/stackslib/src/chainstate/stacks/miner.rs @@ -25,7 +25,7 @@ use std::time::Instant; use clarity::vm::ast::errors::ParseErrors; use clarity::vm::ast::ASTRules; use clarity::vm::database::BurnStateDB; -use clarity::vm::errors::Error as InterpreterError; +use clarity::vm::errors::VmExecutionError; use serde::Deserialize; use stacks_common::codec::StacksMessageCodec; use stacks_common::types::chainstate::{ @@ -675,7 +675,7 @@ impl TransactionResult { } ClarityRuntimeTxError::AnalysisError(e) => { let clarity_err = Error::ClarityError(clarity_error::Interpreter( - InterpreterError::Unchecked(e), + VmExecutionError::Unchecked(e), )); if epoch_id < StacksEpochId::Epoch21 { // this would invalidate the block, so it's problematic diff --git a/stackslib/src/chainstate/stacks/mod.rs b/stackslib/src/chainstate/stacks/mod.rs index 7bf4d87c5df..9a0f43b890d 100644 --- a/stackslib/src/chainstate/stacks/mod.rs +++ b/stackslib/src/chainstate/stacks/mod.rs @@ -19,7 +19,7 @@ use std::{error, fmt, io}; use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::{CostErrors, ExecutionCost}; -use clarity::vm::errors::Error as clarity_interpreter_error; +use clarity::vm::errors::VmExecutionError; use clarity::vm::representations::{ClarityName, ContractName}; use clarity::vm::types::{ PrincipalData, QualifiedContractIdentifier, StandardPrincipalData, Value, @@ -342,8 +342,8 @@ impl From for Error { } } -impl From for Error { - fn from(e: clarity_interpreter_error) -> Error { +impl From for Error { + fn from(e: VmExecutionError) -> Error { Error::ClarityError(clarity_error::Interpreter(e)) } } diff --git a/stackslib/src/clarity_cli.rs b/stackslib/src/clarity_cli.rs index 1ae8f648de6..c54db47e155 100644 --- a/stackslib/src/clarity_cli.rs +++ b/stackslib/src/clarity_cli.rs @@ -51,7 +51,7 @@ use crate::clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; use crate::clarity::vm::database::{ BurnStateDB, ClarityDatabase, HeadersDB, STXBalance, NULL_BURN_STATE_DB, }; -use crate::clarity::vm::errors::{Error, InterpreterResult, RuntimeErrorType}; +use crate::clarity::vm::errors::{InterpreterResult, RuntimeErrorType, VmExecutionError}; use crate::clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use crate::clarity::vm::{ analysis, ast, eval_all, ClarityVersion, ContractContext, ContractName, SymbolicExpression, @@ -149,7 +149,7 @@ fn parse( contract_identifier: &QualifiedContractIdentifier, source_code: &str, clarity_version: ClarityVersion, -) -> Result, Error> { +) -> Result, VmExecutionError> { let ast = build_ast_with_rules( contract_identifier, source_code, @@ -442,7 +442,10 @@ where /// Execute program in a transient environment. To be used only by CLI tools /// for program evaluation, not by consensus critical code. -pub fn vm_execute(program: &str, clarity_version: ClarityVersion) -> Result, Error> { +pub fn vm_execute( + program: &str, + clarity_version: ClarityVersion, +) -> Result, VmExecutionError> { let contract_id = QualifiedContractIdentifier::transient(); let mut contract_context = ContractContext::new(contract_id.clone(), clarity_version); let mut marf = MemoryBackingStore::new(); @@ -784,13 +787,13 @@ fn get_eval_input(invoked_by: &str, args: &[String]) -> EvalInput { let mut buffer = String::new(); friendly_expect( io::stdin().read_to_string(&mut buffer), - "Error reading from stdin.", + "VmExecutionError reading from stdin.", ); buffer } else { friendly_expect( fs::read_to_string(&args[2]), - &format!("Error reading file: {}", args[2]), + &format!("VmExecutionError reading file: {}", args[2]), ) } }; @@ -1004,13 +1007,13 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option = @@ -1121,7 +1124,10 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option buffer, Err(error) => { - eprintln!("Error reading from stdin:\n{error}"); + eprintln!("VmExecutionError reading from stdin:\n{error}"); panic_test!(); } } @@ -1310,7 +1316,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option (i32, Option { where A: FnOnce(&AssetMap, &mut ClarityDatabase) -> Option, F: FnOnce(&mut OwnedEnvironment) -> Result<(R, AssetMap, Vec), E>, - E: From, + E: From, { using!(self.log, "log", |log| { using!(self.cost_track, "cost tracker", |cost_track| { @@ -2071,7 +2071,7 @@ impl ClarityTransactionConnection<'_, '_> { rollback_wrapper.depth() ); } - rollback_wrapper.commit().map_err(InterpreterError::from)?; + rollback_wrapper.commit().map_err(VmExecutionError::from)?; // now we can reset the memory usage for the edit-log self.cost_track .as_mut() diff --git a/stackslib/src/clarity_vm/special.rs b/stackslib/src/clarity_vm/special.rs index 64e41881280..9f01c8526ee 100644 --- a/stackslib/src/clarity_vm/special.rs +++ b/stackslib/src/clarity_vm/special.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use clarity::vm::contexts::GlobalContext; -use clarity::vm::errors::Error as ClarityError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier, Value}; /// Handle special cases of contract-calls -- namely, those into PoX that should lock up STX @@ -27,7 +27,7 @@ pub fn handle_contract_call_special_cases( function_name: &str, args: &[Value], result: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { pox_locking::handle_contract_call_special_cases( global_context, sender, diff --git a/stackslib/src/clarity_vm/tests/contracts.rs b/stackslib/src/clarity_vm/tests/contracts.rs index 27a9023e46f..72cfc254536 100644 --- a/stackslib/src/clarity_vm/tests/contracts.rs +++ b/stackslib/src/clarity_vm/tests/contracts.rs @@ -17,7 +17,7 @@ use clarity::types::StacksEpochId; use clarity::vm::ast::ASTRules; use clarity::vm::clarity::Error as ClarityError; -use clarity::vm::errors::{CheckErrors, Error}; +use clarity::vm::errors::{CheckErrors, VmExecutionError}; use clarity::vm::types::SequenceData::Buffer; use clarity::vm::types::{ BuffData, OptionalData, PrincipalData, QualifiedContractIdentifier, TupleData, TypeSignature, @@ -461,7 +461,7 @@ fn trait_invocation_cross_epoch() { ) .unwrap_err(); - if let ClarityError::Interpreter(Error::Unchecked(CheckErrors::TypeValueError(trait_ref_type, value))) = error { + if let ClarityError::Interpreter(VmExecutionError::Unchecked(CheckErrors::TypeValueError(trait_ref_type, value))) = error { assert!(matches!(*trait_ref_type, TypeSignature::TraitReferenceType(_))); } else { panic!("Expected an Interpreter(UncheckedError(TypeValue(TraitReferenceType, Principal))) during Epoch-2.2"); @@ -485,7 +485,7 @@ fn trait_invocation_cross_epoch() { ) .unwrap_err(); - if let ClarityError::Interpreter(Error::Unchecked(CheckErrors::TypeValueError(trait_ref_type, value))) = error { + if let ClarityError::Interpreter(VmExecutionError::Unchecked(CheckErrors::TypeValueError(trait_ref_type, value))) = error { assert!(matches!(*trait_ref_type, TypeSignature::TraitReferenceType(_))); } else { panic!("Expected an Interpreter(UncheckedError(TypeValue(TraitReferenceType, Principal))) during Epoch-2.2"); diff --git a/stackslib/src/clarity_vm/tests/costs.rs b/stackslib/src/clarity_vm/tests/costs.rs index d710a799fc4..dfd39fd1e2a 100644 --- a/stackslib/src/clarity_vm/tests/costs.rs +++ b/stackslib/src/clarity_vm/tests/costs.rs @@ -23,7 +23,7 @@ use clarity::vm::costs::{ DefaultVersion, ExecutionCost, LimitedCostTracker, COSTS_1_NAME, COSTS_2_NAME, COSTS_3_NAME, COSTS_4_NAME, }; -use clarity::vm::errors::Error; +use clarity::vm::errors::VmExecutionError; use clarity::vm::events::StacksTransactionEvent; use clarity::vm::functions::NativeFunctions; use clarity::vm::representations::SymbolicExpression; @@ -175,7 +175,7 @@ fn execute_transaction( contract_identifier: &QualifiedContractIdentifier, tx: &str, args: &[SymbolicExpression], -) -> Result<(Value, AssetMap, Vec), Error> { +) -> Result<(Value, AssetMap, Vec), VmExecutionError> { env.execute_transaction(issuer, None, contract_identifier.clone(), tx, args) } diff --git a/stackslib/src/clarity_vm/tests/forking.rs b/stackslib/src/clarity_vm/tests/forking.rs index 6dc33055629..bd6d96924eb 100644 --- a/stackslib/src/clarity_vm/tests/forking.rs +++ b/stackslib/src/clarity_vm/tests/forking.rs @@ -17,7 +17,7 @@ use clarity::vm::analysis::errors::CheckErrors; use clarity::vm::ast::ASTRules; use clarity::vm::contexts::OwnedEnvironment; -use clarity::vm::errors::{Error, InterpreterResult as Result, RuntimeErrorType}; +use clarity::vm::errors::{InterpreterResult as Result, RuntimeErrorType, VmExecutionError}; use clarity::vm::test_util::{ execute, is_committed, is_err_code, symbols_from_values, TEST_BURN_STATE_DB, TEST_HEADER_DB, }; @@ -189,7 +189,7 @@ fn test_at_block_good(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc let resp = branch(x, version, 1, "reset").unwrap_err(); eprintln!("{}", resp); match resp { - Error::Runtime(x, _) => assert_eq!( + VmExecutionError::Runtime(x, _) => assert_eq!( x, RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash::from( vec![2; 32].as_slice() @@ -225,7 +225,7 @@ fn test_at_block_missing_defines(#[case] version: ClarityVersion, #[case] epoch: .unwrap(); } - fn initialize_2(owned_env: &mut OwnedEnvironment) -> Error { + fn initialize_2(owned_env: &mut OwnedEnvironment) -> VmExecutionError { let c_b = QualifiedContractIdentifier::local("contract-b").unwrap(); let contract = "(define-private (problematic-cc) diff --git a/stackslib/src/clarity_vm/tests/large_contract.rs b/stackslib/src/clarity_vm/tests/large_contract.rs index b90216bd960..dc5dff0074c 100644 --- a/stackslib/src/clarity_vm/tests/large_contract.rs +++ b/stackslib/src/clarity_vm/tests/large_contract.rs @@ -20,7 +20,7 @@ use clarity::vm::ast::{self, ASTRules}; use clarity::vm::clarity::{ClarityConnection, TransactionConnection}; use clarity::vm::contexts::OwnedEnvironment; use clarity::vm::database::HeadersDB; -use clarity::vm::errors::Error as InterpreterError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::test_util::*; use clarity::vm::tests::{test_clarity_versions, BurnStateDB}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier, Value}; @@ -1255,7 +1255,7 @@ fn test_deep_tuples() { }); match error { - ClarityError::Interpreter(InterpreterError::Runtime(r_e, _)) => { + ClarityError::Interpreter(VmExecutionError::Runtime(r_e, _)) => { eprintln!("Runtime error: {:?}", r_e); } other => { @@ -1324,7 +1324,7 @@ fn test_deep_tuples_ast_precheck() { }); match error { - ClarityError::Interpreter(InterpreterError::Runtime(r_e, _)) => { + ClarityError::Interpreter(VmExecutionError::Runtime(r_e, _)) => { eprintln!("Runtime error: {:?}", r_e); } other => { @@ -1399,7 +1399,7 @@ fn test_deep_type_nesting() { }); match error { - ClarityError::Interpreter(InterpreterError::Runtime(r_e, _)) => { + ClarityError::Interpreter(VmExecutionError::Runtime(r_e, _)) => { eprintln!("Runtime error: {:?}", r_e); } other => { diff --git a/stackslib/src/clarity_vm/tests/simple_tests.rs b/stackslib/src/clarity_vm/tests/simple_tests.rs index 0fb38cdf9e4..053f378e3c8 100644 --- a/stackslib/src/clarity_vm/tests/simple_tests.rs +++ b/stackslib/src/clarity_vm/tests/simple_tests.rs @@ -1,5 +1,5 @@ use clarity::vm::contexts::OwnedEnvironment; -use clarity::vm::errors::{Error, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeErrorType, VmExecutionError}; use clarity::vm::test_util::{TEST_BURN_STATE_DB, TEST_HEADER_DB}; use clarity::vm::types::QualifiedContractIdentifier; use stacks_common::consts::{FIRST_BURNCHAIN_CONSENSUS_HASH, FIRST_STACKS_BLOCK_HASH}; @@ -62,7 +62,7 @@ fn test_at_unknown_block() { .unwrap_err(); eprintln!("{}", err); match err { - Error::Runtime(x, _) => assert_eq!( + VmExecutionError::Runtime(x, _) => assert_eq!( x, RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash::from( vec![2; 32].as_slice() diff --git a/stackslib/src/net/api/callreadonly.rs b/stackslib/src/net/api/callreadonly.rs index cc9715b1727..96f5c089a10 100644 --- a/stackslib/src/net/api/callreadonly.rs +++ b/stackslib/src/net/api/callreadonly.rs @@ -18,7 +18,7 @@ use clarity::vm::analysis::CheckErrors; use clarity::vm::ast::parser::v1::CLARITY_NAME_REGEX; use clarity::vm::clarity::ClarityConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; -use clarity::vm::errors::Error::Unchecked; +use clarity::vm::errors::VmExecutionError::Unchecked; use clarity::vm::representations::{CONTRACT_NAME_REGEX_STRING, STANDARD_PRINCIPAL_REGEX_STRING}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::{ClarityName, ContractName, SymbolicExpression, Value}; diff --git a/stackslib/src/net/api/fastcallreadonly.rs b/stackslib/src/net/api/fastcallreadonly.rs index cabd8c9db2d..1f5a2902adc 100644 --- a/stackslib/src/net/api/fastcallreadonly.rs +++ b/stackslib/src/net/api/fastcallreadonly.rs @@ -19,7 +19,7 @@ use clarity::vm::analysis::CheckErrors; use clarity::vm::ast::parser::v1::CLARITY_NAME_REGEX; use clarity::vm::clarity::ClarityConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; -use clarity::vm::errors::Error::Unchecked; +use clarity::vm::errors::VmExecutionError::Unchecked; use clarity::vm::representations::{CONTRACT_NAME_REGEX_STRING, STANDARD_PRINCIPAL_REGEX_STRING}; use clarity::vm::types::PrincipalData; use clarity::vm::{ClarityName, ContractName, SymbolicExpression, Value}; diff --git a/stackslib/src/net/mod.rs b/stackslib/src/net/mod.rs index 1dd559c0cfd..bdb8116d080 100644 --- a/stackslib/src/net/mod.rs +++ b/stackslib/src/net/mod.rs @@ -19,7 +19,7 @@ use std::io::{Read, Write}; use std::net::{IpAddr, SocketAddr}; use std::{error, fmt, io}; -use clarity::vm::errors::Error as InterpreterError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use libstackerdb::{Error as libstackerdb_error, StackerDBChunkData}; use p2p::{DropReason, DropSource}; @@ -533,8 +533,8 @@ impl From for Error { } } -impl From for Error { - fn from(e: InterpreterError) -> Self { +impl From for Error { + fn from(e: VmExecutionError) -> Self { Error::ClarityError(e.into()) } } From 4b9257cc4b358461bfe0aa6f3330ecc19ac8bd60 Mon Sep 17 00:00:00 2001 From: Jacinta Ferrant Date: Wed, 17 Sep 2025 16:07:39 -0700 Subject: [PATCH 2/4] Add descriptions to VmExecutionError and its variants Signed-off-by: Jacinta Ferrant --- clarity-types/src/errors/mod.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/clarity-types/src/errors/mod.rs b/clarity-types/src/errors/mod.rs index 8037ed7f7b5..fd66681c227 100644 --- a/clarity-types/src/errors/mod.rs +++ b/clarity-types/src/errors/mod.rs @@ -39,13 +39,19 @@ pub struct IncomparableError { } #[derive(Debug)] +/// Errors that can occur during the runtime execution, including type-checking +/// failures, interpreter issues, runtime errors, and premature returns. pub enum VmExecutionError { /// UncheckedErrors are errors that *should* be caught by the - /// TypeChecker and other check passes. Test executions may - /// trigger these errors. + /// TypeChecker and other check passes. Test executions may + /// trigger these errors. Unchecked(CheckErrors), + /// Errors originating from the interpreter during program execution. + /// These *should never* occur. Test executions may trigger these errors Interpreter(InterpreterError), + /// Errors that occur during runtime execution, with an optional stack trace. Runtime(RuntimeErrorType, Option), + /// Errors triggered during Clarity contract evaluation that cause early termination. ShortReturn(ShortReturnType), } From 8952b53e2b4067be6288328697d47a9c9f166dcb Mon Sep 17 00:00:00 2001 From: Jacinta Ferrant Date: Thu, 18 Sep 2025 11:43:50 -0700 Subject: [PATCH 3/4] CRC: add more detailed documentation. Leave interpreter to prevent conflicts with its rename Signed-off-by: Jacinta Ferrant --- clarity-types/src/errors/mod.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/clarity-types/src/errors/mod.rs b/clarity-types/src/errors/mod.rs index fd66681c227..1d53dddb867 100644 --- a/clarity-types/src/errors/mod.rs +++ b/clarity-types/src/errors/mod.rs @@ -38,20 +38,30 @@ pub struct IncomparableError { pub err: T, } +/// Errors that can occur during the runtime execution of Clarity contracts in the virtual machine. +/// These encompass type-checking failures, interpreter issues, runtime errors, and premature returns. +/// Unlike static analysis errors in `ClarityError::StaticCheck(CheckError)` or `ClarityError::Parse(ParseError)`, +/// which are caught before execution during type-checking or parsing, these errors occur during dynamic +/// evaluation and may involve conditions not detectable statically, such as dynamically constructed expressions +/// (e.g., based on VRF seeds or runtime data). #[derive(Debug)] -/// Errors that can occur during the runtime execution, including type-checking -/// failures, interpreter issues, runtime errors, and premature returns. pub enum VmExecutionError { - /// UncheckedErrors are errors that *should* be caught by the - /// TypeChecker and other check passes. Test executions may - /// trigger these errors. + /// Type-checking errors caught during runtime analysis, which should typically be detected by + /// static type-checking passes before execution. These may occur in test executions or when + /// dynamic expression construction (e.g., using runtime data like VRF seeds) creates structures + /// violating type or resource constraints (e.g., excessive stack depth). + /// The `CheckErrorKind` wraps the specific type-checking error encountered at runtime. Unchecked(CheckErrors), - /// Errors originating from the interpreter during program execution. - /// These *should never* occur. Test executions may trigger these errors Interpreter(InterpreterError), - /// Errors that occur during runtime execution, with an optional stack trace. + /// Errors that occur during runtime execution of Clarity code, such as arithmetic errors or + /// invalid operations, expected as part of contract evaluation. + /// The `RuntimeErrorType` wraps the specific runtime error, and the `Option` provides + /// an optional stack trace for debugging, if available. Runtime(RuntimeErrorType, Option), - /// Errors triggered during Clarity contract evaluation that cause early termination. + /// Errors triggered during Clarity contract evaluation that cause early termination with + /// insufficient results (e.g., unwrapping an empty `Option`). + /// The `EarlyReturnError` wraps the specific early return condition, detailing the premature + /// termination cause. ShortReturn(ShortReturnType), } From 78287226790b996a2457878610c5c7ac07891104 Mon Sep 17 00:00:00 2001 From: Jacinta Ferrant Date: Thu, 18 Sep 2025 12:35:01 -0700 Subject: [PATCH 4/4] CRC: remove accidental search replace in println and format Signed-off-by: Jacinta Ferrant --- stackslib/src/clarity_cli.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/stackslib/src/clarity_cli.rs b/stackslib/src/clarity_cli.rs index c54db47e155..a40c3774c69 100644 --- a/stackslib/src/clarity_cli.rs +++ b/stackslib/src/clarity_cli.rs @@ -787,13 +787,13 @@ fn get_eval_input(invoked_by: &str, args: &[String]) -> EvalInput { let mut buffer = String::new(); friendly_expect( io::stdin().read_to_string(&mut buffer), - "VmExecutionError reading from stdin.", + "Error reading from stdin.", ); buffer } else { friendly_expect( fs::read_to_string(&args[2]), - &format!("VmExecutionError reading file: {}", args[2]), + &format!("Error reading file: {}", args[2]), ) } }; @@ -1007,13 +1007,13 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option = @@ -1124,10 +1124,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option buffer, Err(error) => { - eprintln!("VmExecutionError reading from stdin:\n{error}"); + eprintln!("Error reading from stdin:\n{error}"); panic_test!(); } } @@ -1316,7 +1313,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option (i32, Option