diff --git a/radix-engine-interface/src/api/api.rs b/radix-engine-interface/src/api/api.rs index ac71bbd230f..d351691f346 100644 --- a/radix-engine-interface/src/api/api.rs +++ b/radix-engine-interface/src/api/api.rs @@ -1,19 +1,18 @@ use crate::api::types::ScryptoActor; use crate::api::wasm_input::NativeFnInvocation; use crate::crypto::Hash; -use crate::data::ScryptoCustomTypeId; +use crate::data::ScryptoDecode; use crate::model::*; use sbor::rust::fmt::Debug; use sbor::rust::string::String; use sbor::rust::vec::Vec; -use sbor::Decode; use super::types::*; pub trait ScryptoNativeInvocation: Into + SysInvocation {} pub trait SysInvocation { - type Output: Debug + Decode; + type Output: Debug + ScryptoDecode; } pub trait SysNativeInvokable { diff --git a/radix-engine-interface/src/data/custom_value.rs b/radix-engine-interface/src/data/custom_value.rs index eb60568d722..a62731ea507 100644 --- a/radix-engine-interface/src/data/custom_value.rs +++ b/radix-engine-interface/src/data/custom_value.rs @@ -39,8 +39,8 @@ pub enum ScryptoCustomValue { NonFungibleId(NonFungibleId), } -impl CustomValue for ScryptoCustomValue { - fn encode_type_id(&self, encoder: &mut ScryptoEncoder) { +impl> Encode for ScryptoCustomValue { + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { match self { ScryptoCustomValue::PackageAddress(_) => { encoder.write_type_id(SborTypeId::Custom(ScryptoCustomTypeId::PackageAddress)) @@ -105,7 +105,7 @@ impl CustomValue for ScryptoCustomValue { } } - fn encode_body(&self, encoder: &mut ScryptoEncoder) { + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { match self { // TODO: vector free ScryptoCustomValue::PackageAddress(v) => encoder.write_slice(&v.to_vec()), @@ -119,13 +119,13 @@ impl CustomValue for ScryptoCustomValue { ScryptoCustomValue::Vault(v) => encoder.write_slice(v.as_slice()), ScryptoCustomValue::Expression(v) => { let buf = v.to_vec(); - encoder.write_size(buf.len()); + encoder.write_size(buf.len())?; encoder.write_slice(&buf) } ScryptoCustomValue::Blob(v) => encoder.write_slice(&v.to_vec()), ScryptoCustomValue::NonFungibleAddress(v) => { let buf = v.to_vec(); - encoder.write_size(buf.len()); + encoder.write_size(buf.len())?; encoder.write_slice(&buf) } ScryptoCustomValue::Hash(v) => encoder.write_slice(&v.to_vec()), @@ -137,16 +137,21 @@ impl CustomValue for ScryptoCustomValue { ScryptoCustomValue::PreciseDecimal(v) => encoder.write_slice(&v.to_vec()), ScryptoCustomValue::NonFungibleId(v) => { let buf = v.to_vec(); - encoder.write_size(buf.len()); + encoder.write_size(buf.len())?; encoder.write_slice(&buf) } } } +} +impl> Decode for ScryptoCustomValue { fn decode_body_with_type_id( - decoder: &mut ScryptoDecoder, - type_id: ScryptoCustomTypeId, + decoder: &mut D, + type_id: SborTypeId, ) -> Result { + let SborTypeId::Custom(type_id) = type_id else { + return Err(DecodeError::UnexpectedCustomTypeId { actual: type_id.as_u8() }); + }; match type_id { ScryptoCustomTypeId::PackageAddress => { let n = 27; diff --git a/radix-engine-interface/src/data/indexed_value.rs b/radix-engine-interface/src/data/indexed_value.rs index 068a233ede2..acbc420810c 100644 --- a/radix-engine-interface/src/data/indexed_value.rs +++ b/radix-engine-interface/src/data/indexed_value.rs @@ -13,6 +13,8 @@ use utils::ContextualDisplay; #[derive(Debug, Clone, PartialEq, Eq, TypeId, Encode, Decode)] pub enum ScryptoValueDecodeError { + RawValueEncodeError(EncodeError), + TypedValueEncodeError(EncodeError), DecodeError(DecodeError), ValueIndexingError(ValueIndexingError), } @@ -51,13 +53,14 @@ impl IndexedScryptoValue { Self::from_typed(&()) } - pub fn from_typed>(value: &T) -> Self { - let bytes = encode(value); + pub fn from_typed(value: &T) -> Self { + let bytes = + scrypto_encode(value).expect("Failed to encode trusted value for IndexedScryptoValue"); Self::from_slice(&bytes).expect("Failed to convert trusted value into IndexedScryptoValue") } pub fn from_slice(slice: &[u8]) -> Result { - let value = decode_any(slice).map_err(ScryptoValueDecodeError::DecodeError)?; + let value = scrypto_decode(slice).map_err(ScryptoValueDecodeError::DecodeError)?; Self::from_value(value) } @@ -69,7 +72,8 @@ impl IndexedScryptoValue { } Ok(Self { - raw: encode_any(&value), + raw: scrypto_encode(&value) + .map_err(|err| ScryptoValueDecodeError::RawValueEncodeError(err))?, dom: value, component_addresses: visitor.component_addresses, resource_addresses: visitor.resource_addresses, @@ -165,7 +169,8 @@ impl IndexedScryptoValue { } self.bucket_ids = new_bucket_ids; - self.raw = encode_any(&self.dom); + self.raw = scrypto_encode(&self.dom) + .expect("Previously encodable raw value is no longer encodable after replacement"); Ok(()) } @@ -240,7 +245,7 @@ impl ScryptoCustomValueVisitor { } } -impl CustomValueVisitor for ScryptoCustomValueVisitor { +impl CustomValueVisitor for ScryptoCustomValueVisitor { type Err = ValueIndexingError; fn visit( @@ -332,7 +337,7 @@ mod tests { #[test] fn should_reject_duplicate_ids() { - let buckets = scrypto_encode(&vec![Bucket(0), Bucket(0)]); + let buckets = scrypto_encode(&vec![Bucket(0), Bucket(0)]).unwrap(); assert_eq!( IndexedScryptoValue::from_slice(&buckets), Err(ScryptoValueDecodeError::ValueIndexingError( diff --git a/radix-engine-interface/src/data/mod.rs b/radix-engine-interface/src/data/mod.rs index 2f3a1782b66..d459af2e914 100644 --- a/radix-engine-interface/src/data/mod.rs +++ b/radix-engine-interface/src/data/mod.rs @@ -16,25 +16,52 @@ pub use custom_type_id::*; pub use custom_value::*; pub use indexed_value::*; use sbor::rust::vec::Vec; -use sbor::{decode, encode, Decode, DecodeError, Encode}; +use sbor::{ + Decode, DecodeError, Decoder, Encode, EncodeError, Encoder, SborTypeId, SborValue, TypeId, + VecDecoder, VecEncoder, +}; pub use schema_matcher::*; pub use schema_path::*; pub use value_formatter::*; -// TODO: add trait alias for `Encode` and `Decode` as well, once it becomes stable. +pub const MAX_SCRYPTO_SBOR_DEPTH: u8 = 64; -pub type ScryptoEncoder<'a> = sbor::Encoder<'a, ScryptoCustomTypeId>; -pub type ScryptoDecoder<'a> = sbor::Decoder<'a, ScryptoCustomTypeId>; -pub type ScryptoTypeId = sbor::SborTypeId; -pub type ScryptoValue = sbor::SborValue; +pub type ScryptoEncoder<'a> = VecEncoder<'a, ScryptoCustomTypeId, MAX_SCRYPTO_SBOR_DEPTH>; +pub type ScryptoDecoder<'a> = VecDecoder<'a, ScryptoCustomTypeId, MAX_SCRYPTO_SBOR_DEPTH>; +pub type ScryptoSborTypeId = SborTypeId; +pub type ScryptoValue = SborValue; + +// The following trait "aliases" are to be used in parameters. +// +// They are much nicer to read than the underlying traits, but because they are "new", and are defined +// via blanket impls, they can only be used for parameters, but cannot be used for implementations. +// +// Implementations should instead implement the underlying traits: +// * TypeId +// * Encode (impl over all E: Encoder) +// * Decode (impl over all D: Decoder) +// +// TODO: Change these to be Trait aliases once stable in rust: https://github.com/rust-lang/rust/issues/41517 +pub trait ScryptoTypeId: TypeId {} +impl + ?Sized> ScryptoTypeId for T {} + +pub trait ScryptoDecode: for<'a> Decode> {} +impl Decode>> ScryptoDecode for T {} + +pub trait ScryptoEncode: for<'a> Encode> {} +impl Encode> + ?Sized> ScryptoEncode for T {} /// Encodes a data structure into byte array. -pub fn scrypto_encode + ?Sized>(v: &T) -> Vec { - encode(v) +pub fn scrypto_encode(value: &T) -> Result, EncodeError> { + let mut buf = Vec::with_capacity(512); + let encoder = ScryptoEncoder::new(&mut buf); + encoder.encode_payload(value)?; + Ok(buf) } -pub fn scrypto_decode>(buf: &[u8]) -> Result { - decode(buf) +/// Decodes a data structure from a byte array. +pub fn scrypto_decode(buf: &[u8]) -> Result { + ScryptoDecoder::new(buf).decode_payload() } #[macro_export] @@ -48,16 +75,15 @@ macro_rules! count { #[macro_export] macro_rules! args { ($($args: expr),*) => {{ - use ::sbor::Encode; + use ::sbor::Encoder; let mut buf = ::sbor::rust::vec::Vec::new(); let mut encoder = radix_engine_interface::data::ScryptoEncoder::new(&mut buf); - encoder.write_type_id(radix_engine_interface::data::ScryptoTypeId::Struct); + encoder.write_type_id(radix_engine_interface::data::ScryptoSborTypeId::Struct).unwrap(); // Hack: stringify to skip ownership move semantics - encoder.write_size(radix_engine_interface::count!($(stringify!($args)),*)); + encoder.write_size(radix_engine_interface::count!($(stringify!($args)),*)).unwrap(); $( let arg = $args; - arg.encode_type_id(&mut encoder); - arg.encode_body(&mut encoder); + encoder.encode(&arg).unwrap(); )* buf }}; @@ -69,7 +95,13 @@ mod tests { use crate::model::*; use crate::scrypto; use sbor::rust::borrow::ToOwned; + use sbor::rust::cell::RefCell; + use sbor::rust::collections::BTreeMap; use sbor::rust::collections::BTreeSet; + use sbor::rust::collections::HashMap; + use sbor::rust::collections::HashSet; + use sbor::rust::hash::Hash; + use sbor::rust::rc::Rc; use sbor::rust::string::String; #[test] @@ -86,6 +118,7 @@ mod tests { a: 1, b: "abc".to_owned(), }) + .unwrap() ) } @@ -94,4 +127,370 @@ mod tests { let id = NonFungibleId::from_u32(1); let _x = args!(BTreeSet::from([id])); } + + #[test] + fn test_encode_deep_scrypto_values() { + // This test tests that the ScryptoValue Encode implementation correctly increments the depth + + // Test deep scrypto value vecs + let valid_value = build_value_of_vec_of_depth(MAX_SCRYPTO_SBOR_DEPTH); + assert!(scrypto_encode(&valid_value).is_ok()); + + let invalid_value = build_value_of_vec_of_depth(MAX_SCRYPTO_SBOR_DEPTH + 1); + assert!(matches!( + scrypto_encode(&invalid_value), + Err(EncodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + + // Test deep scrypto value tuples + let valid_value = build_value_of_tuple_of_depth(MAX_SCRYPTO_SBOR_DEPTH); + assert!(scrypto_encode(&valid_value).is_ok()); + + let invalid_value = build_value_of_tuple_of_depth(MAX_SCRYPTO_SBOR_DEPTH + 1); + assert!(matches!( + scrypto_encode(&invalid_value), + Err(EncodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + } + + #[test] + fn test_decode_deep_scrypto_values() { + // This test tests that the ScryptoValue Decode implementation correctly increments the depth + + // Test deep scrypto value vecs + let valid_payload = + encode_ignore_depth(&build_value_of_vec_of_depth(MAX_SCRYPTO_SBOR_DEPTH)); + assert!(scrypto_decode::(&valid_payload).is_ok()); + + let invalid_payload = + encode_ignore_depth(&build_value_of_vec_of_depth(MAX_SCRYPTO_SBOR_DEPTH + 1)); + assert!(matches!( + scrypto_decode::(&invalid_payload), + Err(DecodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + + // Test deep scrypto value tuples + let valid_payload = + encode_ignore_depth(&build_value_of_tuple_of_depth(MAX_SCRYPTO_SBOR_DEPTH)); + assert!(scrypto_decode::(&valid_payload).is_ok()); + + let invalid_payload = + encode_ignore_depth(&build_value_of_tuple_of_depth(MAX_SCRYPTO_SBOR_DEPTH + 1)); + assert!(matches!( + scrypto_decode::(&invalid_payload), + Err(DecodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + } + + #[test] + fn test_encode_deep_typed_codecs() { + // This test tests that various typed codecs have an Encode implementation which correctly increments the depth + // It also tests that depth behaves identically to the ScryptoValue interpretation + + // Test deep vecs + let valid_value = wrap_in_64_collections(Option::::None); + assert!(scrypto_encode(&valid_value).is_ok()); + let valid_value_as_scrypto_value = + decode_ignore_depth::(&encode_ignore_depth(&valid_value)); + assert!(scrypto_encode(&valid_value_as_scrypto_value).is_ok()); + + let invalid_value = vec![wrap_in_64_collections(Option::::None)]; + assert!(matches!( + scrypto_encode(&invalid_value), + Err(EncodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + let invalid_value_as_scrypto_value = + decode_ignore_depth::(&encode_ignore_depth(&invalid_value)); + assert!(matches!( + scrypto_encode(&invalid_value_as_scrypto_value), + Err(EncodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + + // Test deep nested types + let valid_value = build_nested_struct_of_depth(MAX_SCRYPTO_SBOR_DEPTH); + assert!(scrypto_encode(&valid_value).is_ok()); + let valid_value_as_scrypto_value = + decode_ignore_depth::(&encode_ignore_depth(&valid_value)); + assert!(scrypto_encode(&valid_value_as_scrypto_value).is_ok()); + + let invalid_value = vec![build_nested_struct_of_depth(MAX_SCRYPTO_SBOR_DEPTH)]; + assert!(matches!( + scrypto_encode(&invalid_value), + Err(EncodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + let invalid_value_as_scrypto_value = + decode_ignore_depth::(&encode_ignore_depth(&invalid_value)); + assert!(matches!( + scrypto_encode(&invalid_value_as_scrypto_value), + Err(EncodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + + // Test hashmaps + let valid_value = wrap_in_hashmap(build_nested_struct_of_depth(MAX_SCRYPTO_SBOR_DEPTH - 2)); // Maps add 2 depth (for now) + assert!(scrypto_encode(&valid_value).is_ok()); + let valid_value_as_scrypto_value = + decode_ignore_depth::(&encode_ignore_depth(&valid_value)); + assert!(scrypto_encode(&valid_value_as_scrypto_value).is_ok()); + + let invalid_value = vec![wrap_in_hashmap(build_nested_struct_of_depth( + MAX_SCRYPTO_SBOR_DEPTH - 2, + ))]; + assert!(matches!( + scrypto_encode(&invalid_value), + Err(EncodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + let invalid_value_as_scrypto_value = + decode_ignore_depth::(&encode_ignore_depth(&invalid_value)); + assert!(matches!( + scrypto_encode(&invalid_value_as_scrypto_value), + Err(EncodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + + // Test hashsets + tuples + let valid_value = wrap_in_61_vecs(Some(wrap_in_tuple_single(wrap_in_hashset("hello")))); + assert!(scrypto_encode(&valid_value).is_ok()); + let valid_value_as_scrypto_value = + decode_ignore_depth::(&encode_ignore_depth(&valid_value)); + assert!(scrypto_encode(&valid_value_as_scrypto_value).is_ok()); + + let invalid_value = vec![wrap_in_61_vecs(Some(wrap_in_tuple_single( + wrap_in_hashset("hello"), + )))]; + assert!(matches!( + scrypto_encode(&invalid_value), + Err(EncodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + let invalid_value_as_scrypto_value = + decode_ignore_depth::(&encode_ignore_depth(&invalid_value)); + assert!(matches!( + scrypto_encode(&invalid_value_as_scrypto_value), + Err(EncodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + } + + #[test] + fn test_decode_deep_typed_codecs() { + // This test tests that various typed codecs have a Decode implementation which correctly increments the depth + // It also tests that depth behaves identically to the ScryptoValue interpretation + + // Test deep vecs + let valid_payload = encode_ignore_depth(&wrap_in_64_collections(Option::::None)); + assert!(scrypto_decode::>(&valid_payload).is_ok()); + assert!(scrypto_decode::(&valid_payload).is_ok()); + + let invalid_payload = + encode_ignore_depth(&vec![wrap_in_64_collections(Option::::None)]); // 65 deep + assert!(matches!( + scrypto_decode::>>(&invalid_payload), + Err(DecodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + assert!(matches!( + scrypto_decode::(&invalid_payload), + Err(DecodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + + // Test deep nested types + let valid_payload = + encode_ignore_depth(&build_nested_struct_of_depth(MAX_SCRYPTO_SBOR_DEPTH)); + assert!(scrypto_decode::(&valid_payload).is_ok()); + assert!(scrypto_decode::(&valid_payload).is_ok()); + + let invalid_payload = + encode_ignore_depth(&vec![build_nested_struct_of_depth(MAX_SCRYPTO_SBOR_DEPTH)]); // 65 deep + assert!(matches!( + scrypto_decode::>(&invalid_payload), + Err(DecodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + assert!(matches!( + scrypto_decode::(&invalid_payload), + Err(DecodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + + // Test hashmaps + let valid_payload = encode_ignore_depth(&wrap_in_hashmap(build_nested_struct_of_depth( + MAX_SCRYPTO_SBOR_DEPTH - 2, + ))); // Maps add 2 depth (for now) + assert!(scrypto_decode::>(&valid_payload).is_ok()); + assert!(scrypto_decode::(&valid_payload).is_ok()); + + let invalid_payload = encode_ignore_depth(&vec![wrap_in_hashmap( + build_nested_struct_of_depth(MAX_SCRYPTO_SBOR_DEPTH - 2), + )]); + assert!(matches!( + scrypto_decode::>>(&invalid_payload), + Err(DecodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + assert!(matches!( + scrypto_decode::(&invalid_payload), + Err(DecodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + + // Test hashsets + tuples + let valid_payload = encode_ignore_depth(&wrap_in_61_vecs(Some(wrap_in_tuple_single( + wrap_in_hashset("hello"), + )))); + assert!(scrypto_decode::,)>>(&valid_payload).is_ok()); + assert!(scrypto_decode::(&valid_payload).is_ok()); + + let invalid_payload = encode_ignore_depth(&vec![wrap_in_61_vecs(Some( + wrap_in_tuple_single(wrap_in_hashset("hello")), + ))]); + assert!(matches!( + scrypto_decode::,)>>>(&invalid_payload), + Err(DecodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + assert!(matches!( + scrypto_decode::(&invalid_payload), + Err(DecodeError::MaxDepthExceeded(MAX_SCRYPTO_SBOR_DEPTH)) + )); + } + + fn encode_ignore_depth< + V: for<'a> Encode>, + >( + value: &V, + ) -> Vec { + let mut buf = Vec::new(); + let encoder = VecEncoder::::new(&mut buf); + encoder.encode_payload(value).unwrap(); + buf + } + + fn decode_ignore_depth< + 'a, + T: Decode>, + >( + payload: &'a [u8], + ) -> T { + let decoder = VecDecoder::::new(payload); + decoder.decode_payload().unwrap() + } + + fn build_value_of_vec_of_depth(depth: u8) -> ScryptoValue { + let mut value = ScryptoValue::Array { + element_type_id: SborTypeId::Array, + elements: vec![], + }; + let loop_count = depth - 1; + for _ in 0..loop_count { + value = ScryptoValue::Array { + element_type_id: SborTypeId::Array, + elements: vec![value], + }; + } + value + } + + fn build_value_of_tuple_of_depth(depth: u8) -> ScryptoValue { + let mut value = ScryptoValue::Tuple { elements: vec![] }; + let loop_count = depth - 1; + for _ in 0..loop_count { + value = ScryptoValue::Tuple { + elements: vec![value], + }; + } + value + } + + #[scrypto(TypeId, Encode, Decode)] + #[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] + struct NestedType { + inner: Box>>>, + } + + fn build_nested_struct_of_depth(depth: u8) -> NestedType { + assert!(depth % 2 == 0); + assert!(depth >= 2); + + // Note - each nesting introduces 2 depth - one for the NestedType, another for the Option (the Box/Rc/RefCell should be transparent) + let mut value = NestedType { + inner: Box::new(Rc::new(None)), + }; + let loop_count = (depth / 2) - 1; + for _ in 0..loop_count { + value = NestedType { + inner: Box::new(Rc::new(Some(RefCell::new(value)))), + }; + } + value + } + + type SixtyOneDeepVec = SixteenDeepVec< + SixteenDeepVec>>>>>, + >; + type SixteenDeepVec = FourDeepVec>>>; + type FourDeepVec = Vec>>>; + + fn wrap_in_61_vecs(inner: Option) -> SixtyOneDeepVec { + vec![wrap_in_16_vecs(Some(wrap_in_16_vecs(Some( + wrap_in_16_vecs(Some(wrap_in_4_vecs(Some(wrap_in_4_vecs(Some( + wrap_in_4_vecs(inner), + )))))), + ))))] + } + + fn wrap_in_16_vecs(inner: Option) -> SixteenDeepVec { + wrap_in_4_vecs(Some(wrap_in_4_vecs(Some(wrap_in_4_vecs(Some( + wrap_in_4_vecs(inner), + )))))) + } + + fn wrap_in_4_vecs(inner: Option) -> FourDeepVec { + let inner = match inner { + Some(inner) => vec![inner], + None => vec![], + }; + vec![vec![vec![inner]]] + } + + type SixtyFourDeepCollection = SixteenDeepCollection< + SixteenDeepCollection>>, + >; + + fn wrap_in_64_collections(inner: Option) -> SixtyFourDeepCollection { + wrap_in_16_collections(Some(wrap_in_16_collections(Some(wrap_in_16_collections( + Some(wrap_in_16_collections(inner)), + ))))) + } + + type SixteenDeepCollection = + FourDeepCollection>>>; + + fn wrap_in_16_collections(inner: Option) -> SixteenDeepCollection { + wrap_in_4_collections(Some(wrap_in_4_collections(Some(wrap_in_4_collections( + Some(wrap_in_4_collections(inner)), + ))))) + } + + // NB - can't use Hash stuff here because they can't nest + // NOTE - Maps encode currently as Vec> so count as two deep + type FourDeepCollection = BTreeMap>>; + + fn wrap_in_4_collections(inner: Option) -> FourDeepCollection { + let inner = match inner { + Some(inner) => vec![inner], + None => vec![], + }; + let mut inner2 = BTreeSet::new(); + inner2.insert(inner); + let mut inner3 = BTreeMap::new(); + inner3.insert(1, inner2); + inner3 + } + + fn wrap_in_hashmap(inner: T) -> HashMap { + let mut value = HashMap::new(); + value.insert(1, inner); + value + } + + fn wrap_in_hashset(inner: T) -> HashSet { + let mut value = HashSet::new(); + value.insert(inner); + value + } + + fn wrap_in_tuple_single(inner: T) -> (T,) { + (inner,) + } } diff --git a/radix-engine-interface/src/data/schema_matcher.rs b/radix-engine-interface/src/data/schema_matcher.rs index 69931c46a52..97c5f51b8d0 100644 --- a/radix-engine-interface/src/data/schema_matcher.rs +++ b/radix-engine-interface/src/data/schema_matcher.rs @@ -2,7 +2,7 @@ use crate::data::*; use sbor::*; use scrypto_abi::{Fields, Type}; -pub fn sbor_type_id(ty: &Type) -> Option { +pub fn sbor_type_id(ty: &Type) -> Option { match ty { Type::Unit => Some(SborTypeId::Unit), Type::Bool => Some(SborTypeId::Bool), diff --git a/radix-engine-interface/src/data/value_formatter.rs b/radix-engine-interface/src/data/value_formatter.rs index 33a5e76dd12..ec69248b951 100644 --- a/radix-engine-interface/src/data/value_formatter.rs +++ b/radix-engine-interface/src/data/value_formatter.rs @@ -127,7 +127,7 @@ pub fn format_scrypto_value( Ok(()) } -pub fn format_type_id(f: &mut F, type_id: &ScryptoTypeId) -> fmt::Result { +pub fn format_type_id(f: &mut F, type_id: &ScryptoSborTypeId) -> fmt::Result { match type_id { SborTypeId::Unit => f.write_str("Unit"), SborTypeId::Bool => f.write_str("Bool"), diff --git a/radix-engine-interface/src/lib.rs b/radix-engine-interface/src/lib.rs index 785b1be7f30..a209941b7bd 100644 --- a/radix-engine-interface/src/lib.rs +++ b/radix-engine-interface/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit = "256"] // Enables certain tests of deep typed SBOR to function #[cfg(not(any(feature = "std", feature = "alloc")))] compile_error!("Either feature `std` or `alloc` must be enabled for this crate."); diff --git a/radix-engine-interface/src/macros.rs b/radix-engine-interface/src/macros.rs index 77918f29d6a..e617ba507fe 100644 --- a/radix-engine-interface/src/macros.rs +++ b/radix-engine-interface/src/macros.rs @@ -77,23 +77,25 @@ macro_rules! scrypto_type { } } - impl sbor::Encode for $t { + impl> + sbor::Encode for $t + { #[inline] - fn encode_type_id( - &self, - encoder: &mut sbor::Encoder, - ) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut sbor::Encoder) { - encoder.write_slice(&self.to_vec()); + fn encode_body(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> { + encoder.write_slice(&self.to_vec()) } } - impl sbor::Decode for $t { + impl> + sbor::Decode for $t + { fn decode_body_with_type_id( - decoder: &mut sbor::Decoder, + decoder: &mut D, type_id: sbor::SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -118,25 +120,27 @@ macro_rules! scrypto_type { } } - impl sbor::Encode for $t { + impl> + sbor::Encode for $t + { #[inline] - fn encode_type_id( - &self, - encoder: &mut sbor::Encoder, - ) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut sbor::Encoder) { + fn encode_body(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> { let bytes = self.to_vec(); - encoder.write_size(bytes.len()); - encoder.write_slice(&bytes); + encoder.write_size(bytes.len())?; + encoder.write_slice(&bytes) } } - impl sbor::Decode for $t { + impl> + sbor::Decode for $t + { fn decode_body_with_type_id( - decoder: &mut sbor::Decoder, + decoder: &mut D, type_id: sbor::SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; diff --git a/radix-engine-interface/src/math/decimal.rs b/radix-engine-interface/src/math/decimal.rs index 13e16bd11b9..c501b8f4158 100644 --- a/radix-engine-interface/src/math/decimal.rs +++ b/radix-engine-interface/src/math/decimal.rs @@ -1045,8 +1045,8 @@ mod tests { #[test] fn test_encode_decimal_type_decimal() { let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::new(&mut bytes); - dec!("1").encode_type_id(&mut enc); + let mut enc = ScryptoEncoder::new(&mut bytes); + dec!("1").encode_type_id(&mut enc).unwrap(); assert_eq!(bytes, vec![Decimal::type_id().as_u8()]); } @@ -1054,9 +1054,9 @@ mod tests { fn test_encode_decimal_value_decimal() { let dec = dec!("0"); let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::new(&mut bytes); - dec.encode_type_id(&mut enc); - dec.encode_body(&mut enc); + let mut enc = ScryptoEncoder::new(&mut bytes); + dec.encode_type_id(&mut enc).unwrap(); + dec.encode_body(&mut enc).unwrap(); assert_eq!(bytes, { let mut a = [0; 33]; a[0] = Decimal::type_id().as_u8(); @@ -1067,9 +1067,9 @@ mod tests { #[test] fn test_decode_decimal_type_decimal() { let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::new(&mut bytes); - dec!("1").encode_type_id(&mut enc); - let mut decoder = Decoder::new(&bytes); + let mut enc = ScryptoEncoder::new(&mut bytes); + dec!("1").encode_type_id(&mut enc).unwrap(); + let mut decoder = ScryptoDecoder::new(&bytes); let typ = decoder.read_type_id().unwrap(); assert_eq!(typ, Decimal::type_id()); } @@ -1078,11 +1078,11 @@ mod tests { fn test_decode_decimal_value_decimal() { let dec = dec!("1.23456789"); let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::new(&mut bytes); - dec.encode_type_id(&mut enc); - dec.encode_body(&mut enc); - let mut decoder = Decoder::new(&bytes); - let val = Decimal::decode(&mut decoder).unwrap(); + let mut enc = ScryptoEncoder::new(&mut bytes); + dec.encode_type_id(&mut enc).unwrap(); + dec.encode_body(&mut enc).unwrap(); + let mut decoder = ScryptoDecoder::new(&bytes); + let val = decoder.decode::().unwrap(); assert_eq!(val, dec!("1.23456789")); } diff --git a/radix-engine-interface/src/math/integer.rs b/radix-engine-interface/src/math/integer.rs index 376bcca6364..c326262c6e5 100644 --- a/radix-engine-interface/src/math/integer.rs +++ b/radix-engine-interface/src/math/integer.rs @@ -291,20 +291,21 @@ macro_rules! sbor_codec { } } - impl Encode for $t { + impl> Encode for $t { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_slice(&self.to_le_bytes()); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_slice(&self.to_le_bytes()) } } - impl Decode for $t { + impl> Decode for $t { fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -887,24 +888,25 @@ mod tests { use super::*; use crate::data::*; - fn encode_integers(enc: &mut Encoder) { - I8::by(1i8).encode(enc); - I16::by(1i8).encode(enc); - I32::by(1i8).encode(enc); - I64::by(1i8).encode(enc); - I128::by(1i8).encode(enc); - U8::by(1u8).encode(enc); - U16::by(1u8).encode(enc); - U32::by(1u8).encode(enc); - U64::by(1u8).encode(enc); - U128::by(1u8).encode(enc); + fn encode_integers(encoder: &mut ScryptoEncoder) -> Result<(), EncodeError> { + encoder.encode(&I8::by(1i8))?; + encoder.encode(&I16::by(1i8))?; + encoder.encode(&I32::by(1i8))?; + encoder.encode(&I64::by(1i8))?; + encoder.encode(&I128::by(1i8))?; + encoder.encode(&U8::by(1u8))?; + encoder.encode(&U16::by(1u8))?; + encoder.encode(&U32::by(1u8))?; + encoder.encode(&U64::by(1u8))?; + encoder.encode(&U128::by(1u8))?; + Ok(()) } #[test] fn test_integer_encoding() { let mut bytes = Vec::with_capacity(512); let mut enc = ScryptoEncoder::new(&mut bytes); - encode_integers(&mut enc); + encode_integers(&mut enc).unwrap(); assert_eq!( vec![ @@ -927,18 +929,18 @@ mod tests { fn test_integer_decoding() { let mut bytes = Vec::with_capacity(512); let mut enc = ScryptoEncoder::new(&mut bytes); - encode_integers(&mut enc); - - let mut dec = ScryptoDecoder::new(&bytes); - assert_eq!(I8::by(1i8), ::decode(&mut dec).unwrap()); - assert_eq!(I16::by(1i8), ::decode(&mut dec).unwrap()); - assert_eq!(I32::by(1i8), ::decode(&mut dec).unwrap()); - assert_eq!(I64::by(1i8), ::decode(&mut dec).unwrap()); - assert_eq!(I128::by(1i8), ::decode(&mut dec).unwrap()); - assert_eq!(U8::by(1u8), ::decode(&mut dec).unwrap()); - assert_eq!(U16::by(1u8), ::decode(&mut dec).unwrap()); - assert_eq!(U32::by(1u8), ::decode(&mut dec).unwrap()); - assert_eq!(U64::by(1u8), ::decode(&mut dec).unwrap()); - assert_eq!(U128::by(1u8), ::decode(&mut dec).unwrap()); + encode_integers(&mut enc).unwrap(); + + let mut decoder = ScryptoDecoder::new(&bytes); + assert_eq!(I8::by(1i8), decoder.decode::().unwrap()); + assert_eq!(I16::by(1i8), decoder.decode::().unwrap()); + assert_eq!(I32::by(1i8), decoder.decode::().unwrap()); + assert_eq!(I64::by(1i8), decoder.decode::().unwrap()); + assert_eq!(I128::by(1i8), decoder.decode::().unwrap()); + assert_eq!(U8::by(1u8), decoder.decode::().unwrap()); + assert_eq!(U16::by(1u8), decoder.decode::().unwrap()); + assert_eq!(U32::by(1u8), decoder.decode::().unwrap()); + assert_eq!(U64::by(1u8), decoder.decode::().unwrap()); + assert_eq!(U128::by(1u8), decoder.decode::().unwrap()); } } diff --git a/radix-engine-interface/src/math/precise_decimal.rs b/radix-engine-interface/src/math/precise_decimal.rs index e165bf29807..afdf805da1e 100644 --- a/radix-engine-interface/src/math/precise_decimal.rs +++ b/radix-engine-interface/src/math/precise_decimal.rs @@ -1069,8 +1069,8 @@ mod tests { #[test] fn test_encode_decimal_type_precise_decimal() { let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::new(&mut bytes); - pdec!("1").encode_type_id(&mut enc); + let mut enc = ScryptoEncoder::new(&mut bytes); + pdec!("1").encode_type_id(&mut enc).unwrap(); assert_eq!(bytes, vec![PreciseDecimal::type_id().as_u8()]); } @@ -1078,9 +1078,9 @@ mod tests { fn test_encode_decimal_value_precise_decimal() { let pdec = pdec!("0"); let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::new(&mut bytes); - pdec.encode_type_id(&mut enc); - pdec.encode_body(&mut enc); + let mut enc = ScryptoEncoder::new(&mut bytes); + pdec.encode_type_id(&mut enc).unwrap(); + pdec.encode_body(&mut enc).unwrap(); assert_eq!(bytes, { let mut a = [0; 65]; a[0] = PreciseDecimal::type_id().as_u8(); @@ -1091,9 +1091,9 @@ mod tests { #[test] fn test_decode_decimal_type_precise_decimal() { let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::new(&mut bytes); - pdec!("1").encode_type_id(&mut enc); - let mut decoder = Decoder::new(&bytes); + let mut enc = ScryptoEncoder::new(&mut bytes); + pdec!("1").encode_type_id(&mut enc).unwrap(); + let mut decoder = ScryptoDecoder::new(&bytes); let typ = decoder.read_type_id().unwrap(); assert_eq!(typ, PreciseDecimal::type_id()); } @@ -1102,11 +1102,11 @@ mod tests { fn test_decode_decimal_value_precise_decimal() { let pdec = pdec!("1.23456789"); let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::new(&mut bytes); - pdec.encode_type_id(&mut enc); - pdec.encode_body(&mut enc); - let mut decoder = Decoder::new(&bytes); - let val = PreciseDecimal::decode(&mut decoder).unwrap(); + let mut enc = ScryptoEncoder::new(&mut bytes); + pdec.encode_type_id(&mut enc).unwrap(); + pdec.encode_body(&mut enc).unwrap(); + let mut decoder = ScryptoDecoder::new(&bytes); + let val = decoder.decode::().unwrap(); assert_eq!(val, pdec!("1.23456789")); } diff --git a/radix-engine-interface/src/model/resource/mint_params.rs b/radix-engine-interface/src/model/resource/mint_params.rs index 7f22b6a3e8b..4bae3c6480f 100644 --- a/radix-engine-interface/src/model/resource/mint_params.rs +++ b/radix-engine-interface/src/model/resource/mint_params.rs @@ -32,7 +32,7 @@ impl MintParams { { let mut encoded = HashMap::new(); for (id, e) in entries { - encoded.insert(id, (e.immutable_data(), e.mutable_data())); + encoded.insert(id, (e.immutable_data().unwrap(), e.mutable_data().unwrap())); } Self::NonFungible { entries: encoded } diff --git a/radix-engine-interface/src/model/resource/non_fungible_data.rs b/radix-engine-interface/src/model/resource/non_fungible_data.rs index 74ca68ca26f..69ebd8e4846 100644 --- a/radix-engine-interface/src/model/resource/non_fungible_data.rs +++ b/radix-engine-interface/src/model/resource/non_fungible_data.rs @@ -1,5 +1,5 @@ use sbor::rust::vec::Vec; -use sbor::DecodeError; +use sbor::{DecodeError, EncodeError}; use scrypto_abi::Type; /// Represents the data structure of a non-fungible. @@ -10,10 +10,10 @@ pub trait NonFungibleData { Self: Sized; /// Returns the serialization of the immutable data part. - fn immutable_data(&self) -> Vec; + fn immutable_data(&self) -> Result, EncodeError>; /// Returns the serialization of the mutable data part. - fn mutable_data(&self) -> Vec; + fn mutable_data(&self) -> Result, EncodeError>; /// Returns the schema of the immutable data. fn immutable_data_schema() -> Type; diff --git a/radix-engine-interface/src/model/resource/non_fungible_id.rs b/radix-engine-interface/src/model/resource/non_fungible_id.rs index 942222049dc..e76f4e23497 100644 --- a/radix-engine-interface/src/model/resource/non_fungible_id.rs +++ b/radix-engine-interface/src/model/resource/non_fungible_id.rs @@ -17,17 +17,17 @@ pub struct NonFungibleId(pub Vec); impl NonFungibleId { /// Creates a non-fungible ID from an arbitrary byte array. pub fn from_bytes(v: Vec) -> Self { - Self(scrypto_encode(&v)) + Self(scrypto_encode(&v).expect("Error encoding byte array")) } /// Creates a non-fungible ID from a `u32` number. pub fn from_u32(u: u32) -> Self { - Self(scrypto_encode(&u)) + Self(scrypto_encode(&u).expect("Error encoding u32")) } /// Creates a non-fungible ID from a `u64` number. pub fn from_u64(u: u64) -> Self { - Self(scrypto_encode(&u)) + Self(scrypto_encode(&u).expect("Error encoding u64")) } } @@ -62,28 +62,28 @@ fn validate_id(slice: &[u8]) -> Result<(), DecodeError> { let type_id = decoder.read_type_id()?; match type_id { // TODO: add more allowed types as agreed - ScryptoTypeId::U32 => { + ScryptoSborTypeId::U32 => { decoder.read_slice(4)?; } - ScryptoTypeId::U64 => { + ScryptoSborTypeId::U64 => { decoder.read_slice(8)?; } - ScryptoTypeId::Array => { + ScryptoSborTypeId::Array => { let element_type_id = decoder.read_type_id()?; - if element_type_id == ScryptoTypeId::U8 { + if element_type_id == ScryptoSborTypeId::U8 { let size = decoder.read_size()?; decoder.read_slice(size)?; } else { return Err(DecodeError::UnexpectedTypeId { actual: element_type_id.as_u8(), - expected: ScryptoTypeId::U8.as_u8(), + expected: ScryptoSborTypeId::U8.as_u8(), }); } } type_id => { return Err(DecodeError::UnexpectedTypeId { actual: type_id.as_u8(), - expected: ScryptoTypeId::U32.as_u8(), // TODO: make it a vec + expected: ScryptoSborTypeId::U32.as_u8(), // TODO: make it a vec }); } } diff --git a/radix-engine-stores/src/memory_db.rs b/radix-engine-stores/src/memory_db.rs index 48935447a50..8634129318c 100644 --- a/radix-engine-stores/src/memory_db.rs +++ b/radix-engine-stores/src/memory_db.rs @@ -34,15 +34,17 @@ impl Default for SerializedInMemorySubstateStore { impl ReadableSubstateStore for SerializedInMemorySubstateStore { fn get_substate(&self, substate_id: &SubstateId) -> Option { self.substates - .get(&scrypto_encode(substate_id)) + .get(&scrypto_encode(substate_id).expect("Could not encode substate id")) .map(|b| scrypto_decode(&b).unwrap()) } } impl WriteableSubstateStore for SerializedInMemorySubstateStore { fn put_substate(&mut self, substate_id: SubstateId, substate: OutputValue) { - self.substates - .insert(scrypto_encode(&substate_id), scrypto_encode(&substate)); + self.substates.insert( + scrypto_encode(&substate_id).expect("Could not encode substate id"), + scrypto_encode(&substate).expect("Could not encode substate"), + ); } } diff --git a/radix-engine-stores/src/rocks_db.rs b/radix-engine-stores/src/rocks_db.rs index d44809be82a..6187e999b9e 100644 --- a/radix-engine-stores/src/rocks_db.rs +++ b/radix-engine-stores/src/rocks_db.rs @@ -4,8 +4,7 @@ use std::path::PathBuf; use radix_engine::ledger::*; use radix_engine::model::PersistedSubstate; use radix_engine::types::*; -use radix_engine_interface::api::types::RENodeId; -use radix_engine_interface::data::ScryptoCustomTypeId; +use radix_engine_interface::{api::types::RENodeId, data::ScryptoDecode}; use rocksdb::{DBWithThreadMode, Direction, IteratorMode, SingleThreaded, DB}; pub struct RadixEngineDB { @@ -28,11 +27,13 @@ impl RadixEngineDB { let start = &scrypto_encode(&SubstateId( RENodeId::Global(GlobalAddress::Package(PackageAddress::Normal([0; 26]))), SubstateOffset::Global(GlobalOffset::Global), - )); + )) + .unwrap(); let end = &scrypto_encode(&SubstateId( RENodeId::Global(GlobalAddress::Package(PackageAddress::Normal([255; 26]))), SubstateOffset::Global(GlobalOffset::Global), - )); + )) + .unwrap(); let substate_ids: Vec = self.list_items(start, end); substate_ids .into_iter() @@ -58,11 +59,13 @@ impl RadixEngineDB { let start = &scrypto_encode(&SubstateId( RENodeId::Global(GlobalAddress::Component(start)), SubstateOffset::Global(GlobalOffset::Global), - )); + )) + .unwrap(); let end = &scrypto_encode(&SubstateId( RENodeId::Global(GlobalAddress::Component(end)), SubstateOffset::Global(GlobalOffset::Global), - )); + )) + .unwrap(); let substate_ids: Vec = self.list_items(start, end); substate_ids .into_iter() @@ -97,11 +100,13 @@ impl RadixEngineDB { let start = &scrypto_encode(&SubstateId( RENodeId::Global(GlobalAddress::Resource(ResourceAddress::Normal([0; 26]))), SubstateOffset::Global(GlobalOffset::Global), - )); + )) + .unwrap(); let end = &scrypto_encode(&SubstateId( RENodeId::Global(GlobalAddress::Resource(ResourceAddress::Normal([255; 26]))), SubstateOffset::Global(GlobalOffset::Global), - )); + )) + .unwrap(); let substate_ids: Vec = self.list_items(start, end); substate_ids .into_iter() @@ -119,11 +124,7 @@ impl RadixEngineDB { .collect() } - fn list_items>( - &self, - start: &[u8], - inclusive_end: &[u8], - ) -> Vec { + fn list_items(&self, start: &[u8], inclusive_end: &[u8]) -> Vec { let mut iter = self .db .iterator(IteratorMode::From(start, Direction::Forward)); @@ -142,11 +143,18 @@ impl RadixEngineDB { fn read(&self, substate_id: &SubstateId) -> Option> { // TODO: Use get_pinned - self.db.get(scrypto_encode(substate_id)).unwrap() + self.db + .get(scrypto_encode(substate_id).expect("Could not encode substate id")) + .unwrap() } fn write(&self, substate_id: SubstateId, value: Vec) { - self.db.put(scrypto_encode(&substate_id), value).unwrap(); + self.db + .put( + scrypto_encode(&substate_id).expect("Could not encode substate id"), + value, + ) + .unwrap(); } } @@ -155,11 +163,14 @@ impl QueryableSubstateStore for RadixEngineDB { &self, kv_store_id: &KeyValueStoreId, ) -> HashMap, PersistedSubstate> { - let unit = scrypto_encode(&()); + let unit = scrypto_encode(&()).unwrap(); let id = scrypto_encode(&SubstateId( RENodeId::KeyValueStore(kv_store_id.clone()), - SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(&unit))), - )); + SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry( + scrypto_encode(&unit).unwrap(), + )), + )) + .unwrap(); let mut iter = self .db @@ -189,12 +200,16 @@ impl QueryableSubstateStore for RadixEngineDB { impl ReadableSubstateStore for RadixEngineDB { fn get_substate(&self, substate_id: &SubstateId) -> Option { - self.read(substate_id).map(|b| scrypto_decode(&b).unwrap()) + self.read(substate_id) + .map(|b| scrypto_decode(&b).expect("Could not decode persisted substate")) } } impl WriteableSubstateStore for RadixEngineDB { fn put_substate(&mut self, substate_id: SubstateId, substate: OutputValue) { - self.write(substate_id, scrypto_encode(&substate)); + self.write( + substate_id, + scrypto_encode(&substate).expect("Could not encode substate for persistence"), + ); } } diff --git a/radix-engine/benches/radix_engine.rs b/radix-engine/benches/radix_engine.rs index 37555c9da02..9716f6bcb04 100644 --- a/radix-engine/benches/radix_engine.rs +++ b/radix-engine/benches/radix_engine.rs @@ -24,7 +24,7 @@ fn bench_transfer(c: &mut Criterion) { wasm_instrumenter: WasmInstrumenter::default(), wasm_metering_config: WasmMeteringConfig::new( InstructionCostRules::tiered(1, 5, 10, 5000), - 512, + 1024, ), }; diff --git a/radix-engine/benches/transaction.rs b/radix-engine/benches/transaction.rs index 1530f72a9f5..a0aebfa39b1 100644 --- a/radix-engine/benches/transaction.rs +++ b/radix-engine/benches/transaction.rs @@ -79,7 +79,7 @@ fn bench_transaction_validation(c: &mut Criterion) { ) .notarize(&signer) .build(); - let transaction_bytes = transaction.to_bytes(); + let transaction_bytes = transaction.to_bytes().unwrap(); println!("Transaction size: {} bytes", transaction_bytes.len()); let validator = NotarizedTransactionValidator::new(ValidationConfig::simulator()); diff --git a/radix-engine/src/engine/errors.rs b/radix-engine/src/engine/errors.rs index d6bc398f945..7064388b22b 100644 --- a/radix-engine/src/engine/errors.rs +++ b/radix-engine/src/engine/errors.rs @@ -89,6 +89,7 @@ pub enum KernelError { // SBOR decoding InvalidScryptoValue(ScryptoValueDecodeError), InvalidSborValue(DecodeError), + InvalidSborValueOnEncode(EncodeError), // RENode StoredNodeRemoved(RENodeId), diff --git a/radix-engine/src/engine/interpreters/native_interpreter.rs b/radix-engine/src/engine/interpreters/native_interpreter.rs index 86d13ef07b6..11fba120e2f 100644 --- a/radix-engine/src/engine/interpreters/native_interpreter.rs +++ b/radix-engine/src/engine/interpreters/native_interpreter.rs @@ -3,10 +3,9 @@ use crate::model::*; use crate::types::*; use radix_engine_interface::api::api::{EngineApi, SysInvokableNative}; use radix_engine_interface::api::types::{NativeFunction, NativeMethod, RENodeId}; -use radix_engine_interface::data::{IndexedScryptoValue, ScryptoCustomTypeId}; +use radix_engine_interface::data::{IndexedScryptoValue, ScryptoEncode}; use radix_engine_interface::model::*; use sbor::rust::fmt::Debug; -use sbor::*; impl> Into for InvokeError { fn into(self) -> RuntimeError { @@ -125,7 +124,7 @@ impl Resolver for NativeResolver { } } -pub trait NativeInvocation: NativeExecutable + Encode + Debug { +pub trait NativeInvocation: NativeExecutable + ScryptoEncode + Debug { fn info(&self) -> NativeInvocationInfo; } diff --git a/radix-engine/src/engine/interpreters/wasm_runtime.rs b/radix-engine/src/engine/interpreters/wasm_runtime.rs index 306bee9f13c..76ea72038f1 100644 --- a/radix-engine/src/engine/interpreters/wasm_runtime.rs +++ b/radix-engine/src/engine/interpreters/wasm_runtime.rs @@ -1,7 +1,7 @@ use crate::engine::*; use crate::fee::*; use crate::model::InvokeError; -use crate::types::{scrypto_decode, scrypto_encode, Encode, ScryptoInvocation}; +use crate::types::{scrypto_decode, scrypto_encode, ScryptoInvocation}; use crate::wasm::*; use radix_engine_interface::api::api::{EngineApi, SysInvokableNative}; use radix_engine_interface::api::wasm_input::{ @@ -11,7 +11,7 @@ use radix_engine_interface::api::wasm_input::{ ProofMethodInvocation, RadixEngineInput, ResourceManagerFunctionInvocation, ResourceManagerMethodInvocation, VaultMethodInvocation, WorktopMethodInvocation, }; -use radix_engine_interface::data::{IndexedScryptoValue, ScryptoCustomTypeId}; +use radix_engine_interface::data::{IndexedScryptoValue, ScryptoEncode}; use sbor::rust::vec::Vec; /// A glue between system api (call frame and track abstraction) and WASM. @@ -300,8 +300,12 @@ where } } -fn encode>(output: T) -> Vec { - scrypto_encode(&output) +fn encode(output: T) -> Result, InvokeError> { + scrypto_encode(&output).map_err(|err| { + InvokeError::Downstream(RuntimeError::KernelError( + KernelError::InvalidSborValueOnEncode(err), + )) + }) } impl<'y, Y> WasmRuntime for RadixEngineWasmRuntime<'y, Y> @@ -328,33 +332,29 @@ where RadixEngineInput::InvokeNativeFn(native_fn) => { self.invoke_native_fn(native_fn).map(|v| v.raw)? } - RadixEngineInput::CreateNode(node) => { - self.system_api.sys_create_node(node).map(encode)? - } + RadixEngineInput::CreateNode(node) => encode(self.system_api.sys_create_node(node)?)?, RadixEngineInput::GetVisibleNodeIds() => { - self.system_api.sys_get_visible_nodes().map(encode)? - } - RadixEngineInput::DropNode(node_id) => { - self.system_api.sys_drop_node(node_id).map(encode)? + encode(self.system_api.sys_get_visible_nodes()?)? } - RadixEngineInput::LockSubstate(node_id, offset, mutable) => self - .system_api - .sys_lock_substate(node_id, offset, mutable) - .map(encode)?, + RadixEngineInput::DropNode(node_id) => encode(self.system_api.sys_drop_node(node_id)?)?, + RadixEngineInput::LockSubstate(node_id, offset, mutable) => encode( + self.system_api + .sys_lock_substate(node_id, offset, mutable)?, + )?, RadixEngineInput::Read(lock_handle) => self.system_api.sys_read(lock_handle)?, RadixEngineInput::Write(lock_handle, value) => { - self.system_api.sys_write(lock_handle, value).map(encode)? + encode(self.system_api.sys_write(lock_handle, value)?)? } RadixEngineInput::DropLock(lock_handle) => { - self.system_api.sys_drop_lock(lock_handle).map(encode)? + encode(self.system_api.sys_drop_lock(lock_handle)?)? } - RadixEngineInput::GetActor() => self.system_api.sys_get_actor().map(encode)?, + RadixEngineInput::GetActor() => encode(self.system_api.sys_get_actor()?)?, RadixEngineInput::GetTransactionHash() => { - self.system_api.sys_get_transaction_hash().map(encode)? + encode(self.system_api.sys_get_transaction_hash()?)? } - RadixEngineInput::GenerateUuid() => self.system_api.sys_generate_uuid().map(encode)?, + RadixEngineInput::GenerateUuid() => encode(self.system_api.sys_generate_uuid()?)?, RadixEngineInput::EmitLog(level, message) => { - self.system_api.sys_emit_log(level, message).map(encode)? + encode(self.system_api.sys_emit_log(level, message)?)? } }; diff --git a/radix-engine/src/engine/track.rs b/radix-engine/src/engine/track.rs index 3efb23ff68f..b87caace17f 100644 --- a/radix-engine/src/engine/track.rs +++ b/radix-engine/src/engine/track.rs @@ -477,7 +477,9 @@ impl<'s, R: FeeReserve> Track<'s, R> { &mut self, transaction: &Executable, ) -> Result<(), FeeReserveError> { - let encoded_instructions_byte_length = scrypto_encode(transaction.instructions()).len(); + let encoded_instructions_byte_length = scrypto_encode(transaction.instructions()) + .expect("Valid transaction had instructions which couldn't be encoded") + .len(); let blobs_size = { let mut total_size: usize = 0; for blob in transaction.blobs() { @@ -742,7 +744,9 @@ impl<'s> FinalizingTrack<'s> { ) -> Option { substate_store.get_substate(&substate_id).map(|s| OutputId { substate_id: substate_id.clone(), - substate_hash: hash(scrypto_encode(&s.substate)), + substate_hash: hash( + scrypto_encode(&s.substate).expect("Saved substate couldn't be re-encoded"), + ), version: s.version, }) } diff --git a/radix-engine/src/ledger/bootstrap.rs b/radix-engine/src/ledger/bootstrap.rs index a7fbf62901d..e0d545f79ba 100644 --- a/radix-engine/src/ledger/bootstrap.rs +++ b/radix-engine/src/ledger/bootstrap.rs @@ -245,7 +245,7 @@ where wasm_instrumenter: WasmInstrumenter::default(), wasm_metering_config: WasmMeteringConfig::new( InstructionCostRules::tiered(1, 5, 10, 5000), - 512, + 1024, ), }; @@ -282,7 +282,7 @@ mod tests { let wasm_engine = DefaultWasmEngine::default(); let wasm_instrumenter = WasmInstrumenter::default(); let wasm_metering_config = - WasmMeteringConfig::new(InstructionCostRules::tiered(1, 5, 10, 5000), 512); + WasmMeteringConfig::new(InstructionCostRules::tiered(1, 5, 10, 5000), 1024); let scrypto_interpreter = ScryptoInterpreter { wasm_engine, wasm_instrumenter, diff --git a/radix-engine/src/model/package/substates.rs b/radix-engine/src/model/package/substates.rs index a1d9d2f96bc..7b06ed4b5c6 100644 --- a/radix-engine/src/model/package/substates.rs +++ b/radix-engine/src/model/package/substates.rs @@ -11,7 +11,9 @@ pub struct PackageSubstate { impl Debug for PackageSubstate { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("PackageSubstate").finish() + f.debug_struct("PackageSubstate") + .field("blueprint_abis", &self.blueprint_abis) + .finish() } } diff --git a/radix-engine/src/model/package_extractor.rs b/radix-engine/src/model/package_extractor.rs index b488c0b9bfc..12bedb91aa9 100644 --- a/radix-engine/src/model/package_extractor.rs +++ b/radix-engine/src/model/package_extractor.rs @@ -26,7 +26,7 @@ pub fn extract_abi(code: &[u8]) -> Result, Extract let wasm_instrumenter = WasmInstrumenter::default(); let metering_params = - WasmMeteringConfig::new(InstructionCostRules::tiered(1, 5, 10, 50000), 512); + WasmMeteringConfig::new(InstructionCostRules::tiered(1, 5, 10, 5000), 1024); let instrumented_code = wasm_instrumenter.instrument(code, &metering_params); let mut fee_reserve = SystemLoanFeeReserve::default(); fee_reserve.credit(EXTRACT_ABI_CREDIT); diff --git a/radix-engine/src/model/transaction_processor/executables.rs b/radix-engine/src/model/transaction_processor/executables.rs index 4cb55541fa0..bb4b865f7de 100644 --- a/radix-engine/src/model/transaction_processor/executables.rs +++ b/radix-engine/src/model/transaction_processor/executables.rs @@ -148,8 +148,10 @@ impl TransactionProcessor { let val = path .get_from_value_mut(&mut value) .expect("Failed to locate an expression value using SBOR path"); - *val = - decode_any(&scrypto_encode(&buckets)).expect("Failed to decode Vec") + *val = scrypto_decode( + &scrypto_encode(&buckets).expect("Failed to encode Vec"), + ) + .expect("Failed to decode Vec") } "ENTIRE_AUTH_ZONE" => { let proofs = @@ -158,8 +160,10 @@ impl TransactionProcessor { let val = path .get_from_value_mut(&mut value) .expect("Failed to locate an expression value using SBOR path"); - *val = - decode_any(&scrypto_encode(&proofs)).expect("Failed to decode Vec") + *val = scrypto_decode( + &scrypto_encode(&proofs).expect("Failed to encode Vec"), + ) + .expect("Failed to decode Vec") } _ => {} // no-op } diff --git a/radix-engine/src/state_manager/staging.rs b/radix-engine/src/state_manager/staging.rs index 09a0880d0f8..c1986c47d4f 100644 --- a/radix-engine/src/state_manager/staging.rs +++ b/radix-engine/src/state_manager/staging.rs @@ -126,9 +126,7 @@ impl<'t, 's, S: ReadableSubstateStore> StagedSubstateStore<'t, 's, S> { let node = self.stores.nodes.get(&id).unwrap(); if let Some(output) = node.outputs.get(substate_id) { - // TODO: Remove encoding/decoding - let encoded_output = scrypto_encode(output); - return Some(scrypto_decode(&encoded_output).unwrap()); + return Some(output.clone()); } self.get_substate_recurse(substate_id, node.parent_id) diff --git a/radix-engine/src/state_manager/state_diff.rs b/radix-engine/src/state_manager/state_diff.rs index d6e2f019d82..87f6cbfdfe6 100644 --- a/radix-engine/src/state_manager/state_diff.rs +++ b/radix-engine/src/state_manager/state_diff.rs @@ -29,7 +29,14 @@ impl StateDiff { for (substate_id, output_value) in &self.up_substates { let output_id = OutputId { substate_id: substate_id.clone(), - substate_hash: hash(scrypto_encode(&output_value.substate)), + substate_hash: hash( + scrypto_encode(&output_value.substate).unwrap_or_else(|err| { + panic!( + "Could not encode newly-committed substate: {:?}. Substate: {:?}", + err, &output_value.substate + ) + }), + ), version: output_value.version, }; receipt.up(output_id); diff --git a/radix-engine/src/transaction/transaction_receipt.rs b/radix-engine/src/transaction/transaction_receipt.rs index e761fdc9593..c918a886eb4 100644 --- a/radix-engine/src/transaction/transaction_receipt.rs +++ b/radix-engine/src/transaction/transaction_receipt.rs @@ -1,7 +1,7 @@ use colored::*; use radix_engine_interface::address::{AddressDisplayContext, NO_NETWORK}; use radix_engine_interface::api::types::{GlobalAddress, Level}; -use radix_engine_interface::data::{IndexedScryptoValue, ScryptoCustomTypeId}; +use radix_engine_interface::data::{IndexedScryptoValue, ScryptoDecode}; use radix_engine_interface::model::*; use transaction::manifest::decompiler::{decompile_instruction, DecompilationContext}; use transaction::model::*; @@ -217,7 +217,7 @@ impl TransactionReceipt { } } - pub fn output>(&self, nth: usize) -> T { + pub fn output(&self, nth: usize) -> T { scrypto_decode::(&self.expect_commit_success()[nth][..]) .expect("Wrong instruction output type!") } diff --git a/radix-engine/src/types.rs b/radix-engine/src/types.rs index d4117964d27..e3cb9955f4d 100644 --- a/radix-engine/src/types.rs +++ b/radix-engine/src/types.rs @@ -7,13 +7,14 @@ pub use radix_engine_interface::constants::*; pub use radix_engine_interface::core::Expression; pub use radix_engine_interface::crypto::*; use radix_engine_interface::data::IndexedScryptoValue; -pub use radix_engine_interface::data::{scrypto_decode, scrypto_encode}; +pub use radix_engine_interface::data::{ + scrypto_decode, scrypto_encode, ScryptoDecode, ScryptoEncode, ScryptoTypeId, +}; pub use radix_engine_interface::dec; pub use radix_engine_interface::math::{Decimal, RoundingMode, I256}; pub use radix_engine_interface::model::*; pub use radix_engine_interface::scrypto; -pub use sbor::decode_any; pub use sbor::rust::borrow::ToOwned; pub use sbor::rust::boxed::Box; pub use sbor::rust::cell::{Ref, RefCell, RefMut}; diff --git a/radix-engine/src/wasm/errors.rs b/radix-engine/src/wasm/errors.rs index cbde318b84c..80d7bc0dc72 100644 --- a/radix-engine/src/wasm/errors.rs +++ b/radix-engine/src/wasm/errors.rs @@ -85,6 +85,7 @@ pub enum WasmError { MemoryAllocError, MemoryAccessError, InvalidScryptoValue(ScryptoValueDecodeError), + InvalidScryptoValueResponse(EncodeError), WasmError(String), FunctionNotFound, InvalidRadixEngineInput, diff --git a/radix-engine/src/wasm/wasm_metering_config.rs b/radix-engine/src/wasm/wasm_metering_config.rs index d0cf561ba7a..89cc5920def 100644 --- a/radix-engine/src/wasm/wasm_metering_config.rs +++ b/radix-engine/src/wasm/wasm_metering_config.rs @@ -21,7 +21,7 @@ impl WasmMeteringConfig { instruction_cost_rules, max_stack_size, }; - let hash = hash(scrypto_encode(¶ms)); + let hash = hash(scrypto_encode(¶ms).unwrap()); Self { params, hash } } diff --git a/radix-engine/src/wasm/wasm_validator.rs b/radix-engine/src/wasm/wasm_validator.rs index 6dd30fe6989..58d32c5ffeb 100644 --- a/radix-engine/src/wasm/wasm_validator.rs +++ b/radix-engine/src/wasm/wasm_validator.rs @@ -31,7 +31,7 @@ impl WasmValidator { // we are using. To deal with this, we attempt to instrument the input module with // some mocked parameters and reject it if fails to do so. let mocked_wasm_metering_config = - WasmMeteringConfig::new(InstructionCostRules::constant(1, 100), 500); + WasmMeteringConfig::new(InstructionCostRules::constant(1, 100), 1024); WasmModule::init(code)? .enforce_no_floating_point()? diff --git a/radix-engine/tests/abi.rs b/radix-engine/tests/abi.rs index 76da872b645..5eabde236e5 100644 --- a/radix-engine/tests/abi.rs +++ b/radix-engine/tests/abi.rs @@ -90,98 +90,102 @@ fn test_arg(method_name: &str, args: Vec, expected_result: ExpectedResult) { #[test] fn test_invalid_output_fails() { - test_arg("invalid_output", scrypto_encode(&()), InvalidOutput) + test_arg( + "invalid_output", + scrypto_encode(&()).unwrap(), + InvalidOutput, + ) } #[test] fn test_input_arg_unit_succeeds() { - test_arg("unit", scrypto_encode(&()), Success) + test_arg("unit", scrypto_encode(&()).unwrap(), Success) } #[test] fn test_invalid_input_arg_unit_fails() { - test_arg("unit", scrypto_encode(&0u8), InvalidInput) + test_arg("unit", scrypto_encode(&0u8).unwrap(), InvalidInput) } #[test] fn test_input_arg_bool_succeeds() { - test_arg("bool", scrypto_encode(&true), Success) + test_arg("bool", scrypto_encode(&true).unwrap(), Success) } #[test] fn test_invalid_input_arg_bool_fails() { - test_arg("unit", scrypto_encode(&0u8), InvalidInput) + test_arg("unit", scrypto_encode(&0u8).unwrap(), InvalidInput) } #[test] fn test_input_arg_ivalue_succeeds() { - test_arg("i8", scrypto_encode(&0i8), Success); - test_arg("i16", scrypto_encode(&0i16), Success); - test_arg("i32", scrypto_encode(&0i32), Success); - test_arg("i64", scrypto_encode(&0i64), Success); - test_arg("i128", scrypto_encode(&0i128), Success); + test_arg("i8", scrypto_encode(&0i8).unwrap(), Success); + test_arg("i16", scrypto_encode(&0i16).unwrap(), Success); + test_arg("i32", scrypto_encode(&0i32).unwrap(), Success); + test_arg("i64", scrypto_encode(&0i64).unwrap(), Success); + test_arg("i128", scrypto_encode(&0i128).unwrap(), Success); } #[test] fn test_input_arg_ivalue_fails() { - test_arg("i8", scrypto_encode(&()), InvalidInput); - test_arg("i16", scrypto_encode(&()), InvalidInput); - test_arg("i32", scrypto_encode(&()), InvalidInput); - test_arg("i64", scrypto_encode(&()), InvalidInput); - test_arg("i128", scrypto_encode(&()), InvalidInput); + test_arg("i8", scrypto_encode(&()).unwrap(), InvalidInput); + test_arg("i16", scrypto_encode(&()).unwrap(), InvalidInput); + test_arg("i32", scrypto_encode(&()).unwrap(), InvalidInput); + test_arg("i64", scrypto_encode(&()).unwrap(), InvalidInput); + test_arg("i128", scrypto_encode(&()).unwrap(), InvalidInput); } #[test] fn test_input_arg_uvalue_succeeds() { - test_arg("u8", scrypto_encode(&0u8), Success); - test_arg("u16", scrypto_encode(&0u16), Success); - test_arg("u32", scrypto_encode(&0u32), Success); - test_arg("u64", scrypto_encode(&0u64), Success); - test_arg("u128", scrypto_encode(&0u128), Success); + test_arg("u8", scrypto_encode(&0u8).unwrap(), Success); + test_arg("u16", scrypto_encode(&0u16).unwrap(), Success); + test_arg("u32", scrypto_encode(&0u32).unwrap(), Success); + test_arg("u64", scrypto_encode(&0u64).unwrap(), Success); + test_arg("u128", scrypto_encode(&0u128).unwrap(), Success); } #[test] fn test_input_arg_uvalue_fails() { - test_arg("u8", scrypto_encode(&()), InvalidInput); - test_arg("u16", scrypto_encode(&()), InvalidInput); - test_arg("u32", scrypto_encode(&()), InvalidInput); - test_arg("u64", scrypto_encode(&()), InvalidInput); - test_arg("u128", scrypto_encode(&()), InvalidInput); + test_arg("u8", scrypto_encode(&()).unwrap(), InvalidInput); + test_arg("u16", scrypto_encode(&()).unwrap(), InvalidInput); + test_arg("u32", scrypto_encode(&()).unwrap(), InvalidInput); + test_arg("u64", scrypto_encode(&()).unwrap(), InvalidInput); + test_arg("u128", scrypto_encode(&()).unwrap(), InvalidInput); } #[test] fn test_input_arg_result_succeeds() { let okay: Result<(), ()> = Ok(()); let error: Result<(), ()> = Err(()); - test_arg("result", scrypto_encode(&okay), Success); - test_arg("result", scrypto_encode(&error), Success); + test_arg("result", scrypto_encode(&okay).unwrap(), Success); + test_arg("result", scrypto_encode(&error).unwrap(), Success); } #[test] fn test_invalid_input_arg_result_fails() { - test_arg("result", scrypto_encode(&0u8), InvalidInput); + test_arg("result", scrypto_encode(&0u8).unwrap(), InvalidInput); } #[test] fn test_input_arg_tree_map_succeeds() { let mut tree_map = BTreeMap::new(); tree_map.insert((), ()); - test_arg("tree_map", scrypto_encode(&tree_map), Success); + test_arg("tree_map", scrypto_encode(&tree_map).unwrap(), Success); } #[test] fn test_invalid_input_arg_tree_map_fails() { - test_arg("tree_map", scrypto_encode(&0u8), InvalidInput); + test_arg("tree_map", scrypto_encode(&0u8).unwrap(), InvalidInput); } #[test] fn test_input_arg_hash_set_succeeds() { let mut hash_set = HashSet::new(); hash_set.insert(()); - test_arg("hash_set", scrypto_encode(&hash_set), Success); + test_arg("hash_set", scrypto_encode(&hash_set).unwrap(), Success); } #[test] fn test_invalid_input_arg_hash_set_fails() { - test_arg("hash_set", scrypto_encode(&0u8), InvalidInput); + test_arg("hash_set", scrypto_encode(&0u8).unwrap(), InvalidInput); } diff --git a/radix-engine/tests/blueprints/abi/src/lib.rs b/radix-engine/tests/blueprints/abi/src/lib.rs index 45f818719e6..12d231a8257 100644 --- a/radix-engine/tests/blueprints/abi/src/lib.rs +++ b/radix-engine/tests/blueprints/abi/src/lib.rs @@ -24,7 +24,7 @@ blueprint! { #[no_mangle] pub extern "C" fn AbiComponent2_main(_input: *mut u8) -> *mut u8 { - ::scrypto::buffer::scrypto_encode_to_buffer(&()) + ::scrypto::buffer::scrypto_encode_to_buffer(&()).unwrap() } #[no_mangle] @@ -159,5 +159,5 @@ pub extern "C" fn AbiComponent2_abi(_input: *mut u8) -> *mut u8 { ], }; - ::scrypto::buffer::scrypto_encode_to_buffer(&abi) + ::scrypto::buffer::scrypto_encode_to_buffer(&abi).unwrap() } diff --git a/radix-engine/tests/blueprints/data_access/src/lib.rs b/radix-engine/tests/blueprints/data_access/src/lib.rs index 1f444c74cd3..3c00fe05c47 100644 --- a/radix-engine/tests/blueprints/data_access/src/lib.rs +++ b/radix-engine/tests/blueprints/data_access/src/lib.rs @@ -24,7 +24,10 @@ blueprint! { SubstateOffset::Component(ComponentOffset::State), true, )); - call_engine(RadixEngineInput::Write(lock_handle, scrypto_encode(&()))) + call_engine(RadixEngineInput::Write( + lock_handle, + scrypto_encode(&()).unwrap(), + )) } pub fn create_component_and_read_info() -> ComponentInfoSubstate { @@ -45,7 +48,7 @@ blueprint! { SubstateOffset::Component(ComponentOffset::Info), true, )); - let input = RadixEngineInput::Write(lock_handle, scrypto_encode(&())); + let input = RadixEngineInput::Write(lock_handle, scrypto_encode(&()).unwrap()); call_engine(input) } } diff --git a/radix-engine/tests/blueprints/kernel/src/lib.rs b/radix-engine/tests/blueprints/kernel/src/lib.rs index 47c1451e4b2..278453fef15 100644 --- a/radix-engine/tests/blueprints/kernel/src/lib.rs +++ b/radix-engine/tests/blueprints/kernel/src/lib.rs @@ -38,7 +38,7 @@ blueprint! { let input = RadixEngineInput::CreateNode(ScryptoRENode::Component( Runtime::package_address(), "invalid_blueprint".to_owned(), - scrypto_encode(&NodeCreate {}), + scrypto_encode(&NodeCreate {}).unwrap(), )); let _: ComponentId = call_engine(input); } @@ -48,7 +48,7 @@ blueprint! { let input = RadixEngineInput::CreateNode(ScryptoRENode::Component( package_address, "NodeCreate".to_owned(), - scrypto_encode(&NodeCreate {}), + scrypto_encode(&NodeCreate {}).unwrap(), )); let _: ComponentId = call_engine(input); } diff --git a/radix-engine/tests/blueprints/kv_store/src/cyclic_map.rs b/radix-engine/tests/blueprints/kv_store/src/cyclic_map.rs index 3d66ebabd54..61f4b795101 100644 --- a/radix-engine/tests/blueprints/kv_store/src/cyclic_map.rs +++ b/radix-engine/tests/blueprints/kv_store/src/cyclic_map.rs @@ -23,18 +23,21 @@ blueprint! { }; let node_id = RENodeId::KeyValueStore(kv_store1_id); - let offset = - SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(&0u32))); - let substate = - KeyValueStoreEntrySubstate(Some(scrypto_encode(&KeyValueStore::<(), ()> { + let offset = SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry( + scrypto_encode(&0u32).unwrap(), + )); + let substate = KeyValueStoreEntrySubstate(Some( + scrypto_encode(&KeyValueStore::<(), ()> { id: kv_store0_id, key: PhantomData, value: PhantomData, - }))); + }) + .unwrap(), + )); let input = RadixEngineInput::LockSubstate(node_id, offset, true); let lock_handle: LockHandle = call_engine(input); - let input = RadixEngineInput::Write(lock_handle, scrypto_encode(&substate)); + let input = RadixEngineInput::Write(lock_handle, scrypto_encode(&substate).unwrap()); let _: () = call_engine(input); CyclicMap { store: kv_store0 }.instantiate().globalize() @@ -45,18 +48,21 @@ blueprint! { let kv_store_id = kv_store.id.clone(); let node_id = RENodeId::KeyValueStore(kv_store_id.clone()); - let offset = - SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(&0u32))); - let substate = - KeyValueStoreEntrySubstate(Some(scrypto_encode(&KeyValueStore::<(), ()> { + let offset = SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry( + scrypto_encode(&0u32).unwrap(), + )); + let substate = KeyValueStoreEntrySubstate(Some( + scrypto_encode(&KeyValueStore::<(), ()> { id: kv_store_id, key: PhantomData, value: PhantomData, - }))); + }) + .unwrap(), + )); let input = RadixEngineInput::LockSubstate(node_id, offset, true); let lock_handle: LockHandle = call_engine(input); - let input = RadixEngineInput::Write(lock_handle, scrypto_encode(&substate)); + let input = RadixEngineInput::Write(lock_handle, scrypto_encode(&substate).unwrap()); let _: () = call_engine(input); CyclicMap { store: kv_store }.instantiate().globalize() diff --git a/radix-engine/tests/blueprints/package/src/lib.rs b/radix-engine/tests/blueprints/package/src/lib.rs index 381a62a137b..ee309f2560a 100644 --- a/radix-engine/tests/blueprints/package/src/lib.rs +++ b/radix-engine/tests/blueprints/package/src/lib.rs @@ -39,7 +39,7 @@ pub extern "C" fn LargeReturnSize_abi(_input: *mut u8) -> *mut u8 { export_name: "LargeReturnSize_f_main".to_string(), }], }; - ::scrypto::buffer::scrypto_encode_to_buffer(&abi) + ::scrypto::buffer::scrypto_encode_to_buffer(&abi).unwrap() } #[no_mangle] @@ -62,7 +62,7 @@ pub extern "C" fn MaxReturnSize_abi(_input: *mut u8) -> *mut u8 { }], }; - ::scrypto::buffer::scrypto_encode_to_buffer(&abi) + ::scrypto::buffer::scrypto_encode_to_buffer(&abi).unwrap() } #[no_mangle] @@ -85,7 +85,7 @@ pub extern "C" fn ZeroReturnSize_abi(_input: *mut u8) -> *mut u8 { }], }; - ::scrypto::buffer::scrypto_encode_to_buffer(&abi) + ::scrypto::buffer::scrypto_encode_to_buffer(&abi).unwrap() } blueprint! { diff --git a/radix-engine/tests/fee.rs b/radix-engine/tests/fee.rs index 0f7741fdad1..afff18b7364 100644 --- a/radix-engine/tests/fee.rs +++ b/radix-engine/tests/fee.rs @@ -193,7 +193,10 @@ where let account_comp_state = IndexedScryptoValue::from_slice(&account_comp.raw).unwrap(); if let Some(kv_store_id) = account_comp_state.kv_store_ids.iter().next() { if let Some(KeyValueStoreEntrySubstate(Some(value))) = test_runner - .inspect_key_value_entry(kv_store_id.clone(), scrypto_encode(&resource_address)) + .inspect_key_value_entry( + kv_store_id.clone(), + scrypto_encode(&resource_address).unwrap(), + ) { let kv_store_entry_value = IndexedScryptoValue::from_slice(&value).unwrap(); let vault_id = kv_store_entry_value.vault_ids.iter().next().unwrap(); diff --git a/radix-engine/tests/fuzz_transactions.rs b/radix-engine/tests/fuzz_transactions.rs index 2ecd4019c2f..d5ab91559b8 100644 --- a/radix-engine/tests/fuzz_transactions.rs +++ b/radix-engine/tests/fuzz_transactions.rs @@ -35,7 +35,7 @@ fn execute_single_transaction(transaction: NotarizedTransaction) { wasm_instrumenter: WasmInstrumenter::default(), wasm_metering_config: WasmMeteringConfig::new( InstructionCostRules::tiered(1, 5, 10, 5000), - 512, + 1024, ), }; let execution_config = ExecutionConfig::standard(); diff --git a/radix-engine/tests/metering.rs b/radix-engine/tests/metering.rs index fbc9197fb12..9f9aa33bddb 100644 --- a/radix-engine/tests/metering.rs +++ b/radix-engine/tests/metering.rs @@ -54,7 +54,7 @@ fn test_recursion() { // Act // In this test case, each call frame costs 4 stack units - let code = wat2wasm(&include_str!("wasm/recursion.wat").replace("${n}", "128")); + let code = wat2wasm(&include_str!("wasm/recursion.wat").replace("${n}", "256")); let package_address = test_runner.publish_package(code, generate_single_function_abi("Test", "f")); let manifest = ManifestBuilder::new(&NetworkDefinition::simulator()) @@ -74,7 +74,7 @@ fn test_recursion_stack_overflow() { let mut test_runner = TestRunner::new(true, &mut store); // Act - let code = wat2wasm(&include_str!("wasm/recursion.wat").replace("${n}", "129")); + let code = wat2wasm(&include_str!("wasm/recursion.wat").replace("${n}", "257")); let package_address = test_runner.publish_package(code, generate_single_function_abi("Test", "f")); let manifest = ManifestBuilder::new(&NetworkDefinition::simulator()) diff --git a/radix-engine/tests/transaction_executor.rs b/radix-engine/tests/transaction_executor.rs index 1638f115a4f..f28e3fc02a4 100644 --- a/radix-engine/tests/transaction_executor.rs +++ b/radix-engine/tests/transaction_executor.rs @@ -129,7 +129,7 @@ fn test_normal_transaction_flow() { wasm_instrumenter: WasmInstrumenter::default(), wasm_metering_config: WasmMeteringConfig::new( InstructionCostRules::tiered(1, 5, 10, 5000), - 512, + 1024, ), }; @@ -141,7 +141,8 @@ fn test_normal_transaction_flow() { start_epoch_inclusive: 0, end_epoch_exclusive: 0 + DEFAULT_MAX_EPOCH_RANGE, }) - .to_bytes(); + .to_bytes() + .unwrap(); let validator = NotarizedTransactionValidator::new(ValidationConfig::simulator()); let transaction = validator diff --git a/sbor-derive/src/decode.rs b/sbor-derive/src/decode.rs index 4635b32f3be..16e2cb4568e 100644 --- a/sbor-derive/src/decode.rs +++ b/sbor-derive/src/decode.rs @@ -22,8 +22,8 @@ pub fn handle_decode(input: TokenStream) -> Result { .. } = parse2(input)?; let custom_type_id = custom_type_id(&attrs); - let (impl_generics, ty_generics, where_clause, sbor_cti) = - build_generics(&generics, custom_type_id)?; + let (impl_generics, ty_generics, where_clause, custom_type_id_generic, decoder_generic) = + build_decode_generics(&generics, custom_type_id)?; let output = match data { Data::Struct(s) => match s.fields { @@ -37,13 +37,14 @@ pub fn handle_decode(input: TokenStream) -> Result { let s_ids = s.iter().map(|f| &f.ident); let s_types = s.iter().map(|f| &f.ty); quote! { - impl #impl_generics ::sbor::Decode <#sbor_cti> for #ident #ty_generics #where_clause { - fn decode_body_with_type_id(decoder: &mut ::sbor::Decoder <#sbor_cti>, type_id: ::sbor::SborTypeId<#sbor_cti>) -> Result { + impl #impl_generics ::sbor::Decode <#custom_type_id_generic, #decoder_generic> for #ident #ty_generics #where_clause { + #[inline] + fn decode_body_with_type_id(decoder: &mut #decoder_generic, type_id: ::sbor::SborTypeId<#custom_type_id_generic>) -> Result { use ::sbor::{self, Decode}; decoder.check_preloaded_type_id(type_id, ::sbor::type_id::SborTypeId::Struct)?; decoder.read_and_check_size(#ns_len)?; Ok(Self { - #(#ns_ids: <#ns_types>::decode(decoder)?,)* + #(#ns_ids: decoder.decode::<#ns_types>()?,)* #(#s_ids: <#s_types>::default()),* }) } @@ -57,14 +58,15 @@ pub fn handle_decode(input: TokenStream) -> Result { if is_decoding_skipped(f) { fields.push(parse_quote! {<#ty>::default()}) } else { - fields.push(parse_quote! {<#ty>::decode(decoder)?}) + fields.push(parse_quote! {decoder.decode::<#ty>()?}) } } let ns_len = Index::from(unnamed.iter().filter(|f| !is_decoding_skipped(f)).count()); quote! { - impl #impl_generics ::sbor::Decode <#sbor_cti> for #ident #ty_generics #where_clause { - fn decode_body_with_type_id(decoder: &mut ::sbor::Decoder <#sbor_cti>, type_id: ::sbor::SborTypeId<#sbor_cti>) -> Result { + impl #impl_generics ::sbor::Decode <#custom_type_id_generic, #decoder_generic> for #ident #ty_generics #where_clause { + #[inline] + fn decode_body_with_type_id(decoder: &mut #decoder_generic, type_id: ::sbor::SborTypeId<#custom_type_id_generic>) -> Result { use ::sbor::{self, Decode}; decoder.check_preloaded_type_id(type_id, ::sbor::type_id::SborTypeId::Struct)?; decoder.read_and_check_size(#ns_len)?; @@ -77,8 +79,9 @@ pub fn handle_decode(input: TokenStream) -> Result { } syn::Fields::Unit => { quote! { - impl #impl_generics ::sbor::Decode <#sbor_cti> for #ident #ty_generics #where_clause { - fn decode_body_with_type_id(decoder: &mut ::sbor::Decoder <#sbor_cti>, type_id: ::sbor::SborTypeId<#sbor_cti>) -> Result { + impl #impl_generics ::sbor::Decode <#custom_type_id_generic, #decoder_generic> for #ident #ty_generics #where_clause { + #[inline] + fn decode_body_with_type_id(decoder: &mut #decoder_generic, type_id: ::sbor::SborTypeId<#custom_type_id_generic>) -> Result { decoder.check_preloaded_type_id(type_id, ::sbor::type_id::SborTypeId::Struct)?; decoder.read_and_check_size(0)?; Ok(Self {}) @@ -108,7 +111,7 @@ pub fn handle_decode(input: TokenStream) -> Result { #discriminator => { decoder.read_and_check_size(#ns_len)?; Ok(Self::#v_id { - #(#ns_ids: <#ns_types>::decode(decoder)?,)* + #(#ns_ids: decoder.decode::<#ns_types>()?,)* #(#s_ids: <#s_types>::default(),)* }) } @@ -121,7 +124,7 @@ pub fn handle_decode(input: TokenStream) -> Result { if is_decoding_skipped(f) { fields.push(parse_quote! {<#ty>::default()}) } else { - fields.push(parse_quote! {<#ty>::decode(decoder)?}) + fields.push(parse_quote! {decoder.decode::<#ty>()?}) } } let ns_len = @@ -147,8 +150,9 @@ pub fn handle_decode(input: TokenStream) -> Result { }); quote! { - impl #impl_generics ::sbor::Decode <#sbor_cti> for #ident #ty_generics #where_clause { - fn decode_body_with_type_id(decoder: &mut ::sbor::Decoder <#sbor_cti>, type_id: ::sbor::SborTypeId<#sbor_cti>) -> Result { + impl #impl_generics ::sbor::Decode <#custom_type_id_generic, #decoder_generic> for #ident #ty_generics #where_clause { + #[inline] + fn decode_body_with_type_id(decoder: &mut #decoder_generic, type_id: ::sbor::SborTypeId<#custom_type_id_generic>) -> Result { use ::sbor::{self, Decode}; decoder.check_preloaded_type_id(type_id, ::sbor::type_id::SborTypeId::Enum)?; let discriminator = decoder.read_discriminator()?; @@ -191,13 +195,14 @@ mod tests { assert_code_eq( output, quote! { - impl ::sbor::Decode for Test { - fn decode_body_with_type_id(decoder: &mut ::sbor::Decoder, type_id: ::sbor::SborTypeId) -> Result { + impl > ::sbor::Decode for Test { + #[inline] + fn decode_body_with_type_id(decoder: &mut DEC, type_id: ::sbor::SborTypeId) -> Result { use ::sbor::{self, Decode}; decoder.check_preloaded_type_id(type_id, ::sbor::type_id::SborTypeId::Struct)?; decoder.read_and_check_size(1)?; Ok(Self { - a: ::decode(decoder)?, + a: decoder.decode::()?, }) } } @@ -216,13 +221,14 @@ mod tests { assert_code_eq( output, quote! { - impl ::sbor::Decode for Test { - fn decode_body_with_type_id(decoder: &mut ::sbor::Decoder, type_id: ::sbor::SborTypeId) -> Result { + impl > ::sbor::Decode for Test { + #[inline] + fn decode_body_with_type_id(decoder: &mut DEC, type_id: ::sbor::SborTypeId) -> Result { use ::sbor::{self, Decode}; decoder.check_preloaded_type_id(type_id, ::sbor::type_id::SborTypeId::Struct)?; decoder.read_and_check_size(1)?; Ok(Self { - a: ::decode(decoder)?, + a: decoder.decode::()?, }) } } @@ -238,13 +244,14 @@ mod tests { assert_code_eq( output, quote! { - impl <'a, CTI: ::sbor::type_id::CustomTypeId> ::sbor::Decode for Test<'a> { - fn decode_body_with_type_id(decoder: &mut ::sbor::Decoder, type_id: ::sbor::SborTypeId) -> Result { + impl <'a, CTI: ::sbor::type_id::CustomTypeId, DEC: ::sbor::decoder::Decoder > ::sbor::Decode for Test<'a> { + #[inline] + fn decode_body_with_type_id(decoder: &mut DEC, type_id: ::sbor::SborTypeId) -> Result { use ::sbor::{self, Decode}; decoder.check_preloaded_type_id(type_id, ::sbor::type_id::SborTypeId::Struct)?; decoder.read_and_check_size(1)?; Ok(Self { - a: <&'a u32>::decode(decoder)?, + a: decoder.decode::<&'a u32>()?, }) } } @@ -260,8 +267,9 @@ mod tests { assert_code_eq( output, quote! { - impl ::sbor::Decode for Test { - fn decode_body_with_type_id(decoder: &mut ::sbor::Decoder, type_id: ::sbor::SborTypeId) -> Result { + impl > ::sbor::Decode for Test { + #[inline] + fn decode_body_with_type_id(decoder: &mut DEC, type_id: ::sbor::SborTypeId) -> Result { use ::sbor::{self, Decode}; decoder.check_preloaded_type_id(type_id, ::sbor::type_id::SborTypeId::Enum)?; let discriminator = decoder.read_discriminator()?; @@ -272,12 +280,12 @@ mod tests { }, "B" => { decoder.read_and_check_size(1)?; - Ok(Self::B(::decode(decoder)?)) + Ok(Self::B(decoder.decode::()?)) }, "C" => { decoder.read_and_check_size(1)?; Ok(Self::C { - x: ::decode(decoder)?, + x: decoder.decode::()?, }) }, _ => Err(::sbor::DecodeError::UnknownDiscriminator(discriminator)) @@ -296,8 +304,9 @@ mod tests { assert_code_eq( output, quote! { - impl ::sbor::Decode for Test { - fn decode_body_with_type_id(decoder: &mut ::sbor::Decoder, type_id: ::sbor::SborTypeId) -> Result { + impl > ::sbor::Decode for Test { + #[inline] + fn decode_body_with_type_id(decoder: &mut DEC, type_id: ::sbor::SborTypeId) -> Result { use ::sbor::{self, Decode}; decoder.check_preloaded_type_id(type_id, ::sbor::type_id::SborTypeId::Struct)?; decoder.read_and_check_size(0)?; diff --git a/sbor-derive/src/encode.rs b/sbor-derive/src/encode.rs index 32977afec7b..c87cb2c96ac 100644 --- a/sbor-derive/src/encode.rs +++ b/sbor-derive/src/encode.rs @@ -22,8 +22,8 @@ pub fn handle_encode(input: TokenStream) -> Result { .. } = parse2(input)?; let custom_type_id = custom_type_id(&attrs); - let (impl_generics, ty_generics, where_clause, sbor_cti) = - build_generics(&generics, custom_type_id)?; + let (impl_generics, ty_generics, where_clause, custom_type_id_generic, encoder_generic) = + build_encode_generics(&generics, custom_type_id)?; let output = match data { Data::Struct(s) => match s.fields { @@ -33,16 +33,18 @@ pub fn handle_encode(input: TokenStream) -> Result { let ns_ids = ns.iter().map(|f| &f.ident); let ns_len = Index::from(ns_ids.len()); quote! { - impl #impl_generics ::sbor::Encode <#sbor_cti> for #ident #ty_generics #where_clause { + impl #impl_generics ::sbor::Encode <#custom_type_id_generic, #encoder_generic> for #ident #ty_generics #where_clause { #[inline] - fn encode_type_id(&self, encoder: &mut ::sbor::Encoder <#sbor_cti>) { - encoder.write_type_id(::sbor::type_id::SborTypeId::Struct); + fn encode_type_id(&self, encoder: &mut #encoder_generic) -> Result<(), ::sbor::EncodeError> { + encoder.write_type_id(::sbor::type_id::SborTypeId::Struct) } + #[inline] - fn encode_body(&self, encoder: &mut ::sbor::Encoder <#sbor_cti>) { + fn encode_body(&self, encoder: &mut #encoder_generic) -> Result<(), ::sbor::EncodeError> { use ::sbor::{self, Encode}; - encoder.write_size(#ns_len); - #(self.#ns_ids.encode(encoder);)* + encoder.write_size(#ns_len)?; + #(encoder.encode(&self.#ns_ids)?;)* + Ok(()) } } } @@ -56,30 +58,33 @@ pub fn handle_encode(input: TokenStream) -> Result { } let ns_len = Index::from(ns_indices.len()); quote! { - impl #impl_generics ::sbor::Encode <#sbor_cti> for #ident #ty_generics #where_clause { + impl #impl_generics ::sbor::Encode <#custom_type_id_generic, #encoder_generic> for #ident #ty_generics #where_clause { #[inline] - fn encode_type_id(&self, encoder: &mut ::sbor::Encoder <#sbor_cti>) { - encoder.write_type_id(::sbor::type_id::SborTypeId::Struct); + fn encode_type_id(&self, encoder: &mut #encoder_generic) -> Result<(), ::sbor::EncodeError> { + encoder.write_type_id(::sbor::type_id::SborTypeId::Struct) } + #[inline] - fn encode_body(&self, encoder: &mut ::sbor::Encoder <#sbor_cti>) { + fn encode_body(&self, encoder: &mut #encoder_generic) -> Result<(), ::sbor::EncodeError> { use ::sbor::{self, Encode}; - encoder.write_size(#ns_len); - #(self.#ns_indices.encode(encoder);)* + encoder.write_size(#ns_len)?; + #(encoder.encode(&self.#ns_indices)?;)* + Ok(()) } } } } syn::Fields::Unit => { quote! { - impl #impl_generics ::sbor::Encode <#sbor_cti> for #ident #ty_generics #where_clause { + impl #impl_generics ::sbor::Encode <#custom_type_id_generic, #encoder_generic> for #ident #ty_generics #where_clause { #[inline] - fn encode_type_id(&self, encoder: &mut ::sbor::Encoder <#sbor_cti>) { - encoder.write_type_id(::sbor::type_id::SborTypeId::Struct); + fn encode_type_id(&self, encoder: &mut #encoder_generic) -> Result<(), ::sbor::EncodeError> { + encoder.write_type_id(::sbor::type_id::SborTypeId::Struct) } + #[inline] - fn encode_body(&self, encoder: &mut ::sbor::Encoder <#sbor_cti>) { - encoder.write_size(0); + fn encode_body(&self, encoder: &mut #encoder_generic) -> Result<(), ::sbor::EncodeError> { + encoder.write_size(0) } } } @@ -100,9 +105,9 @@ pub fn handle_encode(input: TokenStream) -> Result { let ns_len = Index::from(ns.len()); quote! { Self::#v_id {#(#ns_ids,)* ..} => { - encoder.write_discriminator(#discriminator); - encoder.write_size(#ns_len); - #(#ns_ids2.encode(encoder);)* + encoder.write_discriminator(#discriminator)?; + encoder.write_size(#ns_len)?; + #(encoder.encode(#ns_ids2)?;)* } } } @@ -117,17 +122,17 @@ pub fn handle_encode(input: TokenStream) -> Result { let ns_len = Index::from(ns_args.len()); quote! { Self::#v_id (#(#args),*) => { - encoder.write_discriminator(#discriminator); - encoder.write_size(#ns_len); - #(#ns_args.encode(encoder);)* + encoder.write_discriminator(#discriminator)?; + encoder.write_size(#ns_len)?; + #(encoder.encode(#ns_args)?;)* } } } syn::Fields::Unit => { quote! { Self::#v_id => { - encoder.write_discriminator(#discriminator); - encoder.write_size(0); + encoder.write_discriminator(#discriminator)?; + encoder.write_size(0)?; } } } @@ -136,30 +141,34 @@ pub fn handle_encode(input: TokenStream) -> Result { if match_arms.len() == 0 { quote! { - impl #impl_generics ::sbor::Encode <#sbor_cti> for #ident #ty_generics #where_clause { + impl #impl_generics ::sbor::Encode <#custom_type_id_generic, #encoder_generic> for #ident #ty_generics #where_clause { #[inline] - fn encode_type_id(&self, encoder: &mut ::sbor::Encoder <#sbor_cti>) { - encoder.write_type_id(::sbor::type_id::SborTypeId::Enum); + fn encode_type_id(&self, encoder: &mut #encoder_generic) -> Result<(), ::sbor::EncodeError> { + encoder.write_type_id(::sbor::type_id::SborTypeId::Enum) } + #[inline] - fn encode_body(&self, encoder: &mut ::sbor::Encoder <#sbor_cti>) { + fn encode_body(&self, encoder: &mut #encoder_generic) -> Result<(), ::sbor::EncodeError> { + Ok(()) } } } } else { quote! { - impl #impl_generics ::sbor::Encode <#sbor_cti> for #ident #ty_generics #where_clause { + impl #impl_generics ::sbor::Encode <#custom_type_id_generic, #encoder_generic> for #ident #ty_generics #where_clause { #[inline] - fn encode_type_id(&self, encoder: &mut ::sbor::Encoder <#sbor_cti>) { - encoder.write_type_id(::sbor::type_id::SborTypeId::Enum); + fn encode_type_id(&self, encoder: &mut #encoder_generic) -> Result<(), ::sbor::EncodeError> { + encoder.write_type_id(::sbor::type_id::SborTypeId::Enum) } + #[inline] - fn encode_body(&self, encoder: &mut ::sbor::Encoder <#sbor_cti>) { + fn encode_body(&self, encoder: &mut #encoder_generic) -> Result<(), ::sbor::EncodeError> { use ::sbor::{self, Encode}; match self { #(#match_arms)* } + Ok(()) } } } @@ -196,16 +205,18 @@ mod tests { assert_code_eq( output, quote! { - impl ::sbor::Encode for Test { + impl > ::sbor::Encode for Test { #[inline] - fn encode_type_id(&self, encoder: &mut ::sbor::Encoder) { - encoder.write_type_id(::sbor::type_id::SborTypeId::Struct); + fn encode_type_id(&self, encoder: &mut ENC) -> Result<(), ::sbor::EncodeError> { + encoder.write_type_id(::sbor::type_id::SborTypeId::Struct) } + #[inline] - fn encode_body(&self, encoder: &mut ::sbor::Encoder) { + fn encode_body(&self, encoder: &mut ENC) -> Result<(), ::sbor::EncodeError> { use ::sbor::{self, Encode}; - encoder.write_size(1); - self.a.encode(encoder); + encoder.write_size(1)?; + encoder.encode(&self.a)?; + Ok(()) } } }, @@ -220,30 +231,32 @@ mod tests { assert_code_eq( output, quote! { - impl ::sbor::Encode for Test { + impl > ::sbor::Encode for Test { #[inline] - fn encode_type_id(&self, encoder: &mut ::sbor::Encoder) { - encoder.write_type_id(::sbor::type_id::SborTypeId::Enum); + fn encode_type_id(&self, encoder: &mut ENC) -> Result<(), ::sbor::EncodeError> { + encoder.write_type_id(::sbor::type_id::SborTypeId::Enum) } + #[inline] - fn encode_body(&self, encoder: &mut ::sbor::Encoder) { + fn encode_body(&self, encoder: &mut ENC) -> Result<(), ::sbor::EncodeError> { use ::sbor::{self, Encode}; match self { Self::A => { - encoder.write_discriminator("A"); - encoder.write_size(0); + encoder.write_discriminator("A")?; + encoder.write_size(0)?; } Self::B(a0) => { - encoder.write_discriminator("B"); - encoder.write_size(1); - a0.encode(encoder); + encoder.write_discriminator("B")?; + encoder.write_size(1)?; + encoder.encode(a0)?; } Self::C { x, .. } => { - encoder.write_discriminator("C"); - encoder.write_size(1); - x.encode(encoder); + encoder.write_discriminator("C")?; + encoder.write_size(1)?; + encoder.encode(x)?; } } + Ok(()) } } }, @@ -258,15 +271,17 @@ mod tests { assert_code_eq( output, quote! { - impl ::sbor::Encode for Test { + impl > ::sbor::Encode for Test { #[inline] - fn encode_type_id(&self, encoder: &mut ::sbor::Encoder) { - encoder.write_type_id(::sbor::type_id::SborTypeId::Struct); + fn encode_type_id(&self, encoder: &mut ENC) -> Result<(), ::sbor::EncodeError> { + encoder.write_type_id(::sbor::type_id::SborTypeId::Struct) } + #[inline] - fn encode_body(&self, encoder: &mut ::sbor::Encoder) { + fn encode_body(&self, encoder: &mut ENC) -> Result<(), ::sbor::EncodeError> { use ::sbor::{self, Encode}; - encoder.write_size(0); + encoder.write_size(0)?; + Ok(()) } } }, @@ -284,15 +299,17 @@ mod tests { assert_code_eq( output, quote! { - impl ::sbor::Encode for Test { + impl > ::sbor::Encode for Test { #[inline] - fn encode_type_id(&self, encoder: &mut ::sbor::Encoder) { - encoder.write_type_id(::sbor::type_id::SborTypeId::Struct); + fn encode_type_id(&self, encoder: &mut ENC) -> Result<(), ::sbor::EncodeError> { + encoder.write_type_id(::sbor::type_id::SborTypeId::Struct) } + #[inline] - fn encode_body(&self, encoder: &mut ::sbor::Encoder) { + fn encode_body(&self, encoder: &mut ENC) -> Result<(), ::sbor::EncodeError> { use ::sbor::{self, Encode}; - encoder.write_size(0); + encoder.write_size(0)?; + Ok(()) } } }, @@ -310,15 +327,17 @@ mod tests { assert_code_eq( output, quote! { - impl ::sbor::Encode<::sbor::basic::NoCustomTypeId> for Test { + impl > ::sbor::Encode<::sbor::basic::NoCustomTypeId, ENC> for Test { #[inline] - fn encode_type_id(&self, encoder: &mut ::sbor::Encoder<::sbor::basic::NoCustomTypeId>) { - encoder.write_type_id(::sbor::type_id::SborTypeId::Struct); + fn encode_type_id(&self, encoder: &mut ENC) -> Result<(), ::sbor::EncodeError> { + encoder.write_type_id(::sbor::type_id::SborTypeId::Struct) } + #[inline] - fn encode_body(&self, encoder: &mut ::sbor::Encoder<::sbor::basic::NoCustomTypeId>) { + fn encode_body(&self, encoder: &mut ENC) -> Result<(), ::sbor::EncodeError> { use ::sbor::{self, Encode}; - encoder.write_size(0); + encoder.write_size(0)?; + Ok(()) } } }, diff --git a/sbor-derive/src/utils.rs b/sbor-derive/src/utils.rs index bd97e2bcf94..b91d2c3e786 100644 --- a/sbor-derive/src/utils.rs +++ b/sbor-derive/src/utils.rs @@ -97,11 +97,55 @@ pub fn custom_type_id(attrs: &[Attribute]) -> Option { .unwrap_or(None) } +pub fn build_decode_generics( + original_generics: &Generics, + custom_type_id: Option, +) -> syn::Result<(Generics, TypeGenerics, Option<&WhereClause>, Path, Path)> { + let (mut impl_generics, ty_generics, where_clause, custom_type_id_generic) = + build_generics(original_generics, custom_type_id)?; + + let decoder_generic: Path = parse_quote! { DEC }; + + impl_generics + .params + .push(parse_quote!(#decoder_generic: ::sbor::decoder::Decoder<#custom_type_id_generic>)); + + Ok(( + impl_generics, + ty_generics, + where_clause, + custom_type_id_generic, + decoder_generic, + )) +} + +pub fn build_encode_generics( + original_generics: &Generics, + custom_type_id: Option, +) -> syn::Result<(Generics, TypeGenerics, Option<&WhereClause>, Path, Path)> { + let (mut impl_generics, ty_generics, where_clause, custom_type_id_generic) = + build_generics(original_generics, custom_type_id)?; + + let encoder_generic: Path = parse_quote! { ENC }; + + impl_generics + .params + .push(parse_quote!(#encoder_generic: ::sbor::encoder::Encoder<#custom_type_id_generic>)); + + Ok(( + impl_generics, + ty_generics, + where_clause, + custom_type_id_generic, + encoder_generic, + )) +} + pub fn build_generics( - generics: &Generics, + original_generics: &Generics, custom_type_id: Option, ) -> syn::Result<(Generics, TypeGenerics, Option<&WhereClause>, Path)> { - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let (impl_generics, ty_generics, where_clause) = original_generics.split_for_impl(); // Unwrap for mutation let mut impl_generics: Generics = parse_quote! { #impl_generics }; diff --git a/sbor-tests/benches/bench.rs b/sbor-tests/benches/bench.rs index 96479fe873b..9657bdcf4a2 100644 --- a/sbor-tests/benches/bench.rs +++ b/sbor-tests/benches/bench.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate bencher; use bencher::Bencher; -use sbor::NoCustomTypeId; +use sbor::{basic_decode, basic_encode}; mod adapter; mod data; @@ -20,7 +20,7 @@ fn encode_simple_bincode(b: &mut Bencher) { fn encode_simple_sbor(b: &mut Bencher) { let t = data::get_simple_dataset(SIMPLE_REAPT); - b.iter(|| sbor::encode::(&t)); + b.iter(|| basic_encode(&t)); } fn decode_simple_json(b: &mut Bencher) { @@ -37,8 +37,8 @@ fn decode_simple_bincode(b: &mut Bencher) { fn decode_simple_sbor(b: &mut Bencher) { let t = data::get_simple_dataset(SIMPLE_REAPT); - let bytes = sbor::encode::(&t); - b.iter(|| sbor::decode::(&bytes)); + let bytes = basic_encode(&t).unwrap(); + b.iter(|| basic_decode::(&bytes)); } benchmark_group!( diff --git a/sbor-tests/tests/decode.rs b/sbor-tests/tests/decode.rs index ea82b2fbceb..b6e37217004 100644 --- a/sbor-tests/tests/decode.rs +++ b/sbor-tests/tests/decode.rs @@ -40,10 +40,10 @@ fn test_decode_struct() { 0, // number of fields ]; - let mut decoder = Decoder::::new(&bytes); - let a = TestStructNamed::decode(&mut decoder).unwrap(); - let b = TestStructUnnamed::decode(&mut decoder).unwrap(); - let c = TestStructUnit::decode(&mut decoder).unwrap(); + let mut decoder = BasicDecoder::new(&bytes); + let a = decoder.decode::().unwrap(); + let b = decoder.decode::().unwrap(); + let c = decoder.decode::().unwrap(); assert_eq!(TestStructNamed { state: 3 }, a); assert_eq!(TestStructUnnamed(3), b); @@ -73,10 +73,10 @@ fn test_decode_enum() { 0, // number of fields ]; - let mut decoder = Decoder::::new(&bytes); - let a = TestEnum::decode(&mut decoder).unwrap(); - let b = TestEnum::decode(&mut decoder).unwrap(); - let c = TestEnum::decode(&mut decoder).unwrap(); + let mut decoder = BasicDecoder::new(&bytes); + let a = decoder.decode::().unwrap(); + let b = decoder.decode::().unwrap(); + let c = decoder.decode::().unwrap(); assert_eq!(TestEnum::A { x: 2, y: 3 }, a); assert_eq!(TestEnum::B(1), b); @@ -95,8 +95,8 @@ fn test_decode_empty_enum() { 9, 3, 0, 0, 0, // field value ]; - let mut decoder = Decoder::::new(&bytes); - let result = EmptyEnum::decode(&mut decoder); + let mut decoder = BasicDecoder::new(&bytes); + let result = decoder.decode::(); assert!(matches!(result, Err(DecodeError::UnknownDiscriminator(_)))); } diff --git a/sbor-tests/tests/encode.rs b/sbor-tests/tests/encode.rs index b8d21268cc2..05da73fb6d8 100644 --- a/sbor-tests/tests/encode.rs +++ b/sbor-tests/tests/encode.rs @@ -32,10 +32,10 @@ fn test_encode_struct() { let c = TestStructUnit {}; let mut bytes = Vec::with_capacity(512); - let mut encoder = Encoder::::new(&mut bytes); - a.encode(&mut encoder); - b.encode(&mut encoder); - c.encode(&mut encoder); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&a).unwrap(); + encoder.encode(&b).unwrap(); + encoder.encode(&c).unwrap(); #[rustfmt::skip] assert_eq!( @@ -62,10 +62,10 @@ fn test_encode_enum() { let c = TestEnum::C; let mut bytes = Vec::with_capacity(512); - let mut encoder = Encoder::::new(&mut bytes); - a.encode(&mut encoder); - b.encode(&mut encoder); - c.encode(&mut encoder); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&a).unwrap(); + encoder.encode(&b).unwrap(); + encoder.encode(&c).unwrap(); #[rustfmt::skip] assert_eq!( diff --git a/sbor-tests/tests/skip.rs b/sbor-tests/tests/skip.rs index 8bd84ad6579..856d9117210 100644 --- a/sbor-tests/tests/skip.rs +++ b/sbor-tests/tests/skip.rs @@ -36,10 +36,10 @@ fn test_struct_with_skip() { let c = TestStructUnit; let mut bytes = Vec::with_capacity(512); - let mut encoder = Encoder::::new(&mut bytes); - a.encode(&mut encoder); - b.encode(&mut encoder); - c.encode(&mut encoder); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&a).unwrap(); + encoder.encode(&b).unwrap(); + encoder.encode(&c).unwrap(); #[rustfmt::skip] assert_eq!( @@ -49,19 +49,19 @@ fn test_struct_with_skip() { 9, 2, 0, 0, 0, // field value 16, // struct type - 1, // number of fields + 1, // number of fields 9, 4, 0, 0, 0, // field value 16, // struct type - 0, // number of fields + 0, // number of fields ], bytes ); - let mut decoder = Decoder::::new(&bytes); - let a = TestStructNamed::decode(&mut decoder).unwrap(); - let b = TestStructUnnamed::decode(&mut decoder).unwrap(); - let c = TestStructUnit::decode(&mut decoder).unwrap(); + let mut decoder = BasicDecoder::new(&bytes); + let a = decoder.decode::().unwrap(); + let b = decoder.decode::().unwrap(); + let c = decoder.decode::().unwrap(); assert_eq!(TestStructNamed { x: 0, y: 2 }, a); assert_eq!(TestStructUnnamed(0, 4), b); @@ -75,10 +75,10 @@ fn test_enum_with_skip() { let c = TestEnum::C; let mut bytes = Vec::with_capacity(512); - let mut encoder = Encoder::::new(&mut bytes); - a.encode(&mut encoder); - b.encode(&mut encoder); - c.encode(&mut encoder); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&a).unwrap(); + encoder.encode(&b).unwrap(); + encoder.encode(&c).unwrap(); #[rustfmt::skip] assert_eq!( @@ -103,10 +103,10 @@ fn test_enum_with_skip() { bytes ); - let mut decoder = Decoder::::new(&bytes); - let a = TestEnum::decode(&mut decoder).unwrap(); - let b = TestEnum::decode(&mut decoder).unwrap(); - let c = TestEnum::decode(&mut decoder).unwrap(); + let mut decoder = BasicDecoder::new(&bytes); + let a = decoder.decode::().unwrap(); + let b = decoder.decode::().unwrap(); + let c = decoder.decode::().unwrap(); assert_eq!(TestEnum::A { x: 0, y: 2 }, a); assert_eq!(TestEnum::B(0, 4), b); diff --git a/sbor-tests/tests/value.rs b/sbor-tests/tests/value.rs index acb0c9bc836..5e804b95fee 100644 --- a/sbor-tests/tests/value.rs +++ b/sbor-tests/tests/value.rs @@ -35,8 +35,8 @@ fn test_encode_as_json() { c: (2, vec![3, 4]), d: "5".to_string(), }; - let bytes = crate::encode::(&sample); - let any = crate::decode_any::(&bytes).unwrap(); + let bytes = basic_encode(&sample).unwrap(); + let any = basic_decode::(&bytes).unwrap(); assert_json_eq( any, diff --git a/sbor/src/basic.rs b/sbor/src/basic.rs index 0e38737b3b5..ae187092792 100644 --- a/sbor/src/basic.rs +++ b/sbor/src/basic.rs @@ -1,3 +1,4 @@ +use crate::rust::vec::Vec; use crate::*; #[cfg_attr( @@ -16,11 +17,45 @@ pub enum NoCustomTypeId {} #[derive(Debug, Clone, PartialEq, Eq)] pub enum NoCustomValue {} -pub type BasicEncoder<'a> = Encoder<'a, NoCustomTypeId>; -pub type BasicDecoder<'a> = Decoder<'a, NoCustomTypeId>; +pub const DEFAULT_BASIC_MAX_DEPTH: u8 = 64; +pub type BasicEncoder<'a> = VecEncoder<'a, NoCustomTypeId, DEFAULT_BASIC_MAX_DEPTH>; +pub type BasicDecoder<'a> = VecDecoder<'a, NoCustomTypeId, DEFAULT_BASIC_MAX_DEPTH>; pub type BasicSborValue = SborValue; pub type BasicSborTypeId = SborTypeId; +// The following trait "aliases" are to be used in parameters. +// +// They are much nicer to read than the underlying traits, but because they are "new", and are defined +// via blanket impls, they can only be used for parameters, but cannot be used for implementations. +// +// Implementations should instead implement the underlying traits: +// * TypeId (impl over all X: CustomTypeId) +// * Encode (impl over all X: CustomTypeId, E: Encoder) +// * Decode (impl over all X: CustomTypeId, D: Decoder) +// +// TODO: Change these to be Trait aliases once stable in rust: https://github.com/rust-lang/rust/issues/41517 +pub trait BasicTypeId: TypeId {} +impl + ?Sized> BasicTypeId for T {} + +pub trait BasicDecode: for<'a> Decode> {} +impl Decode>> BasicDecode for T {} + +pub trait BasicEncode: for<'a> Encode> {} +impl Encode> + ?Sized> BasicEncode for T {} + +/// Encode a `T` into byte array. +pub fn basic_encode(v: &T) -> Result, EncodeError> { + let mut buf = Vec::with_capacity(512); + let encoder = BasicEncoder::new(&mut buf); + encoder.encode_payload(v)?; + Ok(buf) +} + +/// Decode an instance of `T` from a slice. +pub fn basic_decode(buf: &[u8]) -> Result { + BasicDecoder::new(buf).decode_payload() +} + impl CustomTypeId for NoCustomTypeId { fn as_u8(&self) -> u8 { panic!("No custom type") @@ -31,16 +66,21 @@ impl CustomTypeId for NoCustomTypeId { } } -impl CustomValue for NoCustomValue { - fn encode_type_id(&self, _encoder: &mut Encoder) { +impl> Encode for NoCustomValue { + fn encode_type_id(&self, _encoder: &mut E) -> Result<(), EncodeError> { panic!("No custom value") } - fn encode_body(&self, _encoder: &mut Encoder) { + fn encode_body(&self, _encoder: &mut E) -> Result<(), EncodeError> { panic!("No custom value") } +} - fn decode_body_with_type_id(_decoder: &mut Decoder, _type_id: X) -> Result +impl> Decode for NoCustomValue { + fn decode_body_with_type_id( + _decoder: &mut D, + _type_id: SborTypeId, + ) -> Result where Self: Sized, { diff --git a/sbor/src/codec/array.rs b/sbor/src/codec/array.rs index e2693263809..34c3a4121fd 100644 --- a/sbor/src/codec/array.rs +++ b/sbor/src/codec/array.rs @@ -2,41 +2,48 @@ use crate::rust::mem::MaybeUninit; use crate::type_id::*; use crate::*; -impl + TypeId> Encode for [T] { +impl, T: Encode + TypeId> Encode for [T] { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_type_id(T::type_id()); - encoder.write_size(self.len()); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(T::type_id())?; + encoder.write_size(self.len())?; if T::type_id() == SborTypeId::U8 || T::type_id() == SborTypeId::I8 { let ptr = self.as_ptr().cast::(); let slice = unsafe { sbor::rust::slice::from_raw_parts(ptr, self.len()) }; - encoder.write_slice(slice); + encoder.write_slice(slice)?; } else { for v in self { - v.encode_body(encoder); + encoder.encode_deeper_body(v)?; } } + Ok(()) } } -impl + TypeId, const N: usize> Encode for [T; N] { +impl, T: Encode + TypeId, const N: usize> Encode + for [T; N] +{ #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - self.as_slice().encode_body(encoder); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_slice().encode_body(encoder) } } -impl + TypeId, const N: usize> Decode for [T; N] { +impl, T: Decode + TypeId, const N: usize> Decode + for [T; N] +{ + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -54,7 +61,7 @@ impl + TypeId, const N: usize> Decode for [T // Decode element by element for elem in &mut data[..] { - elem.write(T::decode_body_with_type_id(decoder, element_type_id)?); + elem.write(decoder.decode_deeper_body_with_type_id(element_type_id)?); } // Use &mut as an assertion of unique "ownership" diff --git a/sbor/src/codec/boolean.rs b/sbor/src/codec/boolean.rs index ebbd6a61a9b..f7aa3a229bf 100644 --- a/sbor/src/codec/boolean.rs +++ b/sbor/src/codec/boolean.rs @@ -1,20 +1,22 @@ use crate::type_id::*; use crate::*; -impl Encode for bool { +impl> Encode for bool { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_byte(if *self { 1u8 } else { 0u8 }); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_byte(if *self { 1u8 } else { 0u8 }) } } -impl Decode for bool { +impl> Decode for bool { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; diff --git a/sbor/src/codec/collection.rs b/sbor/src/codec/collection.rs index afe74359a21..63f9a33a3ea 100644 --- a/sbor/src/codec/collection.rs +++ b/sbor/src/codec/collection.rs @@ -5,89 +5,98 @@ use crate::rust::vec::Vec; use crate::type_id::*; use crate::*; -impl + TypeId> Encode for Vec { +impl, T: Encode + TypeId> Encode for Vec { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - self.as_slice().encode_body(encoder); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_slice().encode_body(encoder)?; + Ok(()) } } -impl + TypeId> Encode for BTreeSet { +impl, T: Encode + TypeId> Encode for BTreeSet { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_type_id(T::type_id()); - encoder.write_size(self.len()); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(T::type_id())?; + encoder.write_size(self.len())?; for v in self { - v.encode_body(encoder); + encoder.encode_deeper_body(v)?; } + Ok(()) } } -impl + TypeId + Ord + Hash> Encode for HashSet { +impl, T: Encode + TypeId + Ord + Hash> Encode + for HashSet +{ #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_type_id(T::type_id()); - encoder.write_size(self.len()); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(T::type_id())?; + encoder.write_size(self.len())?; for v in self { - v.encode_body(encoder); + encoder.encode_deeper_body(v)?; } + Ok(()) } } -impl + TypeId, V: Encode + TypeId> Encode +impl, K: Encode, V: Encode> Encode for BTreeMap { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_type_id(<(K, V)>::type_id()); - encoder.write_size(self.len()); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(<(K, V)>::type_id())?; + encoder.write_size(self.len())?; for (k, v) in self { - encoder.write_size(2); - k.encode(encoder); - v.encode(encoder); + encoder.encode_deeper_body(&(k, v))?; } + Ok(()) } } -impl + TypeId + Ord + Hash, V: Encode + TypeId> Encode +impl, K: Encode + Ord + Hash, V: Encode> Encode for HashMap { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_type_id(<(K, V)>::type_id()); - encoder.write_size(self.len()); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(<(K, V)>::type_id())?; + encoder.write_size(self.len())?; let keys: BTreeSet<&K> = self.keys().collect(); for key in keys { - encoder.write_size(2); - key.encode(encoder); - self.get(key).unwrap().encode(encoder); + encoder.encode_deeper_body(&(key, self.get(key).unwrap()))?; } + Ok(()) } } -impl + TypeId> Decode for Vec { +impl, T: Decode + TypeId> Decode for Vec { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -105,16 +114,19 @@ impl + TypeId> Decode for Vec { } else { let mut result = Vec::::with_capacity(if len <= 1024 { len } else { 1024 }); for _ in 0..len { - result.push(T::decode_body_with_type_id(decoder, element_type_id)?); + result.push(decoder.decode_deeper_body_with_type_id(element_type_id)?); } Ok(result) } } } -impl + TypeId + Ord> Decode for BTreeSet { +impl, T: Decode + TypeId + Ord> Decode + for BTreeSet +{ + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -123,9 +135,12 @@ impl + TypeId + Ord> Decode for BTreeSet } } -impl + TypeId + Hash + Eq> Decode for HashSet { +impl, T: Decode + TypeId + Hash + Eq> Decode + for HashSet +{ + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -134,11 +149,12 @@ impl + TypeId + Hash + Eq> Decode for HashSe } } -impl + TypeId + Ord, V: Decode + TypeId> Decode +impl, K: Decode + Ord, V: Decode> Decode for BTreeMap { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -147,11 +163,12 @@ impl + TypeId + Ord, V: Decode + TypeId> } } -impl + TypeId + Hash + Eq, V: Decode + TypeId> Decode +impl, K: Decode + Hash + Eq, V: Decode> Decode for HashMap { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; diff --git a/sbor/src/codec/integer.rs b/sbor/src/codec/integer.rs index fc7b03d189f..2b14efcf3ed 100644 --- a/sbor/src/codec/integer.rs +++ b/sbor/src/codec/integer.rs @@ -1,38 +1,41 @@ use crate::type_id::*; use crate::*; -impl Encode for i8 { +impl> Encode for i8 { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_byte(*self as u8); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_byte(*self as u8) } } -impl Encode for u8 { +impl> Encode for u8 { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_byte(*self); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_byte(*self) } } macro_rules! encode_int { ($type:ident, $type_id:ident) => { - impl Encode for $type { + impl> Encode for $type { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_slice(&(*self).to_le_bytes()); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_slice(&(*self).to_le_bytes()) } } }; @@ -47,31 +50,34 @@ encode_int!(u32, TYPE_U32); encode_int!(u64, TYPE_U64); encode_int!(u128, TYPE_U128); -impl Encode for isize { +impl> Encode for isize { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - (*self as i64).encode_body(encoder); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + (*self as i64).encode_body(encoder) } } -impl Encode for usize { +impl> Encode for usize { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - (*self as u64).encode_body(encoder); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + (*self as u64).encode_body(encoder) } } -impl Decode for i8 { +impl> Decode for i8 { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -80,9 +86,10 @@ impl Decode for i8 { } } -impl Decode for u8 { +impl> Decode for u8 { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -93,9 +100,10 @@ impl Decode for u8 { macro_rules! decode_int { ($type:ident, $type_id:ident, $n:expr) => { - impl Decode for $type { + impl> Decode for $type { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -117,9 +125,10 @@ decode_int!(u32, TYPE_U32, 4); decode_int!(u64, TYPE_U64, 8); decode_int!(u128, TYPE_U128, 16); -impl Decode for isize { +impl> Decode for isize { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -127,9 +136,10 @@ impl Decode for isize { } } -impl Decode for usize { +impl> Decode for usize { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; diff --git a/sbor/src/codec/misc.rs b/sbor/src/codec/misc.rs index 4053d9e22a3..68c151f99b1 100644 --- a/sbor/src/codec/misc.rs +++ b/sbor/src/codec/misc.rs @@ -6,83 +6,106 @@ use crate::rust::rc::Rc; use crate::type_id::*; use crate::*; -impl<'a, X: CustomTypeId, B: ?Sized + 'a + ToOwned + Encode + TypeId> Encode +impl<'a, X: CustomTypeId, E: Encoder, T: ?Sized + Encode> Encode for &T { + #[inline] + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + (*self).encode_type_id(encoder) + } + + #[inline] + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + (*self).encode_body(encoder) + } +} + +impl<'a, X: CustomTypeId, E: Encoder, B: ?Sized + 'a + ToOwned + Encode> Encode for Cow<'a, B> { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(B::type_id()) + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_ref().encode_type_id(encoder) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - self.as_ref().encode_body(encoder); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_ref().encode_body(encoder) } } -impl + TypeId> Encode for Box { +impl, T: Encode> Encode for Box { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(T::type_id()) + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_ref().encode_type_id(encoder) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - self.as_ref().encode_body(encoder); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_ref().encode_body(encoder) } } -impl + TypeId> Encode for RefCell { +impl, T: Encode> Encode for Rc { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(T::type_id()) + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_ref().encode_type_id(encoder) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - self.borrow().encode_body(encoder); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_ref().encode_body(encoder) } } -impl<'a, X: CustomTypeId, B: ?Sized + 'a + ToOwned, O: Decode + TypeId> Decode - for Cow<'a, B> +impl, T: Encode> Encode for RefCell { + #[inline] + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.borrow().encode_type_id(encoder) + } + + #[inline] + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.borrow().encode_body(encoder) + } +} + +impl<'a, X: CustomTypeId, D: Decoder, B: ?Sized + 'a + ToOwned, O: Decode> + Decode for Cow<'a, B> { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { - decoder.check_preloaded_type_id(type_id, O::type_id())?; - let v = O::decode_body_with_type_id(decoder, type_id)?; - Ok(Cow::Owned(v)) + Ok(Cow::Owned(O::decode_body_with_type_id(decoder, type_id)?)) } } -impl + TypeId> Decode for Box { +impl, T: Decode> Decode for Box { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { - decoder.check_preloaded_type_id(type_id, T::type_id())?; - let v = T::decode_body_with_type_id(decoder, type_id)?; - Ok(Box::new(v)) + Ok(Box::new(T::decode_body_with_type_id(decoder, type_id)?)) } } -impl + TypeId> Decode for Rc { +impl, T: Decode> Decode for Rc { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { - decoder.check_preloaded_type_id(type_id, T::type_id())?; - let v = T::decode_body_with_type_id(decoder, type_id)?; - Ok(Rc::new(v)) + Ok(Rc::new(T::decode_body_with_type_id(decoder, type_id)?)) } } -impl + TypeId> Decode for RefCell { +impl, T: Decode + TypeId> Decode for RefCell { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { - decoder.check_preloaded_type_id(type_id, T::type_id())?; - let v = T::decode_body_with_type_id(decoder, type_id)?; - Ok(RefCell::new(v)) + Ok(RefCell::new(T::decode_body_with_type_id(decoder, type_id)?)) } } diff --git a/sbor/src/codec/option.rs b/sbor/src/codec/option.rs index 3c0753fb7c6..cc6e9acb0ec 100644 --- a/sbor/src/codec/option.rs +++ b/sbor/src/codec/option.rs @@ -2,30 +2,33 @@ use crate::constants::*; use crate::type_id::*; use crate::*; -impl + TypeId> Encode for Option { +impl, T: Encode + TypeId> Encode for Option { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { match self { Some(v) => { - encoder.write_discriminator(OPTION_VARIANT_SOME); - encoder.write_size(1); - v.encode(encoder); + encoder.write_discriminator(OPTION_VARIANT_SOME)?; + encoder.write_size(1)?; + encoder.encode(v)?; } None => { - encoder.write_discriminator(OPTION_VARIANT_NONE); - encoder.write_size(0); + encoder.write_discriminator(OPTION_VARIANT_NONE)?; + encoder.write_size(0)?; } } + Ok(()) } } -impl> Decode for Option { +impl, T: Decode> Decode for Option { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -34,7 +37,7 @@ impl> Decode for Option { match discriminator.as_ref() { OPTION_VARIANT_SOME => { decoder.read_and_check_size(1)?; - Ok(Some(T::decode(decoder)?)) + Ok(Some(decoder.decode()?)) } OPTION_VARIANT_NONE => { decoder.read_and_check_size(0)?; diff --git a/sbor/src/codec/result.rs b/sbor/src/codec/result.rs index 7f6b7db1f8f..b80d11be49e 100644 --- a/sbor/src/codec/result.rs +++ b/sbor/src/codec/result.rs @@ -2,33 +2,38 @@ use crate::constants::*; use crate::type_id::*; use crate::*; -impl, E: Encode> Encode for Result { +impl, T: Encode, E: Encode> Encode + for Result +{ #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut Enc) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { + fn encode_body(&self, encoder: &mut Enc) -> Result<(), EncodeError> { match self { Ok(o) => { - encoder.write_discriminator(RESULT_VARIANT_OK); - encoder.write_size(1); - o.encode(encoder); + encoder.write_discriminator(RESULT_VARIANT_OK)?; + encoder.write_size(1)?; + encoder.encode(o)?; } Err(e) => { - encoder.write_discriminator(RESULT_VARIANT_ERR); - encoder.write_size(1); - e.encode(encoder); + encoder.write_discriminator(RESULT_VARIANT_ERR)?; + encoder.write_size(1)?; + encoder.encode(e)?; } } + Ok(()) } } -impl + TypeId, E: Decode + TypeId> Decode - for Result +impl, T: Decode + TypeId, E: Decode + TypeId> + Decode for Result { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; @@ -36,11 +41,11 @@ impl + TypeId, E: Decode + TypeId> Decode match discriminator.as_ref() { RESULT_VARIANT_OK => { decoder.read_and_check_size(1)?; - Ok(Ok(T::decode(decoder)?)) + Ok(Ok(decoder.decode()?)) } RESULT_VARIANT_ERR => { decoder.read_and_check_size(1)?; - Ok(Err(E::decode(decoder)?)) + Ok(Err(decoder.decode()?)) } _ => Err(DecodeError::UnknownDiscriminator(discriminator)), } diff --git a/sbor/src/codec/string.rs b/sbor/src/codec/string.rs index c5e6d114c3a..8ef0245ccf4 100644 --- a/sbor/src/codec/string.rs +++ b/sbor/src/codec/string.rs @@ -2,44 +2,36 @@ use crate::rust::string::String; use crate::type_id::*; use crate::*; -impl Encode for str { +impl> Encode for str { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } - #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_size(self.len()); - encoder.write_slice(self.as_bytes()); - } -} -impl Encode for &str { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); - } - #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_size(self.len()); - encoder.write_slice(self.as_bytes()); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_size(self.len())?; + encoder.write_slice(self.as_bytes())?; + Ok(()) } } -impl Encode for String { +impl> Encode for String { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - self.as_str().encode_body(encoder); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_str().encode_body(encoder) } } -impl Decode for String { +impl> Decode for String { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; diff --git a/sbor/src/codec/tuple.rs b/sbor/src/codec/tuple.rs index 6e69ee84f0a..11377f6e7b2 100644 --- a/sbor/src/codec/tuple.rs +++ b/sbor/src/codec/tuple.rs @@ -3,21 +3,23 @@ use crate::*; macro_rules! encode_tuple { ($n:tt $($idx:tt $name:ident)+) => { - impl),+> Encode for ($($name,)+) { + impl, $($name: Encode),+> Encode for ($($name,)+) { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut Enc) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } - #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_size($n); - $(self.$idx.encode(encoder);)+ + #[inline] + fn encode_body(&self, encoder: &mut Enc) -> Result<(), EncodeError> { + encoder.write_size($n)?; + $(encoder.encode(&self.$idx)?;)+ + Ok(()) } } }; } +encode_tuple! { 1 0 A } encode_tuple! { 2 0 A 1 B } encode_tuple! { 3 0 A 1 B 2 C } encode_tuple! { 4 0 A 1 B 2 C 3 D } @@ -30,17 +32,19 @@ encode_tuple! { 10 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J } macro_rules! decode_tuple { ($n:tt $($idx:tt $name:ident)+) => { - impl),+> Decode for ($($name,)+) { - fn decode_body_with_type_id(decoder: &mut Decoder, type_id: SborTypeId) -> Result { + impl, $($name: Decode),+> Decode for ($($name,)+) { + #[inline] + fn decode_body_with_type_id(decoder: &mut Dec, type_id: SborTypeId) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; decoder.read_and_check_size($n)?; - Ok(($($name::decode(decoder)?),+)) + Ok(($(decoder.decode::<$name>()?,)+)) } } }; } +decode_tuple! { 1 0 A } decode_tuple! { 2 0 A 1 B } decode_tuple! { 3 0 A 1 B 2 C } decode_tuple! { 4 0 A 1 B 2 C 3 D } diff --git a/sbor/src/codec/unit.rs b/sbor/src/codec/unit.rs index 24739fbc3b3..b23727e4c3d 100644 --- a/sbor/src/codec/unit.rs +++ b/sbor/src/codec/unit.rs @@ -1,20 +1,22 @@ use crate::type_id::*; use crate::*; -impl Encode for () { +impl> Encode for () { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - encoder.write_byte(0); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_byte(0) } } -impl Decode for () { +impl> Decode for () { + #[inline] fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; diff --git a/sbor/src/decode.rs b/sbor/src/decode.rs index 40b8df19278..4aa27745f63 100644 --- a/sbor/src/decode.rs +++ b/sbor/src/decode.rs @@ -1,332 +1,34 @@ -use crate::rust::marker::PhantomData; -use crate::rust::string::String; +use crate::decoder::*; use crate::type_id::*; -use crate::*; - -/// Represents an error ocurred during decoding. -#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeId)] -pub enum DecodeError { - ExtraTrailingBytes(usize), - - BufferUnderflow { required: usize, remaining: usize }, - - UnexpectedTypeId { expected: u8, actual: u8 }, - - UnexpectedSize { expected: usize, actual: usize }, - - UnknownTypeId(u8), - - UnknownDiscriminator(String), - - InvalidUnit(u8), - - InvalidBool(u8), - - InvalidUtf8, - - SizeTooLarge, - - InvalidCustomValue, // TODO: generify custom error codes -} /// A data structure that can be decoded from a byte array using SBOR. -pub trait Decode: Sized { - /// Decodes from the byte array encapsulated by the given decoder. - fn decode(decoder: &mut Decoder) -> Result { - let type_id = decoder.read_type_id()?; - Self::decode_body_with_type_id(decoder, type_id) - } - - /// Decodes from the byte array encapsulated by the given decoder, with a preloaded type id. +pub trait Decode>: Sized { + /// Decodes the type from the decoder, using a preloaded type id. + /// + /// You may want to call `decoder.decode_deeper_body_with_type_id` instead of this method. See + /// the below section for details. + /// + /// ## Direct calls and SBOR Depth + /// + /// In order to avoid SBOR depth differentials and disagreement about whether a payload + /// is valid, typed codec implementations should ensure that the SBOR depth as measured + /// during the encoding/decoding process agrees with the SborValue codec. + /// + /// Each layer of the SborValue counts as one depth. + /// + /// If the decoder you're writing is embedding a child type (and is represented as such + /// in the SborValue type), then you should call `decoder.decode_body_with_type_id` to increment + /// the SBOR depth tracker. + /// + /// You should only call `T::decode_body_with_type_id` directly when the decoding of that type + /// into an SborValue doesn't increase the SBOR depth in the decoder, that is: + /// * When the wrapping type is invisible to the SborValue, ie: + /// * Smart pointers + /// * Transparent wrappers + /// * Where the use of the inner type is invisible to SborValue, ie: + /// * Where the use of `T::decode_body_with_type_id` is coincidental / code re-use fn decode_body_with_type_id( - decoder: &mut Decoder, + decoder: &mut D, type_id: SborTypeId, ) -> Result; } - -/// A `Decoder` abstracts the logic for decoding basic types. -pub struct Decoder<'de, X: CustomTypeId> { - input: &'de [u8], - offset: usize, - phantom: PhantomData, -} - -impl<'de, X: CustomTypeId> Decoder<'de, X> { - pub fn new(input: &'de [u8]) -> Self { - Self { - input, - offset: 0, - phantom: PhantomData, - } - } - - #[inline] - pub fn remaining(&self) -> usize { - self.input.len() - self.offset - } - - pub fn require(&self, n: usize) -> Result<(), DecodeError> { - if self.remaining() < n { - Err(DecodeError::BufferUnderflow { - required: n, - remaining: self.remaining(), - }) - } else { - Ok(()) - } - } - - pub fn read_type_id(&mut self) -> Result, DecodeError> { - let id = self.read_byte()?; - SborTypeId::from_u8(id).ok_or(DecodeError::UnknownTypeId(id)) - } - - pub fn read_discriminator(&mut self) -> Result { - let n = self.read_size()?; - let slice = self.read_slice(n)?; - String::from_utf8(slice.to_vec()).map_err(|_| DecodeError::InvalidUtf8) - } - - pub fn read_size(&mut self) -> Result { - // LEB128 and 4 bytes max - let mut size = 0usize; - let mut shift = 0; - loop { - let byte = self.read_byte()?; - size |= ((byte & 0x7F) as usize) << shift; - if byte < 0x80 { - break; - } - shift += 7; - if shift >= 28 { - return Err(DecodeError::SizeTooLarge); - } - } - Ok(size) - } - - pub fn read_byte(&mut self) -> Result { - self.require(1)?; - let result = self.input[self.offset]; - self.offset += 1; - Ok(result) - } - - pub fn read_slice(&mut self, n: usize) -> Result<&'de [u8], DecodeError> { - self.require(n)?; - let slice = &self.input[self.offset..self.offset + n]; - self.offset += n; - Ok(slice) - } - - pub fn check_preloaded_type_id( - &self, - type_id: SborTypeId, - expected: SborTypeId, - ) -> Result, DecodeError> { - if type_id == expected { - Ok(type_id) - } else { - Err(DecodeError::UnexpectedTypeId { - actual: type_id.as_u8(), - expected: expected.as_u8(), - }) - } - } - - pub fn read_and_check_type_id( - &mut self, - expected: SborTypeId, - ) -> Result, DecodeError> { - let type_id = self.read_type_id()?; - self.check_preloaded_type_id(type_id, expected) - } - - pub fn read_and_check_size(&mut self, expected: usize) -> Result<(), DecodeError> { - let len = self.read_size()?; - if len != expected { - return Err(DecodeError::UnexpectedSize { - expected, - actual: len, - }); - } - - Ok(()) - } - - pub fn check_end(&self) -> Result<(), DecodeError> { - let n = self.remaining(); - if n != 0 { - Err(DecodeError::ExtraTrailingBytes(n)) - } else { - Ok(()) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::encode::Encode; - use crate::encode::Encoder; - use crate::rust::borrow::ToOwned; - use crate::rust::boxed::Box; - use crate::rust::cell::RefCell; - use crate::rust::collections::*; - use crate::rust::rc::Rc; - use crate::rust::string::String; - use crate::rust::vec; - use crate::rust::vec::Vec; - - fn encode_decode_size(size: usize) -> Result<(), DecodeError> { - // Encode - let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::::new(&mut bytes); - enc.write_size(size); - - let mut dec = Decoder::::new(&bytes); - dec.read_and_check_size(size)?; - dec.check_end()?; - Ok(()) - } - - #[test] - pub fn test_vlq() { - encode_decode_size(0x00000000).unwrap(); - encode_decode_size(0x0000007F).unwrap(); - encode_decode_size(0x00000080).unwrap(); - encode_decode_size(0x00002000).unwrap(); - encode_decode_size(0x00003FFF).unwrap(); - encode_decode_size(0x00004000).unwrap(); - encode_decode_size(0x001FFFFF).unwrap(); - encode_decode_size(0x00200000).unwrap(); - encode_decode_size(0x08000000).unwrap(); - encode_decode_size(0x0FFFFFFF).unwrap(); - } - - #[test] - pub fn test_vlq_too_large() { - let mut dec = Decoder::::new(&[0xff, 0xff, 0xff, 0xff, 0x00]); - assert_eq!(dec.read_size(), Err(DecodeError::SizeTooLarge)); - } - - fn assert_decoding(dec: &mut Decoder) { - <()>::decode(dec).unwrap(); - assert_eq!(true, ::decode(dec).unwrap()); - assert_eq!(1, ::decode(dec).unwrap()); - assert_eq!(1, ::decode(dec).unwrap()); - assert_eq!(1, ::decode(dec).unwrap()); - assert_eq!(1, ::decode(dec).unwrap()); - assert_eq!(1, ::decode(dec).unwrap()); - assert_eq!(1, ::decode(dec).unwrap()); - assert_eq!(1, ::decode(dec).unwrap()); - assert_eq!(1, ::decode(dec).unwrap()); - assert_eq!(1, ::decode(dec).unwrap()); - assert_eq!(1, ::decode(dec).unwrap()); - assert_eq!("hello", ::decode(dec).unwrap()); - - assert_eq!([1u32, 2u32, 3u32], <[u32; 3]>::decode(dec).unwrap()); - assert_eq!((1u32, 2u32), <(u32, u32)>::decode(dec).unwrap()); - - assert_eq!(vec![1u32, 2u32, 3u32], >::decode(dec).unwrap()); - let mut set = BTreeSet::::new(); - set.insert(1); - set.insert(2); - assert_eq!(set, >::decode(dec).unwrap()); - let mut map = BTreeMap::::new(); - map.insert(1, 2); - map.insert(3, 4); - assert_eq!(map, >::decode(dec).unwrap()); - - assert_eq!(Some(1u32), >::decode(dec).unwrap()); - assert_eq!(None, >::decode(dec).unwrap()); - assert_eq!(Ok(1u32), >::decode(dec).unwrap()); - assert_eq!( - Err("hello".to_owned()), - >::decode(dec).unwrap() - ); - } - - #[test] - pub fn test_decoding() { - let bytes = vec![ - 0, 0, // unit - 1, 1, // bool - 2, 1, // i8 - 3, 1, 0, // i16 - 4, 1, 0, 0, 0, // i32 - 5, 1, 0, 0, 0, 0, 0, 0, 0, // i64 - 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // i128 - 7, 1, // u8 - 8, 1, 0, // u16 - 9, 1, 0, 0, 0, // u32 - 10, 1, 0, 0, 0, 0, 0, 0, 0, // u64 - 11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // u128 - 12, 5, 104, 101, 108, 108, 111, // string - 32, 9, 3, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, // array - 33, 2, 9, 1, 0, 0, 0, 9, 2, 0, 0, 0, // tuple - 32, 9, 3, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, // vec - 32, 7, 2, 1, 2, // set - 32, 33, 2, 2, 7, 1, 7, 2, 2, 7, 3, 7, 4, // map - 17, 4, 83, 111, 109, 101, 1, 9, 1, 0, 0, 0, // Some - 17, 4, 78, 111, 110, 101, 0, // None - 17, 2, 79, 107, 1, 9, 1, 0, 0, 0, // Ok - 17, 3, 69, 114, 114, 1, 12, 5, 104, 101, 108, 108, 111, // Err - ]; - let mut dec = Decoder::::new(&bytes); - assert_decoding(&mut dec); - } - - #[test] - pub fn test_decode_box() { - let bytes = vec![7u8, 5u8]; - let mut dec = Decoder::::new(&bytes); - let x = >::decode(&mut dec).unwrap(); - assert_eq!(Box::new(5u8), x); - } - - #[test] - pub fn test_decode_rc() { - let bytes = vec![7u8, 5u8]; - let mut dec = Decoder::::new(&bytes); - let x = >::decode(&mut dec).unwrap(); - assert_eq!(Rc::new(5u8), x); - } - - #[test] - pub fn test_decode_ref_cell() { - let bytes = vec![7u8, 5u8]; - let mut dec = Decoder::::new(&bytes); - let x = >::decode(&mut dec).unwrap(); - assert_eq!(RefCell::new(5u8), x); - } - - #[derive(sbor::TypeId, sbor::Encode, sbor::Decode, PartialEq, Eq, Debug)] - struct NFA { - a: [u8; 32], - b: Vec, - } - - #[test] - pub fn test_generic_array() { - let value1 = [ - NFA { - a: [1u8; 32], - b: vec![1], - }, - NFA { - a: [2u8; 32], - b: vec![2], - }, - ]; - - // Encode - let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::::new(&mut bytes); - value1.encode(&mut enc); - - let mut dec = Decoder::::new(&bytes); - let value2 = <[NFA; 2]>::decode(&mut dec).unwrap(); - assert_eq!(value1, value2); - } -} diff --git a/sbor/src/decoder.rs b/sbor/src/decoder.rs new file mode 100644 index 00000000000..6d2b9ba7018 --- /dev/null +++ b/sbor/src/decoder.rs @@ -0,0 +1,409 @@ +use crate::rust::marker::PhantomData; +use crate::rust::string::String; +use crate::type_id::*; +use crate::*; + +/// Represents an error ocurred during decoding. +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeId)] +pub enum DecodeError { + ExtraTrailingBytes(usize), + + BufferUnderflow { required: usize, remaining: usize }, + + UnexpectedTypeId { expected: u8, actual: u8 }, + + UnexpectedCustomTypeId { actual: u8 }, + + UnexpectedSize { expected: usize, actual: usize }, + + UnknownTypeId(u8), + + UnknownDiscriminator(String), + + InvalidUnit(u8), + + InvalidBool(u8), + + InvalidUtf8, + + SizeTooLarge, + + MaxDepthExceeded(u8), + + InvalidCustomValue, // TODO: generify custom error codes +} + +pub trait Decoder: Sized { + /// Consumes the Decoder and decodes the value as a full payload + #[inline] + fn decode_payload>(mut self) -> Result { + let value = self.decode()?; + self.check_end()?; + Ok(value) + } + + /// Decodes the value as part of a larger payload + /// + /// This method decodes the value's SBOR type id, and then its SBOR body. + fn decode>(&mut self) -> Result { + let type_id = self.read_type_id()?; + self.decode_deeper_body_with_type_id(type_id) + } + + /// Decodes the SBOR body of a child value as part of a larger payload. + /// + /// In many cases, you may wish to directly call `T::decode_body_with_type_id` instead of this method. + /// See the below section for details. + /// + /// ## Direct calls and SBOR Depth + /// + /// In order to avoid SBOR depth differentials and disagreement about whether a payload + /// is valid, typed codec implementations should ensure that the SBOR depth as measured + /// during the encoding/decoding process agrees with the SborValue codec. + /// + /// Each layer of the SborValue counts as one depth. + /// + /// If the decoder you're writing is embedding a child type (and is represented as such + /// in the SborValue type), then you should call `decoder.decode_body_with_type_id` to increment + /// the SBOR depth tracker. + /// + /// You should call `T::decode_body_with_type_id` directly when the decoding of that type + /// into an SborValue doesn't increase the SBOR depth in the decoder, that is: + /// * When the wrapping type is invisible to the SborValue, ie: + /// * Smart pointers + /// * Transparent wrappers + /// * Where the use of the inner type is invisible to SborValue, ie: + /// * Where the use of `T::decode_body_with_type_id` is coincidental / code re-use + fn decode_deeper_body_with_type_id>( + &mut self, + type_id: SborTypeId, + ) -> Result; + + #[inline] + fn read_type_id(&mut self) -> Result, DecodeError> { + let id = self.read_byte()?; + SborTypeId::from_u8(id).ok_or(DecodeError::UnknownTypeId(id)) + } + + fn read_discriminator(&mut self) -> Result { + let n = self.read_size()?; + let slice = self.read_slice(n)?; + String::from_utf8(slice.to_vec()).map_err(|_| DecodeError::InvalidUtf8) + } + + fn read_size(&mut self) -> Result { + // LEB128 and 4 bytes max + let mut size = 0usize; + let mut shift = 0; + loop { + let byte = self.read_byte()?; + size |= ((byte & 0x7F) as usize) << shift; + if byte < 0x80 { + break; + } + shift += 7; + if shift >= 28 { + return Err(DecodeError::SizeTooLarge); + } + } + Ok(size) + } + + #[inline] + fn check_preloaded_type_id( + &self, + type_id: SborTypeId, + expected: SborTypeId, + ) -> Result, DecodeError> { + if type_id == expected { + Ok(type_id) + } else { + Err(DecodeError::UnexpectedTypeId { + actual: type_id.as_u8(), + expected: expected.as_u8(), + }) + } + } + + #[inline] + fn read_and_check_type_id( + &mut self, + expected: SborTypeId, + ) -> Result, DecodeError> { + let type_id = self.read_type_id()?; + self.check_preloaded_type_id(type_id, expected) + } + + #[inline] + fn read_and_check_size(&mut self, expected: usize) -> Result<(), DecodeError> { + let len = self.read_size()?; + if len != expected { + return Err(DecodeError::UnexpectedSize { + expected, + actual: len, + }); + } + + Ok(()) + } + + fn check_end(&self) -> Result<(), DecodeError>; + + fn read_byte(&mut self) -> Result; + + fn read_slice(&mut self, n: usize) -> Result<&[u8], DecodeError>; +} + +/// A `Decoder` abstracts the logic for decoding basic types. +pub struct VecDecoder<'de, X: CustomTypeId, const MAX_DEPTH: u8> { + input: &'de [u8], + offset: usize, + stack_depth: u8, + phantom: PhantomData, +} + +impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> VecDecoder<'de, X, MAX_DEPTH> { + pub fn new(input: &'de [u8]) -> Self { + Self { + input, + offset: 0, + stack_depth: 0, + phantom: PhantomData, + } + } + + #[inline] + fn require_remaining(&self, n: usize) -> Result<(), DecodeError> { + if self.remaining_bytes() < n { + Err(DecodeError::BufferUnderflow { + required: n, + remaining: self.remaining_bytes(), + }) + } else { + Ok(()) + } + } + + #[inline] + fn remaining_bytes(&self) -> usize { + self.input.len() - self.offset + } + + #[inline] + fn track_stack_depth_increase(&mut self) -> Result<(), DecodeError> { + self.stack_depth += 1; + if self.stack_depth > MAX_DEPTH { + return Err(DecodeError::MaxDepthExceeded(MAX_DEPTH)); + } + Ok(()) + } + + #[inline] + fn track_stack_depth_decrease(&mut self) -> Result<(), DecodeError> { + self.stack_depth -= 1; + Ok(()) + } +} + +impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> Decoder for VecDecoder<'de, X, MAX_DEPTH> { + fn decode_deeper_body_with_type_id>( + &mut self, + type_id: SborTypeId, + ) -> Result { + self.track_stack_depth_increase()?; + let decoded = T::decode_body_with_type_id(self, type_id)?; + self.track_stack_depth_decrease()?; + Ok(decoded) + } + + #[inline] + fn read_byte(&mut self) -> Result { + self.require_remaining(1)?; + let result = self.input[self.offset]; + self.offset += 1; + Ok(result) + } + + #[inline] + fn read_slice(&mut self, n: usize) -> Result<&'de [u8], DecodeError> { + self.require_remaining(n)?; + let slice = &self.input[self.offset..self.offset + n]; + self.offset += n; + Ok(slice) + } + + #[inline] + fn check_end(&self) -> Result<(), DecodeError> { + let n = self.remaining_bytes(); + if n != 0 { + Err(DecodeError::ExtraTrailingBytes(n)) + } else { + Ok(()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::rust::borrow::ToOwned; + use crate::rust::boxed::Box; + use crate::rust::cell::RefCell; + use crate::rust::collections::*; + use crate::rust::rc::Rc; + use crate::rust::string::String; + use crate::rust::vec; + use crate::rust::vec::Vec; + + fn encode_decode_size(size: usize) -> Result<(), DecodeError> { + // Encode + let mut bytes = Vec::with_capacity(512); + let mut enc = BasicEncoder::new(&mut bytes); + enc.write_size(size).unwrap(); + + let mut dec = BasicDecoder::new(&bytes); + dec.read_and_check_size(size)?; + dec.check_end()?; + Ok(()) + } + + #[test] + pub fn test_vlq() { + encode_decode_size(0x00000000).unwrap(); + encode_decode_size(0x0000007F).unwrap(); + encode_decode_size(0x00000080).unwrap(); + encode_decode_size(0x00002000).unwrap(); + encode_decode_size(0x00003FFF).unwrap(); + encode_decode_size(0x00004000).unwrap(); + encode_decode_size(0x001FFFFF).unwrap(); + encode_decode_size(0x00200000).unwrap(); + encode_decode_size(0x08000000).unwrap(); + encode_decode_size(0x0FFFFFFF).unwrap(); + } + + #[test] + pub fn test_vlq_too_large() { + let mut dec = BasicDecoder::new(&[0xff, 0xff, 0xff, 0xff, 0x00]); + assert_eq!(dec.read_size(), Err(DecodeError::SizeTooLarge)); + } + + fn assert_decoding(dec: &mut BasicDecoder) { + dec.decode::<()>().unwrap(); + assert_eq!(true, dec.decode::().unwrap()); + assert_eq!(1, dec.decode::().unwrap()); + assert_eq!(1, dec.decode::().unwrap()); + assert_eq!(1, dec.decode::().unwrap()); + assert_eq!(1, dec.decode::().unwrap()); + assert_eq!(1, dec.decode::().unwrap()); + assert_eq!(1, dec.decode::().unwrap()); + assert_eq!(1, dec.decode::().unwrap()); + assert_eq!(1, dec.decode::().unwrap()); + assert_eq!(1, dec.decode::().unwrap()); + assert_eq!(1, dec.decode::().unwrap()); + assert_eq!("hello", dec.decode::().unwrap()); + + assert_eq!([1u32, 2u32, 3u32], dec.decode::<[u32; 3]>().unwrap()); + assert_eq!((1u32, 2u32), dec.decode::<(u32, u32)>().unwrap()); + + assert_eq!(vec![1u32, 2u32, 3u32], dec.decode::>().unwrap()); + let mut set = BTreeSet::::new(); + set.insert(1); + set.insert(2); + assert_eq!(set, dec.decode::>().unwrap()); + let mut map = BTreeMap::::new(); + map.insert(1, 2); + map.insert(3, 4); + assert_eq!(map, dec.decode::>().unwrap()); + + assert_eq!(Some(1u32), dec.decode::>().unwrap()); + assert_eq!(None, dec.decode::>().unwrap()); + assert_eq!(Ok(1u32), dec.decode::>().unwrap()); + assert_eq!( + Err("hello".to_owned()), + dec.decode::>().unwrap() + ); + } + + #[test] + pub fn test_decoding() { + let bytes = vec![ + 0, 0, // unit + 1, 1, // bool + 2, 1, // i8 + 3, 1, 0, // i16 + 4, 1, 0, 0, 0, // i32 + 5, 1, 0, 0, 0, 0, 0, 0, 0, // i64 + 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // i128 + 7, 1, // u8 + 8, 1, 0, // u16 + 9, 1, 0, 0, 0, // u32 + 10, 1, 0, 0, 0, 0, 0, 0, 0, // u64 + 11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // u128 + 12, 5, 104, 101, 108, 108, 111, // string + 32, 9, 3, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, // array + 33, 2, 9, 1, 0, 0, 0, 9, 2, 0, 0, 0, // tuple + 32, 9, 3, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, // vec + 32, 7, 2, 1, 2, // set + 32, 33, 2, 2, 7, 1, 7, 2, 2, 7, 3, 7, 4, // map + 17, 4, 83, 111, 109, 101, 1, 9, 1, 0, 0, 0, // Some + 17, 4, 78, 111, 110, 101, 0, // None + 17, 2, 79, 107, 1, 9, 1, 0, 0, 0, // Ok + 17, 3, 69, 114, 114, 1, 12, 5, 104, 101, 108, 108, 111, // Err + ]; + let mut dec = BasicDecoder::new(&bytes); + assert_decoding(&mut dec); + } + + #[test] + pub fn test_decode_box() { + let bytes = vec![7u8, 5u8]; + let mut dec = BasicDecoder::new(&bytes); + let x = dec.decode::>().unwrap(); + assert_eq!(Box::new(5u8), x); + } + + #[test] + pub fn test_decode_rc() { + let bytes = vec![7u8, 5u8]; + let mut dec = BasicDecoder::new(&bytes); + let x = dec.decode::>().unwrap(); + assert_eq!(Rc::new(5u8), x); + } + + #[test] + pub fn test_decode_ref_cell() { + let bytes = vec![7u8, 5u8]; + let mut dec = BasicDecoder::new(&bytes); + let x = dec.decode::>().unwrap(); + assert_eq!(RefCell::new(5u8), x); + } + + #[derive(sbor::TypeId, sbor::Encode, sbor::Decode, PartialEq, Eq, Debug)] + struct NFA { + a: [u8; 32], + b: Vec, + } + + #[test] + pub fn test_generic_array() { + let value1 = [ + NFA { + a: [1u8; 32], + b: vec![1], + }, + NFA { + a: [2u8; 32], + b: vec![2], + }, + ]; + + // Encode + let mut bytes = Vec::with_capacity(512); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&value1).unwrap(); + + let mut decoder = BasicDecoder::new(&bytes); + let value2 = decoder.decode::<[NFA; 2]>().unwrap(); + assert_eq!(value1, value2); + } +} diff --git a/sbor/src/encode.rs b/sbor/src/encode.rs index 7d39b5e5001..12e2a0979ba 100644 --- a/sbor/src/encode.rs +++ b/sbor/src/encode.rs @@ -1,170 +1,34 @@ -use crate::rust::marker::PhantomData; -use crate::rust::vec::Vec; +use crate::encoder::*; use crate::type_id::*; /// A data structure that can be serialized into a byte array using SBOR. -pub trait Encode { - /// Encodes this object into the byte buffer encapsulated by the given encoder. - fn encode(&self, encoder: &mut Encoder) { - self.encode_type_id(encoder); - self.encode_body(encoder); - } - - fn encode_type_id(&self, encoder: &mut Encoder); - - fn encode_body(&self, encoder: &mut Encoder); -} - -/// An `Encoder` abstracts the logic for writing core types into a byte buffer. -pub struct Encoder<'a, X: CustomTypeId> { - buf: &'a mut Vec, - phantom: PhantomData, -} - -impl<'a, X: CustomTypeId> Encoder<'a, X> { - pub fn new(buf: &'a mut Vec) -> Self { - Self { - buf, - phantom: PhantomData, - } - } - - pub fn write_type_id(&mut self, ty: SborTypeId) { - self.buf.push(ty.as_u8()); - } - - pub fn write_discriminator(&mut self, discriminator: &str) { - self.write_size(discriminator.len()); - self.write_slice(discriminator.as_bytes()); - } - - pub fn write_size(&mut self, mut size: usize) { - // LEB128 and 4 bytes max - assert!(size <= 0x0FFFFFFF); // 268,435,455 - loop { - let seven_bits = size & 0x7F; - size = size >> 7; - if size == 0 { - self.write_byte(seven_bits as u8); - break; - } else { - self.write_byte(seven_bits as u8 | 0x80); - } - } - } - - pub fn write_byte(&mut self, n: u8) { - self.buf.push(n); - } - - pub fn write_slice(&mut self, slice: &[u8]) { - self.buf.extend(slice); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::rust::borrow::ToOwned; - use crate::rust::boxed::Box; - use crate::rust::collections::*; - use crate::rust::string::String; - use crate::rust::vec; - use crate::NoCustomTypeId; - - fn do_encoding(enc: &mut Encoder) { - ().encode(enc); - true.encode(enc); - 1i8.encode(enc); - 1i16.encode(enc); - 1i32.encode(enc); - 1i64.encode(enc); - 1i128.encode(enc); - 1u8.encode(enc); - 1u16.encode(enc); - 1u32.encode(enc); - 1u64.encode(enc); - 1u128.encode(enc); - "hello".encode(enc); - - [1u32, 2u32, 3u32].encode(enc); - (1u32, 2u32).encode(enc); - - vec![1u32, 2u32, 3u32].encode(enc); - let mut set = BTreeSet::::new(); - set.insert(1); - set.insert(2); - set.encode(enc); - let mut map = BTreeMap::::new(); - map.insert(1, 2); - map.insert(3, 4); - map.encode(enc); - - Some(1u32).encode(enc); - Option::::None.encode(enc); - Result::::Ok(1u32).encode(enc); - Result::::Err("hello".to_owned()).encode(enc); - } - - #[test] - pub fn test_encoding() { - let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::::new(&mut bytes); - do_encoding(&mut enc); - - assert_eq!( - vec![ - 0, 0, // unit - 1, 1, // bool - 2, 1, // i8 - 3, 1, 0, // i16 - 4, 1, 0, 0, 0, // i32 - 5, 1, 0, 0, 0, 0, 0, 0, 0, // i64 - 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // i128 - 7, 1, // u8 - 8, 1, 0, // u16 - 9, 1, 0, 0, 0, // u32 - 10, 1, 0, 0, 0, 0, 0, 0, 0, // u64 - 11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // u128 - 12, 5, 104, 101, 108, 108, 111, // string - 32, 9, 3, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, // array - 33, 2, 9, 1, 0, 0, 0, 9, 2, 0, 0, 0, // tuple - 32, 9, 3, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, // vec - 32, 7, 2, 1, 2, // set - 32, 33, 2, 2, 7, 1, 7, 2, 2, 7, 3, 7, 4, // map - 17, 4, 83, 111, 109, 101, 1, 9, 1, 0, 0, 0, // Some - 17, 4, 78, 111, 110, 101, 0, // None - 17, 2, 79, 107, 1, 9, 1, 0, 0, 0, // Ok - 17, 3, 69, 114, 114, 1, 12, 5, 104, 101, 108, 108, 111, // Err - ], - bytes - ); - } - - #[test] - pub fn test_encode_box() { - let x = Box::new(5u8); - let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::::new(&mut bytes); - x.encode(&mut enc); - assert_eq!(bytes, vec![7, 5]) - } - - #[test] - pub fn test_encode_rc() { - let x = crate::rust::rc::Rc::new(5u8); - let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::::new(&mut bytes); - x.encode(&mut enc); - assert_eq!(bytes, vec![7, 5]) - } - - #[test] - pub fn test_encode_ref_cell() { - let x = crate::rust::cell::RefCell::new(5u8); - let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::::new(&mut bytes); - x.encode(&mut enc); - assert_eq!(bytes, vec![7, 5]) - } +pub trait Encode> { + /// Encodes the SBOR type id of the type to the encoder + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError>; + + /// Encodes the SBOR body of the type to the encoder. + /// + /// You may want to call `encoder.encode_deeper_body` instead of this method. See + /// the below section for details. + /// + /// ## Direct calls and SBOR Depth + /// + /// In order to avoid SBOR depth differentials and disagreement about whether a payload + /// is valid, typed codec implementations should ensure that the SBOR depth as measured + /// during the encoding/decoding process agrees with the SborValue codec. + /// + /// Each layer of the SborValue counts as one depth. + /// + /// If the encoder you're writing is embedding a child type (and is represented as such + /// in the SborValue type), then you should call `encoder.encode_body` to increment + /// the SBOR depth tracker. + /// + /// You should only call `value.encode_body` directly when the encoding of that type + /// into an SborValue doesn't increase the SBOR depth in the encoder, that is: + /// * When the wrapping type is invisible to the SborValue, ie: + /// * Smart pointers + /// * Transparent wrappers + /// * Where the use of the inner type is invisible to SborValue, ie: + /// * Where the use of `value.encode_body` is coincidental / code re-use + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError>; } diff --git a/sbor/src/encoder.rs b/sbor/src/encoder.rs new file mode 100644 index 00000000000..25e42d86c0d --- /dev/null +++ b/sbor/src/encoder.rs @@ -0,0 +1,292 @@ +use crate::rust::marker::PhantomData; +use crate::rust::vec::Vec; +use crate::*; + +/// Represents an error occurred during encoding. +#[derive(Debug, Clone, PartialEq, Eq, TypeId, Encode, Decode)] +pub enum EncodeError { + MaxDepthExceeded(u8), + SizeTooLarge { actual: usize, max_allowed: usize }, +} + +pub trait Encoder: Sized { + /// Consumes the Encoder and encodes the value as a full payload + #[inline] + fn encode_payload + ?Sized>(mut self, value: &T) -> Result<(), EncodeError> { + self.encode(value) + } + + /// Encodes the value as part of a larger payload + /// + /// This method encodes the value's SBOR type id, and then its SBOR body. + fn encode + ?Sized>(&mut self, value: &T) -> Result<(), EncodeError> { + value.encode_type_id(self)?; + self.encode_deeper_body(value) + } + + /// Encodes the SBOR body of a child value as part of a larger payload. + /// + /// In many cases, you may wish to directly call `value.encode_body` instead of this method. See + /// the below section for details. + /// + /// ## Direct calls and SBOR Depth + /// + /// In order to avoid SBOR depth differentials and disagreement about whether a payload + /// is valid, typed codec implementations should ensure that the SBOR depth as measured + /// during the encoding/decoding process agrees with the SborValue codec. + /// + /// Each layer of the SborValue counts as one depth. + /// + /// If the encoder you're writing is embedding a child type (and is represented as such + /// in the SborValue type), then you should call `encoder.encode_body` to increment + /// the SBOR depth tracker. + /// + /// You should call `value.encode_body` directly when the encoding of that type + /// into an SborValue doesn't increase the SBOR depth in the encoder, that is: + /// * When the wrapping type is invisible to the SborValue, ie: + /// * Smart pointers + /// * Transparent wrappers + /// * Where the use of the inner type is invisible to SborValue, ie: + /// * Where the use of `value.encode_body` is coincidental / code re-use + fn encode_deeper_body + ?Sized>( + &mut self, + value: &T, + ) -> Result<(), EncodeError>; + + #[inline] + fn write_type_id(&mut self, ty: SborTypeId) -> Result<(), EncodeError> { + self.write_byte(ty.as_u8()) + } + + fn write_discriminator(&mut self, discriminator: &str) -> Result<(), EncodeError> { + self.write_size(discriminator.len())?; + self.write_slice(discriminator.as_bytes()) + } + + fn write_size(&mut self, mut size: usize) -> Result<(), EncodeError> { + // LEB128 and 4 bytes max + // This means the max size is 0x0FFFFFFF = 268,435,455 + if size > 0x0FFFFFFF { + return Err(EncodeError::SizeTooLarge { + actual: size, + max_allowed: 0x0FFFFFFF, + }); + } + loop { + let seven_bits = size & 0x7F; + size = size >> 7; + if size == 0 { + self.write_byte(seven_bits as u8)?; + break; + } else { + self.write_byte(seven_bits as u8 | 0x80)?; + } + } + Ok(()) + } + + fn write_byte(&mut self, n: u8) -> Result<(), EncodeError>; + + fn write_slice(&mut self, slice: &[u8]) -> Result<(), EncodeError>; +} + +/// An `Encoder` abstracts the logic for writing core types into a byte buffer. +pub struct VecEncoder<'a, X: CustomTypeId, const MAX_DEPTH: u8> { + buf: &'a mut Vec, + stack_depth: u8, + phantom: PhantomData, +} + +impl<'a, X: CustomTypeId, const MAX_DEPTH: u8> VecEncoder<'a, X, MAX_DEPTH> { + pub fn new(buf: &'a mut Vec) -> Self { + Self { + buf, + stack_depth: 0, + phantom: PhantomData, + } + } + + #[inline] + fn track_stack_depth_increase(&mut self) -> Result<(), EncodeError> { + self.stack_depth += 1; + if self.stack_depth > MAX_DEPTH { + return Err(EncodeError::MaxDepthExceeded(MAX_DEPTH)); + } + Ok(()) + } + + #[inline] + fn track_stack_depth_decrease(&mut self) -> Result<(), EncodeError> { + self.stack_depth -= 1; + Ok(()) + } +} + +impl<'a, X: CustomTypeId, const MAX_DEPTH: u8> Encoder for VecEncoder<'a, X, MAX_DEPTH> { + fn encode_deeper_body + ?Sized>( + &mut self, + value: &T, + ) -> Result<(), EncodeError> { + self.track_stack_depth_increase()?; + value.encode_body(self)?; + self.track_stack_depth_decrease() + } + + #[inline] + fn write_byte(&mut self, n: u8) -> Result<(), EncodeError> { + self.buf.push(n); + Ok(()) + } + + #[inline] + fn write_slice(&mut self, slice: &[u8]) -> Result<(), EncodeError> { + self.buf.extend(slice); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::rust::borrow::ToOwned; + use crate::rust::boxed::Box; + use crate::rust::collections::*; + use crate::rust::string::String; + use crate::rust::vec; + use crate::BasicEncoder; + + fn do_encoding(encoder: &mut BasicEncoder) -> Result<(), EncodeError> { + encoder.encode(&())?; + encoder.encode(&true)?; + encoder.encode(&1i8)?; + encoder.encode(&1i16)?; + encoder.encode(&1i32)?; + encoder.encode(&1i64)?; + encoder.encode(&1i128)?; + encoder.encode(&1u8)?; + encoder.encode(&1u16)?; + encoder.encode(&1u32)?; + encoder.encode(&1u64)?; + encoder.encode(&1u128)?; + encoder.encode("hello")?; + + encoder.encode(&[1u32, 2u32, 3u32])?; + encoder.encode(&(1u32, 2u32))?; + + encoder.encode(&vec![1u32, 2u32, 3u32])?; + let mut set = BTreeSet::::new(); + set.insert(1); + set.insert(2); + encoder.encode(&set)?; + let mut map = BTreeMap::::new(); + map.insert(1, 2); + map.insert(3, 4); + encoder.encode(&map)?; + + encoder.encode(&Some(1u32))?; + encoder.encode(&Option::::None)?; + encoder.encode(&Result::::Ok(1u32))?; + encoder.encode(&Result::::Err("hello".to_owned()))?; + + Ok(()) + } + + #[test] + pub fn test_encoding() { + let mut bytes = Vec::with_capacity(512); + let mut enc = BasicEncoder::new(&mut bytes); + do_encoding(&mut enc).unwrap(); + + assert_eq!( + vec![ + 0, 0, // unit + 1, 1, // bool + 2, 1, // i8 + 3, 1, 0, // i16 + 4, 1, 0, 0, 0, // i32 + 5, 1, 0, 0, 0, 0, 0, 0, 0, // i64 + 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // i128 + 7, 1, // u8 + 8, 1, 0, // u16 + 9, 1, 0, 0, 0, // u32 + 10, 1, 0, 0, 0, 0, 0, 0, 0, // u64 + 11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // u128 + 12, 5, 104, 101, 108, 108, 111, // string + 32, 9, 3, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, // array + 33, 2, 9, 1, 0, 0, 0, 9, 2, 0, 0, 0, // tuple + 32, 9, 3, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, // vec + 32, 7, 2, 1, 2, // set + 32, 33, 2, 2, 7, 1, 7, 2, 2, 7, 3, 7, 4, // map + 17, 4, 83, 111, 109, 101, 1, 9, 1, 0, 0, 0, // Some + 17, 4, 78, 111, 110, 101, 0, // None + 17, 2, 79, 107, 1, 9, 1, 0, 0, 0, // Ok + 17, 3, 69, 114, 114, 1, 12, 5, 104, 101, 108, 108, 111, // Err + ], + bytes + ); + } + + #[test] + pub fn test_size_too_large_error() { + const MAX_SIZE: usize = 0x0FFFFFFF; // 268,435,455, so this many bytes is about 268MB + const TOO_LARGE_SIZE: usize = MAX_SIZE + 1; + + assert!(basic_encode(&vec![0u8; MAX_SIZE]).is_ok()); + assert!(matches!( + basic_encode(&vec![0u8; MAX_SIZE + 1]), + Err(EncodeError::SizeTooLarge { + actual: TOO_LARGE_SIZE, + max_allowed: MAX_SIZE + }) + )); + } + + #[test] + pub fn test_encode_cow_borrowed() { + let mut set = BTreeSet::::new(); + set.insert(1); + set.insert(2); + let x = crate::rust::borrow::Cow::Borrowed(&set); + let mut bytes = Vec::with_capacity(512); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&x).unwrap(); + assert_eq!(bytes, vec![32, 7, 2, 1, 2]) // Same as set above + } + + #[test] + pub fn test_encode_cow_owned() { + use crate::rust::borrow::Cow; + let x: Cow = Cow::Owned(5u8); + let mut bytes = Vec::with_capacity(512); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&x).unwrap(); + assert_eq!(bytes, vec![7, 5]) + } + + #[test] + pub fn test_encode_box() { + let x = Box::new(5u8); + let mut bytes = Vec::with_capacity(512); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&x).unwrap(); + assert_eq!(bytes, vec![7, 5]) + } + + #[test] + pub fn test_encode_rc() { + let x = crate::rust::rc::Rc::new(5u8); + let mut bytes = Vec::with_capacity(512); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&x).unwrap(); + assert_eq!(bytes, vec![7, 5]) + } + + #[test] + pub fn test_encode_ref_cell() { + let x = crate::rust::cell::RefCell::new(5u8); + let mut bytes = Vec::with_capacity(512); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&x).unwrap(); + assert_eq!(bytes, vec![7, 5]) + } +} diff --git a/sbor/src/lib.rs b/sbor/src/lib.rs index 8d40a9d1aa1..ad90b96cc59 100644 --- a/sbor/src/lib.rs +++ b/sbor/src/lib.rs @@ -11,10 +11,14 @@ pub mod basic; pub mod codec; /// SBOR constants pub mod constants; -/// SBOR decoding. +/// SBOR decode trait. pub mod decode; -/// SBOR encoding. +/// SBOR decoding. +pub mod decoder; +/// SBOR encode trait. pub mod encode; +/// SBOR encoding. +pub mod encoder; /// SBOR paths. pub mod path; /// A facade of Rust types. @@ -26,28 +30,14 @@ pub mod value; pub use basic::*; pub use constants::*; -pub use decode::{Decode, DecodeError, Decoder}; -pub use encode::{Encode, Encoder}; +pub use decode::Decode; +pub use decoder::{DecodeError, Decoder, VecDecoder}; +pub use encode::Encode; +pub use encoder::{EncodeError, Encoder, VecEncoder}; pub use path::{SborPath, SborPathBuf}; pub use type_id::*; pub use value::*; -/// Encode a `T` into byte array. -pub fn encode + ?Sized>(v: &T) -> crate::rust::vec::Vec { - let mut buf = crate::rust::vec::Vec::with_capacity(512); - let mut enc = Encoder::new(&mut buf); - v.encode(&mut enc); - buf -} - -/// Decode an instance of `T` from a slice. -pub fn decode>(buf: &[u8]) -> Result { - let mut dec = Decoder::new(buf); - let v = T::decode(&mut dec)?; - dec.check_end()?; - Ok(v) -} - // Re-export derives extern crate sbor_derive; pub use sbor_derive::{Decode, Encode, TypeId}; diff --git a/sbor/src/path.rs b/sbor/src/path.rs index ac25aae307a..af9f60b0436 100644 --- a/sbor/src/path.rs +++ b/sbor/src/path.rs @@ -1,7 +1,7 @@ use crate::rust::vec; use crate::rust::vec::Vec; use crate::value::SborValue; -use crate::{CustomTypeId, CustomValue}; +use crate::CustomTypeId; #[derive(Eq, PartialEq, Clone)] pub struct SborPathBuf(Vec); @@ -35,7 +35,7 @@ impl SborPath { SborPath(path) } - pub fn get_from_value<'a, X: CustomTypeId, Y: CustomValue>( + pub fn get_from_value<'a, X: CustomTypeId, Y>( &'a self, value: &'a SborValue, ) -> Option<&'a SborValue> { @@ -43,7 +43,7 @@ impl SborPath { rel_path.get_from(value) } - pub fn get_from_value_mut<'a, X: CustomTypeId, Y: CustomValue>( + pub fn get_from_value_mut<'a, X: CustomTypeId, Y>( &'a self, value: &'a mut SborValue, ) -> Option<&'a mut SborValue> { @@ -66,7 +66,7 @@ impl<'a> SborValueRetriever<'a> { (index, SborValueRetriever(extended_path)) } - fn get_from_vector>( + fn get_from_vector( &self, values: &'a [SborValue], ) -> Option<&'a SborValue> { @@ -76,7 +76,7 @@ impl<'a> SborValueRetriever<'a> { .and_then(|value| next_path.get_from(value)) } - fn get_from>( + fn get_from( self, value: &'a SborValue, ) -> Option<&'a SborValue> { @@ -93,7 +93,7 @@ impl<'a> SborValueRetriever<'a> { } } - fn get_from_vector_mut>( + fn get_from_vector_mut( &self, values: &'a mut [SborValue], ) -> Option<&'a mut SborValue> { @@ -103,7 +103,7 @@ impl<'a> SborValueRetriever<'a> { .and_then(|value| next_path.get_from_mut(value)) } - fn get_from_mut>( + fn get_from_mut( self, value: &'a mut SborValue, ) -> Option<&'a mut SborValue> { diff --git a/sbor/src/type_id.rs b/sbor/src/type_id.rs index 22f40a4b11d..e010794e0f0 100644 --- a/sbor/src/type_id.rs +++ b/sbor/src/type_id.rs @@ -246,6 +246,7 @@ macro_rules! type_id_tuple { }; } +type_id_tuple! { 1 0 A } type_id_tuple! { 2 0 A 1 B } type_id_tuple! { 3 0 A 1 B 2 C } type_id_tuple! { 4 0 A 1 B 2 C 3 D } diff --git a/sbor/src/value.rs b/sbor/src/value.rs index c0678aad658..0e90885ff35 100644 --- a/sbor/src/value.rs +++ b/sbor/src/value.rs @@ -1,26 +1,22 @@ use crate::decode::*; +use crate::decoder::*; use crate::encode::*; +use crate::encoder::*; use crate::path::SborPathBuf; use crate::rust::fmt::Debug; use crate::rust::string::String; use crate::rust::vec::Vec; use crate::type_id::*; -pub trait CustomValue: Debug + Clone + PartialEq + Eq { - fn encode_type_id(&self, encoder: &mut Encoder); - fn encode_body(&self, encoder: &mut Encoder); - fn decode_body_with_type_id(decoder: &mut Decoder, type_id: X) -> Result - where - Self: Sized; -} - +/// Y is the CustomValue type. This is likely an enum, capturing all the custom values for the +/// particular SBOR extension. #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "type") // See https://serde.rs/enum-representations.html )] #[derive(Debug, Clone, PartialEq, Eq)] -pub enum SborValue> { +pub enum SborValue { Unit, Bool { value: bool, @@ -73,267 +69,231 @@ pub enum SborValue> { Tuple { elements: Vec>, }, - Custom { value: Y, }, } -/// Encodes any SBOR value into byte array. -pub fn encode_any>(value: &SborValue) -> Vec { - let mut bytes = Vec::new(); - encode_any_with_buffer(value, &mut bytes); - bytes -} - -/// Encodes any SBOR value with a given buffer -pub fn encode_any_with_buffer>( - value: &SborValue, - buffer: &mut Vec, -) { - let mut encoder = ::sbor::Encoder::new(buffer); - encode_type_id(value, &mut encoder); - encode_body(value, &mut encoder); -} - -fn encode_type_id>( - value: &SborValue, - encoder: &mut Encoder, -) { - match value { - SborValue::Unit => encoder.write_type_id(SborTypeId::Unit), - SborValue::Bool { .. } => encoder.write_type_id(SborTypeId::Bool), - SborValue::I8 { .. } => encoder.write_type_id(SborTypeId::I8), - SborValue::I16 { .. } => encoder.write_type_id(SborTypeId::I16), - SborValue::I32 { .. } => encoder.write_type_id(SborTypeId::I32), - SborValue::I64 { .. } => encoder.write_type_id(SborTypeId::I64), - SborValue::I128 { .. } => encoder.write_type_id(SborTypeId::I128), - SborValue::U8 { .. } => encoder.write_type_id(SborTypeId::U8), - SborValue::U16 { .. } => encoder.write_type_id(SborTypeId::U16), - SborValue::U32 { .. } => encoder.write_type_id(SborTypeId::U32), - SborValue::U64 { .. } => encoder.write_type_id(SborTypeId::U64), - SborValue::U128 { .. } => encoder.write_type_id(SborTypeId::U128), - SborValue::String { .. } => encoder.write_type_id(SborTypeId::String), - SborValue::Struct { .. } => encoder.write_type_id(SborTypeId::Struct), - SborValue::Enum { .. } => encoder.write_type_id(SborTypeId::Enum), - SborValue::Array { .. } => encoder.write_type_id(SborTypeId::Array), - SborValue::Tuple { .. } => encoder.write_type_id(SborTypeId::Tuple), - SborValue::Custom { value } => value.encode_type_id(encoder), +impl, Y: Encode> Encode for SborValue { + #[inline] + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + match self { + SborValue::Unit => encoder.write_type_id(SborTypeId::Unit), + SborValue::Bool { .. } => encoder.write_type_id(SborTypeId::Bool), + SborValue::I8 { .. } => encoder.write_type_id(SborTypeId::I8), + SborValue::I16 { .. } => encoder.write_type_id(SborTypeId::I16), + SborValue::I32 { .. } => encoder.write_type_id(SborTypeId::I32), + SborValue::I64 { .. } => encoder.write_type_id(SborTypeId::I64), + SborValue::I128 { .. } => encoder.write_type_id(SborTypeId::I128), + SborValue::U8 { .. } => encoder.write_type_id(SborTypeId::U8), + SborValue::U16 { .. } => encoder.write_type_id(SborTypeId::U16), + SborValue::U32 { .. } => encoder.write_type_id(SborTypeId::U32), + SborValue::U64 { .. } => encoder.write_type_id(SborTypeId::U64), + SborValue::U128 { .. } => encoder.write_type_id(SborTypeId::U128), + SborValue::String { .. } => encoder.write_type_id(SborTypeId::String), + SborValue::Struct { .. } => encoder.write_type_id(SborTypeId::Struct), + SborValue::Enum { .. } => encoder.write_type_id(SborTypeId::Enum), + SborValue::Array { .. } => encoder.write_type_id(SborTypeId::Array), + SborValue::Tuple { .. } => encoder.write_type_id(SborTypeId::Tuple), + SborValue::Custom { value } => value.encode_type_id(encoder), + } } -} -fn encode_body>( - value: &SborValue, - encoder: &mut Encoder, -) { - match value { - SborValue::Unit => { - ().encode_body(encoder); - } - SborValue::Bool { value } => { - value.encode_body(encoder); - } - SborValue::I8 { value } => { - value.encode_body(encoder); - } - SborValue::I16 { value } => { - value.encode_body(encoder); - } - SborValue::I32 { value } => { - value.encode_body(encoder); - } - SborValue::I64 { value } => { - value.encode_body(encoder); - } - SborValue::I128 { value } => { - value.encode_body(encoder); - } - SborValue::U8 { value } => { - value.encode_body(encoder); - } - SborValue::U16 { value } => { - value.encode_body(encoder); - } - SborValue::U32 { value } => { - value.encode_body(encoder); - } - SborValue::U64 { value } => { - value.encode_body(encoder); - } - SborValue::U128 { value } => { - value.encode_body(encoder); - } - SborValue::String { value } => { - value.encode_body(encoder); - } - SborValue::Struct { fields } => { - encoder.write_size(fields.len()); - for field in fields { - encode_type_id(field, encoder); - encode_body(field, encoder); + #[inline] + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + match self { + SborValue::Unit => { + (()).encode_body(encoder)?; } - } - SborValue::Enum { - discriminator, - fields, - } => { - encoder.write_discriminator(discriminator); - encoder.write_size(fields.len()); - for field in fields { - encode_type_id(field, encoder); - encode_body(field, encoder); + SborValue::Bool { value } => { + value.encode_body(encoder)?; } - } - SborValue::Array { - element_type_id, - elements, - } => { - encoder.write_type_id(element_type_id.clone()); - encoder.write_size(elements.len()); - for e in elements { - encode_body(e, encoder); + SborValue::I8 { value } => { + value.encode_body(encoder)?; } - } - SborValue::Tuple { elements } => { - encoder.write_size(elements.len()); - for e in elements { - encode_type_id(e, encoder); - encode_body(e, encoder); + SborValue::I16 { value } => { + value.encode_body(encoder)?; } - } - // custom - SborValue::Custom { value } => { - value.encode_body(encoder); - } - } -} - -/// Decode any SBOR data. -pub fn decode_any>( - data: &[u8], -) -> Result, DecodeError> { - let mut decoder = Decoder::new(data); - let type_id = decoder.read_type_id()?; - let result = decode_body_with_type_id(type_id, &mut decoder); - decoder.check_end()?; - result -} - -fn decode_body_with_type_id>( - type_id: SborTypeId, - decoder: &mut Decoder, -) -> Result, DecodeError> { - match type_id { - // primitive types - SborTypeId::Unit => { - <()>::decode_body_with_type_id(decoder, type_id)?; - Ok(SborValue::Unit) - } - SborTypeId::Bool => Ok(SborValue::Bool { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::I8 => Ok(SborValue::I8 { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::I16 => Ok(SborValue::I16 { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::I32 => Ok(SborValue::I32 { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::I64 => Ok(SborValue::I64 { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::I128 => Ok(SborValue::I128 { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::U8 => Ok(SborValue::U8 { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::U16 => Ok(SborValue::U16 { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::U32 => Ok(SborValue::U32 { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::U64 => Ok(SborValue::U64 { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::U128 => Ok(SborValue::U128 { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - SborTypeId::String => Ok(SborValue::String { - value: ::decode_body_with_type_id(decoder, type_id)?, - }), - // struct & enum - SborTypeId::Struct => { - // number of fields - let len = decoder.read_size()?; - // fields - let mut fields = Vec::new(); - for _ in 0..len { - let type_id = decoder.read_type_id()?; - fields.push(decode_body_with_type_id(type_id, decoder)?); + SborValue::I32 { value } => { + value.encode_body(encoder)?; } - Ok(SborValue::Struct { fields }) - } - SborTypeId::Enum => { - // discriminator - let discriminator = ::decode_body_with_type_id(decoder, String::type_id())?; - // number of fields - let len = decoder.read_size()?; - // fields - let mut fields = Vec::new(); - for _ in 0..len { - let type_id = decoder.read_type_id()?; - fields.push(decode_body_with_type_id(type_id, decoder)?); + SborValue::I64 { value } => { + value.encode_body(encoder)?; + } + SborValue::I128 { value } => { + value.encode_body(encoder)?; } - Ok(SborValue::Enum { + SborValue::U8 { value } => { + value.encode_body(encoder)?; + } + SborValue::U16 { value } => { + value.encode_body(encoder)?; + } + SborValue::U32 { value } => { + value.encode_body(encoder)?; + } + SborValue::U64 { value } => { + value.encode_body(encoder)?; + } + SborValue::U128 { value } => { + value.encode_body(encoder)?; + } + SborValue::String { value } => { + value.encode_body(encoder)?; + } + SborValue::Struct { fields } => { + encoder.write_size(fields.len())?; + for field in fields { + encoder.encode(field)?; + } + } + SborValue::Enum { discriminator, fields, - }) - } - // composite types - SborTypeId::Array => { - // element type - let element_type_id = decoder.read_type_id()?; - // length - let len = decoder.read_size()?; - // values - let mut elements = Vec::new(); - for _ in 0..len { - elements.push(decode_body_with_type_id(element_type_id, decoder)?); + } => { + encoder.write_discriminator(discriminator)?; + encoder.write_size(fields.len())?; + for field in fields { + encoder.encode(field)?; + } } - Ok(SborValue::Array { + SborValue::Array { element_type_id, elements, - }) + } => { + encoder.write_type_id(*element_type_id)?; + encoder.write_size(elements.len())?; + for item in elements { + encoder.encode_deeper_body(item)?; + } + } + SborValue::Tuple { elements } => { + encoder.write_size(elements.len())?; + for field in elements { + encoder.encode(field)?; + } + } + // custom + SborValue::Custom { value } => { + value.encode_body(encoder)?; + } } - SborTypeId::Tuple => { - //length - let len = decoder.read_size()?; - // values - let mut elements = Vec::new(); - for _ in 0..len { - let type_id = decoder.read_type_id()?; - elements.push(decode_body_with_type_id(type_id, decoder)?); + Ok(()) + } +} + +impl, Y: Decode> Decode for SborValue { + #[inline] + fn decode_body_with_type_id( + decoder: &mut D, + type_id: SborTypeId, + ) -> Result { + match type_id { + // primitive types + SborTypeId::Unit => { + <()>::decode_body_with_type_id(decoder, type_id)?; + Ok(SborValue::Unit) + } + SborTypeId::Bool => Ok(SborValue::Bool { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::I8 => Ok(SborValue::I8 { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::I16 => Ok(SborValue::I16 { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::I32 => Ok(SborValue::I32 { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::I64 => Ok(SborValue::I64 { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::I128 => Ok(SborValue::I128 { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::U8 => Ok(SborValue::U8 { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::U16 => Ok(SborValue::U16 { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::U32 => Ok(SborValue::U32 { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::U64 => Ok(SborValue::U64 { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::U128 => Ok(SborValue::U128 { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + SborTypeId::String => Ok(SborValue::String { + value: ::decode_body_with_type_id(decoder, type_id)?, + }), + // struct & enum + SborTypeId::Struct => { + // number of fields + let len = decoder.read_size()?; + // fields + let mut fields = Vec::with_capacity(if len <= 1024 { len } else { 1024 }); + for _ in 0..len { + fields.push(decoder.decode()?); + } + Ok(SborValue::Struct { fields }) + } + SborTypeId::Enum => { + // discriminator + let discriminator = decoder.read_discriminator()?; + // number of fields + let len = decoder.read_size()?; + // fields + let mut fields = Vec::with_capacity(if len <= 1024 { len } else { 1024 }); + for _ in 0..len { + fields.push(decoder.decode()?); + } + Ok(SborValue::Enum { + discriminator, + fields, + }) } - Ok(SborValue::Tuple { elements }) + // composite types + SborTypeId::Array => { + // element type + let element_type_id = decoder.read_type_id()?; + // length + let len = decoder.read_size()?; + // values + let mut elements = Vec::with_capacity(if len <= 1024 { len } else { 1024 }); + for _ in 0..len { + elements.push(decoder.decode_deeper_body_with_type_id(element_type_id)?); + } + Ok(SborValue::Array { + element_type_id, + elements, + }) + } + SborTypeId::Tuple => { + //length + let len = decoder.read_size()?; + // values + let mut elements = Vec::with_capacity(if len <= 1024 { len } else { 1024 }); + for _ in 0..len { + elements.push(decoder.decode()?); + } + Ok(SborValue::Tuple { elements }) + } + SborTypeId::Custom(_) => Ok(SborValue::Custom { + value: Y::decode_body_with_type_id(decoder, type_id)?, + }), } - SborTypeId::Custom(type_id) => Ok(SborValue::Custom { - value: Y::decode_body_with_type_id(decoder, type_id)?, - }), } } -pub fn traverse_any, V, E>( +pub fn traverse_any, E>( path: &mut SborPathBuf, value: &SborValue, visitor: &mut V, -) -> Result<(), E> -where - V: CustomValueVisitor, -{ +) -> Result<(), E> { match value { // primitive types SborValue::Unit @@ -381,7 +341,7 @@ where Ok(()) } -pub trait CustomValueVisitor> { +pub trait CustomValueVisitor { type Err; fn visit(&mut self, path: &mut SborPathBuf, value: &Y) -> Result<(), Self::Err>; @@ -479,8 +439,8 @@ mod tests { y: map1, z: map2, }; - let bytes = encode::(&data); - let value = decode_any::(&bytes).unwrap(); + let bytes = basic_encode(&data).unwrap(); + let value = basic_decode(&bytes).unwrap(); assert_eq!( BasicSborValue::Struct { @@ -576,9 +536,87 @@ mod tests { ); let mut bytes2 = Vec::new(); - let mut enc = Encoder::new(&mut bytes2); - encode_type_id(&value, &mut enc); - encode_body(&value, &mut enc); + let mut encoder = BasicEncoder::new(&mut bytes2); + encoder.encode(&value).unwrap(); assert_eq!(bytes2, bytes); } + + #[test] + pub fn test_max_depth_array_decode_behaviour() { + let allowable_payload = encode_array_of_depth(DEFAULT_BASIC_MAX_DEPTH).unwrap(); + let allowable_result = basic_decode::(&allowable_payload); + assert!(allowable_result.is_ok()); + + let forbidden_payload = encode_array_of_depth(DEFAULT_BASIC_MAX_DEPTH + 1).unwrap(); + let forbidden_result = basic_decode::(&forbidden_payload); + assert!(forbidden_result.is_err()); + } + + #[test] + pub fn test_max_depth_struct_decode_behaviour() { + let allowable_payload = encode_struct_of_depth(DEFAULT_BASIC_MAX_DEPTH).unwrap(); + let allowable_result = basic_decode::(&allowable_payload); + assert!(allowable_result.is_ok()); + + let forbidden_payload = encode_struct_of_depth(DEFAULT_BASIC_MAX_DEPTH + 1).unwrap(); + let forbidden_result = basic_decode::(&forbidden_payload); + assert!(forbidden_result.is_err()); + } + + #[test] + pub fn test_max_depth_tuple_decode_behaviour() { + let allowable_payload = encode_tuple_of_depth(DEFAULT_BASIC_MAX_DEPTH).unwrap(); + let allowable_result = basic_decode::(&allowable_payload); + assert!(allowable_result.is_ok()); + + let forbidden_payload = encode_tuple_of_depth(DEFAULT_BASIC_MAX_DEPTH + 1).unwrap(); + let forbidden_result = basic_decode::(&forbidden_payload); + assert!(forbidden_result.is_err()); + } + + pub fn encode_array_of_depth(depth: u8) -> Result, EncodeError> { + let mut buf = Vec::new(); + let mut encoder = BasicEncoder::new(&mut buf); + encoder.write_type_id(SborTypeId::Array)?; + // Encodes depth - 1 array bodies + for _ in 1..depth { + encoder.write_type_id(SborTypeId::Array)?; // Child type + encoder.write_size(1)?; + } + // And finishes off encoding a single layer + encoder.write_type_id(SborTypeId::Array)?; // Child type + encoder.write_size(0)?; + + Ok(buf) + } + + pub fn encode_struct_of_depth(depth: u8) -> Result, EncodeError> { + let mut buf = Vec::new(); + let mut encoder = BasicEncoder::new(&mut buf); + // Encodes depth - 1 structs containing 1 child + for _ in 1..depth { + encoder.write_type_id(SborTypeId::Struct)?; + encoder.write_size(1)?; + } + // And finishes off encoding a single layer with 0 children + encoder.write_type_id(SborTypeId::Struct)?; + encoder.write_size(0)?; + + Ok(buf) + } + + pub fn encode_tuple_of_depth(depth: u8) -> Result, EncodeError> { + let mut buf = Vec::new(); + let mut encoder = BasicEncoder::new(&mut buf); + // Encodes depth - 1 structs containing 1 child + for _ in 1..depth { + encoder.write_type_id(SborTypeId::Tuple)?; + encoder.write_size(1)?; + } + // And finishes off encoding a single layer with 0 children + encoder.write_type_id(SborTypeId::Tuple)?; + encoder.write_size(0)?; + + Ok(buf) + } } diff --git a/scrypto-derive/src/blueprint.rs b/scrypto-derive/src/blueprint.rs index d43d70741a3..d63c2db1a12 100644 --- a/scrypto-derive/src/blueprint.rs +++ b/scrypto-derive/src/blueprint.rs @@ -103,7 +103,7 @@ pub fn handle_blueprint(input: TokenStream) -> Result { fns, }; - ::scrypto::buffer::scrypto_encode_to_buffer(&output) + ::scrypto::buffer::scrypto_encode_to_buffer(&output).unwrap() } } }; @@ -257,7 +257,7 @@ fn generate_dispatcher( let stmt: Stmt = parse_quote! { let rtn = ::scrypto::buffer::scrypto_encode_to_buffer( &#module_ident::#bp_ident::#ident(#(#dispatch_args),*) - ); + ).unwrap(); }; trace!("Generated stmt: {}", quote! { #stmt }); stmts.push(stmt); @@ -605,7 +605,7 @@ mod tests { ); let state: DataRef = component_data.get(); - let rtn = ::scrypto::buffer::scrypto_encode_to_buffer(&Test_impl::Test::x(state.deref(), input.arg0)); + let rtn = ::scrypto::buffer::scrypto_encode_to_buffer(&Test_impl::Test::x(state.deref(), input.arg0)).unwrap(); rtn } @@ -621,7 +621,7 @@ mod tests { ::scrypto::resource::init_resource_system(::scrypto::resource::ResourceSystem::new()); let input: Test_y_Input = ::scrypto::buffer::scrypto_decode_from_buffer(args).unwrap(); - let rtn = ::scrypto::buffer::scrypto_encode_to_buffer(&Test_impl::Test::y(input.arg0)); + let rtn = ::scrypto::buffer::scrypto_encode_to_buffer(&Test_impl::Test::y(input.arg0)).unwrap(); rtn } @@ -652,7 +652,7 @@ mod tests { structure, fns, }; - ::scrypto::buffer::scrypto_encode_to_buffer(&output) + ::scrypto::buffer::scrypto_encode_to_buffer(&output).unwrap() } #[allow(non_camel_case_types)] @@ -735,7 +735,7 @@ mod tests { structure, fns, }; - ::scrypto::buffer::scrypto_encode_to_buffer(&output) + ::scrypto::buffer::scrypto_encode_to_buffer(&output).unwrap() } #[allow(non_camel_case_types)] diff --git a/scrypto-derive/src/non_fungible_data.rs b/scrypto-derive/src/non_fungible_data.rs index c0f711d1fe6..b33286309a4 100644 --- a/scrypto-derive/src/non_fungible_data.rs +++ b/scrypto-derive/src/non_fungible_data.rs @@ -46,17 +46,18 @@ pub fn handle_non_fungible_data(input: TokenStream) -> Result { impl radix_engine_interface::model::NonFungibleData for #ident { fn decode(immutable_data: &[u8], mutable_data: &[u8]) -> Result { use ::sbor::{type_id::*, *}; - let mut decoder_nm = Decoder::new(immutable_data); - decoder_nm.read_and_check_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct)?; + use ::scrypto::data::*; + let mut decoder_nm = ScryptoDecoder::new(immutable_data); + decoder_nm.read_and_check_type_id(ScryptoSborTypeId::Struct)?; decoder_nm.read_and_check_size(#im_n)?; - let mut decoder_m = Decoder::new(mutable_data); - decoder_m.read_and_check_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct)?; + let mut decoder_m = ScryptoDecoder::new(mutable_data); + decoder_m.read_and_check_type_id(ScryptoSborTypeId::Struct)?; decoder_m.read_and_check_size(#m_n)?; let decoded = Self { - #(#im_ids: <#im_types>::decode(&mut decoder_nm)?,)* - #(#m_ids: <#m_types>::decode(&mut decoder_m)?,)* + #(#im_ids: decoder_nm.decode::<#im_types>()?,)* + #(#m_ids: decoder_m.decode::<#m_types>()?,)* }; decoder_nm.check_end()?; @@ -65,33 +66,35 @@ pub fn handle_non_fungible_data(input: TokenStream) -> Result { Ok(decoded) } - fn immutable_data(&self) -> ::sbor::rust::vec::Vec { + fn immutable_data(&self) -> Result<::sbor::rust::vec::Vec, ::sbor::EncodeError> { use ::sbor::{type_id::*, *}; + use ::scrypto::data::*; let mut bytes = Vec::with_capacity(512); - let mut encoder = Encoder::new(&mut bytes); - encoder.write_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct); - encoder.write_size(#im_n); + let mut encoder = ScryptoEncoder::new(&mut bytes); + encoder.write_type_id(ScryptoSborTypeId::Struct)?; + encoder.write_size(#im_n)?; #( - self.#im_ids2.encode(&mut encoder); + encoder.encode(&self.#im_ids2)?; )* - bytes + Ok(bytes) } - fn mutable_data(&self) -> ::sbor::rust::vec::Vec { + fn mutable_data(&self) -> Result<::sbor::rust::vec::Vec, ::sbor::EncodeError> { use ::sbor::{type_id::*, *}; use ::sbor::rust::vec::Vec; + use ::scrypto::data::*; let mut bytes = Vec::with_capacity(512); - let mut encoder = Encoder::new(&mut bytes); - encoder.write_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct); - encoder.write_size(#m_n); + let mut encoder = ScryptoEncoder::new(&mut bytes); + encoder.write_type_id(ScryptoSborTypeId::Struct)?; + encoder.write_size(#m_n)?; #( - self.#m_ids2.encode(&mut encoder); + encoder.encode(&self.#m_ids2)?; )* - bytes + Ok(bytes) } fn immutable_data_schema() -> ::scrypto::abi::Type { @@ -175,38 +178,41 @@ mod tests { impl radix_engine_interface::model::NonFungibleData for MyStruct { fn decode(immutable_data: &[u8], mutable_data: &[u8]) -> Result { use ::sbor::{type_id::*, *}; - let mut decoder_nm = Decoder::new(immutable_data); - decoder_nm.read_and_check_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct)?; + use ::scrypto::data::*; + let mut decoder_nm = ScryptoDecoder::new(immutable_data); + decoder_nm.read_and_check_type_id(ScryptoSborTypeId::Struct)?; decoder_nm.read_and_check_size(1)?; - let mut decoder_m = Decoder::new(mutable_data); - decoder_m.read_and_check_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct)?; + let mut decoder_m = ScryptoDecoder::new(mutable_data); + decoder_m.read_and_check_type_id(ScryptoSborTypeId::Struct)?; decoder_m.read_and_check_size(1)?; let decoded = Self { - field_1: ::decode(&mut decoder_nm)?, - field_2: ::decode(&mut decoder_m)?, + field_1: decoder_nm.decode::()?, + field_2: decoder_m.decode::()?, }; decoder_nm.check_end()?; decoder_m.check_end()?; Ok(decoded) } - fn immutable_data(&self) -> ::sbor::rust::vec::Vec { + fn immutable_data(&self) -> Result<::sbor::rust::vec::Vec, ::sbor::EncodeError> { use ::sbor::{type_id::*, *}; + use ::scrypto::data::*; let mut bytes = Vec::with_capacity(512); - let mut encoder = Encoder::new(&mut bytes); - encoder.write_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct); - encoder.write_size(1); - self.field_1.encode(&mut encoder); - bytes + let mut encoder = ScryptoEncoder::new(&mut bytes); + encoder.write_type_id(ScryptoSborTypeId::Struct)?; + encoder.write_size(1)?; + encoder.encode(&self.field_1)?; + Ok(bytes) } - fn mutable_data(&self) -> ::sbor::rust::vec::Vec { + fn mutable_data(&self) -> Result<::sbor::rust::vec::Vec, ::sbor::EncodeError> { use ::sbor::{type_id::*, *}; use ::sbor::rust::vec::Vec; + use ::scrypto::data::*; let mut bytes = Vec::with_capacity(512); - let mut encoder = Encoder::new(&mut bytes); - encoder.write_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct); - encoder.write_size(1); - self.field_2.encode(&mut encoder); - bytes + let mut encoder = ScryptoEncoder::new(&mut bytes); + encoder.write_type_id(ScryptoSborTypeId::Struct)?; + encoder.write_size(1)?; + encoder.encode(&self.field_2)?; + Ok(bytes) } fn immutable_data_schema() -> ::scrypto::abi::Type { use ::sbor::rust::borrow::ToOwned; diff --git a/scrypto-tests/tests/non_fungible_data.rs b/scrypto-tests/tests/non_fungible_data.rs index 325e0cb945c..9a75f8d0fb6 100644 --- a/scrypto-tests/tests/non_fungible_data.rs +++ b/scrypto-tests/tests/non_fungible_data.rs @@ -15,8 +15,11 @@ fn test_non_fungible_data() { a: 1, b: "Test".to_owned(), }; - let instance_decoded = - Sample::decode(&instance.immutable_data(), &instance.mutable_data()).unwrap(); + let instance_decoded = Sample::decode( + &instance.immutable_data().unwrap(), + &instance.mutable_data().unwrap(), + ) + .unwrap(); assert_eq!(instance_decoded, instance); let immutable_data_schema = Sample::immutable_data_schema(); diff --git a/scrypto-unit/src/test_runner.rs b/scrypto-unit/src/test_runner.rs index 3f871e399a8..5896912c3b0 100644 --- a/scrypto-unit/src/test_runner.rs +++ b/scrypto-unit/src/test_runner.rs @@ -49,7 +49,7 @@ impl<'s, S: ReadableSubstateStore + WriteableSubstateStore> TestRunner<'s, S> { let scrypto_interpreter = ScryptoInterpreter { wasm_metering_config: WasmMeteringConfig::new( InstructionCostRules::tiered(1, 5, 10, 5000), - 512, + 1024, ), wasm_engine: DefaultWasmEngine::default(), wasm_instrumenter: WasmInstrumenter::default(), @@ -637,15 +637,15 @@ impl<'s, S: ReadableSubstateStore + WriteableSubstateStore> TestRunner<'s, S> { let mut entries = HashMap::new(); entries.insert( NonFungibleId::from_u32(1), - (scrypto_encode(&()), scrypto_encode(&())), + (scrypto_encode(&()).unwrap(), scrypto_encode(&()).unwrap()), ); entries.insert( NonFungibleId::from_u32(2), - (scrypto_encode(&()), scrypto_encode(&())), + (scrypto_encode(&()).unwrap(), scrypto_encode(&()).unwrap()), ); entries.insert( NonFungibleId::from_u32(3), - (scrypto_encode(&()), scrypto_encode(&())), + (scrypto_encode(&()).unwrap(), scrypto_encode(&()).unwrap()), ); let manifest = ManifestBuilder::new(&NetworkDefinition::simulator()) diff --git a/scrypto/src/buffer/codec.rs b/scrypto/src/buffer/codec.rs index 79182e82ee9..6587175998a 100644 --- a/scrypto/src/buffer/codec.rs +++ b/scrypto/src/buffer/codec.rs @@ -6,15 +6,13 @@ use crate::buffer::*; use radix_engine_interface::data::*; /// Encodes a data structure into a Scrypto buffer. -pub fn scrypto_encode_to_buffer + ?Sized>(v: &T) -> *mut u8 { - let bytes = scrypto_encode(v); - scrypto_alloc_initialized(bytes) +pub fn scrypto_encode_to_buffer(v: &T) -> Result<*mut u8, EncodeError> { + let bytes = scrypto_encode(v)?; + Ok(scrypto_alloc_initialized(bytes)) } /// Decode a data structure from a Scrypto buffer. -pub fn scrypto_decode_from_buffer + ?Sized>( - ptr: *mut u8, -) -> Result { +pub fn scrypto_decode_from_buffer(ptr: *mut u8) -> Result { scrypto_consume(ptr, |slice| scrypto_decode(slice)) } @@ -31,7 +29,7 @@ mod tests { #[test] fn test_encode_for_radix_engine() { - let encoded = scrypto_encode_to_buffer("abc"); + let encoded = scrypto_encode_to_buffer("abc").unwrap(); let decoded: String = scrypto_decode_from_buffer(encoded).unwrap(); assert_eq!(decoded, "abc"); } diff --git a/scrypto/src/component/component.rs b/scrypto/src/component/component.rs index 2f57436ffcf..61563cc9bc9 100644 --- a/scrypto/src/component/component.rs +++ b/scrypto/src/component/component.rs @@ -3,7 +3,9 @@ use radix_engine_interface::api::types::{ ComponentId, ComponentOffset, GlobalAddress, RENodeId, ScryptoMethodIdent, ScryptoRENode, ScryptoReceiver, SubstateOffset, }; -use radix_engine_interface::data::{scrypto_decode, ScryptoCustomTypeId}; +use radix_engine_interface::data::{ + scrypto_decode, ScryptoCustomTypeId, ScryptoDecode, ScryptoEncode, +}; use radix_engine_interface::model::*; use radix_engine_interface::scrypto_type; @@ -24,9 +26,7 @@ use crate::scrypto; use radix_engine_derive::Describe; /// Represents the state of a component. -pub trait ComponentState: - Encode + Decode -{ +pub trait ComponentState: ScryptoEncode + ScryptoDecode { /// Instantiates a component from this data structure. fn instantiate(self) -> C; } @@ -58,7 +58,7 @@ pub struct ComponentStateSubstate { impl Component { /// Invokes a method on this component. - pub fn call>(&self, method: &str, args: Vec) -> T { + pub fn call(&self, method: &str, args: Vec) -> T { let mut sys_calls = ScryptoEnv; let rtn = sys_calls .sys_invoke_scrypto_method( @@ -97,7 +97,7 @@ impl Component { .unwrap() } - pub fn sys_add_access_check>( + pub fn sys_add_access_check( &mut self, access_rules: AccessRules, sys_calls: &mut Y, @@ -117,7 +117,7 @@ impl Component { self.sys_globalize(&mut ScryptoEnv).unwrap() } - pub fn sys_globalize>( + pub fn sys_globalize( self, sys_calls: &mut Y, ) -> Result @@ -135,7 +135,7 @@ pub struct BorrowedGlobalComponent(pub ComponentAddress); impl BorrowedGlobalComponent { /// Invokes a method on this component. - pub fn call>(&self, method: &str, args: Vec) -> T { + pub fn call(&self, method: &str, args: Vec) -> T { let mut syscalls = ScryptoEnv; let raw = syscalls .sys_invoke_scrypto_method( diff --git a/scrypto/src/component/kv_store.rs b/scrypto/src/component/kv_store.rs index c5c6e7d3078..ed870c8c761 100644 --- a/scrypto/src/component/kv_store.rs +++ b/scrypto/src/component/kv_store.rs @@ -19,10 +19,7 @@ use crate::engine::scrypto_env::ScryptoEnv; use crate::runtime::{DataRef, DataRefMut}; /// A scalable key-value map which loads entries on demand. -pub struct KeyValueStore< - K: Encode + Decode, - V: Encode + Decode, -> { +pub struct KeyValueStore { pub id: KeyValueStoreId, pub key: PhantomData, pub value: PhantomData, @@ -32,11 +29,7 @@ pub struct KeyValueStore< #[derive(Debug, Clone, TypeId, Encode, Decode, PartialEq, Eq)] pub struct KeyValueStoreEntrySubstate(pub Option>); -impl< - K: Encode + Decode, - V: Encode + Decode, - > KeyValueStore -{ +impl KeyValueStore { /// Creates a new key value store. pub fn new() -> Self { let mut syscalls = ScryptoEnv; @@ -54,7 +47,8 @@ impl< /// Returns the value that is associated with the given key. pub fn get(&self, key: &K) -> Option> { let mut syscalls = ScryptoEnv; - let offset = SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(key))); + let offset = + SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(key).unwrap())); let lock_handle = syscalls .sys_lock_substate(RENodeId::KeyValueStore(self.id), offset, false) .unwrap(); @@ -72,7 +66,8 @@ impl< pub fn get_mut(&mut self, key: &K) -> Option> { let mut syscalls = ScryptoEnv; - let offset = SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(key))); + let offset = + SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(key).unwrap())); let lock_handle = syscalls .sys_lock_substate(RENodeId::KeyValueStore(self.id), offset.clone(), true) .unwrap(); @@ -91,14 +86,15 @@ impl< /// Inserts a new key-value pair into this map. pub fn insert(&self, key: K, value: V) { let mut syscalls = ScryptoEnv; - let offset = - SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(&key))); + let offset = SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry( + scrypto_encode(&key).unwrap(), + )); let lock_handle = syscalls .sys_lock_substate(RENodeId::KeyValueStore(self.id), offset.clone(), true) .unwrap(); - let substate = KeyValueStoreEntrySubstate(Some(scrypto_encode(&value))); + let substate = KeyValueStoreEntrySubstate(Some(scrypto_encode(&value).unwrap())); syscalls - .sys_write(lock_handle, scrypto_encode(&substate)) + .sys_write(lock_handle, scrypto_encode(&substate).unwrap()) .unwrap(); syscalls.sys_drop_lock(lock_handle).unwrap(); } @@ -129,10 +125,8 @@ impl fmt::Display for ParseKeyValueStoreError { // binary //======== -impl< - K: Encode + Decode, - V: Encode + Decode, - > TryFrom<&[u8]> for KeyValueStore +impl TryFrom<&[u8]> + for KeyValueStore { type Error = ParseKeyValueStoreError; @@ -148,11 +142,7 @@ impl< } } -impl< - K: Encode + Decode, - V: Encode + Decode, - > KeyValueStore -{ +impl KeyValueStore { pub fn to_vec(&self) -> Vec { self.id.to_vec() } @@ -160,41 +150,41 @@ impl< // TODO: extend scrypto_type! macro to support generics -impl< - K: Encode + Decode, - V: Encode + Decode, - > TypeId for KeyValueStore +impl TypeId + for KeyValueStore { #[inline] - fn type_id() -> ScryptoTypeId { + fn type_id() -> ScryptoSborTypeId { SborTypeId::Custom(ScryptoCustomTypeId::KeyValueStore) } } impl< - K: Encode + Decode, - V: Encode + Decode, - > Encode for KeyValueStore + K: ScryptoEncode + ScryptoDecode, + V: ScryptoEncode + ScryptoDecode, + E: Encoder, + > Encode for KeyValueStore { #[inline] - fn encode_type_id(&self, encoder: &mut ScryptoEncoder) { - encoder.write_type_id(Self::type_id()); + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(Self::type_id()) } #[inline] - fn encode_body(&self, encoder: &mut ScryptoEncoder) { - encoder.write_slice(&self.to_vec()); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_slice(&self.to_vec()) } } impl< - K: Encode + Decode, - V: Encode + Decode, - > Decode for KeyValueStore + K: ScryptoEncode + ScryptoDecode, + V: ScryptoEncode + ScryptoDecode, + D: Decoder, + > Decode for KeyValueStore { fn decode_body_with_type_id( - decoder: &mut ScryptoDecoder, - type_id: ScryptoTypeId, + decoder: &mut D, + type_id: ScryptoSborTypeId, ) -> Result { decoder.check_preloaded_type_id(type_id, Self::type_id())?; let slice = decoder.read_slice(36)?; @@ -202,10 +192,8 @@ impl< } } -impl< - K: Encode + Decode + Describe, - V: Encode + Decode + Describe, - > Describe for KeyValueStore +impl + Describe for KeyValueStore { fn describe() -> Type { Type::KeyValueStore { @@ -219,10 +207,8 @@ impl< // text //====== -impl< - K: Encode + Decode, - V: Encode + Decode, - > FromStr for KeyValueStore +impl FromStr + for KeyValueStore { type Err = ParseKeyValueStoreError; @@ -233,20 +219,16 @@ impl< } } -impl< - K: Encode + Decode, - V: Encode + Decode, - > fmt::Display for KeyValueStore +impl fmt::Display + for KeyValueStore { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "{}", hex::encode(self.to_vec())) } } -impl< - K: Encode + Decode, - V: Encode + Decode, - > fmt::Debug for KeyValueStore +impl fmt::Debug + for KeyValueStore { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "{}", self) diff --git a/scrypto/src/component/package.rs b/scrypto/src/component/package.rs index 24363423b22..8ad194e7a48 100644 --- a/scrypto/src/component/package.rs +++ b/scrypto/src/component/package.rs @@ -1,8 +1,7 @@ -use radix_engine_interface::data::ScryptoCustomTypeId; +use radix_engine_interface::data::ScryptoDecode; use radix_engine_interface::model::*; use sbor::rust::vec::Vec; -use sbor::*; use crate::runtime::*; @@ -12,12 +11,7 @@ pub struct BorrowedPackage(pub(crate) PackageAddress); impl BorrowedPackage { /// Invokes a function on this package. - pub fn call>( - &self, - blueprint_name: &str, - function: &str, - args: Vec, - ) -> T { + pub fn call(&self, blueprint_name: &str, function: &str, args: Vec) -> T { Runtime::call_function(self.0, blueprint_name, function, args) } } diff --git a/scrypto/src/component/system.rs b/scrypto/src/component/system.rs index ad5942168cf..7d33b103d2d 100644 --- a/scrypto/src/component/system.rs +++ b/scrypto/src/component/system.rs @@ -70,7 +70,7 @@ impl ComponentSystem { .sys_create_node(ScryptoRENode::Component( Runtime::package_address(), blueprint_name.to_string(), - scrypto_encode(&state), + scrypto_encode(&state).unwrap(), )) .unwrap(); Component(node_id.into()) diff --git a/scrypto/src/engine/scrypto_env.rs b/scrypto/src/engine/scrypto_env.rs index a5f5b09352b..4466969e59c 100644 --- a/scrypto/src/engine/scrypto_env.rs +++ b/scrypto/src/engine/scrypto_env.rs @@ -5,7 +5,7 @@ use radix_engine_interface::api::types::{ }; use radix_engine_interface::api::wasm_input::RadixEngineInput; use radix_engine_interface::crypto::Hash; -use radix_engine_interface::data::ScryptoCustomTypeId; +use radix_engine_interface::data::ScryptoDecode; use sbor::rust::fmt::Debug; use sbor::rust::string::String; use sbor::rust::vec::Vec; @@ -18,11 +18,11 @@ extern "C" { /// Utility function for making a radix engine call. #[cfg(target_arch = "wasm32")] -pub fn call_engine>(input: RadixEngineInput) -> V { +pub fn call_engine(input: RadixEngineInput) -> V { use crate::buffer::{scrypto_decode_from_buffer, *}; unsafe { - let input_ptr = scrypto_encode_to_buffer(&input); + let input_ptr = scrypto_encode_to_buffer(&input).unwrap(); let output_ptr = radix_engine(input_ptr); scrypto_decode_from_buffer::(output_ptr).unwrap() } @@ -34,7 +34,7 @@ pub fn call_engine_to_raw(input: RadixEngineInput) -> Vec { use crate::buffer::{scrypto_buffer_to_vec, *}; unsafe { - let input_ptr = scrypto_encode_to_buffer(&input); + let input_ptr = scrypto_encode_to_buffer(&input).unwrap(); let output_ptr = radix_engine(input_ptr); scrypto_buffer_to_vec(output_ptr) } @@ -42,7 +42,7 @@ pub fn call_engine_to_raw(input: RadixEngineInput) -> Vec { /// Utility function for making a radix engine call. #[cfg(not(target_arch = "wasm32"))] -pub fn call_engine>(_input: RadixEngineInput) -> V { +pub fn call_engine(_input: RadixEngineInput) -> V { todo!() } /// Utility function for making a radix engine call. @@ -161,7 +161,7 @@ macro_rules! sys_env_native_fn { $vis $fn $fn_name($($args)*, env: &mut Y) -> Result<$rtn, E> where Y: radix_engine_interface::api::api::SysNativeInvokable<$invocation, E>, - E: sbor::rust::fmt::Debug + TypeId + Decode, + E: sbor::rust::fmt::Debug + TypeId + radix_engine_interface::data::ScryptoDecode, { radix_engine_interface::api::api::SysNativeInvokable::sys_invoke(env, $invocation { $($invocation_args)* }) } @@ -171,7 +171,7 @@ macro_rules! sys_env_native_fn { $vis $fn $fn_name(env: &mut Y) -> Result<$rtn, E> where Y: radix_engine_interface::api::api::SysNativeInvokable<$invocation, E>, - E: sbor::rust::fmt::Debug + TypeId + Decode, + E: sbor::rust::fmt::Debug + TypeId + radix_engine_interface::data::ScryptoDecode, { radix_engine_interface::api::api::SysNativeInvokable::sys_invoke(env, $invocation { $($invocation_args)* }) } diff --git a/scrypto/src/prelude/mod.rs b/scrypto/src/prelude/mod.rs index 9a46b783be3..4de2cd381c1 100644 --- a/scrypto/src/prelude/mod.rs +++ b/scrypto/src/prelude/mod.rs @@ -31,7 +31,7 @@ pub use sbor::rust::string::String; pub use sbor::rust::string::ToString; pub use sbor::rust::vec; pub use sbor::rust::vec::Vec; -pub use sbor::{decode_any, encode_any, Decode, DecodeError, Encode, TypeId}; +pub use sbor::{Decode, DecodeError, Encode, TypeId}; pub use super::radix_engine_derive; pub use super::radix_engine_interface; diff --git a/scrypto/src/resource/auth_zone.rs b/scrypto/src/resource/auth_zone.rs index 43cd746b186..2b1ea9a6d03 100644 --- a/scrypto/src/resource/auth_zone.rs +++ b/scrypto/src/resource/auth_zone.rs @@ -1,12 +1,11 @@ use radix_engine_interface::api::api::{EngineApi, SysNativeInvokable}; use radix_engine_interface::api::types::RENodeId; -use radix_engine_interface::data::ScryptoCustomTypeId; +use radix_engine_interface::data::{ScryptoDecode, ScryptoTypeId}; use radix_engine_interface::math::Decimal; use radix_engine_interface::model::*; use sbor::rust::collections::BTreeSet; use sbor::rust::fmt::Debug; use sbor::rust::vec::Vec; -use sbor::*; use scrypto::engine::scrypto_env::ScryptoEnv; /// Represents the auth zone, which is used by system for checking @@ -17,7 +16,7 @@ use scrypto::engine::scrypto_env::ScryptoEnv; pub struct ComponentAuthZone {} impl ComponentAuthZone { - pub fn sys_drain + Decode>( + pub fn sys_drain( env: &mut Y, ) -> Result, E> where @@ -33,9 +32,7 @@ impl ComponentAuthZone { }) } - pub fn sys_clear + Decode>( - env: &mut Y, - ) -> Result<(), E> + pub fn sys_clear(env: &mut Y) -> Result<(), E> where Y: EngineApi + SysNativeInvokable, { @@ -49,9 +46,7 @@ impl ComponentAuthZone { }) } - pub fn sys_pop + Decode>( - env: &mut Y, - ) -> Result + pub fn sys_pop(env: &mut Y) -> Result where Y: EngineApi + SysNativeInvokable, { @@ -65,10 +60,7 @@ impl ComponentAuthZone { }) } - pub fn sys_create_proof< - Y, - E: Debug + TypeId + Decode, - >( + pub fn sys_create_proof( resource_address: ResourceAddress, env: &mut Y, ) -> Result @@ -86,10 +78,7 @@ impl ComponentAuthZone { }) } - pub fn sys_create_proof_by_amount< - Y, - E: Debug + TypeId + Decode, - >( + pub fn sys_create_proof_by_amount( amount: Decimal, resource_address: ResourceAddress, env: &mut Y, @@ -109,10 +98,7 @@ impl ComponentAuthZone { }) } - pub fn sys_create_proof_by_ids< - Y, - E: Debug + TypeId + Decode, - >( + pub fn sys_create_proof_by_ids( ids: &BTreeSet, resource_address: ResourceAddress, env: &mut Y, @@ -132,11 +118,7 @@ impl ComponentAuthZone { }) } - pub fn sys_push< - P: Into, - Y, - E: Debug + TypeId + Decode, - >( + pub fn sys_push, Y, E: Debug + ScryptoTypeId + ScryptoDecode>( proof: P, env: &mut Y, ) -> Result<(), E> diff --git a/scrypto/src/resource/bucket.rs b/scrypto/src/resource/bucket.rs index f238664e54a..cdcccf7f476 100644 --- a/scrypto/src/resource/bucket.rs +++ b/scrypto/src/resource/bucket.rs @@ -1,27 +1,23 @@ use crate::resource::{ComponentAuthZone, NonFungible, ScryptoProof}; use radix_engine_interface::api::api::SysNativeInvokable; -use radix_engine_interface::data::ScryptoCustomTypeId; +use radix_engine_interface::data::{ScryptoDecode, ScryptoTypeId}; use radix_engine_interface::math::Decimal; use radix_engine_interface::model::*; use sbor::rust::collections::BTreeSet; use sbor::rust::fmt::Debug; use sbor::rust::vec::Vec; -use sbor::*; use scrypto::engine::scrypto_env::ScryptoEnv; use scrypto::scrypto_env_native_fn; pub trait SysBucket { - fn sys_new + Decode>( + fn sys_new( receiver: ResourceAddress, sys_calls: &mut Y, ) -> Result where Y: SysNativeInvokable; - fn sys_burn + Decode>( - self, - env: &mut Y, - ) -> Result<(), E> + fn sys_burn(self, env: &mut Y) -> Result<(), E> where Y: SysNativeInvokable + SysNativeInvokable; @@ -29,9 +25,9 @@ pub trait SysBucket { fn sys_resource_address(&self, env: &mut Y) -> Result where Y: SysNativeInvokable, - E: Debug + TypeId + Decode; + E: Debug + ScryptoTypeId + ScryptoDecode; - fn sys_create_proof + Decode>( + fn sys_create_proof( &self, sys_calls: &mut Y, ) -> Result @@ -40,7 +36,7 @@ pub trait SysBucket { } impl SysBucket for Bucket { - fn sys_new + Decode>( + fn sys_new( receiver: ResourceAddress, sys_calls: &mut Y, ) -> Result @@ -50,10 +46,7 @@ impl SysBucket for Bucket { sys_calls.sys_invoke(ResourceManagerCreateBucketInvocation { receiver }) } - fn sys_burn + Decode>( - self, - env: &mut Y, - ) -> Result<(), E> + fn sys_burn(self, env: &mut Y) -> Result<(), E> where Y: SysNativeInvokable + SysNativeInvokable, @@ -68,12 +61,12 @@ impl SysBucket for Bucket { fn sys_resource_address(&self, env: &mut Y) -> Result where Y: SysNativeInvokable, - E: Debug + TypeId + Decode, + E: Debug + ScryptoTypeId + ScryptoDecode, { env.sys_invoke(BucketGetResourceAddressInvocation { receiver: self.0 }) } - fn sys_create_proof + Decode>( + fn sys_create_proof( &self, sys_calls: &mut Y, ) -> Result diff --git a/scrypto/src/resource/proof.rs b/scrypto/src/resource/proof.rs index d8223bca1b2..e4387a2013a 100644 --- a/scrypto/src/resource/proof.rs +++ b/scrypto/src/resource/proof.rs @@ -1,12 +1,11 @@ use radix_engine_interface::api::api::{EngineApi, SysNativeInvokable}; use radix_engine_interface::api::types::{ProofId, RENodeId}; -use radix_engine_interface::data::ScryptoCustomTypeId; +use radix_engine_interface::data::{ScryptoDecode, ScryptoTypeId}; use radix_engine_interface::math::Decimal; use radix_engine_interface::model::*; use sbor::rust::collections::BTreeSet; use sbor::rust::fmt::Debug; use sbor::rust::vec::Vec; -use sbor::*; use scrypto::engine::scrypto_env::ScryptoEnv; use scrypto::scrypto_env_native_fn; @@ -47,13 +46,13 @@ impl From for ProofValidationMode { } pub trait SysProof { - fn sys_clone + Decode>( + fn sys_clone( &self, sys_calls: &mut Y, ) -> Result where Y: EngineApi + SysNativeInvokable; - fn sys_drop + Decode>( + fn sys_drop( self, sys_calls: &mut Y, ) -> Result<(), E> @@ -62,7 +61,7 @@ pub trait SysProof { } impl SysProof for Proof { - fn sys_clone + Decode>( + fn sys_clone( &self, sys_calls: &mut Y, ) -> Result @@ -72,7 +71,7 @@ impl SysProof for Proof { sys_calls.sys_invoke(ProofCloneInvocation { receiver: self.0 }) } - fn sys_drop + Decode>( + fn sys_drop( self, sys_calls: &mut Y, ) -> Result<(), E> diff --git a/scrypto/src/resource/resource_builder.rs b/scrypto/src/resource/resource_builder.rs index 33e244695c9..3790ecea178 100644 --- a/scrypto/src/resource/resource_builder.rs +++ b/scrypto/src/resource/resource_builder.rs @@ -224,7 +224,7 @@ impl NonFungibleResourceBuilder { { let mut encoded = HashMap::new(); for (id, e) in entries { - encoded.insert(id, (e.immutable_data(), e.mutable_data())); + encoded.insert(id, (e.immutable_data().unwrap(), e.mutable_data().unwrap())); } self.build(Some(MintParams::NonFungible { entries: encoded })) diff --git a/scrypto/src/resource/resource_manager.rs b/scrypto/src/resource/resource_manager.rs index 7259f6eea79..3a85890261d 100644 --- a/scrypto/src/resource/resource_manager.rs +++ b/scrypto/src/resource/resource_manager.rs @@ -218,7 +218,10 @@ impl ResourceManager { /// Mints non-fungible resources pub fn mint_non_fungible(&mut self, id: &NonFungibleId, data: T) -> Bucket { let mut entries = HashMap::new(); - entries.insert(id.clone(), (data.immutable_data(), data.mutable_data())); + entries.insert( + id.clone(), + (data.immutable_data().unwrap(), data.mutable_data().unwrap()), + ); self.mint_internal(MintParams::NonFungible { entries }) } @@ -240,6 +243,6 @@ impl ResourceManager { id: &NonFungibleId, new_data: T, ) { - self.update_non_fungible_data_internal(id.clone(), new_data.mutable_data()) + self.update_non_fungible_data_internal(id.clone(), new_data.mutable_data().unwrap()) } } diff --git a/scrypto/src/resource/vault.rs b/scrypto/src/resource/vault.rs index e6b128a1a73..fa214d80db9 100644 --- a/scrypto/src/resource/vault.rs +++ b/scrypto/src/resource/vault.rs @@ -1,11 +1,10 @@ use radix_engine_interface::api::api::{EngineApi, SysNativeInvokable}; -use radix_engine_interface::data::ScryptoCustomTypeId; +use radix_engine_interface::data::ScryptoDecode; use radix_engine_interface::math::Decimal; use radix_engine_interface::model::*; use sbor::rust::collections::BTreeSet; use sbor::rust::fmt::Debug; use sbor::rust::vec::Vec; -use sbor::*; use scrypto::engine::scrypto_env::ScryptoEnv; use scrypto::scrypto_env_native_fn; @@ -13,19 +12,13 @@ use crate::resource::*; use crate::scrypto; pub trait SysVault { - fn sys_amount>( - &self, - sys_calls: &mut Y, - ) -> Result + fn sys_amount(&self, sys_calls: &mut Y) -> Result where Y: EngineApi + SysNativeInvokable; } impl SysVault for Vault { - fn sys_amount>( - &self, - sys_calls: &mut Y, - ) -> Result + fn sys_amount(&self, sys_calls: &mut Y) -> Result where Y: EngineApi + SysNativeInvokable, { diff --git a/scrypto/src/runtime/data.rs b/scrypto/src/runtime/data.rs index 358956ece0e..b3c02cb4d05 100644 --- a/scrypto/src/runtime/data.rs +++ b/scrypto/src/runtime/data.rs @@ -2,33 +2,32 @@ use radix_engine_interface::api::api::EngineApi; use radix_engine_interface::api::types::{ ComponentOffset, KeyValueStoreOffset, LockHandle, RENodeId, SubstateOffset, }; -use radix_engine_interface::data::{scrypto_decode, scrypto_encode, ScryptoCustomTypeId}; +use radix_engine_interface::data::{scrypto_decode, scrypto_encode, ScryptoDecode, ScryptoEncode}; use sbor::rust::fmt; use sbor::rust::marker::PhantomData; use sbor::rust::ops::{Deref, DerefMut}; -use sbor::{Decode, Encode}; use scrypto::engine::scrypto_env::ScryptoEnv; use crate::component::{ComponentStateSubstate, KeyValueStoreEntrySubstate}; -pub struct DataRef> { +pub struct DataRef { lock_handle: LockHandle, value: V, } -impl> fmt::Display for DataRef { +impl fmt::Display for DataRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.value.fmt(f) } } -impl> DataRef { +impl DataRef { pub fn new(lock_handle: LockHandle, value: V) -> DataRef { DataRef { lock_handle, value } } } -impl> Deref for DataRef { +impl Deref for DataRef { type Target = V; fn deref(&self) -> &Self::Target { @@ -36,26 +35,26 @@ impl> Deref for DataRef { } } -impl> Drop for DataRef { +impl Drop for DataRef { fn drop(&mut self) { let mut syscalls = ScryptoEnv; syscalls.sys_drop_lock(self.lock_handle).unwrap(); } } -pub struct DataRefMut> { +pub struct DataRefMut { lock_handle: LockHandle, offset: SubstateOffset, value: V, } -impl> fmt::Display for DataRefMut { +impl fmt::Display for DataRefMut { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.value.fmt(f) } } -impl> DataRefMut { +impl DataRefMut { pub fn new(lock_handle: LockHandle, offset: SubstateOffset, value: V) -> DataRefMut { DataRefMut { lock_handle, @@ -65,16 +64,16 @@ impl> DataRefMut { } } -impl> Drop for DataRefMut { +impl Drop for DataRefMut { fn drop(&mut self) { let mut syscalls = ScryptoEnv; - let bytes = scrypto_encode(&self.value); + let bytes = scrypto_encode(&self.value).unwrap(); let substate = match &self.offset { SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(..)) => { - scrypto_encode(&KeyValueStoreEntrySubstate(Some(bytes))) + scrypto_encode(&KeyValueStoreEntrySubstate(Some(bytes))).unwrap() } SubstateOffset::Component(ComponentOffset::State) => { - scrypto_encode(&ComponentStateSubstate { raw: bytes }) + scrypto_encode(&ComponentStateSubstate { raw: bytes }).unwrap() } s @ _ => panic!("Unsupported substate: {:?}", s), }; @@ -84,7 +83,7 @@ impl> Drop for DataRefMut { } } -impl> Deref for DataRefMut { +impl Deref for DataRefMut { type Target = V; fn deref(&self) -> &Self::Target { @@ -92,19 +91,19 @@ impl> Deref for DataRefMut { } } -impl> DerefMut for DataRefMut { +impl DerefMut for DataRefMut { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.value } } -pub struct DataPointer + Decode> { +pub struct DataPointer { node_id: RENodeId, offset: SubstateOffset, phantom_data: PhantomData, } -impl + Decode> DataPointer { +impl DataPointer { pub fn new(node_id: RENodeId, offset: SubstateOffset) -> Self { Self { node_id, diff --git a/scrypto/src/runtime/runtime.rs b/scrypto/src/runtime/runtime.rs index 108ebc08bee..0c7d6396eaa 100644 --- a/scrypto/src/runtime/runtime.rs +++ b/scrypto/src/runtime/runtime.rs @@ -4,13 +4,12 @@ use radix_engine_interface::api::types::{ }; use radix_engine_interface::constants::EPOCH_MANAGER; use radix_engine_interface::crypto::*; -use radix_engine_interface::data::{scrypto_decode, ScryptoCustomTypeId}; +use radix_engine_interface::data::{scrypto_decode, ScryptoDecode, ScryptoTypeId}; use radix_engine_interface::model::*; use sbor::rust::borrow::ToOwned; use sbor::rust::fmt::Debug; use sbor::rust::string::*; use sbor::rust::vec::Vec; -use sbor::*; use scrypto::engine::scrypto_env::ScryptoEnv; /// The transaction runtime. @@ -25,7 +24,7 @@ impl Runtime { pub fn sys_current_epoch(env: &mut Y) -> Result where Y: SysNativeInvokable, - E: Debug + TypeId + Decode, + E: Debug + ScryptoTypeId + ScryptoDecode, { env.sys_invoke(EpochManagerGetCurrentEpochInvocation { receiver: EPOCH_MANAGER, @@ -53,7 +52,7 @@ impl Runtime { } /// Invokes a function on a blueprint. - pub fn call_function, S2: AsRef, T: Decode>( + pub fn call_function, S2: AsRef, T: ScryptoDecode>( package_address: PackageAddress, blueprint_name: S1, function_name: S2, @@ -74,7 +73,7 @@ impl Runtime { } /// Invokes a method on a component. - pub fn call_method, T: Decode>( + pub fn call_method, T: ScryptoDecode>( component_address: ComponentAddress, method: S, args: Vec, diff --git a/simulator/src/resim/config.rs b/simulator/src/resim/config.rs index e703ea78b36..c122a807ab5 100644 --- a/simulator/src/resim/config.rs +++ b/simulator/src/resim/config.rs @@ -48,7 +48,7 @@ pub fn get_configs() -> Result { } pub fn set_configs(configs: &Configs) -> Result<(), Error> { - fs::write(get_configs_path()?, scrypto_encode(configs)).map_err(Error::IOError) + fs::write(get_configs_path()?, scrypto_encode(configs).unwrap()).map_err(Error::IOError) } pub fn get_default_account() -> Result { diff --git a/simulator/src/resim/mod.rs b/simulator/src/resim/mod.rs index 691f808457d..549d8e97c25 100644 --- a/simulator/src/resim/mod.rs +++ b/simulator/src/resim/mod.rs @@ -180,7 +180,7 @@ pub fn handle_manifest( wasm_instrumenter: WasmInstrumenter::default(), wasm_metering_config: WasmMeteringConfig::new( InstructionCostRules::tiered(1, 5, 10, 5000), - 512, + 1024, ), }; diff --git a/simulator/src/rtmc/mod.rs b/simulator/src/rtmc/mod.rs index 586009e28c7..ada43bc4578 100644 --- a/simulator/src/rtmc/mod.rs +++ b/simulator/src/rtmc/mod.rs @@ -29,6 +29,7 @@ pub struct Args { #[derive(Debug)] pub enum Error { IoError(std::io::Error), + EncodeError(sbor::EncodeError), CompileError(transaction::manifest::CompileError), ParseNetworkError(ParseNetworkError), } @@ -48,7 +49,11 @@ pub fn run() -> Result<(), Error> { } } let transaction = compile(&content, &network, blobs).map_err(Error::CompileError)?; - std::fs::write(args.output, scrypto_encode(&transaction)).map_err(Error::IoError)?; + std::fs::write( + args.output, + scrypto_encode(&transaction).map_err(Error::EncodeError)?, + ) + .map_err(Error::IoError)?; Ok(()) } diff --git a/simulator/src/utils/cargo.rs b/simulator/src/utils/cargo.rs index 2b4e3a0a038..df116a1a531 100644 --- a/simulator/src/utils/cargo.rs +++ b/simulator/src/utils/cargo.rs @@ -27,6 +27,8 @@ pub enum BuildError { AbiExtractionError(ExtractAbiError), + AbiEncodeError(sbor::EncodeError), + InvalidManifestFile(PathBuf), } @@ -169,8 +171,11 @@ pub fn build_package>( let wasm = fs::read(&wasm_path).map_err(|err| BuildError::IOErrorAtPath(err, wasm_path.clone()))?; let abi = extract_abi(&wasm).map_err(BuildError::AbiExtractionError)?; - fs::write(&abi_path, scrypto_encode(&abi)) - .map_err(|err| BuildError::IOErrorAtPath(err, abi_path.clone()))?; + fs::write( + &abi_path, + scrypto_encode(&abi).map_err(BuildError::AbiEncodeError)?, + ) + .map_err(|err| BuildError::IOErrorAtPath(err, abi_path.clone()))?; // Build without ABI run_cargo_build(&manifest_path, &target_path, trace, true)?; diff --git a/transaction/src/builder/manifest_builder.rs b/transaction/src/builder/manifest_builder.rs index 654c51b3b4c..0f9db073ce0 100644 --- a/transaction/src/builder/manifest_builder.rs +++ b/transaction/src/builder/manifest_builder.rs @@ -19,7 +19,6 @@ use sbor::rust::str::FromStr; use sbor::rust::string::String; use sbor::rust::string::ToString; use sbor::rust::vec::Vec; -use sbor::*; use scrypto::abi::*; use scrypto::access_rule_node; use scrypto::rule; @@ -34,16 +33,10 @@ macro_rules! args_from_bytes_vec { ($args: expr) => {{ let mut fields = Vec::new(); for arg in $args { - fields.push( - ::sbor::decode_any::< - ::scrypto::data::ScryptoCustomTypeId, - ::scrypto::data::ScryptoCustomValue, - >(&arg) - .unwrap(), - ); + fields.push(::scrypto::data::scrypto_decode(&arg).unwrap()); } - let input_struct = ::sbor::SborValue::Struct { fields }; - ::sbor::encode_any(&input_struct) + let input_struct = ::scrypto::data::ScryptoValue::Struct { fields }; + ::scrypto::data::scrypto_encode(&input_struct).unwrap() }}; } @@ -341,7 +334,7 @@ impl ManifestBuilder { blueprint_name: RESOURCE_MANAGER_BLUEPRINT.to_string(), function_name: ResourceManagerFunction::Create.to_string(), }, - args: scrypto_encode(&input), + args: scrypto_encode(&input).unwrap(), }); self @@ -411,11 +404,10 @@ impl ManifestBuilder { let mut fields = Vec::new(); for arg in arguments { - fields - .push(::sbor::decode_any::(&arg).unwrap()); + fields.push(scrypto_decode(&arg).unwrap()); } - let input_struct = ::sbor::SborValue::Struct { fields }; - let bytes = ::sbor::encode_any(&input_struct); + let input_struct = ScryptoValue::Struct { fields }; + let bytes = scrypto_encode(&input_struct).unwrap(); Ok(self .add_instruction(Instruction::CallFunction { @@ -509,7 +501,7 @@ impl ManifestBuilder { let code_hash = hash(&code); self.blobs.insert(code_hash, code); - let abi = scrypto_encode(&abi); + let abi = scrypto_encode(&abi).unwrap(); let abi_hash = hash(&abi); self.blobs.insert(abi_hash, abi); @@ -658,7 +650,8 @@ impl ManifestBuilder { args: scrypto_encode(&ResourceManagerMintInvocation { receiver: resource_address, mint_params: MintParams::Fungible { amount }, - }), + }) + .unwrap(), }); self } @@ -675,7 +668,8 @@ impl ManifestBuilder { args: scrypto_encode(&ResourceManagerBurnInvocation { receiver: resource_address, bucket: Bucket(bucket_id), - }), + }) + .unwrap(), }) .0 }) @@ -699,7 +693,8 @@ impl ManifestBuilder { args: scrypto_encode(&ResourceManagerBurnInvocation { receiver: non_fungible_address.resource_address(), bucket: Bucket(bucket_id), - }), + }) + .unwrap(), }) .0 }, @@ -966,13 +961,13 @@ impl ManifestBuilder { let value = arg.parse::().map_err(|_| { BuildArgsError::FailedToParse(i, t.clone(), arg.to_owned()) })?; - Ok(scrypto_encode(&value)) + Ok(scrypto_encode(&value).unwrap()) } Type::PreciseDecimal => { let value = arg.parse::().map_err(|_| { BuildArgsError::FailedToParse(i, t.clone(), arg.to_owned()) })?; - Ok(scrypto_encode(&value)) + Ok(scrypto_encode(&value).unwrap()) } Type::PackageAddress => { let value = self @@ -981,7 +976,7 @@ impl ManifestBuilder { .map_err(|_| { BuildArgsError::FailedToParse(i, t.clone(), arg.to_owned()) })?; - Ok(scrypto_encode(&value)) + Ok(scrypto_encode(&value).unwrap()) } Type::ComponentAddress => { let value = self @@ -990,7 +985,7 @@ impl ManifestBuilder { .map_err(|_| { BuildArgsError::FailedToParse(i, t.clone(), arg.to_owned()) })?; - Ok(scrypto_encode(&value)) + Ok(scrypto_encode(&value).unwrap()) } Type::ResourceAddress => { let value = self @@ -999,19 +994,19 @@ impl ManifestBuilder { .map_err(|_| { BuildArgsError::FailedToParse(i, t.clone(), arg.to_owned()) })?; - Ok(scrypto_encode(&value)) + Ok(scrypto_encode(&value).unwrap()) } Type::Hash => { let value = arg.parse::().map_err(|_| { BuildArgsError::FailedToParse(i, t.clone(), arg.to_owned()) })?; - Ok(scrypto_encode(&value)) + Ok(scrypto_encode(&value).unwrap()) } Type::NonFungibleId => { let value = arg.parse::().map_err(|_| { BuildArgsError::FailedToParse(i, t.clone(), arg.to_owned()) })?; - Ok(scrypto_encode(&value)) + Ok(scrypto_encode(&value).unwrap()) } Type::Bucket => { let resource_specifier = parse_resource_specifier(arg, &self.decoder) @@ -1050,7 +1045,7 @@ impl ManifestBuilder { .unwrap() } }; - Ok(scrypto_encode(&Bucket(bucket_id))) + Ok(scrypto_encode(&Bucket(bucket_id)).unwrap()) } Type::Proof => { let resource_specifier = parse_resource_specifier(arg, &self.decoder) @@ -1087,7 +1082,7 @@ impl ManifestBuilder { } } }; - Ok(scrypto_encode(&Proof(proof_id))) + Ok(scrypto_encode(&Proof(proof_id)).unwrap()) } _ => Err(BuildArgsError::UnsupportedType(i, t.clone())), }; @@ -1108,13 +1103,13 @@ impl ManifestBuilder { arg: &str, ) -> Result, BuildArgsError> where - T: FromStr + Encode, + T: FromStr + ScryptoEncode, T::Err: fmt::Debug, { let value = arg .parse::() .map_err(|_| BuildArgsError::FailedToParse(i, t.clone(), arg.to_owned()))?; - Ok(scrypto_encode(&value)) + Ok(scrypto_encode(&value).unwrap()) } } diff --git a/transaction/src/builder/transaction_builder.rs b/transaction/src/builder/transaction_builder.rs index 1292fbbf8bc..735e618feda 100644 --- a/transaction/src/builder/transaction_builder.rs +++ b/transaction/src/builder/transaction_builder.rs @@ -32,7 +32,7 @@ impl TransactionBuilder { pub fn sign(mut self, signer: &S) -> Self { let intent = self.transaction_intent(); - let intent_payload = scrypto_encode(&intent); + let intent_payload = scrypto_encode(&intent).unwrap(); self.intent_signatures.push(signer.sign(&intent_payload)); self } @@ -44,7 +44,7 @@ impl TransactionBuilder { pub fn notarize(mut self, signer: &S) -> Self { let signed_intent = self.signed_transaction_intent(); - let signed_intent_payload = scrypto_encode(&signed_intent); + let signed_intent_payload = scrypto_encode(&signed_intent).unwrap(); self.notary_signature = Some(signer.sign(&signed_intent_payload).signature()); self } @@ -109,7 +109,7 @@ mod tests { .notarize(&private_key) .build(); - let bytes = transaction.to_bytes(); + let bytes = transaction.to_bytes().unwrap(); NotarizedTransaction::from_slice(&bytes).unwrap(); } } diff --git a/transaction/src/errors.rs b/transaction/src/errors.rs index 824119c5895..bd3c80df591 100644 --- a/transaction/src/errors.rs +++ b/transaction/src/errors.rs @@ -22,6 +22,13 @@ pub enum SignatureValidationError { InvalidIntentSignature, InvalidNotarySignature, DuplicateSigner, + SerializationError(EncodeError), +} + +impl From for SignatureValidationError { + fn from(err: EncodeError) -> Self { + Self::SerializationError(err) + } } #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeId)] @@ -48,6 +55,7 @@ pub enum CallDataValidationError { #[derive(Debug, Clone, PartialEq, Eq)] pub enum TransactionValidationError { TransactionTooLarge, + SerializationError(EncodeError), DeserializationError(DecodeError), IntentHashRejected, HeaderValidationError(HeaderValidationError), @@ -56,6 +64,12 @@ pub enum TransactionValidationError { CallDataValidationError(CallDataValidationError), } +impl From for TransactionValidationError { + fn from(err: EncodeError) -> Self { + Self::SerializationError(err) + } +} + /// Represents an error when parsing arguments. #[derive(Debug, Clone)] pub enum BuildArgsError { diff --git a/transaction/src/manifest/decompiler.rs b/transaction/src/manifest/decompiler.rs index 644cc71312a..26231025eae 100644 --- a/transaction/src/manifest/decompiler.rs +++ b/transaction/src/manifest/decompiler.rs @@ -4,11 +4,14 @@ use radix_engine_interface::api::types::{ ScryptoFunctionIdent, ScryptoMethodIdent, ScryptoPackage, ScryptoReceiver, }; use radix_engine_interface::core::NetworkDefinition; -use radix_engine_interface::data::{scrypto_decode, IndexedScryptoValue, ValueFormattingContext}; +use radix_engine_interface::data::{ + scrypto_decode, scrypto_encode, IndexedScryptoValue, ScryptoValueDecodeError, + ValueFormattingContext, +}; use radix_engine_interface::model::*; use sbor::rust::collections::*; use sbor::rust::fmt; -use sbor::{encode_any, SborValue}; +use sbor::{EncodeError, SborValue}; use utils::ContextualDisplay; use crate::errors::*; @@ -19,10 +22,24 @@ use crate::validation::*; pub enum DecompileError { InvalidAddress(AddressError), InvalidArguments, + InvalidScryptoValue(ScryptoValueDecodeError), + InvalidSborValue(EncodeError), IdAllocationError(IdAllocationError), FormattingError(fmt::Error), } +impl From for DecompileError { + fn from(error: ScryptoValueDecodeError) -> Self { + Self::InvalidScryptoValue(error) + } +} + +impl From for DecompileError { + fn from(error: EncodeError) -> Self { + Self::InvalidSborValue(error) + } +} + impl From for DecompileError { fn from(error: fmt::Error) -> Self { Self::FormattingError(error) @@ -475,7 +492,7 @@ pub fn format_args( IndexedScryptoValue::from_slice(&args).map_err(|_| DecompileError::InvalidArguments)?; if let SborValue::Struct { fields } = value.dom { for field in fields { - let bytes = encode_any(&field); + let bytes = scrypto_encode(&field)?; let arg = IndexedScryptoValue::from_slice(&bytes) .map_err(|_| DecompileError::InvalidArguments)?; f.write_char(' ')?; @@ -557,7 +574,8 @@ mod tests { resource_type: ResourceType::NonFungible, metadata: HashMap::new(), access_rules: HashMap::new(), - }), + }) + .unwrap(), }], &NetworkDefinition::simulator(), ) diff --git a/transaction/src/manifest/generator.rs b/transaction/src/manifest/generator.rs index ae65358ae4b..e81b423d4f5 100644 --- a/transaction/src/manifest/generator.rs +++ b/transaction/src/manifest/generator.rs @@ -10,7 +10,7 @@ use radix_engine_interface::crypto::{ }; use radix_engine_interface::data::{ scrypto_decode, scrypto_encode, IndexedScryptoValue, ScryptoCustomTypeId, ScryptoCustomValue, - ScryptoTypeId, ScryptoValue, + ScryptoSborTypeId, ScryptoValue, }; use radix_engine_interface::math::{Decimal, PreciseDecimal}; use radix_engine_interface::model::*; @@ -32,7 +32,7 @@ use crate::validation::*; macro_rules! args_from_value_vec { ($args: expr) => {{ let input_struct = ::sbor::SborValue::Struct { fields: $args }; - ::sbor::encode_any(&input_struct) + ::radix_engine_interface::data::scrypto_encode(&input_struct).unwrap() }}; } @@ -66,6 +66,7 @@ pub enum GeneratorError { InvalidEcdsaSecp256k1Signature(String), InvalidEddsaEd25519PublicKey(String), InvalidEddsaEd25519Signature(String), + SborEncodeError(EncodeError), BlobNotFound(String), NameResolverError(NameResolverError), IdValidationError(IdValidationError), @@ -486,7 +487,8 @@ pub fn generate_instruction( }, args: scrypto_encode(&ResourceManagerBucketBurnInvocation { bucket: Bucket(bucket_id), - }), + }) + .unwrap(), } } ast::Instruction::MintFungible { @@ -506,7 +508,7 @@ pub fn generate_instruction( receiver: RENodeId::Global(GlobalAddress::Resource(resource_address)), method_name: ResourceManagerMethod::Mint.to_string(), }, - args: scrypto_encode(&input), + args: scrypto_encode(&input).unwrap(), } } }) @@ -532,7 +534,7 @@ fn generate_args( for v in values { let value = generate_value(v, None, resolver, bech32_decoder, blobs)?; - result.push(encode_any(&value)); + result.push(scrypto_encode(&value).map_err(|err| GeneratorError::SborEncodeError(err))?); } Ok(result) } @@ -1136,7 +1138,7 @@ fn generate_singletons( Ok(result) } -fn generate_type_id(ty: &ast::Type) -> ScryptoTypeId { +fn generate_type_id(ty: &ast::Type) -> ScryptoSborTypeId { match ty { ast::Type::Unit => SborTypeId::Unit, ast::Type::Bool => SborTypeId::Bool, @@ -1429,7 +1431,8 @@ mod tests { mint_params: MintParams::Fungible { amount: Decimal::from_str("100").unwrap(), }, - }), + }) + .unwrap(), } ); } diff --git a/transaction/src/model/notarized_transaction.rs b/transaction/src/model/notarized_transaction.rs index 9a0649e7d9b..c6560ce94fd 100644 --- a/transaction/src/model/notarized_transaction.rs +++ b/transaction/src/model/notarized_transaction.rs @@ -87,11 +87,11 @@ impl TransactionIntent { scrypto_decode(slice) } - pub fn hash(&self) -> Hash { - hash(self.to_bytes()) + pub fn hash(&self) -> Result { + Ok(hash(self.to_bytes()?)) } - pub fn to_bytes(&self) -> Vec { + pub fn to_bytes(&self) -> Result, EncodeError> { scrypto_encode(self) } } @@ -101,11 +101,11 @@ impl SignedTransactionIntent { scrypto_decode(slice) } - pub fn hash(&self) -> Hash { - hash(self.to_bytes()) + pub fn hash(&self) -> Result { + Ok(hash(self.to_bytes()?)) } - pub fn to_bytes(&self) -> Vec { + pub fn to_bytes(&self) -> Result, EncodeError> { scrypto_encode(self) } } @@ -115,11 +115,11 @@ impl NotarizedTransaction { scrypto_decode(slice) } - pub fn hash(&self) -> Hash { - hash(self.to_bytes()) + pub fn hash(&self) -> Result { + Ok(hash(self.to_bytes()?)) } - pub fn to_bytes(&self) -> Vec { + pub fn to_bytes(&self) -> Result, EncodeError> { scrypto_encode(self) } } @@ -156,15 +156,15 @@ mod tests { .unwrap(); // sign - let signature1 = sk1.sign(&intent.to_bytes()); - let signature2 = sk2.sign(&intent.to_bytes()); + let signature1 = sk1.sign(&intent.to_bytes().unwrap()); + let signature2 = sk2.sign(&intent.to_bytes().unwrap()); let signed_intent = SignedTransactionIntent { intent, intent_signatures: vec![signature1.into(), signature2.into()], }; // notarize - let signature3 = sk_notary.sign(&signed_intent.to_bytes()); + let signature3 = sk_notary.sign(&signed_intent.to_bytes().unwrap()); let transaction = NotarizedTransaction { signed_intent, notary_signature: signature3.into(), @@ -172,17 +172,17 @@ mod tests { assert_eq!( "c0636352b663182a4bcd3690387172b511610eae13ce7fd62f00e2eec34a3e88", - transaction.signed_intent.intent.hash().to_string() + transaction.signed_intent.intent.hash().unwrap().to_string() ); assert_eq!( "1d2154ffbab367cb0a98cabf56890f69a4a2844f30250952aa2e1cf14f8a3a55", - transaction.signed_intent.hash().to_string() + transaction.signed_intent.hash().unwrap().to_string() ); assert_eq!( "1be1f70513e05603d77cc9baedb76377b9b674de2fc4a52da416b4b172ff4183", - transaction.hash().to_string() + transaction.hash().unwrap().to_string() ); - assert_eq!("1002100210021009070107f20a00000000000000000a64000000000000000a0500000000000000110e4563647361536563703235366b3101b102f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f901000940420f00090500000010022011010d436c656172417574685a6f6e65002020002011020e4563647361536563703235366b3101b200d3212d882d81f25269cdb05b9cb936145edc7e1ee21399235a936da99c230bbe7cd80e97765a11d3f64457e461801b8566033121f0c286c1f14e99c30e3a05710e4563647361536563703235366b3101b200184d480044bbaf9fb6ac8e9c904541304ad419d9aa7b994c179e71038f11d6c26d22a598407ba48181635f2628a57a21c5b11a51217d0fa3d66220f64f9858d6110e4563647361536563703235366b3101b2006ddbba328dcaf36890026851181f958097c96123516b5da53308117bd0f18a0b07b9ac4fb75212f943f375cba524c51b6e2d995f22538dd4b085c36718aa4cdd", hex::encode(scrypto_encode(&transaction))); + assert_eq!("1002100210021009070107f20a00000000000000000a64000000000000000a0500000000000000110e4563647361536563703235366b3101b102f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f901000940420f00090500000010022011010d436c656172417574685a6f6e65002020002011020e4563647361536563703235366b3101b200d3212d882d81f25269cdb05b9cb936145edc7e1ee21399235a936da99c230bbe7cd80e97765a11d3f64457e461801b8566033121f0c286c1f14e99c30e3a05710e4563647361536563703235366b3101b200184d480044bbaf9fb6ac8e9c904541304ad419d9aa7b994c179e71038f11d6c26d22a598407ba48181635f2628a57a21c5b11a51217d0fa3d66220f64f9858d6110e4563647361536563703235366b3101b2006ddbba328dcaf36890026851181f958097c96123516b5da53308117bd0f18a0b07b9ac4fb75212f943f375cba524c51b6e2d995f22538dd4b085c36718aa4cdd", hex::encode(scrypto_encode(&transaction).unwrap())); } #[test] @@ -212,15 +212,15 @@ mod tests { .unwrap(); // sign - let signature1 = (sk1.public_key(), sk1.sign(&intent.to_bytes())); - let signature2 = (sk2.public_key(), sk2.sign(&intent.to_bytes())); + let signature1 = (sk1.public_key(), sk1.sign(&intent.to_bytes().unwrap())); + let signature2 = (sk2.public_key(), sk2.sign(&intent.to_bytes().unwrap())); let signed_intent = SignedTransactionIntent { intent, intent_signatures: vec![signature1.into(), signature2.into()], }; // notarize - let signature3 = sk_notary.sign(&signed_intent.to_bytes()); + let signature3 = sk_notary.sign(&signed_intent.to_bytes().unwrap()); let transaction = NotarizedTransaction { signed_intent, notary_signature: signature3.into(), @@ -228,16 +228,16 @@ mod tests { assert_eq!( "a102722db980a007ba9b1ea2803dbba03257765e1fbcd069c67cf598c0d5c9f6", - transaction.signed_intent.intent.hash().to_string() + transaction.signed_intent.intent.hash().unwrap().to_string() ); assert_eq!( "132d27d73895255e45dce571a404b86a1e7227dacd7ee28cdafadfaaa1bef5b2", - transaction.signed_intent.hash().to_string() + transaction.signed_intent.hash().unwrap().to_string() ); assert_eq!( "c93121d4b0bbdb021a5bff96739f935f0eb051020425c41a34f2fd35c6c4ad62", - transaction.hash().to_string() + transaction.hash().unwrap().to_string() ); - assert_eq!("1002100210021009070107f20a00000000000000000a64000000000000000a0500000000000000110c45646473614564323535313901b3f381626e41e7027ea431bfe3009e94bdd25a746beec468948d6c3c7c5dc9a54b01000940420f00090500000010022011010d436c656172417574685a6f6e65002020002011020c45646473614564323535313902b34cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba29b4b48bd0748ad96da7c3877906fa23896b12686a98e8e72eea584b340e7ddcfcf35699ed7ed9b569277cdb69c47fab29e54b14c8fb732f6d3f7aada1b5366f4c0c0c45646473614564323535313902b37422b9887598068e32c4448a949adb290d0f4e35b9e01b0ee5f1a1e600fe2674b47d2a6a29556500074619b694fc509b2b2eb8e5ba80edc96b51131b6f8f5726cfae774c845271325e746d903145c343dff3cb411c6f3fab2a36fb55b485373e0f110c45646473614564323535313901b4dcd43f70e6b505e9dc498af97fead9bf746ebe05462599b074188d6c180749ad75302e1d3376016a97c793184d5a53128aac0b55e040fbe1f162d64b566cb907", hex::encode(scrypto_encode(&transaction))); + assert_eq!("1002100210021009070107f20a00000000000000000a64000000000000000a0500000000000000110c45646473614564323535313901b3f381626e41e7027ea431bfe3009e94bdd25a746beec468948d6c3c7c5dc9a54b01000940420f00090500000010022011010d436c656172417574685a6f6e65002020002011020c45646473614564323535313902b34cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba29b4b48bd0748ad96da7c3877906fa23896b12686a98e8e72eea584b340e7ddcfcf35699ed7ed9b569277cdb69c47fab29e54b14c8fb732f6d3f7aada1b5366f4c0c0c45646473614564323535313902b37422b9887598068e32c4448a949adb290d0f4e35b9e01b0ee5f1a1e600fe2674b47d2a6a29556500074619b694fc509b2b2eb8e5ba80edc96b51131b6f8f5726cfae774c845271325e746d903145c343dff3cb411c6f3fab2a36fb55b485373e0f110c45646473614564323535313901b4dcd43f70e6b505e9dc498af97fead9bf746ebe05462599b074188d6c180749ad75302e1d3376016a97c793184d5a53128aac0b55e040fbe1f162d64b566cb907", hex::encode(scrypto_encode(&transaction).unwrap())); } } diff --git a/transaction/src/model/preview_transaction.rs b/transaction/src/model/preview_transaction.rs index 35a5880d5f5..f8a48ac9501 100644 --- a/transaction/src/model/preview_transaction.rs +++ b/transaction/src/model/preview_transaction.rs @@ -22,11 +22,11 @@ pub struct PreviewIntent { } impl PreviewIntent { - pub fn hash(&self) -> Hash { - hash(self.to_bytes()) + pub fn hash(&self) -> Result { + Ok(hash(self.to_bytes()?)) } - pub fn to_bytes(&self) -> Vec { + pub fn to_bytes(&self) -> Result, EncodeError> { scrypto_encode(self) } } diff --git a/transaction/src/model/test_transaction.rs b/transaction/src/model/test_transaction.rs index d149bccdc4c..dbb7b17e4ea 100644 --- a/transaction/src/model/test_transaction.rs +++ b/transaction/src/model/test_transaction.rs @@ -34,7 +34,7 @@ impl TestTransaction { } pub fn get_executable<'a>(&'a self, initial_proofs: Vec) -> Executable<'a> { - let transaction_hash = self.transaction.hash(); + let transaction_hash = self.transaction.hash().unwrap(); let intent = &self.transaction.signed_intent.intent; Executable::new( diff --git a/transaction/src/validation/transaction_validator.rs b/transaction/src/validation/transaction_validator.rs index 905c894ff36..e062b6590fd 100644 --- a/transaction/src/validation/transaction_validator.rs +++ b/transaction/src/validation/transaction_validator.rs @@ -1,9 +1,8 @@ use radix_engine_interface::core::NetworkDefinition; -use radix_engine_interface::crypto::PublicKey; +use radix_engine_interface::crypto::{Hash, PublicKey}; use radix_engine_interface::data::*; use sbor::rust::collections::{BTreeSet, HashSet}; -use sbor::Decode; use radix_engine_interface::constants::*; @@ -13,7 +12,7 @@ use crate::validation::*; pub const MAX_PAYLOAD_SIZE: usize = 4 * 1024 * 1024; -pub trait TransactionValidator> { +pub trait TransactionValidator { fn check_length_and_decode_from_slice( &self, transaction: &[u8], @@ -69,16 +68,16 @@ impl TransactionValidator for NotarizedTransactionValidato transaction: &'t NotarizedTransaction, intent_hash_manager: &'a I, ) -> Result, TransactionValidationError> { - self.validate_intent(&transaction.signed_intent.intent, intent_hash_manager)?; + let intent = &transaction.signed_intent.intent; + let intent_hash = intent.hash()?; + + self.validate_intent(&intent_hash, intent, intent_hash_manager)?; let signer_keys = self .validate_signatures(&transaction) .map_err(TransactionValidationError::SignatureValidationError)?; - let transaction_hash = transaction.hash(); - - let intent = &transaction.signed_intent.intent; - let intent_hash = intent.hash(); + let transaction_hash = transaction.hash()?; let header = &intent.header; @@ -118,12 +117,12 @@ impl NotarizedTransactionValidator { preview_intent: &'t PreviewIntent, intent_hash_manager: &'a I, ) -> Result, TransactionValidationError> { - let transaction_hash = preview_intent.hash(); + let transaction_hash = preview_intent.hash()?; let intent = &preview_intent.intent; let flags = &preview_intent.flags; - let intent_hash = intent.hash(); - self.validate_intent(intent, intent_hash_manager)?; + let intent_hash = intent.hash()?; + self.validate_intent(&intent_hash, intent, intent_hash_manager)?; let initial_proofs = AuthModule::pk_non_fungibles(&preview_intent.signer_public_keys); let mut virtualizable_proofs_resource_addresses = BTreeSet::new(); @@ -163,11 +162,12 @@ impl NotarizedTransactionValidator { pub fn validate_intent( &self, + intent_hash: &Hash, intent: &TransactionIntent, intent_hash_manager: &I, ) -> Result<(), TransactionValidationError> { // verify intent hash - if !intent_hash_manager.allows(&intent.hash()) { + if !intent_hash_manager.allows(intent_hash) { return Err(TransactionValidationError::IntentHashRejected); } @@ -314,7 +314,7 @@ impl NotarizedTransactionValidator { // verify intent signature let mut signers = HashSet::new(); - let intent_payload = transaction.signed_intent.intent.to_bytes(); + let intent_payload = transaction.signed_intent.intent.to_bytes()?; for sig in &transaction.signed_intent.intent_signatures { let public_key = recover(&intent_payload, sig) .ok_or(SignatureValidationError::InvalidIntentSignature)?; @@ -333,7 +333,7 @@ impl NotarizedTransactionValidator { } // verify notary signature - let signed_intent_payload = transaction.signed_intent.to_bytes(); + let signed_intent_payload = transaction.signed_intent.to_bytes()?; if !verify( &signed_intent_payload, &transaction.signed_intent.intent.header.notary_public_key,