pub mod signatures;
pub mod serialization;
use std::{fmt, cmp};
use std::convert::{TryInto, TryFrom};
use std::collections::BTreeMap;
use std::{char, str};
use serde::{Serialize, Deserialize};
use regex::Regex;
use super::util::c32;
use super::representations::{ClarityName, ContractName, SymbolicExpression, SymbolicExpressionType};
use super::errors::{RuntimeErrorType, CheckErrors, InterpreterResult as Result, IncomparableError, InterpreterError};
use super::util::hash;
use super::functions::define::{DefineFunctions};
pub use super::types::signatures::{
TupleTypeSignature, AssetIdentifier, FixedFunction, FunctionSignature,
TypeSignature, SequenceSubtype, StringSubtype, FunctionType, ListTypeData, FunctionArg, parse_name_type_pairs,
BUFF_64, BUFF_32, BUFF_20, BUFF_1, BufferLength, StringUTF8Length
};
pub const MAX_VALUE_SIZE: u32 = 1024 * 1024;
pub const BOUND_VALUE_SERIALIZATION_BYTES: u32 = MAX_VALUE_SIZE * 2;
pub const BOUND_VALUE_SERIALIZATION_HEX: u32 = BOUND_VALUE_SERIALIZATION_BYTES * 2;
pub const MAX_TYPE_DEPTH: u8 = 32;
pub const WRAPPER_VALUE_SIZE: u32 = 1;
#[derive(Debug, Clone, Eq, Serialize, Deserialize)]
pub struct TupleData {
pub type_signature: TupleTypeSignature,
pub data_map: BTreeMap<ClarityName, Value>
}
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BuffData {
pub data: Vec<u8>,
}
#[derive(Debug, Clone, Eq, Serialize, Deserialize)]
pub struct ListData {
pub data: Vec<Value>,
pub type_signature: ListTypeData
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
pub struct StandardPrincipalData(pub u8, pub [u8; 20]);
impl StandardPrincipalData {
pub fn transient() -> StandardPrincipalData {
Self(1, [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1])
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
pub struct QualifiedContractIdentifier {
pub issuer: StandardPrincipalData,
pub name: ContractName
}
impl QualifiedContractIdentifier {
pub fn new(issuer: StandardPrincipalData, name: ContractName) -> QualifiedContractIdentifier {
Self { issuer, name }
}
pub fn local(name: &str) -> Result<QualifiedContractIdentifier> {
let name = name.to_string().try_into()?;
Ok(Self::new(StandardPrincipalData::transient(), name))
}
pub fn transient() -> QualifiedContractIdentifier {
let name = String::from("__transient").try_into().unwrap();
Self {
issuer: StandardPrincipalData::transient(),
name
}
}
pub fn parse(literal: &str) -> Result<QualifiedContractIdentifier> {
let split: Vec<_> = literal.splitn(2, ".").collect();
if split.len() != 2 {
return Err(RuntimeErrorType::ParseError(
"Invalid principal literal: expected a `.` in a qualified contract name".to_string()).into());
}
let sender = PrincipalData::parse_standard_principal(split[0])?;
let name = split[1].to_string().try_into()?;
Ok(QualifiedContractIdentifier::new(sender, name))
}
pub fn to_string(&self) -> String {
format!("{}.{}", self.issuer, self.name.to_string())
}
}
impl fmt::Display for QualifiedContractIdentifier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_string())
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum PrincipalData {
Standard(StandardPrincipalData),
Contract(QualifiedContractIdentifier),
}
pub enum ContractIdentifier {
Relative(ContractName),
Qualified(QualifiedContractIdentifier)
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct OptionalData {
pub data: Option<Box<Value>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ResponseData {
pub committed: bool,
pub data: Box<Value>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
pub struct TraitIdentifier {
pub name: ClarityName,
pub contract_identifier: QualifiedContractIdentifier,
}
impl TraitIdentifier {
pub fn new(issuer: StandardPrincipalData, contract_name: ContractName, name: ClarityName) -> TraitIdentifier {
Self {
name,
contract_identifier: QualifiedContractIdentifier {
issuer,
name: contract_name
}
}
}
pub fn parse_fully_qualified(literal: &str) -> Result<TraitIdentifier> {
let (issuer, contract_name, name) = Self::parse(literal)?;
let issuer = issuer.ok_or(RuntimeErrorType::BadTypeConstruction)?;
Ok(TraitIdentifier::new(issuer, contract_name, name))
}
pub fn parse_sugared_syntax(literal: &str) -> Result<(ContractName, ClarityName)> {
let (_ , contract_name, name) = Self::parse(literal)?;
Ok((contract_name, name))
}
pub fn parse(literal: &str) -> Result<(Option<StandardPrincipalData>, ContractName, ClarityName)> {
let split: Vec<_> = literal.splitn(3, ".").collect();
if split.len() != 3 {
return Err(RuntimeErrorType::ParseError(
"Invalid principal literal: expected a `.` in a qualified contract name".to_string()).into());
}
let issuer = match split[0].len() {
0 => None,
_ => Some(PrincipalData::parse_standard_principal(split[0])?),
};
let contract_name = split[1].to_string().try_into()?;
let name = split[2].to_string().try_into()?;
Ok((issuer, contract_name, name))
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum Value {
Int(i128),
UInt(u128),
Bool(bool),
Sequence(SequenceData),
Principal(PrincipalData),
Tuple(TupleData),
Optional(OptionalData),
Response(ResponseData),
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum SequenceData {
Buffer(BuffData),
List(ListData),
String(CharType),
}
impl SequenceData {
pub fn atom_values(&mut self) -> Vec<SymbolicExpression> {
match self {
SequenceData::Buffer(ref mut data) => data.atom_values(),
SequenceData::List(ref mut data) => data.atom_values(),
SequenceData::String(CharType::ASCII(ref mut data)) => data.atom_values(),
SequenceData::String(CharType::UTF8(ref mut data)) => data.atom_values(),
}
}
pub fn len(&self) -> usize {
match &self {
SequenceData::Buffer(data) => data.items().len(),
SequenceData::List(data) => data.items().len(),
SequenceData::String(CharType::ASCII(data)) => data.items().len(),
SequenceData::String(CharType::UTF8(data)) => data.items().len(),
}
}
pub fn filter<F>(&mut self, filter: &mut F) -> Result<()> where F: FnMut(SymbolicExpression) -> Result<bool> {
macro_rules! drain_filter {
($data:expr, $seq_type:ident) => {
let mut i = 0;
while i != $data.data.len() {
let atom_value = SymbolicExpression::atom_value($seq_type::to_value(&$data.data[i]));
match filter(atom_value) {
Ok(res) if res == false => { $data.data.remove(i); },
Ok(_) => { i += 1; },
Err(err) => return Err(err),
}
}
};
}
match self {
SequenceData::Buffer(ref mut data) => {
drain_filter!(data, BuffData);
},
SequenceData::List(ref mut data) => {
drain_filter!(data, ListData);
},
SequenceData::String(CharType::ASCII(ref mut data)) => {
drain_filter!(data, ASCIIData);
},
SequenceData::String(CharType::UTF8(ref mut data)) => {
drain_filter!(data, UTF8Data);
},
}
Ok(())
}
pub fn append(&mut self, other_seq: &mut SequenceData) -> Result<()> {
match (self, other_seq) {
(SequenceData::List(ref mut inner_data), SequenceData::List(ref mut other_inner_data)) => {
inner_data.append(other_inner_data)
},
(SequenceData::Buffer(ref mut inner_data), SequenceData::Buffer(ref mut other_inner_data)) => {
inner_data.append(other_inner_data)
},
(SequenceData::String(CharType::ASCII(ref mut inner_data)), SequenceData::String(CharType::ASCII(ref mut other_inner_data))) => {
inner_data.append(other_inner_data)
},
(SequenceData::String(CharType::UTF8(ref mut inner_data)), SequenceData::String(CharType::UTF8(ref mut other_inner_data))) => {
inner_data.append(other_inner_data)
},
_ => Err(RuntimeErrorType::BadTypeConstruction.into())
}?;
Ok(())
}
}
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum CharType {
UTF8(UTF8Data),
ASCII(ASCIIData),
}
impl fmt::Display for CharType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CharType::ASCII(string) => write!(f, "{}", string),
CharType::UTF8(string) => write!(f, "{}", string),
}
}
}
impl fmt::Debug for CharType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ASCIIData {
pub data: Vec<u8>,
}
impl fmt::Display for ASCIIData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut escaped_str = String::new();
for c in self.data.iter() {
let escaped_char = format!("{}", std::ascii::escape_default(*c));
escaped_str.push_str(&escaped_char);
}
write!(f, "{}", format!("\"{}\"", escaped_str))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UTF8Data {
pub data: Vec<Vec<u8>>,
}
impl fmt::Display for UTF8Data {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut result = String::new();
for c in self.data.iter() {
if c.len() > 1 {
result.push_str(&format!("\\u{{{}}}", hash::to_hex(&c[..])));
} else {
let escaped_char = format!("{}", std::ascii::escape_default(c[0]));
result.push_str(&escaped_char);
}
}
write!(f, "{}", format!("u\"{}\"", result))
}
}
pub trait SequencedValue<T> {
fn type_signature(&self) -> TypeSignature;
fn items(&self) -> &Vec<T>;
fn drained_items(&mut self) -> Vec<T>;
fn to_value(v: &T) -> Value;
fn atom_values(&mut self) -> Vec<SymbolicExpression> {
self.drained_items().iter().map(|item| {
SymbolicExpression::atom_value(Self::to_value(&item))
}).collect()
}
}
impl SequencedValue<Value> for ListData {
fn items(&self) -> &Vec<Value> {
&self.data
}
fn drained_items(&mut self) -> Vec<Value> {
self.data.drain(..).collect()
}
fn type_signature(&self) -> TypeSignature {
TypeSignature::SequenceType(SequenceSubtype::ListType(self.type_signature.clone()))
}
fn to_value(v: &Value) -> Value {
v.clone()
}
}
impl SequencedValue<u8> for BuffData {
fn items(&self) -> &Vec<u8> {
&self.data
}
fn drained_items(&mut self) -> Vec<u8> {
self.data.drain(..).collect()
}
fn type_signature(&self) -> TypeSignature {
let buff_length = BufferLength::try_from(self.data.len())
.expect("ERROR: Too large of a buffer successfully constructed.");
TypeSignature::SequenceType(SequenceSubtype::BufferType(buff_length))
}
fn to_value(v: &u8) -> Value {
Value::buff_from_byte(*v)
}
}
impl SequencedValue<u8> for ASCIIData {
fn items(&self) -> &Vec<u8> {
&self.data
}
fn drained_items(&mut self) -> Vec<u8> {
self.data.drain(..).collect()
}
fn type_signature(&self) -> TypeSignature {
let buff_length = BufferLength::try_from(self.data.len())
.expect("ERROR: Too large of a buffer successfully constructed.");
TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII(buff_length)))
}
fn to_value(v: &u8) -> Value {
Value::string_ascii_from_bytes(vec![*v])
.expect("ERROR: Invalid ASCII string successfully constructed")
}
}
impl SequencedValue<Vec<u8>> for UTF8Data {
fn items(&self) -> &Vec<Vec<u8>> {
&self.data
}
fn drained_items(&mut self) -> Vec<Vec<u8>> {
self.data.drain(..).collect()
}
fn type_signature(&self) -> TypeSignature {
let str_len = StringUTF8Length::try_from(self.data.len())
.expect("ERROR: Too large of a buffer successfully constructed.");
TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8(str_len)))
}
fn to_value(v: &Vec<u8>) -> Value {
Value::string_utf8_from_bytes(v.clone())
.expect("ERROR: Invalid UTF8 string successfully constructed")
}
}
define_named_enum!(BlockInfoProperty {
Time("time"),
VrfSeed("vrf-seed"),
HeaderHash("header-hash"),
IdentityHeaderHash("id-header-hash"),
BurnchainHeaderHash("burnchain-header-hash"),
MinerAddress("miner-address"),
});
impl OptionalData {
pub fn type_signature(&self) -> TypeSignature {
let type_result = match self.data {
Some(ref v) => TypeSignature::new_option(TypeSignature::type_of(&v)),
None => TypeSignature::new_option(TypeSignature::NoType)
};
type_result.expect("Should not have constructed too large of a type.")
}
}
impl ResponseData {
pub fn type_signature(&self) -> TypeSignature {
let type_result = match self.committed {
true => TypeSignature::new_response(
TypeSignature::type_of(&self.data), TypeSignature::NoType),
false => TypeSignature::new_response(
TypeSignature::NoType, TypeSignature::type_of(&self.data))
};
type_result.expect("Should not have constructed too large of a type.")
}
}
impl BlockInfoProperty {
pub fn type_result(&self) -> TypeSignature {
use self::BlockInfoProperty::*;
match self {
Time => TypeSignature::UIntType,
IdentityHeaderHash | VrfSeed | HeaderHash | BurnchainHeaderHash => BUFF_32.clone(),
MinerAddress => TypeSignature::PrincipalType,
}
}
}
impl PartialEq for ListData {
fn eq(&self, other: &ListData) -> bool {
self.data == other.data
}
}
impl PartialEq for TupleData {
fn eq(&self, other: &TupleData) -> bool {
self.data_map == other.data_map
}
}
pub const NONE: Value = Value::Optional(OptionalData { data: None });
impl Value {
pub fn some(data: Value) -> Result<Value> {
if data.size() + WRAPPER_VALUE_SIZE > MAX_VALUE_SIZE {
Err(CheckErrors::ValueTooLarge.into())
} else if data.depth() + 1 > MAX_TYPE_DEPTH {
Err(CheckErrors::TypeSignatureTooDeep.into())
} else {
Ok(Value::Optional(OptionalData {
data: Some(Box::new(data)) }))
}
}
pub fn none() -> Value {
NONE.clone()
}
pub fn okay_true() -> Value {
Value::Response(ResponseData { committed: true, data: Box::new(Value::Bool(true)) })
}
pub fn err_uint(ecode: u128) -> Value {
Value::Response(ResponseData { committed: false, data: Box::new(Value::UInt(ecode)) })
}
pub fn err_none() -> Value {
Value::Response(ResponseData { committed: false, data: Box::new(NONE.clone()) })
}
pub fn okay(data: Value) -> Result<Value> {
if data.size() + WRAPPER_VALUE_SIZE > MAX_VALUE_SIZE {
Err(CheckErrors::ValueTooLarge.into())
} else if data.depth() + 1 > MAX_TYPE_DEPTH {
Err(CheckErrors::TypeSignatureTooDeep.into())
} else {
Ok(Value::Response(ResponseData {
committed: true,
data: Box::new(data) }))
}
}
pub fn error(data: Value) -> Result<Value> {
if data.size() + WRAPPER_VALUE_SIZE > MAX_VALUE_SIZE {
Err(CheckErrors::ValueTooLarge.into())
} else if data.depth() + 1 > MAX_TYPE_DEPTH {
Err(CheckErrors::TypeSignatureTooDeep.into())
} else {
Ok(Value::Response(ResponseData {
committed: false,
data: Box::new(data) }))
}
}
pub fn size(&self) -> u32 {
TypeSignature::type_of(self).size()
}
pub fn depth(&self) -> u8 {
TypeSignature::type_of(self).depth()
}
pub fn list_with_type(list_data: Vec<Value>, expected_type: ListTypeData) -> Result<Value> {
if (expected_type.get_max_len() as usize) < list_data.len() {
return Err(InterpreterError::FailureConstructingListWithType.into())
}
{
let expected_item_type = expected_type.get_list_item_type();
for item in &list_data {
if !expected_item_type.admits(&item) {
return Err(InterpreterError::FailureConstructingListWithType.into())
}
}
}
Ok(Value::Sequence(SequenceData::List(ListData { data: list_data, type_signature: expected_type })))
}
pub fn list_from(list_data: Vec<Value>) -> Result<Value> {
let type_sig = TypeSignature::construct_parent_list_type(&list_data)?;
Ok(Value::Sequence(SequenceData::List(ListData { data: list_data, type_signature: type_sig })))
}
pub fn buff_from(buff_data: Vec<u8>) -> Result<Value> {
BufferLength::try_from(buff_data.len())?;
Ok(Value::Sequence(SequenceData::Buffer(BuffData { data: buff_data })))
}
pub fn buff_from_byte(byte: u8) -> Value {
Value::Sequence(SequenceData::Buffer(BuffData { data: vec![byte] }))
}
pub fn string_ascii_from_bytes(bytes: Vec<u8>) -> Result<Value> {
BufferLength::try_from(bytes.len())?;
for b in bytes.iter() {
if !b.is_ascii_alphanumeric() && !b.is_ascii_punctuation() && !b.is_ascii_whitespace() {
return Err(CheckErrors::InvalidCharactersDetected.into());
}
}
Ok(Value::Sequence(SequenceData::String(CharType::ASCII(ASCIIData { data: bytes }))))
}
pub fn string_utf8_from_string_utf8_literal(tokenized_str: String) -> Result<Value> {
let wrapped_codepoints_matcher = Regex::new("^\\\\u\\{(?P<value>[[:xdigit:]]+)\\}").unwrap();
let mut window = tokenized_str.as_str();
let mut cursor = 0;
let mut data: Vec<Vec<u8>> = vec![];
while !window.is_empty() {
if let Some(captures) = wrapped_codepoints_matcher.captures(window) {
let matched = captures.name("value").unwrap();
let scalar_value = window[matched.start()..matched.end()].to_string();
let unicode_char = {
let u = u32::from_str_radix(&scalar_value, 16).unwrap();
let c = char::from_u32(u).unwrap();
let mut encoded_char: Vec<u8> = vec![0; c.len_utf8()];
c.encode_utf8(&mut encoded_char[..]);
encoded_char
};
data.push(unicode_char);
cursor += scalar_value.len() + 4;
} else {
let ascii_char = window[0..1].to_string().into_bytes();
data.push(ascii_char);
cursor += 1;
}
StringUTF8Length::try_from(data.len())?;
window = &tokenized_str[cursor..];
}
Ok(Value::Sequence(SequenceData::String(CharType::UTF8(UTF8Data { data }))))
}
pub fn string_utf8_from_bytes(bytes: Vec<u8>) -> Result<Value> {
let validated_utf8_str = match str::from_utf8(&bytes) {
Ok(string) => string,
_ => return Err(CheckErrors::InvalidCharactersDetected.into())
};
let mut data = vec![];
for char in validated_utf8_str.chars() {
let mut encoded_char: Vec<u8> = vec![0; char.len_utf8()];
char.encode_utf8(&mut encoded_char[..]);
data.push(encoded_char);
}
StringUTF8Length::try_from(data.len())?;
Ok(Value::Sequence(SequenceData::String(CharType::UTF8(UTF8Data { data }))))
}
}
impl BuffData {
pub fn len(&self) -> BufferLength {
self.data.len().try_into().unwrap()
}
fn append(&mut self, other_seq: &mut BuffData) -> Result<()> {
self.data.append(&mut other_seq.data);
Ok(())
}
}
impl ListData {
pub fn len(&self) -> u32 {
self.data.len().try_into().unwrap()
}
fn append(&mut self, other_seq: &mut ListData) -> Result<()> {
let entry_type_a = self.type_signature.get_list_item_type();
let entry_type_b = other_seq.type_signature.get_list_item_type();
let entry_type = TypeSignature::factor_out_no_type(&entry_type_a, &entry_type_b)?;
let max_len = self.type_signature.get_max_len() + other_seq.type_signature.get_max_len();
self.type_signature = ListTypeData::new_list(entry_type, max_len)?;
self.data.append(&mut other_seq.data);
Ok(())
}
}
impl ASCIIData {
fn append(&mut self, other_seq: &mut ASCIIData) -> Result<()> {
self.data.append(&mut other_seq.data);
Ok(())
}
pub fn len(&self) -> BufferLength {
self.data.len().try_into().unwrap()
}
}
impl UTF8Data {
fn append(&mut self, other_seq: &mut UTF8Data) -> Result<()> {
self.data.append(&mut other_seq.data);
Ok(())
}
pub fn len(&self) -> BufferLength {
self.data.len().try_into().unwrap()
}
}
impl fmt::Display for OptionalData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.data {
Some(ref x) => write!(f, "(some {})", x),
None => write!(f, "none")
}
}
}
impl fmt::Display for ResponseData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.committed {
true => write!(f, "(ok {})", self.data),
false => write!(f, "(err {})", self.data)
}
}
}
impl fmt::Display for BuffData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", hash::to_hex(&self.data))
}
}
impl fmt::Debug for BuffData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Value::Int(int) => write!(f, "{}", int),
Value::UInt(int) => write!(f, "u{}", int),
Value::Bool(boolean) => write!(f, "{}", boolean),
Value::Tuple(data) => write!(f, "{}", data),
Value::Principal(principal_data) => write!(f, "{}", principal_data),
Value::Optional(opt_data) => write!(f, "{}", opt_data),
Value::Response(res_data) => write!(f, "{}", res_data),
Value::Sequence(SequenceData::Buffer(vec_bytes)) => write!(f, "0x{}", &vec_bytes),
Value::Sequence(SequenceData::String(string)) => write!(f, "{}", string),
Value::Sequence(SequenceData::List(list_data)) => {
write!(f, "(")?;
for (ix, v) in list_data.data.iter().enumerate() {
if ix > 0 {
write!(f, " ")?;
}
write!(f, "{}", v)?;
}
write!(f, ")")
}
}
}
}
impl PrincipalData {
pub fn version(&self) -> u8 {
match self {
PrincipalData::Standard(StandardPrincipalData(version, _)) => *version,
PrincipalData::Contract(QualifiedContractIdentifier { issuer, name: _ }) => {
issuer.0
}
}
}
pub fn parse(literal: &str) -> Result<PrincipalData> {
let literal = if literal.starts_with("'") {
&literal[1..]
} else {
literal
};
if literal.contains(".") {
PrincipalData::parse_qualified_contract_principal(literal)
} else {
PrincipalData::parse_standard_principal(literal)
.map(PrincipalData::from)
}
}
pub fn parse_qualified_contract_principal(literal: &str) -> Result<PrincipalData> {
let contract_id = QualifiedContractIdentifier::parse(literal)?;
Ok(PrincipalData::Contract(contract_id))
}
pub fn parse_standard_principal(literal: &str) -> Result<StandardPrincipalData> {
let (version, data) = c32::c32_address_decode(&literal)
.map_err(|x| { RuntimeErrorType::ParseError(format!("Invalid principal literal: {:?}", x)) })?;
if data.len() != 20 {
return Err(RuntimeErrorType::ParseError(
"Invalid principal literal: Expected 20 data bytes.".to_string()).into());
}
let mut fixed_data = [0; 20];
fixed_data.copy_from_slice(&data[..20]);
Ok(StandardPrincipalData(version, fixed_data))
}
}
impl StandardPrincipalData {
pub fn to_address(&self) -> String {
c32::c32_address(self.0, &self.1[..])
.unwrap_or_else(|_| "INVALID_C32_ADD".to_string())
}
}
impl fmt::Display for StandardPrincipalData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let c32_str = self.to_address();
write!(f, "{}", c32_str)
}
}
impl fmt::Display for PrincipalData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PrincipalData::Standard(sender) => {
write!(f, "{}", sender)
},
PrincipalData::Contract(contract_identifier) => {
write!(f, "{}.{}", contract_identifier.issuer, contract_identifier.name.to_string())
}
}
}
}
impl fmt::Display for TraitIdentifier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.{}", self.contract_identifier, self.name.to_string())
}
}
impl From<StandardPrincipalData> for Value {
fn from(principal: StandardPrincipalData) -> Self {
Value::Principal(PrincipalData::from(principal))
}
}
impl From<QualifiedContractIdentifier> for Value {
fn from(principal: QualifiedContractIdentifier) -> Self {
Value::Principal(PrincipalData::Contract(principal))
}
}
impl From<PrincipalData> for Value {
fn from(p: PrincipalData) -> Self {
Value::Principal(p)
}
}
impl From<StandardPrincipalData> for PrincipalData {
fn from(p: StandardPrincipalData) -> Self {
PrincipalData::Standard(p)
}
}
impl From<QualifiedContractIdentifier> for PrincipalData {
fn from(principal: QualifiedContractIdentifier) -> Self {
PrincipalData::Contract(principal)
}
}
impl From<TupleData> for Value {
fn from(t: TupleData) -> Self {
Value::Tuple(t)
}
}
impl TupleData {
fn new(type_signature: TupleTypeSignature, data_map: BTreeMap<ClarityName, Value>) -> Result<TupleData> {
let t = TupleData { type_signature, data_map };
Ok(t)
}
pub fn len(&self) -> u64 {
self.data_map.len() as u64
}
pub fn from_data(mut data: Vec<(ClarityName, Value)>) -> Result<TupleData> {
let mut type_map = BTreeMap::new();
let mut data_map = BTreeMap::new();
for (name, value) in data.drain(..) {
let type_info = TypeSignature::type_of(&value);
if type_map.contains_key(&name) {
return Err(CheckErrors::NameAlreadyUsed(name.into()).into());
} else {
type_map.insert(name.clone(), type_info);
}
data_map.insert(name, value);
}
Self::new(TupleTypeSignature::try_from(type_map)?, data_map)
}
pub fn from_data_typed(mut data: Vec<(ClarityName, Value)>, expected: &TupleTypeSignature) -> Result<TupleData> {
let mut data_map = BTreeMap::new();
for (name, value) in data.drain(..) {
let expected_type = expected.field_type(&name)
.ok_or(InterpreterError::FailureConstructingTupleWithType)?;
if !expected_type.admits(&value) {
return Err(InterpreterError::FailureConstructingTupleWithType.into());
}
data_map.insert(name, value);
}
Self::new(expected.clone(), data_map)
}
pub fn get(&self, name: &str) -> Result<&Value> {
self.data_map.get(name)
.ok_or_else(|| CheckErrors::NoSuchTupleField(name.to_string(), self.type_signature.clone()).into())
}
pub fn get_owned(mut self, name: &str) -> Result<Value> {
self.data_map.remove(name)
.ok_or_else(|| CheckErrors::NoSuchTupleField(name.to_string(), self.type_signature.clone()).into())
}
}
impl fmt::Display for TupleData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(tuple")?;
for (name, value) in self.data_map.iter() {
write!(f, " ")?;
write!(f, "({} {})", &**name, value)?;
}
write!(f, ")")
}
}
pub enum TupleDefinitionType {
Implicit(Box<[SymbolicExpression]>),
Explicit,
}
pub fn get_definition_type_of_tuple_argument(args: &SymbolicExpression) -> TupleDefinitionType {
if let SymbolicExpressionType::List(ref outer_expr) = args.expr {
if let SymbolicExpressionType::List(_) = (&outer_expr[0]).expr {
return TupleDefinitionType::Implicit(outer_expr.clone());
}
}
TupleDefinitionType::Explicit
}