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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,151 changes: 938 additions & 213 deletions clarity-types/src/errors/analysis.rs

Large diffs are not rendered by default.

17 changes: 14 additions & 3 deletions clarity-types/src/errors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub mod lexer;

use std::{error, fmt};

use analysis::CommonCheckErrorKind;
pub use analysis::{CheckErrorKind, StaticCheckError};
pub use ast::{ParseError, ParseErrorKind, ParseResult};
pub use cost::CostErrors;
Expand Down Expand Up @@ -294,15 +295,25 @@ impl From<RuntimeError> for VmExecutionError {
}
}

// TODO: remove. CommonCheckErrorKind shouldn't be used in the public API.
// So there shouldn't be any need to convert it to a VmExecutionError.
impl From<CommonCheckErrorKind> for VmExecutionError {
fn from(err: CommonCheckErrorKind) -> Self {
VmExecutionError::Unchecked(err.into())
}
}

impl From<CheckErrorKind> for VmExecutionError {
fn from(err: CheckErrorKind) -> Self {
VmExecutionError::Unchecked(err)
}
}

impl From<(CheckErrorKind, &SymbolicExpression)> for VmExecutionError {
fn from(err: (CheckErrorKind, &SymbolicExpression)) -> Self {
VmExecutionError::Unchecked(err.0)
// TODO: remove. CommonCheckErrorKind shouldn't be used in the public API.
// So there shouldn't be any need to convert it to a VmExecutionError.
impl From<(CommonCheckErrorKind, &SymbolicExpression)> for VmExecutionError {
fn from(err: (CommonCheckErrorKind, &SymbolicExpression)) -> Self {
VmExecutionError::Unchecked(err.0.into())
}
}

Expand Down
3 changes: 2 additions & 1 deletion clarity-types/src/tests/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use rstest::rstest;
use stacks_common::types::StacksEpochId;

use crate::VmExecutionError;
use crate::errors::analysis::CommonCheckErrorKind;
use crate::errors::{CheckErrorKind, RuntimeError, VmInternalError};
use crate::types::{
ASCIIData, BuffData, CharType, ListTypeData, MAX_VALUE_SIZE, PrincipalData,
Expand All @@ -38,7 +39,7 @@ fn test_constructors() {
);
assert_eq!(
ListTypeData::new_list(TypeSignature::IntType, MAX_VALUE_SIZE),
Err(CheckErrorKind::ValueTooLarge)
Err(CommonCheckErrorKind::ValueTooLarge)
);

assert_eq!(
Expand Down
22 changes: 11 additions & 11 deletions clarity-types/src/tests/types/signatures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use std::collections::HashSet;

use crate::errors::CheckErrorKind;
use crate::errors::analysis::CommonCheckErrorKind;
use crate::representations::CONTRACT_MAX_NAME_LENGTH;
use crate::types::TypeSignature::{BoolType, IntType, ListUnionType, UIntType};
use crate::types::signatures::{CallableSubtype, TypeSignature};
Expand Down Expand Up @@ -43,7 +43,7 @@ fn test_buffer_length_try_from_u32_trait() {
assert_eq!(MAX_VALUE_SIZE, buffer.get_value());

let err = BufferLength::try_from(MAX_VALUE_SIZE + 1).unwrap_err();
assert_eq!(CheckErrorKind::ValueTooLarge, err);
assert_eq!(CommonCheckErrorKind::ValueTooLarge, err);
}

#[test]
Expand All @@ -55,7 +55,7 @@ fn test_buffer_length_try_from_usize_trait() {
assert_eq!(MAX_VALUE_SIZE, buffer.get_value());

let err = BufferLength::try_from(MAX_VALUE_SIZE as usize + 1).unwrap_err();
assert_eq!(CheckErrorKind::ValueTooLarge, err);
assert_eq!(CommonCheckErrorKind::ValueTooLarge, err);
}

#[test]
Expand All @@ -67,10 +67,10 @@ fn test_buffer_length_try_from_i128_trait() {
assert_eq!(MAX_VALUE_SIZE, buffer.get_value());

let err = BufferLength::try_from(MAX_VALUE_SIZE as i128 + 1).unwrap_err();
assert_eq!(CheckErrorKind::ValueTooLarge, err);
assert_eq!(CommonCheckErrorKind::ValueTooLarge, err);

let err = BufferLength::try_from(-1_i128).unwrap_err();
assert_eq!(CheckErrorKind::ValueOutOfBounds, err);
assert_eq!(CommonCheckErrorKind::ValueOutOfBounds, err);
}

#[test]
Expand Down Expand Up @@ -229,7 +229,7 @@ fn test_string_utf8_length_try_from_u32_trait() {
assert_eq!(MAX_UTF8_VALUE_SIZE, string.get_value());

let err = StringUTF8Length::try_from(MAX_UTF8_VALUE_SIZE + 1).unwrap_err();
assert_eq!(CheckErrorKind::ValueTooLarge, err);
assert_eq!(CommonCheckErrorKind::ValueTooLarge, err);
}

#[test]
Expand All @@ -244,7 +244,7 @@ fn test_string_utf8_length_try_from_usize_trait() {
assert_eq!(MAX_UTF8_VALUE_SIZE, string.get_value());

let err = StringUTF8Length::try_from(MAX_UTF8_VALUE_SIZE as usize + 1).unwrap_err();
assert_eq!(CheckErrorKind::ValueTooLarge, err);
assert_eq!(CommonCheckErrorKind::ValueTooLarge, err);
}

#[test]
Expand All @@ -259,10 +259,10 @@ fn test_string_utf8_length_try_from_i128_trait() {
assert_eq!(MAX_UTF8_VALUE_SIZE, string.get_value());

let err = StringUTF8Length::try_from(MAX_UTF8_VALUE_SIZE as i128 + 1).unwrap_err();
assert_eq!(CheckErrorKind::ValueTooLarge, err);
assert_eq!(CommonCheckErrorKind::ValueTooLarge, err);

let err = StringUTF8Length::try_from(-1_i128).unwrap_err();
assert_eq!(CheckErrorKind::ValueOutOfBounds, err);
assert_eq!(CommonCheckErrorKind::ValueOutOfBounds, err);
}

#[test]
Expand Down Expand Up @@ -826,11 +826,11 @@ fn test_least_supertype() {
for pair in bad_pairs {
matches!(
TypeSignature::least_supertype_v2_1(&pair.0, &pair.1).unwrap_err(),
CheckErrorKind::TypeError(..)
CommonCheckErrorKind::TypeError(..)
);
matches!(
TypeSignature::least_supertype_v2_1(&pair.1, &pair.0).unwrap_err(),
CheckErrorKind::TypeError(..)
CommonCheckErrorKind::TypeError(..)
);
}
}
31 changes: 19 additions & 12 deletions clarity-types/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub use self::signatures::{
AssetIdentifier, BufferLength, ListTypeData, SequenceSubtype, StringSubtype, StringUTF8Length,
TupleTypeSignature, TypeSignature,
};
use crate::errors::analysis::CommonCheckErrorKind;
use crate::errors::{CheckErrorKind, InterpreterResult as Result, RuntimeError, VmInternalError};
use crate::representations::{ClarityName, ContractName, SymbolicExpression};

Expand Down Expand Up @@ -700,7 +701,7 @@ impl fmt::Display for UTF8Data {
}

pub trait SequencedValue<T> {
fn type_signature(&self) -> std::result::Result<TypeSignature, CheckErrorKind>;
fn type_signature(&self) -> std::result::Result<TypeSignature, CommonCheckErrorKind>;

fn items(&self) -> &Vec<T>;

Expand All @@ -725,7 +726,7 @@ impl SequencedValue<Value> for ListData {
self.data.drain(..).collect()
}

fn type_signature(&self) -> std::result::Result<TypeSignature, CheckErrorKind> {
fn type_signature(&self) -> std::result::Result<TypeSignature, CommonCheckErrorKind> {
Ok(TypeSignature::SequenceType(SequenceSubtype::ListType(
self.type_signature.clone(),
)))
Expand All @@ -745,9 +746,11 @@ impl SequencedValue<u8> for BuffData {
self.data.drain(..).collect()
}

fn type_signature(&self) -> std::result::Result<TypeSignature, CheckErrorKind> {
fn type_signature(&self) -> std::result::Result<TypeSignature, CommonCheckErrorKind> {
let buff_length = BufferLength::try_from(self.data.len()).map_err(|_| {
CheckErrorKind::Expects("ERROR: Too large of a buffer successfully constructed.".into())
CommonCheckErrorKind::Expects(
"ERROR: Too large of a buffer successfully constructed.".into(),
)
})?;
Ok(TypeSignature::SequenceType(SequenceSubtype::BufferType(
buff_length,
Expand All @@ -768,9 +771,11 @@ impl SequencedValue<u8> for ASCIIData {
self.data.drain(..).collect()
}

fn type_signature(&self) -> std::result::Result<TypeSignature, CheckErrorKind> {
fn type_signature(&self) -> std::result::Result<TypeSignature, CommonCheckErrorKind> {
let buff_length = BufferLength::try_from(self.data.len()).map_err(|_| {
CheckErrorKind::Expects("ERROR: Too large of a buffer successfully constructed.".into())
CommonCheckErrorKind::Expects(
"ERROR: Too large of a buffer successfully constructed.".into(),
)
})?;
Ok(TypeSignature::SequenceType(SequenceSubtype::StringType(
StringSubtype::ASCII(buff_length),
Expand All @@ -794,9 +799,11 @@ impl SequencedValue<Vec<u8>> for UTF8Data {
self.data.drain(..).collect()
}

fn type_signature(&self) -> std::result::Result<TypeSignature, CheckErrorKind> {
fn type_signature(&self) -> std::result::Result<TypeSignature, CommonCheckErrorKind> {
let str_len = StringUTF8Length::try_from(self.data.len()).map_err(|_| {
CheckErrorKind::Expects("ERROR: Too large of a buffer successfully constructed.".into())
CommonCheckErrorKind::Expects(
"ERROR: Too large of a buffer successfully constructed.".into(),
)
})?;
Ok(TypeSignature::SequenceType(SequenceSubtype::StringType(
StringSubtype::UTF8(str_len),
Expand All @@ -812,19 +819,19 @@ impl SequencedValue<Vec<u8>> for UTF8Data {
}

impl OptionalData {
pub fn type_signature(&self) -> std::result::Result<TypeSignature, CheckErrorKind> {
pub fn type_signature(&self) -> std::result::Result<TypeSignature, CommonCheckErrorKind> {
let type_result = match self.data {
Some(ref v) => TypeSignature::new_option(TypeSignature::type_of(v)?),
None => TypeSignature::new_option(TypeSignature::NoType),
};
type_result.map_err(|_| {
CheckErrorKind::Expects("Should not have constructed too large of a type.".into())
CommonCheckErrorKind::Expects("Should not have constructed too large of a type.".into())
})
}
}

impl ResponseData {
pub fn type_signature(&self) -> std::result::Result<TypeSignature, CheckErrorKind> {
pub fn type_signature(&self) -> std::result::Result<TypeSignature, CommonCheckErrorKind> {
let type_result = match self.committed {
true => TypeSignature::new_response(
TypeSignature::type_of(&self.data)?,
Expand All @@ -836,7 +843,7 @@ impl ResponseData {
),
};
type_result.map_err(|_| {
CheckErrorKind::Expects("Should not have constructed too large of a type.".into())
CommonCheckErrorKind::Expects("Should not have constructed too large of a type.".into())
})
}
}
Expand Down
39 changes: 21 additions & 18 deletions clarity-types/src/types/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use stacks_common::util::hash::{hex_bytes, to_hex};
use stacks_common::util::retry::BoundReader;

use super::{ListTypeData, TupleTypeSignature};
use crate::errors::analysis::StaticCheckErrorKind;
use crate::errors::{CheckErrorKind, IncomparableError, VmInternalError};
use crate::representations::{ClarityName, ContractName, MAX_STRING_LEN};
use crate::types::{
Expand Down Expand Up @@ -394,7 +395,7 @@ impl TypeSignature {
/// size of a `(buff 1024*1024)` is `1+1024*1024` because of the
/// type prefix byte. However, that is 1 byte larger than the maximum
/// buffer size in Clarity.
pub fn max_serialized_size(&self) -> Result<u32, CheckErrorKind> {
pub fn max_serialized_size(&self) -> Result<u32, StaticCheckErrorKind> {
let type_prefix_size = 1;

let max_output_size = match self {
Expand All @@ -405,7 +406,7 @@ impl TypeSignature {
// `some` or similar with `result` types). So, when
// serializing an object with a `NoType`, the other
// branch should always be used.
return Err(CheckErrorKind::CouldNotDetermineSerializationType);
return Err(StaticCheckErrorKind::CouldNotDetermineSerializationType);
}
TypeSignature::IntType => 16,
TypeSignature::UIntType => 16,
Expand All @@ -417,14 +418,14 @@ impl TypeSignature {
.get_max_len()
.checked_mul(list_type.get_list_item_type().max_serialized_size()?)
.and_then(|x| x.checked_add(list_length_encode))
.ok_or_else(|| CheckErrorKind::ValueTooLarge)?
.ok_or_else(|| StaticCheckErrorKind::ValueTooLarge)?
}
TypeSignature::SequenceType(SequenceSubtype::BufferType(buff_length)) => {
// u32 length as big-endian bytes
let buff_length_encode = 4;
u32::from(buff_length)
.checked_add(buff_length_encode)
.ok_or_else(|| CheckErrorKind::ValueTooLarge)?
.ok_or_else(|| StaticCheckErrorKind::ValueTooLarge)?
}
TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII(
length,
Expand All @@ -434,7 +435,7 @@ impl TypeSignature {
// ascii is 1-byte per character
u32::from(length)
.checked_add(str_length_encode)
.ok_or_else(|| CheckErrorKind::ValueTooLarge)?
.ok_or_else(|| StaticCheckErrorKind::ValueTooLarge)?
}
TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8(
length,
Expand All @@ -445,7 +446,7 @@ impl TypeSignature {
u32::from(length)
.checked_mul(4)
.and_then(|x| x.checked_add(str_length_encode))
.ok_or_else(|| CheckErrorKind::ValueTooLarge)?
.ok_or_else(|| StaticCheckErrorKind::ValueTooLarge)?
}
TypeSignature::PrincipalType
| TypeSignature::CallableType(_)
Expand All @@ -468,7 +469,7 @@ impl TypeSignature {
.checked_add(1) // length of key-name
.and_then(|x| x.checked_add(key.len() as u32)) // ClarityName is ascii-only, so 1 byte per length
.and_then(|x| x.checked_add(value_size))
.ok_or_else(|| CheckErrorKind::ValueTooLarge)?;
.ok_or_else(|| StaticCheckErrorKind::ValueTooLarge)?;
}
total_size
}
Expand All @@ -477,25 +478,25 @@ impl TypeSignature {
Ok(size) => size,
// if NoType, then this is just serializing a none
// value, which is only the type prefix
Err(CheckErrorKind::CouldNotDetermineSerializationType) => 0,
Err(StaticCheckErrorKind::CouldNotDetermineSerializationType) => 0,
Err(e) => return Err(e),
}
}
TypeSignature::ResponseType(response_types) => {
let (ok_type, err_type) = response_types.as_ref();
let (ok_type_max_size, no_ok_type) = match ok_type.max_serialized_size() {
Ok(size) => (size, false),
Err(CheckErrorKind::CouldNotDetermineSerializationType) => (0, true),
Err(StaticCheckErrorKind::CouldNotDetermineSerializationType) => (0, true),
Err(e) => return Err(e),
};
let err_type_max_size = match err_type.max_serialized_size() {
Ok(size) => size,
Err(CheckErrorKind::CouldNotDetermineSerializationType) => {
Err(StaticCheckErrorKind::CouldNotDetermineSerializationType) => {
if no_ok_type {
// if both the ok type and the error type are NoType,
// throw a CheckErrorKind. This should not be possible, but the check
// throw a StaticCheckErrorKind. This should not be possible, but the check
// is done out of caution.
return Err(CheckErrorKind::CouldNotDetermineSerializationType);
return Err(StaticCheckErrorKind::CouldNotDetermineSerializationType);
} else {
0
}
Expand All @@ -505,13 +506,13 @@ impl TypeSignature {
cmp::max(ok_type_max_size, err_type_max_size)
}
TypeSignature::ListUnionType(_) => {
return Err(CheckErrorKind::CouldNotDetermineSerializationType);
return Err(StaticCheckErrorKind::CouldNotDetermineSerializationType);
}
};

max_output_size
.checked_add(type_prefix_size)
.ok_or_else(|| CheckErrorKind::ValueTooLarge)
.ok_or_else(|| StaticCheckErrorKind::ValueTooLarge)
}
}

Expand Down Expand Up @@ -612,8 +613,8 @@ impl Value {
TypePrefix::Buffer => {
let mut buffer_len = [0; 4];
r.read_exact(&mut buffer_len)?;
let buffer_len = BufferLength::try_from(u32::from_be_bytes(buffer_len))?;

let buffer_len = BufferLength::try_from(u32::from_be_bytes(buffer_len))
.map_err(CheckErrorKind::from)?;
if let Some(x) = &expected_type {
let passed_test = match x {
TypeSignature::SequenceType(SequenceSubtype::BufferType(
Expand Down Expand Up @@ -844,7 +845,8 @@ impl Value {
TypePrefix::StringASCII => {
let mut buffer_len = [0; 4];
r.read_exact(&mut buffer_len)?;
let buffer_len = BufferLength::try_from(u32::from_be_bytes(buffer_len))?;
let buffer_len = BufferLength::try_from(u32::from_be_bytes(buffer_len))
.map_err(CheckErrorKind::from)?;

if let Some(x) = &expected_type {
let passed_test = match x {
Expand All @@ -869,7 +871,8 @@ impl Value {
TypePrefix::StringUTF8 => {
let mut total_len = [0; 4];
r.read_exact(&mut total_len)?;
let total_len = BufferLength::try_from(u32::from_be_bytes(total_len))?;
let total_len = BufferLength::try_from(u32::from_be_bytes(total_len))
.map_err(CheckErrorKind::from)?;

let mut data: Vec<u8> = vec![0; u32::from(total_len) as usize];

Expand Down
Loading