From 4381102c7e2f79b08abdd6fc1cc99df3eb71f7ae Mon Sep 17 00:00:00 2001 From: David Edey Date: Sat, 19 Nov 2022 19:05:06 +0000 Subject: [PATCH 01/20] refactor: Decode takes a generic Decoder --- radix-engine-interface/src/api/api.rs | 5 +- .../src/data/custom_value.rs | 11 +- .../src/data/indexed_value.rs | 4 +- radix-engine-interface/src/data/mod.rs | 23 +- .../src/data/schema_matcher.rs | 2 +- .../src/data/value_formatter.rs | 2 +- radix-engine-interface/src/macros.rs | 12 +- radix-engine-interface/src/math/decimal.rs | 14 +- radix-engine-interface/src/math/integer.rs | 26 +- .../src/math/precise_decimal.rs | 6 +- .../src/model/resource/non_fungible_id.rs | 12 +- radix-engine-stores/src/rocks_db.rs | 9 +- .../engine/interpreters/native_interpreter.rs | 5 +- .../src/engine/interpreters/wasm_runtime.rs | 6 +- .../src/transaction/transaction_receipt.rs | 4 +- radix-engine/src/types.rs | 2 +- sbor-derive/src/decode.rs | 58 +-- sbor-derive/src/utils.rs | 26 +- sbor-tests/tests/decode.rs | 20 +- sbor-tests/tests/skip.rs | 20 +- sbor/src/basic.rs | 11 +- sbor/src/codec/array.rs | 8 +- sbor/src/codec/boolean.rs | 4 +- sbor/src/codec/collection.rs | 38 +- sbor/src/codec/integer.rs | 20 +- sbor/src/codec/misc.rs | 34 +- sbor/src/codec/option.rs | 6 +- sbor/src/codec/result.rs | 10 +- sbor/src/codec/string.rs | 4 +- sbor/src/codec/tuple.rs | 6 +- sbor/src/codec/unit.rs | 4 +- sbor/src/decode.rs | 327 +--------------- sbor/src/decoder.rs | 363 ++++++++++++++++++ sbor/src/lib.rs | 19 +- sbor/src/path.rs | 14 +- sbor/src/value.rs | 71 ++-- scrypto-derive/src/non_fungible_data.rs | 8 +- scrypto/src/buffer/codec.rs | 4 +- scrypto/src/component/component.rs | 16 +- scrypto/src/component/kv_store.rs | 72 ++-- scrypto/src/component/package.rs | 10 +- scrypto/src/engine/scrypto_env.rs | 10 +- scrypto/src/resource/auth_zone.rs | 34 +- scrypto/src/resource/bucket.rs | 25 +- scrypto/src/resource/proof.rs | 11 +- scrypto/src/resource/vault.rs | 13 +- scrypto/src/runtime/data.rs | 29 +- scrypto/src/runtime/runtime.rs | 9 +- transaction/src/builder/manifest_builder.rs | 3 +- transaction/src/manifest/generator.rs | 4 +- .../src/validation/transaction_validator.rs | 3 +- 51 files changed, 735 insertions(+), 722 deletions(-) create mode 100644 sbor/src/decoder.rs diff --git a/radix-engine-interface/src/api/api.rs b/radix-engine-interface/src/api/api.rs index b06a8bc61fa..ac8141e6f2e 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..14b2a877178 100644 --- a/radix-engine-interface/src/data/custom_value.rs +++ b/radix-engine-interface/src/data/custom_value.rs @@ -39,7 +39,7 @@ pub enum ScryptoCustomValue { NonFungibleId(NonFungibleId), } -impl CustomValue for ScryptoCustomValue { +impl Encode for ScryptoCustomValue { fn encode_type_id(&self, encoder: &mut ScryptoEncoder) { match self { ScryptoCustomValue::PackageAddress(_) => { @@ -142,11 +142,16 @@ impl CustomValue for ScryptoCustomValue { } } } +} +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..210e0f3a577 100644 --- a/radix-engine-interface/src/data/indexed_value.rs +++ b/radix-engine-interface/src/data/indexed_value.rs @@ -51,7 +51,7 @@ impl IndexedScryptoValue { Self::from_typed(&()) } - pub fn from_typed>(value: &T) -> Self { + pub fn from_typed(value: &T) -> Self { let bytes = encode(value); Self::from_slice(&bytes).expect("Failed to convert trusted value into IndexedScryptoValue") } @@ -240,7 +240,7 @@ impl ScryptoCustomValueVisitor { } } -impl CustomValueVisitor for ScryptoCustomValueVisitor { +impl CustomValueVisitor for ScryptoCustomValueVisitor { type Err = ValueIndexingError; fn visit( diff --git a/radix-engine-interface/src/data/mod.rs b/radix-engine-interface/src/data/mod.rs index 2f3a1782b66..505b24ad1e3 100644 --- a/radix-engine-interface/src/data/mod.rs +++ b/radix-engine-interface/src/data/mod.rs @@ -16,7 +16,7 @@ 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, encode, DecodeError}; pub use schema_matcher::*; pub use schema_path::*; pub use value_formatter::*; @@ -24,16 +24,27 @@ pub use value_formatter::*; // TODO: add trait alias for `Encode` and `Decode` as well, once it becomes stable. pub type ScryptoEncoder<'a> = sbor::Encoder<'a, ScryptoCustomTypeId>; -pub type ScryptoDecoder<'a> = sbor::Decoder<'a, ScryptoCustomTypeId>; -pub type ScryptoTypeId = sbor::SborTypeId; +pub type ScryptoDecoder<'a> = sbor::VecDecoder<'a, ScryptoCustomTypeId>; +pub type ScryptoSborTypeId = sbor::SborTypeId; pub type ScryptoValue = sbor::SborValue; +// These trait "aliases" should only be used for parameters, never implementations +// Implementations should implement the underlying traits (TypeId/Encode/Decode) +pub trait ScryptoTypeId: sbor::TypeId {} +impl + ?Sized> ScryptoTypeId for T {} + +pub trait ScryptoDecode: for<'de> sbor::Decode> {} +impl sbor::Decode>> ScryptoDecode for T {} + +pub trait ScryptoEncode: sbor::Encode {} +impl + ?Sized> ScryptoEncode for T {} + /// Encodes a data structure into byte array. -pub fn scrypto_encode + ?Sized>(v: &T) -> Vec { +pub fn scrypto_encode(v: &T) -> Vec { encode(v) } -pub fn scrypto_decode>(buf: &[u8]) -> Result { +pub fn scrypto_decode(buf: &[u8]) -> Result { decode(buf) } @@ -51,7 +62,7 @@ macro_rules! args { use ::sbor::Encode; 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); // Hack: stringify to skip ownership move semantics encoder.write_size(radix_engine_interface::count!($(stringify!($args)),*)); $( 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/macros.rs b/radix-engine-interface/src/macros.rs index 77918f29d6a..ec43d0f55b3 100644 --- a/radix-engine-interface/src/macros.rs +++ b/radix-engine-interface/src/macros.rs @@ -91,9 +91,11 @@ macro_rules! scrypto_type { } } - 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())?; @@ -134,9 +136,11 @@ macro_rules! scrypto_type { } } - 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..f3e8aba8c9b 100644 --- a/radix-engine-interface/src/math/decimal.rs +++ b/radix-engine-interface/src/math/decimal.rs @@ -1045,7 +1045,7 @@ mod tests { #[test] fn test_encode_decimal_type_decimal() { let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::new(&mut bytes); + let mut enc = ScryptoEncoder::new(&mut bytes); dec!("1").encode_type_id(&mut enc); assert_eq!(bytes, vec![Decimal::type_id().as_u8()]); } @@ -1054,7 +1054,7 @@ 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); + let mut enc = ScryptoEncoder::new(&mut bytes); dec.encode_type_id(&mut enc); dec.encode_body(&mut enc); assert_eq!(bytes, { @@ -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); + let mut enc = ScryptoEncoder::new(&mut bytes); dec!("1").encode_type_id(&mut enc); - let mut decoder = Decoder::new(&bytes); + 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); + let mut enc = ScryptoEncoder::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 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..ae85b179a15 100644 --- a/radix-engine-interface/src/math/integer.rs +++ b/radix-engine-interface/src/math/integer.rs @@ -302,9 +302,9 @@ macro_rules! sbor_codec { } } - 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())?; @@ -929,16 +929,16 @@ mod tests { 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()); + 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..19a73c71ac9 100644 --- a/radix-engine-interface/src/math/precise_decimal.rs +++ b/radix-engine-interface/src/math/precise_decimal.rs @@ -1093,7 +1093,7 @@ mod tests { 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 decoder = VecDecoder::new(&bytes); let typ = decoder.read_type_id().unwrap(); assert_eq!(typ, PreciseDecimal::type_id()); } @@ -1105,8 +1105,8 @@ mod tests { 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 decoder = VecDecoder::new(&bytes); + let val = decoder.decode::().unwrap(); assert_eq!(val, pdec!("1.23456789")); } 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..a35cb589251 100644 --- a/radix-engine-interface/src/model/resource/non_fungible_id.rs +++ b/radix-engine-interface/src/model/resource/non_fungible_id.rs @@ -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/rocks_db.rs b/radix-engine-stores/src/rocks_db.rs index d44809be82a..6cfa67f5c07 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 { @@ -119,11 +118,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)); diff --git a/radix-engine/src/engine/interpreters/native_interpreter.rs b/radix-engine/src/engine/interpreters/native_interpreter.rs index 56b9e81b161..ba365edbc68 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 { @@ -124,7 +123,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 0819853b9e3..1bce8c6cc32 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}; /// A glue between system api (call frame and track abstraction) and WASM. /// @@ -299,7 +299,7 @@ where } } -fn encode>(output: T) -> Vec { +fn encode(output: T) -> Vec { scrypto_encode(&output) } 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 809c1c6a3d2..4731f096144 100644 --- a/radix-engine/src/types.rs +++ b/radix-engine/src/types.rs @@ -7,7 +7,7 @@ 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, ScryptoEncode, ScryptoDecode, ScryptoTypeId}; pub use radix_engine_interface::dec; pub use radix_engine_interface::math::{Decimal, RoundingMode, I256}; pub use radix_engine_interface::model::*; diff --git a/sbor-derive/src/decode.rs b/sbor-derive/src/decode.rs index 4635b32f3be..b0048914564 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,13 @@ 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 { + 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 +57,14 @@ 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 { + 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 +77,8 @@ 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 { + 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 +108,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 +121,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 +147,8 @@ 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 { + 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 +191,13 @@ 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 { + 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 +216,13 @@ 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 { + 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 +238,13 @@ 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> { + 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 +260,8 @@ 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 { + 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 +272,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 +296,8 @@ 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 { + 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/utils.rs b/sbor-derive/src/utils.rs index bd97e2bcf94..55db9431f46 100644 --- a/sbor-derive/src/utils.rs +++ b/sbor-derive/src/utils.rs @@ -97,11 +97,33 @@ 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_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/tests/decode.rs b/sbor-tests/tests/decode.rs index ea82b2fbceb..03ad9cf5206 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 = VecDecoder::::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 = VecDecoder::::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 = VecDecoder::::new(&bytes); + let result = decoder.decode::(); assert!(matches!(result, Err(DecodeError::UnknownDiscriminator(_)))); } diff --git a/sbor-tests/tests/skip.rs b/sbor-tests/tests/skip.rs index 8bd84ad6579..d7231c9f8b4 100644 --- a/sbor-tests/tests/skip.rs +++ b/sbor-tests/tests/skip.rs @@ -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 = VecDecoder::::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); @@ -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 = VecDecoder::::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/src/basic.rs b/sbor/src/basic.rs index 0e38737b3b5..8ce14f3e329 100644 --- a/sbor/src/basic.rs +++ b/sbor/src/basic.rs @@ -17,7 +17,7 @@ pub enum NoCustomTypeId {} pub enum NoCustomValue {} pub type BasicEncoder<'a> = Encoder<'a, NoCustomTypeId>; -pub type BasicDecoder<'a> = Decoder<'a, NoCustomTypeId>; +pub type BasicDecoder<'a> = VecDecoder<'a, NoCustomTypeId>; pub type BasicSborValue = SborValue; pub type BasicSborTypeId = SborTypeId; @@ -31,7 +31,7 @@ impl CustomTypeId for NoCustomTypeId { } } -impl CustomValue for NoCustomValue { +impl Encode for NoCustomValue { fn encode_type_id(&self, _encoder: &mut Encoder) { panic!("No custom value") } @@ -39,8 +39,13 @@ impl CustomValue for NoCustomValue { fn encode_body(&self, _encoder: &mut Encoder) { 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..853f083284f 100644 --- a/sbor/src/codec/array.rs +++ b/sbor/src/codec/array.rs @@ -34,9 +34,11 @@ impl + TypeId, const N: usize> Encode for [T } } -impl + TypeId, const N: usize> Decode for [T; N] { +impl, T: Decode + TypeId, const N: usize> Decode + for [T; N] +{ 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 +56,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_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..1cef2b73363 100644 --- a/sbor/src/codec/boolean.rs +++ b/sbor/src/codec/boolean.rs @@ -12,9 +12,9 @@ impl Encode for bool { } } -impl Decode for bool { +impl> Decode for bool { 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..f79c1cd60b3 100644 --- a/sbor/src/codec/collection.rs +++ b/sbor/src/codec/collection.rs @@ -85,9 +85,9 @@ impl + TypeId + Ord + Hash, V: Encode + Type } } -impl + TypeId> Decode for Vec { +impl, T: Decode + TypeId> Decode for Vec { 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 +105,18 @@ 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_body_with_type_id(element_type_id)?); } Ok(result) } } } -impl + TypeId + Ord> Decode for BTreeSet { +impl, T: Decode + TypeId + Ord> Decode + for BTreeSet +{ 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 +125,11 @@ impl + TypeId + Ord> Decode for BTreeSet } } -impl + TypeId + Hash + Eq> Decode for HashSet { +impl, T: Decode + TypeId + Hash + Eq> Decode + for HashSet +{ 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 +138,15 @@ impl + TypeId + Hash + Eq> Decode for HashSe } } -impl + TypeId + Ord, V: Decode + TypeId> Decode - for BTreeMap +impl< + X: CustomTypeId, + D: Decoder, + K: Decode + TypeId + Ord, + V: Decode + TypeId, + > Decode for BTreeMap { 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 +155,15 @@ impl + TypeId + Ord, V: Decode + TypeId> } } -impl + TypeId + Hash + Eq, V: Decode + TypeId> Decode - for HashMap +impl< + X: CustomTypeId, + D: Decoder, + K: Decode + TypeId + Hash + Eq, + V: Decode + TypeId, + > Decode for HashMap { 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..d315ca7645e 100644 --- a/sbor/src/codec/integer.rs +++ b/sbor/src/codec/integer.rs @@ -69,9 +69,9 @@ impl Encode for usize { } } -impl Decode for i8 { +impl> Decode for i8 { 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 +80,9 @@ impl Decode for i8 { } } -impl Decode for u8 { +impl> Decode for u8 { 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 +93,9 @@ impl Decode for u8 { macro_rules! decode_int { ($type:ident, $type_id:ident, $n:expr) => { - impl Decode for $type { + impl> Decode for $type { 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 +117,9 @@ 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 { 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 +127,9 @@ impl Decode for isize { } } -impl Decode for usize { +impl> Decode for usize { 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..eaa59f58273 100644 --- a/sbor/src/codec/misc.rs +++ b/sbor/src/codec/misc.rs @@ -41,48 +41,40 @@ impl + TypeId> Encode for RefCell { } } -impl<'a, X: CustomTypeId, B: ?Sized + 'a + ToOwned, O: Decode + TypeId> Decode - for Cow<'a, B> +impl<'a, X: CustomTypeId, D: Decoder, B: ?Sized + 'a + ToOwned, O: Decode> + Decode for Cow<'a, B> { 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 { 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 { 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 { 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..57ab9b4a921 100644 --- a/sbor/src/codec/option.rs +++ b/sbor/src/codec/option.rs @@ -23,9 +23,9 @@ impl + TypeId> Encode for Option { } } -impl> Decode for Option { +impl, T: Decode> Decode for Option { 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 +34,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..d1419879248 100644 --- a/sbor/src/codec/result.rs +++ b/sbor/src/codec/result.rs @@ -24,11 +24,11 @@ impl, E: Encode> Encode for Result { } } -impl + TypeId, E: Decode + TypeId> Decode - for Result +impl, T: Decode + TypeId, E: Decode + TypeId> + Decode for Result { 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 +36,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..5de28f6480f 100644 --- a/sbor/src/codec/string.rs +++ b/sbor/src/codec/string.rs @@ -37,9 +37,9 @@ impl Encode for String { } } -impl Decode for String { +impl> Decode for String { 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..43453135dca 100644 --- a/sbor/src/codec/tuple.rs +++ b/sbor/src/codec/tuple.rs @@ -30,12 +30,12 @@ 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,)+) { + 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>()?),+)) } } }; diff --git a/sbor/src/codec/unit.rs b/sbor/src/codec/unit.rs index 24739fbc3b3..8a231e8bf2f 100644 --- a/sbor/src/codec/unit.rs +++ b/sbor/src/codec/unit.rs @@ -12,9 +12,9 @@ impl Encode for () { } } -impl Decode for () { +impl> Decode for () { 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..e19c614fc0f 100644 --- a/sbor/src/decode.rs +++ b/sbor/src/decode.rs @@ -1,332 +1,11 @@ -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) - } - +pub trait Decode>: Sized { /// Decodes from the byte array encapsulated by the given decoder, with a preloaded type id. 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..dc423b1018a --- /dev/null +++ b/sbor/src/decoder.rs @@ -0,0 +1,363 @@ +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, + + InvalidCustomValue, // TODO: generify custom error codes +} + +pub trait Decoder: Sized { + fn decode>(&mut self) -> Result { + let type_id = self.read_type_id()?; + self.decode_body_with_type_id(type_id) + } + + fn decode_body_with_type_id>( + &mut self, + type_id: SborTypeId, + ) -> Result { + self.track_decode_depth_increase()?; + let decoded = T::decode_body_with_type_id(self, type_id)?; + self.track_decode_depth_decrease(); + Ok(decoded) + } + + 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) + } + + 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(), + }) + } + } + + 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) + } + + 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 track_decode_depth_increase(&mut self) -> Result<(), DecodeError>; + + fn track_decode_depth_decrease(&mut self); + + 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> { + input: &'de [u8], + offset: usize, + phantom: PhantomData, +} + +impl<'de, X: CustomTypeId> VecDecoder<'de, X> { + pub fn new(input: &'de [u8]) -> Self { + Self { + input, + offset: 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 + } +} + +impl<'de, X: CustomTypeId> Decoder for VecDecoder<'de, X> { + #[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(()) + } + } + + #[inline] + fn track_decode_depth_increase(&mut self) -> Result<(), DecodeError> { + // TODO + Ok(()) + } + + #[inline] + fn track_decode_depth_decrease(&mut self) { + // TODO + } +} + +#[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 = VecDecoder::::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 = VecDecoder::::new(&[0xff, 0xff, 0xff, 0xff, 0x00]); + assert_eq!(dec.read_size(), Err(DecodeError::SizeTooLarge)); + } + + fn assert_decoding(dec: &mut VecDecoder) { + 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 = VecDecoder::::new(&bytes); + assert_decoding(&mut dec); + } + + #[test] + pub fn test_decode_box() { + let bytes = vec![7u8, 5u8]; + let mut dec = VecDecoder::::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 = VecDecoder::::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 = VecDecoder::::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 enc = Encoder::::new(&mut bytes); + value1.encode(&mut enc); + + let mut dec = VecDecoder::::new(&bytes); + let value2 = dec.decode::<[NFA; 2]>().unwrap(); + assert_eq!(value1, value2); + } +} diff --git a/sbor/src/lib.rs b/sbor/src/lib.rs index 8d40a9d1aa1..daea721b6ed 100644 --- a/sbor/src/lib.rs +++ b/sbor/src/lib.rs @@ -11,8 +11,10 @@ pub mod basic; pub mod codec; /// SBOR constants pub mod constants; -/// SBOR decoding. +/// SBOR decode trait. pub mod decode; +/// SBOR decoding. +pub mod decoder; /// SBOR encoding. pub mod encode; /// SBOR paths. @@ -26,7 +28,8 @@ pub mod value; pub use basic::*; pub use constants::*; -pub use decode::{Decode, DecodeError, Decoder}; +pub use decode::Decode; +pub use decoder::{DecodeError, Decoder, VecDecoder}; pub use encode::{Encode, Encoder}; pub use path::{SborPath, SborPathBuf}; pub use type_id::*; @@ -41,11 +44,13 @@ pub fn encode + ?Sized>(v: &T) -> crate::rust::vec } /// 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) +pub fn decode Decode>>( + buf: &[u8], +) -> Result { + let mut decoder = VecDecoder::new(buf); + let value = decoder.decode()?; + decoder.check_end()?; + Ok(value) } // Re-export derives 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/value.rs b/sbor/src/value.rs index c0678aad658..6625ce8d71d 100644 --- a/sbor/src/value.rs +++ b/sbor/src/value.rs @@ -1,4 +1,5 @@ use crate::decode::*; +use crate::decoder::*; use crate::encode::*; use crate::path::SborPathBuf; use crate::rust::fmt::Debug; @@ -6,21 +7,14 @@ 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; -} - +/// CV is CustomValue #[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, @@ -60,35 +54,34 @@ pub enum SborValue> { }, Struct { - fields: Vec>, + fields: Vec>, }, Enum { discriminator: String, - fields: Vec>, + fields: Vec>, }, Array { element_type_id: SborTypeId, - elements: Vec>, + elements: Vec>, }, Tuple { - elements: Vec>, + elements: Vec>, }, - Custom { - value: Y, + value: CV, }, } /// Encodes any SBOR value into byte array. -pub fn encode_any>(value: &SborValue) -> Vec { +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, +pub fn encode_any_with_buffer>( + value: &SborValue, buffer: &mut Vec, ) { let mut encoder = ::sbor::Encoder::new(buffer); @@ -96,8 +89,8 @@ pub fn encode_any_with_buffer>( encode_body(value, &mut encoder); } -fn encode_type_id>( - value: &SborValue, +fn encode_type_id>( + value: &SborValue, encoder: &mut Encoder, ) { match value { @@ -122,10 +115,7 @@ fn encode_type_id>( } } -fn encode_body>( - value: &SborValue, - encoder: &mut Encoder, -) { +fn encode_body>(value: &SborValue, encoder: &mut Encoder) { match value { SborValue::Unit => { ().encode_body(encoder); @@ -209,20 +199,20 @@ fn encode_body>( } /// Decode any SBOR data. -pub fn decode_any>( +pub fn decode_any Decode>>( data: &[u8], -) -> Result, DecodeError> { - let mut decoder = Decoder::new(data); +) -> Result, DecodeError> { + let mut decoder = VecDecoder::new(data); let type_id = decoder.read_type_id()?; - let result = decode_body_with_type_id(type_id, &mut decoder); + let result = decode_body_with_type_id(type_id, &mut decoder)?; decoder.check_end()?; - result + Ok(result) } -fn decode_body_with_type_id>( +fn decode_body_with_type_id, D: Decoder>( type_id: SborTypeId, - decoder: &mut Decoder, -) -> Result, DecodeError> { + decoder: &mut D, +) -> Result, DecodeError> { match type_id { // primitive types SborTypeId::Unit => { @@ -320,20 +310,17 @@ fn decode_body_with_type_id>( } Ok(SborValue::Tuple { elements }) } - SborTypeId::Custom(type_id) => Ok(SborValue::Custom { - value: Y::decode_body_with_type_id(decoder, type_id)?, + SborTypeId::Custom(_) => Ok(SborValue::Custom { + value: decoder.decode_body_with_type_id(type_id)?, }), } } -pub fn traverse_any, V, E>( +pub fn traverse_any, E>( path: &mut SborPathBuf, - value: &SborValue, + value: &SborValue, visitor: &mut V, -) -> Result<(), E> -where - V: CustomValueVisitor, -{ +) -> Result<(), E> { match value { // primitive types SborValue::Unit @@ -381,10 +368,10 @@ where Ok(()) } -pub trait CustomValueVisitor> { +pub trait CustomValueVisitor { type Err; - fn visit(&mut self, path: &mut SborPathBuf, value: &Y) -> Result<(), Self::Err>; + fn visit(&mut self, path: &mut SborPathBuf, value: &CV) -> Result<(), Self::Err>; } #[cfg(test)] diff --git a/scrypto-derive/src/non_fungible_data.rs b/scrypto-derive/src/non_fungible_data.rs index c0f711d1fe6..ea4ba63ae09 100644 --- a/scrypto-derive/src/non_fungible_data.rs +++ b/scrypto-derive/src/non_fungible_data.rs @@ -46,17 +46,17 @@ 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); + let mut decoder_nm = VecDecoder::new(immutable_data); decoder_nm.read_and_check_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct)?; decoder_nm.read_and_check_size(#im_n)?; - let mut decoder_m = Decoder::new(mutable_data); + let mut decoder_m = VecDecoder::new(mutable_data); decoder_m.read_and_check_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::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()?; diff --git a/scrypto/src/buffer/codec.rs b/scrypto/src/buffer/codec.rs index 79182e82ee9..899d22b134e 100644 --- a/scrypto/src/buffer/codec.rs +++ b/scrypto/src/buffer/codec.rs @@ -6,13 +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 { +pub fn scrypto_encode_to_buffer(v: &T) -> *mut u8 { let bytes = scrypto_encode(v); scrypto_alloc_initialized(bytes) } /// Decode a data structure from a Scrypto buffer. -pub fn scrypto_decode_from_buffer + ?Sized>( +pub fn scrypto_decode_from_buffer( ptr: *mut u8, ) -> Result { scrypto_consume(ptr, |slice| scrypto_decode(slice)) diff --git a/scrypto/src/component/component.rs b/scrypto/src/component/component.rs index e662747a713..f9de1142909 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; } @@ -59,7 +59,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( @@ -98,7 +98,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, @@ -118,7 +118,7 @@ impl Component { self.sys_globalize(&mut ScryptoEnv).unwrap() } - pub fn sys_globalize>( + pub fn sys_globalize( self, sys_calls: &mut Y, ) -> Result @@ -136,7 +136,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..278a1aab78c 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; @@ -129,10 +122,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 +139,7 @@ impl< } } -impl< - K: Encode + Decode, - V: Encode + Decode, - > KeyValueStore -{ +impl KeyValueStore { pub fn to_vec(&self) -> Vec { self.id.to_vec() } @@ -160,21 +147,17 @@ 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 +impl Encode + for KeyValueStore { #[inline] fn encode_type_id(&self, encoder: &mut ScryptoEncoder) { @@ -188,13 +171,14 @@ impl< } 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 +186,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 +201,8 @@ impl< // text //====== -impl< - K: Encode + Decode, - V: Encode + Decode, - > FromStr for KeyValueStore +impl FromStr + for KeyValueStore { type Err = ParseKeyValueStoreError; @@ -233,20 +213,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/engine/scrypto_env.rs b/scrypto/src/engine/scrypto_env.rs index a5f5b09352b..a1f43796380 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,7 +18,7 @@ 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 { @@ -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/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/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..25ec2b909c2 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,7 +64,7 @@ impl> DataRefMut { } } -impl> Drop for DataRefMut { +impl Drop for DataRefMut { fn drop(&mut self) { let mut syscalls = ScryptoEnv; let bytes = scrypto_encode(&self.value); @@ -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/transaction/src/builder/manifest_builder.rs b/transaction/src/builder/manifest_builder.rs index 654c51b3b4c..14dd6edfb00 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; @@ -1108,7 +1107,7 @@ impl ManifestBuilder { arg: &str, ) -> Result, BuildArgsError> where - T: FromStr + Encode, + T: FromStr + ScryptoEncode, T::Err: fmt::Debug, { let value = arg diff --git a/transaction/src/manifest/generator.rs b/transaction/src/manifest/generator.rs index 9d6f2dcd9f8..2466b051a75 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::{ args, scrypto_decode, scrypto_encode, IndexedScryptoValue, ScryptoCustomTypeId, - ScryptoCustomValue, ScryptoTypeId, ScryptoValue, + ScryptoCustomValue, ScryptoSborTypeId, ScryptoValue, }; use radix_engine_interface::math::{Decimal, PreciseDecimal}; use radix_engine_interface::model::*; @@ -1136,7 +1136,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, diff --git a/transaction/src/validation/transaction_validator.rs b/transaction/src/validation/transaction_validator.rs index 905c894ff36..0644153e5a7 100644 --- a/transaction/src/validation/transaction_validator.rs +++ b/transaction/src/validation/transaction_validator.rs @@ -3,7 +3,6 @@ use radix_engine_interface::crypto::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], From ba7cc386d947498470df94fe5f5ba7a9bd94ed85 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sat, 19 Nov 2022 20:26:27 +0000 Subject: [PATCH 02/20] feat: Decoder has a const max stack depth --- radix-engine-interface/src/data/mod.rs | 4 +- .../src/math/precise_decimal.rs | 4 +- radix-engine/src/types.rs | 4 +- sbor-tests/tests/decode.rs | 6 +- sbor-tests/tests/skip.rs | 4 +- sbor/src/basic.rs | 2 +- sbor/src/decoder.rs | 36 +- sbor/src/lib.rs | 6 +- sbor/src/value.rs | 518 ++++++++++-------- scrypto-derive/src/non_fungible_data.rs | 4 +- scrypto/src/buffer/codec.rs | 4 +- transaction/src/builder/manifest_builder.rs | 2 +- 12 files changed, 336 insertions(+), 258 deletions(-) diff --git a/radix-engine-interface/src/data/mod.rs b/radix-engine-interface/src/data/mod.rs index 505b24ad1e3..43e8c70a82b 100644 --- a/radix-engine-interface/src/data/mod.rs +++ b/radix-engine-interface/src/data/mod.rs @@ -21,10 +21,10 @@ 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 = 32; pub type ScryptoEncoder<'a> = sbor::Encoder<'a, ScryptoCustomTypeId>; -pub type ScryptoDecoder<'a> = sbor::VecDecoder<'a, ScryptoCustomTypeId>; +pub type ScryptoDecoder<'a> = sbor::VecDecoder<'a, ScryptoCustomTypeId, MAX_SCRYPTO_SBOR_DEPTH>; pub type ScryptoSborTypeId = sbor::SborTypeId; pub type ScryptoValue = sbor::SborValue; diff --git a/radix-engine-interface/src/math/precise_decimal.rs b/radix-engine-interface/src/math/precise_decimal.rs index 19a73c71ac9..8491e897899 100644 --- a/radix-engine-interface/src/math/precise_decimal.rs +++ b/radix-engine-interface/src/math/precise_decimal.rs @@ -1093,7 +1093,7 @@ mod tests { let mut bytes = Vec::with_capacity(512); let mut enc = Encoder::new(&mut bytes); pdec!("1").encode_type_id(&mut enc); - let mut decoder = VecDecoder::new(&bytes); + let mut decoder = ScryptoDecoder::new(&bytes); let typ = decoder.read_type_id().unwrap(); assert_eq!(typ, PreciseDecimal::type_id()); } @@ -1105,7 +1105,7 @@ mod tests { let mut enc = Encoder::new(&mut bytes); pdec.encode_type_id(&mut enc); pdec.encode_body(&mut enc); - let mut decoder = VecDecoder::new(&bytes); + let mut decoder = ScryptoDecoder::new(&bytes); let val = decoder.decode::().unwrap(); assert_eq!(val, pdec!("1.23456789")); } diff --git a/radix-engine/src/types.rs b/radix-engine/src/types.rs index 4731f096144..489253f0894 100644 --- a/radix-engine/src/types.rs +++ b/radix-engine/src/types.rs @@ -7,7 +7,9 @@ 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, ScryptoEncode, ScryptoDecode, ScryptoTypeId}; +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::*; diff --git a/sbor-tests/tests/decode.rs b/sbor-tests/tests/decode.rs index 03ad9cf5206..b6e37217004 100644 --- a/sbor-tests/tests/decode.rs +++ b/sbor-tests/tests/decode.rs @@ -40,7 +40,7 @@ fn test_decode_struct() { 0, // number of fields ]; - let mut decoder = VecDecoder::::new(&bytes); + let mut decoder = BasicDecoder::new(&bytes); let a = decoder.decode::().unwrap(); let b = decoder.decode::().unwrap(); let c = decoder.decode::().unwrap(); @@ -73,7 +73,7 @@ fn test_decode_enum() { 0, // number of fields ]; - let mut decoder = VecDecoder::::new(&bytes); + let mut decoder = BasicDecoder::new(&bytes); let a = decoder.decode::().unwrap(); let b = decoder.decode::().unwrap(); let c = decoder.decode::().unwrap(); @@ -95,7 +95,7 @@ fn test_decode_empty_enum() { 9, 3, 0, 0, 0, // field value ]; - let mut decoder = VecDecoder::::new(&bytes); + let mut decoder = BasicDecoder::new(&bytes); let result = decoder.decode::(); assert!(matches!(result, Err(DecodeError::UnknownDiscriminator(_)))); diff --git a/sbor-tests/tests/skip.rs b/sbor-tests/tests/skip.rs index d7231c9f8b4..07f81d3f527 100644 --- a/sbor-tests/tests/skip.rs +++ b/sbor-tests/tests/skip.rs @@ -58,7 +58,7 @@ fn test_struct_with_skip() { bytes ); - let mut decoder = VecDecoder::::new(&bytes); + let mut decoder = BasicDecoder::new(&bytes); let a = decoder.decode::().unwrap(); let b = decoder.decode::().unwrap(); let c = decoder.decode::().unwrap(); @@ -103,7 +103,7 @@ fn test_enum_with_skip() { bytes ); - let mut decoder = VecDecoder::::new(&bytes); + let mut decoder = BasicDecoder::new(&bytes); let a = decoder.decode::().unwrap(); let b = decoder.decode::().unwrap(); let c = decoder.decode::().unwrap(); diff --git a/sbor/src/basic.rs b/sbor/src/basic.rs index 8ce14f3e329..4900302dce6 100644 --- a/sbor/src/basic.rs +++ b/sbor/src/basic.rs @@ -17,7 +17,7 @@ pub enum NoCustomTypeId {} pub enum NoCustomValue {} pub type BasicEncoder<'a> = Encoder<'a, NoCustomTypeId>; -pub type BasicDecoder<'a> = VecDecoder<'a, NoCustomTypeId>; +pub type BasicDecoder<'a> = DefaultVecDecoder<'a, NoCustomTypeId>; pub type BasicSborValue = SborValue; pub type BasicSborTypeId = SborTypeId; diff --git a/sbor/src/decoder.rs b/sbor/src/decoder.rs index dc423b1018a..e866d7e34e8 100644 --- a/sbor/src/decoder.rs +++ b/sbor/src/decoder.rs @@ -28,6 +28,8 @@ pub enum DecodeError { SizeTooLarge, + MaxDepthExceeded(u8), + InvalidCustomValue, // TODO: generify custom error codes } @@ -122,18 +124,23 @@ pub trait Decoder: Sized { fn read_slice(&mut self, n: usize) -> Result<&[u8], DecodeError>; } +pub const DEFAULT_MAX_DEPTH: u8 = 32; +pub type DefaultVecDecoder<'de, X> = VecDecoder<'de, X, DEFAULT_MAX_DEPTH>; + /// A `Decoder` abstracts the logic for decoding basic types. -pub struct VecDecoder<'de, X: CustomTypeId> { +pub struct VecDecoder<'de, X: CustomTypeId, const MAX_DEPTH: u8> { input: &'de [u8], offset: usize, + decoder_stack_depth: u8, phantom: PhantomData, } -impl<'de, X: CustomTypeId> VecDecoder<'de, X> { +impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> VecDecoder<'de, X, MAX_DEPTH> { pub fn new(input: &'de [u8]) -> Self { Self { input, offset: 0, + decoder_stack_depth: 0, phantom: PhantomData, } } @@ -156,7 +163,7 @@ impl<'de, X: CustomTypeId> VecDecoder<'de, X> { } } -impl<'de, X: CustomTypeId> Decoder for VecDecoder<'de, X> { +impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> Decoder for VecDecoder<'de, X, MAX_DEPTH> { #[inline] fn read_byte(&mut self) -> Result { self.require_remaining(1)?; @@ -185,13 +192,16 @@ impl<'de, X: CustomTypeId> Decoder for VecDecoder<'de, X> { #[inline] fn track_decode_depth_increase(&mut self) -> Result<(), DecodeError> { - // TODO + self.decoder_stack_depth += 1; + if self.decoder_stack_depth > MAX_DEPTH { + return Err(DecodeError::MaxDepthExceeded(MAX_DEPTH)); + } Ok(()) } #[inline] fn track_decode_depth_decrease(&mut self) { - // TODO + self.decoder_stack_depth -= 1; } } @@ -215,7 +225,7 @@ mod tests { let mut enc = Encoder::::new(&mut bytes); enc.write_size(size); - let mut dec = VecDecoder::::new(&bytes); + let mut dec = BasicDecoder::new(&bytes); dec.read_and_check_size(size)?; dec.check_end()?; Ok(()) @@ -237,11 +247,11 @@ mod tests { #[test] pub fn test_vlq_too_large() { - let mut dec = VecDecoder::::new(&[0xff, 0xff, 0xff, 0xff, 0x00]); + let mut dec = BasicDecoder::new(&[0xff, 0xff, 0xff, 0xff, 0x00]); assert_eq!(dec.read_size(), Err(DecodeError::SizeTooLarge)); } - fn assert_decoding(dec: &mut VecDecoder) { + fn assert_decoding(dec: &mut BasicDecoder) { dec.decode::<()>().unwrap(); assert_eq!(true, dec.decode::().unwrap()); assert_eq!(1, dec.decode::().unwrap()); @@ -304,14 +314,14 @@ mod tests { 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 = VecDecoder::::new(&bytes); + let mut dec = BasicDecoder::new(&bytes); assert_decoding(&mut dec); } #[test] pub fn test_decode_box() { let bytes = vec![7u8, 5u8]; - let mut dec = VecDecoder::::new(&bytes); + let mut dec = BasicDecoder::new(&bytes); let x = dec.decode::>().unwrap(); assert_eq!(Box::new(5u8), x); } @@ -319,7 +329,7 @@ mod tests { #[test] pub fn test_decode_rc() { let bytes = vec![7u8, 5u8]; - let mut dec = VecDecoder::::new(&bytes); + let mut dec = BasicDecoder::new(&bytes); let x = dec.decode::>().unwrap(); assert_eq!(Rc::new(5u8), x); } @@ -327,7 +337,7 @@ mod tests { #[test] pub fn test_decode_ref_cell() { let bytes = vec![7u8, 5u8]; - let mut dec = VecDecoder::::new(&bytes); + let mut dec = BasicDecoder::new(&bytes); let x = dec.decode::>().unwrap(); assert_eq!(RefCell::new(5u8), x); } @@ -356,7 +366,7 @@ mod tests { let mut enc = Encoder::::new(&mut bytes); value1.encode(&mut enc); - let mut dec = VecDecoder::::new(&bytes); + let mut dec = BasicDecoder::new(&bytes); let value2 = dec.decode::<[NFA; 2]>().unwrap(); assert_eq!(value1, value2); } diff --git a/sbor/src/lib.rs b/sbor/src/lib.rs index daea721b6ed..7d1e4783ff8 100644 --- a/sbor/src/lib.rs +++ b/sbor/src/lib.rs @@ -29,7 +29,7 @@ pub mod value; pub use basic::*; pub use constants::*; pub use decode::Decode; -pub use decoder::{DecodeError, Decoder, VecDecoder}; +pub use decoder::{DecodeError, Decoder, DefaultVecDecoder, VecDecoder}; pub use encode::{Encode, Encoder}; pub use path::{SborPath, SborPathBuf}; pub use type_id::*; @@ -44,10 +44,10 @@ pub fn encode + ?Sized>(v: &T) -> crate::rust::vec } /// Decode an instance of `T` from a slice. -pub fn decode Decode>>( +pub fn decode Decode>>( buf: &[u8], ) -> Result { - let mut decoder = VecDecoder::new(buf); + let mut decoder = DefaultVecDecoder::new(buf); let value = decoder.decode()?; decoder.check_end()?; Ok(value) diff --git a/sbor/src/value.rs b/sbor/src/value.rs index 6625ce8d71d..25776d5f4ec 100644 --- a/sbor/src/value.rs +++ b/sbor/src/value.rs @@ -72,6 +72,217 @@ pub enum SborValue { }, } +impl> Encode for SborValue { + fn encode_type_id(&self, encoder: &mut Encoder) { + 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(&self, encoder: &mut Encoder) { + match self { + 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 { + field.encode(encoder); + } + } + SborValue::Enum { + discriminator, + fields, + } => { + encoder.write_discriminator(discriminator); + encoder.write_size(fields.len()); + for field in fields { + field.encode(encoder); + } + } + SborValue::Array { + element_type_id, + elements, + } => { + encoder.write_type_id(element_type_id.clone()); + encoder.write_size(elements.len()); + for item in elements { + item.encode_body(encoder); + } + } + SborValue::Tuple { elements } => { + encoder.write_size(elements.len()); + for field in elements { + field.encode(encoder); + } + } + // custom + SborValue::Custom { value } => { + value.encode_body(encoder); + } + } + } +} + +impl, CV: Decode> Decode for SborValue { + fn decode_body_with_type_id( + decoder: &mut D, + type_id: SborTypeId, + ) -> Result { + match type_id { + // primitive types + SborTypeId::Unit => { + decoder.decode_body_with_type_id::<()>(type_id)?; + Ok(SborValue::Unit) + } + SborTypeId::Bool => Ok(SborValue::Bool { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::I8 => Ok(SborValue::I8 { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::I16 => Ok(SborValue::I16 { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::I32 => Ok(SborValue::I32 { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::I64 => Ok(SborValue::I64 { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::I128 => Ok(SborValue::I128 { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::U8 => Ok(SborValue::U8 { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::U16 => Ok(SborValue::U16 { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::U32 => Ok(SborValue::U32 { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::U64 => Ok(SborValue::U64 { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::U128 => Ok(SborValue::U128 { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + SborTypeId::String => Ok(SborValue::String { + value: decoder.decode_body_with_type_id::(type_id)?, + }), + // struct & enum + SborTypeId::Struct => { + // number of fields + let len = decoder.read_size()?; + // fields + let mut fields = Vec::new(); + for _ in 0..len { + fields.push(decoder.decode()?); + } + Ok(SborValue::Struct { fields }) + } + SborTypeId::Enum => { + // discriminator + let discriminator = decoder.decode_body_with_type_id::(String::type_id())?; + // number of fields + let len = decoder.read_size()?; + // fields + let mut fields = Vec::new(); + for _ in 0..len { + fields.push(decoder.decode()?); + } + Ok(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(decoder.decode_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::new(); + for _ in 0..len { + elements.push(decoder.decode()?); + } + Ok(SborValue::Tuple { elements }) + } + SborTypeId::Custom(_) => Ok(SborValue::Custom { + value: decoder.decode_body_with_type_id(type_id)?, + }), + } + } +} + /// Encodes any SBOR value into byte array. pub fn encode_any>(value: &SborValue) -> Vec { let mut bytes = Vec::new(); @@ -85,235 +296,17 @@ pub fn encode_any_with_buffer>( 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), - } -} - -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); - } - } - 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::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::Tuple { elements } => { - encoder.write_size(elements.len()); - for e in elements { - encode_type_id(e, encoder); - encode_body(e, encoder); - } - } - // custom - SborValue::Custom { value } => { - value.encode_body(encoder); - } - } + value.encode(&mut encoder); } /// Decode any SBOR data. -pub fn decode_any Decode>>( +pub fn decode_any Decode>>( data: &[u8], ) -> Result, DecodeError> { - let mut decoder = VecDecoder::new(data); - let type_id = decoder.read_type_id()?; - let result = decode_body_with_type_id(type_id, &mut decoder)?; + let mut decoder = DefaultVecDecoder::new(data); + let value = decoder.decode()?; decoder.check_end()?; - Ok(result) -} - -fn decode_body_with_type_id, D: Decoder>( - type_id: SborTypeId, - decoder: &mut D, -) -> 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)?); - } - 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)?); - } - Ok(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)?); - } - Ok(SborValue::Array { - element_type_id, - elements, - }) - } - 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(SborValue::Tuple { elements }) - } - SborTypeId::Custom(_) => Ok(SborValue::Custom { - value: decoder.decode_body_with_type_id(type_id)?, - }), - } + Ok(value) } pub fn traverse_any, E>( @@ -564,8 +557,83 @@ 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); + value.encode(&mut enc); assert_eq!(bytes2, bytes); } + + #[test] + pub fn test_max_depth_array_decode_behaviour() { + let allowable_payload = encode_array_of_depth(DEFAULT_MAX_DEPTH); + let allowable_result = decode_any::(&allowable_payload); + assert!(allowable_result.is_ok()); + + let forbidden_payload = encode_array_of_depth(DEFAULT_MAX_DEPTH + 1); + let forbidden_result = decode_any::(&forbidden_payload); + assert!(forbidden_result.is_err()); + } + + #[test] + pub fn test_max_depth_struct_decode_behaviour() { + let allowable_payload = encode_struct_of_depth(DEFAULT_MAX_DEPTH); + let allowable_result = decode_any::(&allowable_payload); + assert!(allowable_result.is_ok()); + + let forbidden_payload = encode_struct_of_depth(DEFAULT_MAX_DEPTH + 1); + let forbidden_result = decode_any::(&forbidden_payload); + assert!(forbidden_result.is_err()); + } + + #[test] + pub fn test_max_depth_tuple_decode_behaviour() { + let allowable_payload = encode_tuple_of_depth(DEFAULT_MAX_DEPTH); + let allowable_result = decode_any::(&allowable_payload); + assert!(allowable_result.is_ok()); + + let forbidden_payload = encode_tuple_of_depth(DEFAULT_MAX_DEPTH + 1); + let forbidden_result = decode_any::(&forbidden_payload); + assert!(forbidden_result.is_err()); + } + + pub fn encode_array_of_depth(depth: u8) -> Vec { + 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); + buf + } + + pub fn encode_struct_of_depth(depth: u8) -> Vec { + 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); + buf + } + + pub fn encode_tuple_of_depth(depth: u8) -> Vec { + 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); + buf + } } diff --git a/scrypto-derive/src/non_fungible_data.rs b/scrypto-derive/src/non_fungible_data.rs index ea4ba63ae09..cb2c10881ea 100644 --- a/scrypto-derive/src/non_fungible_data.rs +++ b/scrypto-derive/src/non_fungible_data.rs @@ -46,11 +46,11 @@ 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 = VecDecoder::new(immutable_data); + let mut decoder_nm = ScryptoDecoder::new(immutable_data); decoder_nm.read_and_check_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct)?; decoder_nm.read_and_check_size(#im_n)?; - let mut decoder_m = VecDecoder::new(mutable_data); + let mut decoder_m = ScryptoDecoder::new(mutable_data); decoder_m.read_and_check_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct)?; decoder_m.read_and_check_size(#m_n)?; diff --git a/scrypto/src/buffer/codec.rs b/scrypto/src/buffer/codec.rs index 899d22b134e..2eaa453aba1 100644 --- a/scrypto/src/buffer/codec.rs +++ b/scrypto/src/buffer/codec.rs @@ -12,9 +12,7 @@ pub fn scrypto_encode_to_buffer(v: &T) -> *mut u8 { } /// Decode a data structure from a Scrypto buffer. -pub fn scrypto_decode_from_buffer( - ptr: *mut u8, -) -> Result { +pub fn scrypto_decode_from_buffer(ptr: *mut u8) -> Result { scrypto_consume(ptr, |slice| scrypto_decode(slice)) } diff --git a/transaction/src/builder/manifest_builder.rs b/transaction/src/builder/manifest_builder.rs index 14dd6edfb00..41b1ebbfdc5 100644 --- a/transaction/src/builder/manifest_builder.rs +++ b/transaction/src/builder/manifest_builder.rs @@ -555,7 +555,7 @@ impl ManifestBuilder { ResourceType::Fungible { divisibility: 18 }, metadata, resource_auth, - mint_params + mint_params, ), }) .0 From 7e29c18204ba60245a6193affafa1966641d3745 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sat, 19 Nov 2022 20:53:41 +0000 Subject: [PATCH 03/20] refactor: Removed encode_any / decode_any --- .../src/data/indexed_value.rs | 6 +-- .../transaction_processor/executables.rs | 8 ++-- radix-engine/src/types.rs | 1 - sbor-tests/tests/value.rs | 3 +- sbor/src/value.rs | 40 ++++--------------- scrypto/src/prelude/mod.rs | 2 +- transaction/src/builder/manifest_builder.rs | 21 ++++------ transaction/src/manifest/decompiler.rs | 8 ++-- transaction/src/manifest/generator.rs | 4 +- 9 files changed, 31 insertions(+), 62 deletions(-) diff --git a/radix-engine-interface/src/data/indexed_value.rs b/radix-engine-interface/src/data/indexed_value.rs index 210e0f3a577..20a3692523f 100644 --- a/radix-engine-interface/src/data/indexed_value.rs +++ b/radix-engine-interface/src/data/indexed_value.rs @@ -57,7 +57,7 @@ impl 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 +69,7 @@ impl IndexedScryptoValue { } Ok(Self { - raw: encode_any(&value), + raw: scrypto_encode(&value), dom: value, component_addresses: visitor.component_addresses, resource_addresses: visitor.resource_addresses, @@ -165,7 +165,7 @@ impl IndexedScryptoValue { } self.bucket_ids = new_bucket_ids; - self.raw = encode_any(&self.dom); + self.raw = scrypto_encode(&self.dom); Ok(()) } diff --git a/radix-engine/src/model/transaction_processor/executables.rs b/radix-engine/src/model/transaction_processor/executables.rs index 4cb55541fa0..f82d39f985a 100644 --- a/radix-engine/src/model/transaction_processor/executables.rs +++ b/radix-engine/src/model/transaction_processor/executables.rs @@ -148,8 +148,8 @@ 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 decode Vec") } "ENTIRE_AUTH_ZONE" => { let proofs = @@ -158,8 +158,8 @@ 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 decode Vec") } _ => {} // no-op } diff --git a/radix-engine/src/types.rs b/radix-engine/src/types.rs index 489253f0894..e0d31efa66c 100644 --- a/radix-engine/src/types.rs +++ b/radix-engine/src/types.rs @@ -15,7 +15,6 @@ 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/sbor-tests/tests/value.rs b/sbor-tests/tests/value.rs index acb0c9bc836..49f634b8837 100644 --- a/sbor-tests/tests/value.rs +++ b/sbor-tests/tests/value.rs @@ -36,7 +36,8 @@ fn test_encode_as_json() { d: "5".to_string(), }; let bytes = crate::encode::(&sample); - let any = crate::decode_any::(&bytes).unwrap(); + let any = + crate::decode::>(&bytes).unwrap(); assert_json_eq( any, diff --git a/sbor/src/value.rs b/sbor/src/value.rs index 25776d5f4ec..7c324efdfb7 100644 --- a/sbor/src/value.rs +++ b/sbor/src/value.rs @@ -283,32 +283,6 @@ impl, CV: Decode> Decode for SborValu } } -/// 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); - value.encode(&mut encoder); -} - -/// Decode any SBOR data. -pub fn decode_any Decode>>( - data: &[u8], -) -> Result, DecodeError> { - let mut decoder = DefaultVecDecoder::new(data); - let value = decoder.decode()?; - decoder.check_end()?; - Ok(value) -} - pub fn traverse_any, E>( path: &mut SborPathBuf, value: &SborValue, @@ -460,7 +434,7 @@ mod tests { z: map2, }; let bytes = encode::(&data); - let value = decode_any::(&bytes).unwrap(); + let value = decode::(&bytes).unwrap(); assert_eq!( BasicSborValue::Struct { @@ -564,33 +538,33 @@ mod tests { #[test] pub fn test_max_depth_array_decode_behaviour() { let allowable_payload = encode_array_of_depth(DEFAULT_MAX_DEPTH); - let allowable_result = decode_any::(&allowable_payload); + let allowable_result = decode::(&allowable_payload); assert!(allowable_result.is_ok()); let forbidden_payload = encode_array_of_depth(DEFAULT_MAX_DEPTH + 1); - let forbidden_result = decode_any::(&forbidden_payload); + let forbidden_result = 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_MAX_DEPTH); - let allowable_result = decode_any::(&allowable_payload); + let allowable_result = decode::(&allowable_payload); assert!(allowable_result.is_ok()); let forbidden_payload = encode_struct_of_depth(DEFAULT_MAX_DEPTH + 1); - let forbidden_result = decode_any::(&forbidden_payload); + let forbidden_result = 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_MAX_DEPTH); - let allowable_result = decode_any::(&allowable_payload); + let allowable_result = decode::(&allowable_payload); assert!(allowable_result.is_ok()); let forbidden_payload = encode_tuple_of_depth(DEFAULT_MAX_DEPTH + 1); - let forbidden_result = decode_any::(&forbidden_payload); + let forbidden_result = decode::(&forbidden_payload); assert!(forbidden_result.is_err()); } 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/transaction/src/builder/manifest_builder.rs b/transaction/src/builder/manifest_builder.rs index 41b1ebbfdc5..66654ae31d4 100644 --- a/transaction/src/builder/manifest_builder.rs +++ b/transaction/src/builder/manifest_builder.rs @@ -33,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) }}; } @@ -410,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); Ok(self .add_instruction(Instruction::CallFunction { @@ -555,7 +548,7 @@ impl ManifestBuilder { ResourceType::Fungible { divisibility: 18 }, metadata, resource_auth, - mint_params, + mint_params ), }) .0 diff --git a/transaction/src/manifest/decompiler.rs b/transaction/src/manifest/decompiler.rs index 644cc71312a..7c6ca6b68d9 100644 --- a/transaction/src/manifest/decompiler.rs +++ b/transaction/src/manifest/decompiler.rs @@ -4,11 +4,13 @@ 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, ValueFormattingContext, +}; use radix_engine_interface::model::*; use sbor::rust::collections::*; use sbor::rust::fmt; -use sbor::{encode_any, SborValue}; +use sbor::SborValue; use utils::ContextualDisplay; use crate::errors::*; @@ -475,7 +477,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(' ')?; diff --git a/transaction/src/manifest/generator.rs b/transaction/src/manifest/generator.rs index 2466b051a75..97113783ad8 100644 --- a/transaction/src/manifest/generator.rs +++ b/transaction/src/manifest/generator.rs @@ -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) }}; } @@ -532,7 +532,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)); } Ok(result) } From a43ae7fd20e4adc2e535e72a44a5b9ce7eb09958 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sat, 19 Nov 2022 21:30:26 +0000 Subject: [PATCH 04/20] refactor: Remove encode and decode methods --- .../src/data/indexed_value.rs | 2 +- radix-engine-interface/src/data/mod.rs | 33 +++++++++++-------- sbor-tests/benches/bench.rs | 8 ++--- sbor-tests/tests/value.rs | 5 ++- sbor/src/basic.rs | 27 ++++++++++++++- sbor/src/decoder.rs | 17 ++++++---- sbor/src/lib.rs | 22 ++----------- sbor/src/value.rs | 28 ++++++++-------- 8 files changed, 78 insertions(+), 64 deletions(-) diff --git a/radix-engine-interface/src/data/indexed_value.rs b/radix-engine-interface/src/data/indexed_value.rs index 20a3692523f..31152d70150 100644 --- a/radix-engine-interface/src/data/indexed_value.rs +++ b/radix-engine-interface/src/data/indexed_value.rs @@ -52,7 +52,7 @@ impl IndexedScryptoValue { } pub fn from_typed(value: &T) -> Self { - let bytes = encode(value); + let bytes = scrypto_encode(value); Self::from_slice(&bytes).expect("Failed to convert trusted value into IndexedScryptoValue") } diff --git a/radix-engine-interface/src/data/mod.rs b/radix-engine-interface/src/data/mod.rs index 43e8c70a82b..47ba6059a07 100644 --- a/radix-engine-interface/src/data/mod.rs +++ b/radix-engine-interface/src/data/mod.rs @@ -16,36 +16,41 @@ pub use custom_type_id::*; pub use custom_value::*; pub use indexed_value::*; use sbor::rust::vec::Vec; -use sbor::{decode, encode, DecodeError}; +use sbor::{ + Decode, DecodeError, Decoder, Encode, Encoder, SborTypeId, SborValue, TypeId, VecDecoder, +}; pub use schema_matcher::*; pub use schema_path::*; pub use value_formatter::*; pub const MAX_SCRYPTO_SBOR_DEPTH: u8 = 32; -pub type ScryptoEncoder<'a> = sbor::Encoder<'a, ScryptoCustomTypeId>; -pub type ScryptoDecoder<'a> = sbor::VecDecoder<'a, ScryptoCustomTypeId, MAX_SCRYPTO_SBOR_DEPTH>; -pub type ScryptoSborTypeId = sbor::SborTypeId; -pub type ScryptoValue = sbor::SborValue; +pub type ScryptoEncoder<'a> = Encoder<'a, ScryptoCustomTypeId>; +pub type ScryptoDecoder<'a> = VecDecoder<'a, ScryptoCustomTypeId, MAX_SCRYPTO_SBOR_DEPTH>; +pub type ScryptoSborTypeId = SborTypeId; +pub type ScryptoValue = SborValue; // These trait "aliases" should only be used for parameters, never implementations -// Implementations should implement the underlying traits (TypeId/Encode/Decode) -pub trait ScryptoTypeId: sbor::TypeId {} -impl + ?Sized> ScryptoTypeId for T {} +// Implementations should implement the underlying traits (TypeId/Encode/Decode) +pub trait ScryptoTypeId: TypeId {} +impl + ?Sized> ScryptoTypeId for T {} -pub trait ScryptoDecode: for<'de> sbor::Decode> {} -impl sbor::Decode>> ScryptoDecode for T {} +pub trait ScryptoDecode: for<'de> Decode> {} +impl Decode>> ScryptoDecode for T {} -pub trait ScryptoEncode: sbor::Encode {} -impl + ?Sized> ScryptoEncode for T {} +pub trait ScryptoEncode: Encode {} +impl + ?Sized> ScryptoEncode for T {} /// Encodes a data structure into byte array. pub fn scrypto_encode(v: &T) -> Vec { - encode(v) + let mut buf = Vec::with_capacity(512); + let mut enc = ScryptoEncoder::new(&mut buf); + v.encode(&mut enc); + buf } pub fn scrypto_decode(buf: &[u8]) -> Result { - decode(buf) + ScryptoDecoder::new(buf).decode_payload() } #[macro_export] diff --git a/sbor-tests/benches/bench.rs b/sbor-tests/benches/bench.rs index 96479fe873b..74153042857 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); + b.iter(|| basic_decode::(&bytes)); } benchmark_group!( diff --git a/sbor-tests/tests/value.rs b/sbor-tests/tests/value.rs index 49f634b8837..f41a5d523ab 100644 --- a/sbor-tests/tests/value.rs +++ b/sbor-tests/tests/value.rs @@ -35,9 +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::>(&bytes).unwrap(); + let bytes = basic_encode(&sample); + let any = basic_decode::(&bytes).unwrap(); assert_json_eq( any, diff --git a/sbor/src/basic.rs b/sbor/src/basic.rs index 4900302dce6..538f8f0b5f0 100644 --- a/sbor/src/basic.rs +++ b/sbor/src/basic.rs @@ -16,11 +16,36 @@ pub enum NoCustomTypeId {} #[derive(Debug, Clone, PartialEq, Eq)] pub enum NoCustomValue {} +pub const DEFAULT_BASIC_MAX_DEPTH: u8 = 32; pub type BasicEncoder<'a> = Encoder<'a, NoCustomTypeId>; -pub type BasicDecoder<'a> = DefaultVecDecoder<'a, NoCustomTypeId>; +pub type BasicDecoder<'a> = VecDecoder<'a, NoCustomTypeId, DEFAULT_BASIC_MAX_DEPTH>; pub type BasicSborValue = SborValue; pub type BasicSborTypeId = SborTypeId; +// These trait "aliases" should only be used for parameters, never implementations +// Implementations should implement the underlying traits (TypeId/Encode/Decode) +pub trait BasicTypeId: TypeId {} +impl + ?Sized> BasicTypeId for T {} + +pub trait BasicDecode: for<'de> Decode> {} +impl Decode>> BasicDecode for T {} + +pub trait BasicEncode: Encode {} +impl + ?Sized> BasicEncode for T {} + +/// Encode a `T` into byte array. +pub fn basic_encode(v: &T) -> crate::rust::vec::Vec { + let mut buf = crate::rust::vec::Vec::with_capacity(512); + let mut enc = BasicEncoder::new(&mut buf); + v.encode(&mut enc); + 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") diff --git a/sbor/src/decoder.rs b/sbor/src/decoder.rs index e866d7e34e8..df8cd71d2d3 100644 --- a/sbor/src/decoder.rs +++ b/sbor/src/decoder.rs @@ -34,6 +34,12 @@ pub enum DecodeError { } pub trait Decoder: Sized { + fn decode_payload>(mut self) -> Result { + let value = self.decode()?; + self.check_end()?; + Ok(value) + } + fn decode>(&mut self) -> Result { let type_id = self.read_type_id()?; self.decode_body_with_type_id(type_id) @@ -45,7 +51,7 @@ pub trait Decoder: Sized { ) -> Result { self.track_decode_depth_increase()?; let decoded = T::decode_body_with_type_id(self, type_id)?; - self.track_decode_depth_decrease(); + self.track_decode_depth_decrease()?; Ok(decoded) } @@ -117,16 +123,13 @@ pub trait Decoder: Sized { fn track_decode_depth_increase(&mut self) -> Result<(), DecodeError>; - fn track_decode_depth_decrease(&mut self); + fn track_decode_depth_decrease(&mut self) -> Result<(), DecodeError>; fn read_byte(&mut self) -> Result; fn read_slice(&mut self, n: usize) -> Result<&[u8], DecodeError>; } -pub const DEFAULT_MAX_DEPTH: u8 = 32; -pub type DefaultVecDecoder<'de, X> = VecDecoder<'de, X, DEFAULT_MAX_DEPTH>; - /// A `Decoder` abstracts the logic for decoding basic types. pub struct VecDecoder<'de, X: CustomTypeId, const MAX_DEPTH: u8> { input: &'de [u8], @@ -200,8 +203,9 @@ impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> Decoder for VecDecoder<'de, X } #[inline] - fn track_decode_depth_decrease(&mut self) { + fn track_decode_depth_decrease(&mut self) -> Result<(), DecodeError> { self.decoder_stack_depth -= 1; + Ok(()) } } @@ -209,7 +213,6 @@ impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> Decoder for VecDecoder<'de, X 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; diff --git a/sbor/src/lib.rs b/sbor/src/lib.rs index 7d1e4783ff8..6eb37bf4333 100644 --- a/sbor/src/lib.rs +++ b/sbor/src/lib.rs @@ -15,7 +15,7 @@ pub mod constants; pub mod decode; /// SBOR decoding. pub mod decoder; -/// SBOR encoding. +/// SBOR encode trait. pub mod encode; /// SBOR paths. pub mod path; @@ -29,30 +29,12 @@ pub mod value; pub use basic::*; pub use constants::*; pub use decode::Decode; -pub use decoder::{DecodeError, Decoder, DefaultVecDecoder, VecDecoder}; +pub use decoder::{DecodeError, Decoder, VecDecoder}; pub use encode::{Encode, Encoder}; 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 Decode>>( - buf: &[u8], -) -> Result { - let mut decoder = DefaultVecDecoder::new(buf); - let value = decoder.decode()?; - decoder.check_end()?; - Ok(value) -} - // Re-export derives extern crate sbor_derive; pub use sbor_derive::{Decode, Encode, TypeId}; diff --git a/sbor/src/value.rs b/sbor/src/value.rs index 7c324efdfb7..d64ccb90a71 100644 --- a/sbor/src/value.rs +++ b/sbor/src/value.rs @@ -433,8 +433,8 @@ mod tests { y: map1, z: map2, }; - let bytes = encode::(&data); - let value = decode::(&bytes).unwrap(); + let bytes = basic_encode(&data); + let value = basic_decode(&bytes).unwrap(); assert_eq!( BasicSborValue::Struct { @@ -537,34 +537,34 @@ mod tests { #[test] pub fn test_max_depth_array_decode_behaviour() { - let allowable_payload = encode_array_of_depth(DEFAULT_MAX_DEPTH); - let allowable_result = decode::(&allowable_payload); + let allowable_payload = encode_array_of_depth(DEFAULT_BASIC_MAX_DEPTH); + let allowable_result = basic_decode::(&allowable_payload); assert!(allowable_result.is_ok()); - let forbidden_payload = encode_array_of_depth(DEFAULT_MAX_DEPTH + 1); - let forbidden_result = decode::(&forbidden_payload); + let forbidden_payload = encode_array_of_depth(DEFAULT_BASIC_MAX_DEPTH + 1); + 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_MAX_DEPTH); - let allowable_result = decode::(&allowable_payload); + let allowable_payload = encode_struct_of_depth(DEFAULT_BASIC_MAX_DEPTH); + let allowable_result = basic_decode::(&allowable_payload); assert!(allowable_result.is_ok()); - let forbidden_payload = encode_struct_of_depth(DEFAULT_MAX_DEPTH + 1); - let forbidden_result = decode::(&forbidden_payload); + let forbidden_payload = encode_struct_of_depth(DEFAULT_BASIC_MAX_DEPTH + 1); + 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_MAX_DEPTH); - let allowable_result = decode::(&allowable_payload); + let allowable_payload = encode_tuple_of_depth(DEFAULT_BASIC_MAX_DEPTH); + let allowable_result = basic_decode::(&allowable_payload); assert!(allowable_result.is_ok()); - let forbidden_payload = encode_tuple_of_depth(DEFAULT_MAX_DEPTH + 1); - let forbidden_result = decode::(&forbidden_payload); + let forbidden_payload = encode_tuple_of_depth(DEFAULT_BASIC_MAX_DEPTH + 1); + let forbidden_result = basic_decode::(&forbidden_payload); assert!(forbidden_result.is_err()); } From c38d43ad033263f0225ce606d7a64e471c57571f Mon Sep 17 00:00:00 2001 From: David Edey Date: Sat, 19 Nov 2022 21:37:30 +0000 Subject: [PATCH 05/20] fix: Fix non fungible data derive and tests --- scrypto-derive/src/non_fungible_data.rs | 38 ++++++++++++++----------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/scrypto-derive/src/non_fungible_data.rs b/scrypto-derive/src/non_fungible_data.rs index cb2c10881ea..128013bc385 100644 --- a/scrypto-derive/src/non_fungible_data.rs +++ b/scrypto-derive/src/non_fungible_data.rs @@ -46,12 +46,13 @@ 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::*, *}; + use ::scrypto::data::*; let mut decoder_nm = ScryptoDecoder::new(immutable_data); - decoder_nm.read_and_check_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct)?; + decoder_nm.read_and_check_type_id(ScryptoSborTypeId::Struct)?; decoder_nm.read_and_check_size(#im_n)?; let mut decoder_m = ScryptoDecoder::new(mutable_data); - decoder_m.read_and_check_type_id(SborTypeId::<::scrypto::data::ScryptoCustomTypeId>::Struct)?; + decoder_m.read_and_check_type_id(ScryptoSborTypeId::Struct)?; decoder_m.read_and_check_size(#m_n)?; let decoded = Self { @@ -67,10 +68,11 @@ pub fn handle_non_fungible_data(input: TokenStream) -> Result { fn immutable_data(&self) -> ::sbor::rust::vec::Vec { 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); + let mut encoder = ScryptoEncoder::new(&mut bytes); + encoder.write_type_id(ScryptoSborTypeId::Struct); encoder.write_size(#im_n); #( self.#im_ids2.encode(&mut encoder); @@ -82,10 +84,11 @@ pub fn handle_non_fungible_data(input: TokenStream) -> Result { fn mutable_data(&self) -> ::sbor::rust::vec::Vec { 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); + let mut encoder = ScryptoEncoder::new(&mut bytes); + encoder.write_type_id(ScryptoSborTypeId::Struct); encoder.write_size(#m_n); #( self.#m_ids2.encode(&mut encoder); @@ -175,15 +178,16 @@ 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()?; @@ -191,9 +195,10 @@ mod tests { } fn immutable_data(&self) -> ::sbor::rust::vec::Vec { 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); + let mut encoder = ScryptoEncoder::new(&mut bytes); + encoder.write_type_id(ScryptoSborTypeId::Struct); encoder.write_size(1); self.field_1.encode(&mut encoder); bytes @@ -201,9 +206,10 @@ mod tests { fn mutable_data(&self) -> ::sbor::rust::vec::Vec { 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); + let mut encoder = ScryptoEncoder::new(&mut bytes); + encoder.write_type_id(ScryptoSborTypeId::Struct); encoder.write_size(1); self.field_2.encode(&mut encoder); bytes From 749931b7df7c5f4aeda99d99d0a48f993f4d54e9 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 00:47:15 +0000 Subject: [PATCH 06/20] feat: Encoder is now a trait --- .../src/data/custom_value.rs | 12 +- .../src/data/indexed_value.rs | 15 +- radix-engine-interface/src/data/mod.rs | 32 +-- radix-engine-interface/src/macros.rs | 34 +-- radix-engine-interface/src/math/decimal.rs | 12 +- radix-engine-interface/src/math/integer.rs | 38 +-- .../src/math/precise_decimal.rs | 20 +- .../src/model/resource/mint_params.rs | 2 +- .../src/model/resource/non_fungible_data.rs | 6 +- .../src/model/resource/non_fungible_id.rs | 6 +- radix-engine-stores/src/memory_db.rs | 8 +- radix-engine-stores/src/rocks_db.rs | 46 +++- radix-engine/benches/transaction.rs | 2 +- radix-engine/src/engine/errors.rs | 1 + .../src/engine/interpreters/wasm_runtime.rs | 38 +-- radix-engine/src/engine/track.rs | 8 +- .../transaction_processor/executables.rs | 12 +- radix-engine/src/state_manager/staging.rs | 4 +- radix-engine/src/state_manager/state_diff.rs | 5 +- radix-engine/src/wasm/errors.rs | 1 + radix-engine/src/wasm/wasm_metering_config.rs | 2 +- radix-engine/tests/abi.rs | 68 ++--- radix-engine/tests/blueprints/abi/src/lib.rs | 4 +- .../tests/blueprints/package/src/lib.rs | 6 +- radix-engine/tests/fee.rs | 5 +- radix-engine/tests/transaction_executor.rs | 3 +- sbor-derive/src/encode.rs | 155 +++++++----- sbor-derive/src/utils.rs | 22 ++ sbor-tests/benches/bench.rs | 2 +- sbor-tests/tests/encode.rs | 16 +- sbor-tests/tests/skip.rs | 16 +- sbor-tests/tests/value.rs | 2 +- sbor/src/basic.rs | 27 +- sbor/src/codec/array.rs | 29 ++- sbor/src/codec/boolean.rs | 10 +- sbor/src/codec/collection.rs | 94 ++++--- sbor/src/codec/integer.rs | 51 ++-- sbor/src/codec/misc.rs | 41 ++- sbor/src/codec/option.rs | 20 +- sbor/src/codec/result.rs | 24 +- sbor/src/codec/string.rs | 39 +-- sbor/src/codec/tuple.rs | 15 +- sbor/src/codec/unit.rs | 11 +- sbor/src/decoder.rs | 35 ++- sbor/src/encode.rs | 170 +------------ sbor/src/encoder.rs | 234 ++++++++++++++++++ sbor/src/lib.rs | 5 +- sbor/src/value.rs | 115 +++++---- scrypto-derive/src/blueprint.rs | 12 +- scrypto-derive/src/non_fungible_data.rs | 40 +-- scrypto-tests/tests/non_fungible_data.rs | 7 +- scrypto-unit/src/test_runner.rs | 6 +- scrypto/src/buffer/codec.rs | 8 +- scrypto/src/component/kv_store.rs | 30 ++- scrypto/src/component/system.rs | 2 +- scrypto/src/engine/scrypto_env.rs | 4 +- scrypto/src/resource/resource_builder.rs | 2 +- scrypto/src/resource/resource_manager.rs | 7 +- scrypto/src/runtime/data.rs | 6 +- simulator/src/resim/config.rs | 2 +- simulator/src/rtmc/mod.rs | 7 +- simulator/src/utils/cargo.rs | 9 +- transaction/src/builder/manifest_builder.rs | 37 +-- .../src/builder/transaction_builder.rs | 6 +- transaction/src/errors.rs | 14 ++ transaction/src/manifest/decompiler.rs | 24 +- transaction/src/manifest/generator.rs | 8 +- .../src/model/notarized_transaction.rs | 46 ++-- transaction/src/model/preview_transaction.rs | 6 +- transaction/src/model/test_transaction.rs | 2 +- .../src/validation/transaction_validator.rs | 25 +- 71 files changed, 1055 insertions(+), 778 deletions(-) create mode 100644 sbor/src/encoder.rs diff --git a/radix-engine-interface/src/data/custom_value.rs b/radix-engine-interface/src/data/custom_value.rs index 14b2a877178..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 Encode 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 Encode 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 Encode 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,7 +137,7 @@ impl Encode 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) } } diff --git a/radix-engine-interface/src/data/indexed_value.rs b/radix-engine-interface/src/data/indexed_value.rs index 31152d70150..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,8 +53,9 @@ impl IndexedScryptoValue { Self::from_typed(&()) } - pub fn from_typed(value: &T) -> Self { - let bytes = scrypto_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") } @@ -69,7 +72,8 @@ impl IndexedScryptoValue { } Ok(Self { - raw: scrypto_encode(&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 = scrypto_encode(&self.dom); + self.raw = scrypto_encode(&self.dom) + .expect("Previously encodable raw value is no longer encodable after replacement"); Ok(()) } @@ -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 47ba6059a07..e0f4476bec2 100644 --- a/radix-engine-interface/src/data/mod.rs +++ b/radix-engine-interface/src/data/mod.rs @@ -17,7 +17,8 @@ pub use custom_value::*; pub use indexed_value::*; use sbor::rust::vec::Vec; use sbor::{ - Decode, DecodeError, Decoder, Encode, Encoder, SborTypeId, SborValue, TypeId, VecDecoder, + Decode, DecodeError, Decoder, Encode, EncodeError, Encoder, SborTypeId, SborValue, TypeId, + VecDecoder, VecEncoder, }; pub use schema_matcher::*; pub use schema_path::*; @@ -25,7 +26,7 @@ pub use value_formatter::*; pub const MAX_SCRYPTO_SBOR_DEPTH: u8 = 32; -pub type ScryptoEncoder<'a> = Encoder<'a, ScryptoCustomTypeId>; +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; @@ -35,20 +36,21 @@ pub type ScryptoValue = SborValue; pub trait ScryptoTypeId: TypeId {} impl + ?Sized> ScryptoTypeId for T {} -pub trait ScryptoDecode: for<'de> Decode> {} -impl Decode>> ScryptoDecode for T {} +pub trait ScryptoDecode: for<'a> Decode> {} +impl Decode>> ScryptoDecode for T {} -pub trait ScryptoEncode: Encode {} -impl + ?Sized> ScryptoEncode 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(v: &T) -> Vec { +pub fn scrypto_encode(value: &T) -> Result, EncodeError> { let mut buf = Vec::with_capacity(512); - let mut enc = ScryptoEncoder::new(&mut buf); - v.encode(&mut enc); - buf + let encoder = ScryptoEncoder::new(&mut buf); + encoder.encode_payload(value)?; + Ok(buf) } +/// Decodes a data structure from a byte array. pub fn scrypto_decode(buf: &[u8]) -> Result { ScryptoDecoder::new(buf).decode_payload() } @@ -64,16 +66,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::ScryptoSborTypeId::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 }}; @@ -102,6 +103,7 @@ mod tests { a: 1, b: "abc".to_owned(), }) + .unwrap() ) } diff --git a/radix-engine-interface/src/macros.rs b/radix-engine-interface/src/macros.rs index ec43d0f55b3..e617ba507fe 100644 --- a/radix-engine-interface/src/macros.rs +++ b/radix-engine-interface/src/macros.rs @@ -77,17 +77,17 @@ 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()) } } @@ -120,19 +120,19 @@ 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) } } diff --git a/radix-engine-interface/src/math/decimal.rs b/radix-engine-interface/src/math/decimal.rs index f3e8aba8c9b..c501b8f4158 100644 --- a/radix-engine-interface/src/math/decimal.rs +++ b/radix-engine-interface/src/math/decimal.rs @@ -1046,7 +1046,7 @@ mod tests { fn test_encode_decimal_type_decimal() { let mut bytes = Vec::with_capacity(512); let mut enc = ScryptoEncoder::new(&mut bytes); - dec!("1").encode_type_id(&mut enc); + dec!("1").encode_type_id(&mut enc).unwrap(); assert_eq!(bytes, vec![Decimal::type_id().as_u8()]); } @@ -1055,8 +1055,8 @@ mod tests { let dec = dec!("0"); let mut bytes = Vec::with_capacity(512); let mut enc = ScryptoEncoder::new(&mut bytes); - dec.encode_type_id(&mut enc); - dec.encode_body(&mut enc); + 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(); @@ -1068,7 +1068,7 @@ mod tests { fn test_decode_decimal_type_decimal() { let mut bytes = Vec::with_capacity(512); let mut enc = ScryptoEncoder::new(&mut bytes); - dec!("1").encode_type_id(&mut enc); + 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()); @@ -1079,8 +1079,8 @@ mod tests { let dec = dec!("1.23456789"); let mut bytes = Vec::with_capacity(512); let mut enc = ScryptoEncoder::new(&mut bytes); - dec.encode_type_id(&mut enc); - dec.encode_body(&mut enc); + 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 ae85b179a15..c326262c6e5 100644 --- a/radix-engine-interface/src/math/integer.rs +++ b/radix-engine-interface/src/math/integer.rs @@ -291,14 +291,15 @@ 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()) } } @@ -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,7 +929,7 @@ mod tests { fn test_integer_decoding() { let mut bytes = Vec::with_capacity(512); let mut enc = ScryptoEncoder::new(&mut bytes); - encode_integers(&mut enc); + encode_integers(&mut enc).unwrap(); let mut decoder = ScryptoDecoder::new(&bytes); assert_eq!(I8::by(1i8), decoder.decode::().unwrap()); diff --git a/radix-engine-interface/src/math/precise_decimal.rs b/radix-engine-interface/src/math/precise_decimal.rs index 8491e897899..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,8 +1091,8 @@ 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 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,9 +1102,9 @@ 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 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 a35cb589251..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")) } } 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 6cfa67f5c07..6187e999b9e 100644 --- a/radix-engine-stores/src/rocks_db.rs +++ b/radix-engine-stores/src/rocks_db.rs @@ -27,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() @@ -57,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() @@ -96,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() @@ -137,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(); } } @@ -150,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 @@ -184,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/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 cf087bd2d8b..84ab004f08a 100644 --- a/radix-engine/src/engine/errors.rs +++ b/radix-engine/src/engine/errors.rs @@ -85,6 +85,7 @@ pub enum KernelError { // SBOR decoding InvalidScryptoValue(ScryptoValueDecodeError), InvalidSborValue(DecodeError), + InvalidSborValueOnEncode(EncodeError), // RENode StoredNodeRemoved(RENodeId), diff --git a/radix-engine/src/engine/interpreters/wasm_runtime.rs b/radix-engine/src/engine/interpreters/wasm_runtime.rs index 1bce8c6cc32..e4d8ba5ecbc 100644 --- a/radix-engine/src/engine/interpreters/wasm_runtime.rs +++ b/radix-engine/src/engine/interpreters/wasm_runtime.rs @@ -299,8 +299,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> @@ -327,33 +331,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/model/transaction_processor/executables.rs b/radix-engine/src/model/transaction_processor/executables.rs index f82d39f985a..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 = scrypto_decode(&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 = scrypto_decode(&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..c709fbc0e4c 100644 --- a/radix-engine/src/state_manager/state_diff.rs +++ b/radix-engine/src/state_manager/state_diff.rs @@ -29,7 +29,10 @@ 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) + .expect("Could not encode newly-committed substate"), + ), version: output_value.version, }; receipt.up(output_id); 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/tests/abi.rs b/radix-engine/tests/abi.rs index 53540015c60..fcd4c3deacf 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/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/transaction_executor.rs b/radix-engine/tests/transaction_executor.rs index 1638f115a4f..14118b56e69 100644 --- a/radix-engine/tests/transaction_executor.rs +++ b/radix-engine/tests/transaction_executor.rs @@ -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/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 55db9431f46..b91d2c3e786 100644 --- a/sbor-derive/src/utils.rs +++ b/sbor-derive/src/utils.rs @@ -119,6 +119,28 @@ pub fn build_decode_generics( )) } +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( original_generics: &Generics, custom_type_id: Option, diff --git a/sbor-tests/benches/bench.rs b/sbor-tests/benches/bench.rs index 74153042857..9657bdcf4a2 100644 --- a/sbor-tests/benches/bench.rs +++ b/sbor-tests/benches/bench.rs @@ -37,7 +37,7 @@ fn decode_simple_bincode(b: &mut Bencher) { fn decode_simple_sbor(b: &mut Bencher) { let t = data::get_simple_dataset(SIMPLE_REAPT); - let bytes = basic_encode(&t); + let bytes = basic_encode(&t).unwrap(); b.iter(|| basic_decode::(&bytes)); } 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 07f81d3f527..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!( @@ -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!( diff --git a/sbor-tests/tests/value.rs b/sbor-tests/tests/value.rs index f41a5d523ab..5e804b95fee 100644 --- a/sbor-tests/tests/value.rs +++ b/sbor-tests/tests/value.rs @@ -35,7 +35,7 @@ fn test_encode_as_json() { c: (2, vec![3, 4]), d: "5".to_string(), }; - let bytes = basic_encode(&sample); + let bytes = basic_encode(&sample).unwrap(); let any = basic_decode::(&bytes).unwrap(); assert_json_eq( diff --git a/sbor/src/basic.rs b/sbor/src/basic.rs index 538f8f0b5f0..29520e8a521 100644 --- a/sbor/src/basic.rs +++ b/sbor/src/basic.rs @@ -1,3 +1,4 @@ +use crate::rust::vec::Vec; use crate::*; #[cfg_attr( @@ -17,7 +18,7 @@ pub enum NoCustomTypeId {} pub enum NoCustomValue {} pub const DEFAULT_BASIC_MAX_DEPTH: u8 = 32; -pub type BasicEncoder<'a> = Encoder<'a, NoCustomTypeId>; +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; @@ -27,18 +28,18 @@ pub type BasicSborTypeId = SborTypeId; pub trait BasicTypeId: TypeId {} impl + ?Sized> BasicTypeId for T {} -pub trait BasicDecode: for<'de> Decode> {} -impl Decode>> BasicDecode for T {} +pub trait BasicDecode: for<'a> Decode> {} +impl Decode>> BasicDecode for T {} -pub trait BasicEncode: Encode {} -impl + ?Sized> BasicEncode 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) -> crate::rust::vec::Vec { - let mut buf = crate::rust::vec::Vec::with_capacity(512); - let mut enc = BasicEncoder::new(&mut buf); - v.encode(&mut enc); - buf +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. @@ -56,12 +57,12 @@ impl CustomTypeId for NoCustomTypeId { } } -impl Encode 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") } } diff --git a/sbor/src/codec/array.rs b/sbor/src/codec/array.rs index 853f083284f..a38aafb52c7 100644 --- a/sbor/src/codec/array.rs +++ b/sbor/src/codec/array.rs @@ -2,35 +2,38 @@ 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_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> { + encoder.encode_body(self.as_slice()) } } diff --git a/sbor/src/codec/boolean.rs b/sbor/src/codec/boolean.rs index 1cef2b73363..1fe2aee1e76 100644 --- a/sbor/src/codec/boolean.rs +++ b/sbor/src/codec/boolean.rs @@ -1,14 +1,14 @@ 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 }) } } diff --git a/sbor/src/codec/collection.rs b/sbor/src/codec/collection.rs index f79c1cd60b3..8518cfb8e84 100644 --- a/sbor/src/codec/collection.rs +++ b/sbor/src/codec/collection.rs @@ -5,83 +5,99 @@ 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> { + encoder.encode_body(self.as_slice())?; + 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_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_body(v)?; } + Ok(()) } } -impl + TypeId, V: Encode + TypeId> Encode - for BTreeMap +impl, K: Encode + TypeId, V: Encode + TypeId> + 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.write_size(2)?; + encoder.encode(k)?; + encoder.encode(v)?; } + Ok(()) } } -impl + TypeId + Ord + Hash, V: Encode + TypeId> Encode - for HashMap +impl< + X: CustomTypeId, + E: Encoder, + K: Encode + TypeId + Ord + Hash, + V: Encode + TypeId, + > 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.write_size(2)?; + encoder.encode(key)?; + encoder.encode(self.get(key).unwrap())?; } + Ok(()) } } diff --git a/sbor/src/codec/integer.rs b/sbor/src/codec/integer.rs index d315ca7645e..090a6c8c850 100644 --- a/sbor/src/codec/integer.rs +++ b/sbor/src/codec/integer.rs @@ -1,38 +1,38 @@ 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,25 +47,26 @@ 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) } } diff --git a/sbor/src/codec/misc.rs b/sbor/src/codec/misc.rs index eaa59f58273..a6be3719bc3 100644 --- a/sbor/src/codec/misc.rs +++ b/sbor/src/codec/misc.rs @@ -6,38 +6,53 @@ use crate::rust::rc::Rc; use crate::type_id::*; use crate::*; -impl<'a, X: CustomTypeId, B: ?Sized + 'a + ToOwned + Encode + TypeId> Encode - for Cow<'a, B> +impl<'a, X: CustomTypeId, E: Encoder, B: ?Sized + 'a + ToOwned + Encode + TypeId> + Encode for Cow<'a, B> { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_type_id(B::type_id()) } + #[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 + TypeId> Encode for Box { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_type_id(T::type_id()) } + #[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 + TypeId> Encode for Rc { #[inline] - fn encode_type_id(&self, encoder: &mut Encoder) { + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_type_id(T::type_id()) } + + #[inline] + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.as_ref().encode_body(encoder) + } +} + +impl, T: Encode + TypeId> Encode for RefCell { + #[inline] + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_type_id(T::type_id()) + } + #[inline] - fn encode_body(&self, encoder: &mut Encoder) { - self.borrow().encode_body(encoder); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.borrow().encode_body(encoder) } } diff --git a/sbor/src/codec/option.rs b/sbor/src/codec/option.rs index 57ab9b4a921..ed25d508388 100644 --- a/sbor/src/codec/option.rs +++ b/sbor/src/codec/option.rs @@ -2,24 +2,26 @@ 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(()) } } diff --git a/sbor/src/codec/result.rs b/sbor/src/codec/result.rs index d1419879248..92453ba0341 100644 --- a/sbor/src/codec/result.rs +++ b/sbor/src/codec/result.rs @@ -2,25 +2,29 @@ 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(()) } } diff --git a/sbor/src/codec/string.rs b/sbor/src/codec/string.rs index 5de28f6480f..71f190d1c0a 100644 --- a/sbor/src/codec/string.rs +++ b/sbor/src/codec/string.rs @@ -2,38 +2,43 @@ 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()); + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_size(self.len())?; + encoder.write_slice(self.as_bytes())?; + Ok(()) } } -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()); + 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> { + encoder.encode_body(self.as_str()) } } diff --git a/sbor/src/codec/tuple.rs b/sbor/src/codec/tuple.rs index 43453135dca..40d487c58e7 100644 --- a/sbor/src/codec/tuple.rs +++ b/sbor/src/codec/tuple.rs @@ -3,16 +3,17 @@ 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(()) } } }; diff --git a/sbor/src/codec/unit.rs b/sbor/src/codec/unit.rs index 8a231e8bf2f..403504e9e5b 100644 --- a/sbor/src/codec/unit.rs +++ b/sbor/src/codec/unit.rs @@ -1,14 +1,15 @@ 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) } } diff --git a/sbor/src/decoder.rs b/sbor/src/decoder.rs index df8cd71d2d3..d192a3c4c3d 100644 --- a/sbor/src/decoder.rs +++ b/sbor/src/decoder.rs @@ -49,9 +49,9 @@ pub trait Decoder: Sized { &mut self, type_id: SborTypeId, ) -> Result { - self.track_decode_depth_increase()?; + self.track_stack_depth_increase()?; let decoded = T::decode_body_with_type_id(self, type_id)?; - self.track_decode_depth_decrease()?; + self.track_stack_depth_decrease()?; Ok(decoded) } @@ -121,9 +121,9 @@ pub trait Decoder: Sized { fn check_end(&self) -> Result<(), DecodeError>; - fn track_decode_depth_increase(&mut self) -> Result<(), DecodeError>; + fn track_stack_depth_increase(&mut self) -> Result<(), DecodeError>; - fn track_decode_depth_decrease(&mut self) -> Result<(), DecodeError>; + fn track_stack_depth_decrease(&mut self) -> Result<(), DecodeError>; fn read_byte(&mut self) -> Result; @@ -134,7 +134,7 @@ pub trait Decoder: Sized { pub struct VecDecoder<'de, X: CustomTypeId, const MAX_DEPTH: u8> { input: &'de [u8], offset: usize, - decoder_stack_depth: u8, + stack_depth: u8, phantom: PhantomData, } @@ -143,7 +143,7 @@ impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> VecDecoder<'de, X, MAX_DEPTH> { Self { input, offset: 0, - decoder_stack_depth: 0, + stack_depth: 0, phantom: PhantomData, } } @@ -194,17 +194,17 @@ impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> Decoder for VecDecoder<'de, X } #[inline] - fn track_decode_depth_increase(&mut self) -> Result<(), DecodeError> { - self.decoder_stack_depth += 1; - if self.decoder_stack_depth > MAX_DEPTH { + 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_decode_depth_decrease(&mut self) -> Result<(), DecodeError> { - self.decoder_stack_depth -= 1; + fn track_stack_depth_decrease(&mut self) -> Result<(), DecodeError> { + self.stack_depth -= 1; Ok(()) } } @@ -212,7 +212,6 @@ impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> Decoder for VecDecoder<'de, X #[cfg(test)] mod tests { use super::*; - use crate::encode::Encode; use crate::rust::borrow::ToOwned; use crate::rust::boxed::Box; use crate::rust::cell::RefCell; @@ -225,8 +224,8 @@ mod tests { 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 enc = BasicEncoder::new(&mut bytes); + enc.write_size(size).unwrap(); let mut dec = BasicDecoder::new(&bytes); dec.read_and_check_size(size)?; @@ -366,11 +365,11 @@ mod tests { // Encode let mut bytes = Vec::with_capacity(512); - let mut enc = Encoder::::new(&mut bytes); - value1.encode(&mut enc); + let mut encoder = BasicEncoder::new(&mut bytes); + encoder.encode(&value1).unwrap(); - let mut dec = BasicDecoder::new(&bytes); - let value2 = dec.decode::<[NFA; 2]>().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..9292a528473 100644 --- a/sbor/src/encode.rs +++ b/sbor/src/encode.rs @@ -1,170 +1,8 @@ -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> { + fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError>; + 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..f1154fa6057 --- /dev/null +++ b/sbor/src/encoder.rs @@ -0,0 +1,234 @@ +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 { + fn encode_payload + ?Sized>(mut self, value: &T) -> Result<(), EncodeError> { + self.encode(value) + } + + fn encode + ?Sized>(&mut self, value: &T) -> Result<(), EncodeError> { + value.encode_type_id(self)?; + self.encode_body(value) + } + + fn encode_body + ?Sized>(&mut self, value: &T) -> Result<(), EncodeError> { + self.track_stack_depth_increase()?; + value.encode_body(self)?; + self.track_stack_depth_decrease() + } + + 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 + 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)?; + } + } + Ok(()) + } + + fn write_byte(&mut self, n: u8) -> Result<(), EncodeError>; + + fn write_slice(&mut self, slice: &[u8]) -> Result<(), EncodeError>; + + fn track_stack_depth_increase(&mut self) -> Result<(), EncodeError>; + + fn track_stack_depth_decrease(&mut self) -> 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, + } + } +} + +impl<'a, X: CustomTypeId, const MAX_DEPTH: u8> Encoder for VecEncoder<'a, X, MAX_DEPTH> { + fn write_byte(&mut self, n: u8) -> Result<(), EncodeError> { + self.buf.push(n); + Ok(()) + } + + fn write_slice(&mut self, slice: &[u8]) -> Result<(), EncodeError> { + self.buf.extend(slice); + Ok(()) + } + + #[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(()) + } +} + +#[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_encode_cow_borrowed() { + let mut set = BTreeSet::::new(); + set.insert(1); + 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 6eb37bf4333..ad90b96cc59 100644 --- a/sbor/src/lib.rs +++ b/sbor/src/lib.rs @@ -17,6 +17,8 @@ pub mod decode; pub mod decoder; /// SBOR encode trait. pub mod encode; +/// SBOR encoding. +pub mod encoder; /// SBOR paths. pub mod path; /// A facade of Rust types. @@ -30,7 +32,8 @@ pub use basic::*; pub use constants::*; pub use decode::Decode; pub use decoder::{DecodeError, Decoder, VecDecoder}; -pub use encode::{Encode, Encoder}; +pub use encode::Encode; +pub use encoder::{EncodeError, Encoder, VecEncoder}; pub use path::{SborPath, SborPathBuf}; pub use type_id::*; pub use value::*; diff --git a/sbor/src/value.rs b/sbor/src/value.rs index d64ccb90a71..e98bb65e1a3 100644 --- a/sbor/src/value.rs +++ b/sbor/src/value.rs @@ -1,6 +1,7 @@ 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; @@ -72,8 +73,8 @@ pub enum SborValue { }, } -impl> Encode for SborValue { - fn encode_type_id(&self, encoder: &mut Encoder) { +impl, CV: Encode> Encode for SborValue { + 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), @@ -96,84 +97,85 @@ impl> Encode for SborValue { } } - fn encode_body(&self, encoder: &mut Encoder) { + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { match self { SborValue::Unit => { - ().encode_body(encoder); + encoder.encode_body(&())?; } SborValue::Bool { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::I8 { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::I16 { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::I32 { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::I64 { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::I128 { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::U8 { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::U16 { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::U32 { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::U64 { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::U128 { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::String { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } SborValue::Struct { fields } => { - encoder.write_size(fields.len()); + encoder.write_size(fields.len())?; for field in fields { - field.encode(encoder); + encoder.encode(field)?; } } SborValue::Enum { discriminator, fields, } => { - encoder.write_discriminator(discriminator); - encoder.write_size(fields.len()); + encoder.write_discriminator(discriminator)?; + encoder.write_size(fields.len())?; for field in fields { - field.encode(encoder); + encoder.encode(field)?; } } SborValue::Array { element_type_id, elements, } => { - encoder.write_type_id(element_type_id.clone()); - encoder.write_size(elements.len()); + encoder.write_type_id(*element_type_id)?; + encoder.write_size(elements.len())?; for item in elements { - item.encode_body(encoder); + encoder.encode_body(item)?; } } SborValue::Tuple { elements } => { - encoder.write_size(elements.len()); + encoder.write_size(elements.len())?; for field in elements { - field.encode(encoder); + encoder.encode(field)?; } } // custom SborValue::Custom { value } => { - value.encode_body(encoder); + encoder.encode_body(value)?; } } + Ok(()) } } @@ -433,7 +435,7 @@ mod tests { y: map1, z: map2, }; - let bytes = basic_encode(&data); + let bytes = basic_encode(&data).unwrap(); let value = basic_decode(&bytes).unwrap(); assert_eq!( @@ -530,84 +532,87 @@ mod tests { ); let mut bytes2 = Vec::new(); - let mut enc = Encoder::new(&mut bytes2); - value.encode(&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); + 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); + 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); + 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); + 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); + 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); + 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) -> Vec { + 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); + 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); + 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); - buf + encoder.write_type_id(SborTypeId::Array)?; // Child type + encoder.write_size(0)?; + + Ok(buf) } - pub fn encode_struct_of_depth(depth: u8) -> Vec { + 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); + 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); - buf + encoder.write_type_id(SborTypeId::Struct)?; + encoder.write_size(0)?; + + Ok(buf) } - pub fn encode_tuple_of_depth(depth: u8) -> Vec { + 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); + 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); - buf + 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 128013bc385..b33286309a4 100644 --- a/scrypto-derive/src/non_fungible_data.rs +++ b/scrypto-derive/src/non_fungible_data.rs @@ -66,35 +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 = ScryptoEncoder::new(&mut bytes); - encoder.write_type_id(ScryptoSborTypeId::Struct); - encoder.write_size(#im_n); + 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 = ScryptoEncoder::new(&mut bytes); - encoder.write_type_id(ScryptoSborTypeId::Struct); - encoder.write_size(#m_n); + 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 { @@ -193,26 +193,26 @@ mod tests { 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 = ScryptoEncoder::new(&mut bytes); - encoder.write_type_id(ScryptoSborTypeId::Struct); - encoder.write_size(1); - self.field_1.encode(&mut encoder); - 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 = ScryptoEncoder::new(&mut bytes); - encoder.write_type_id(ScryptoSborTypeId::Struct); - encoder.write_size(1); - self.field_2.encode(&mut encoder); - 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 5a6623a23c0..13ecbc4bb30 100644 --- a/scrypto-unit/src/test_runner.rs +++ b/scrypto-unit/src/test_runner.rs @@ -621,15 +621,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 2eaa453aba1..6587175998a 100644 --- a/scrypto/src/buffer/codec.rs +++ b/scrypto/src/buffer/codec.rs @@ -6,9 +6,9 @@ use crate::buffer::*; use radix_engine_interface::data::*; /// Encodes a data structure into a Scrypto buffer. -pub fn scrypto_encode_to_buffer(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. @@ -29,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/kv_store.rs b/scrypto/src/component/kv_store.rs index 278a1aab78c..ed870c8c761 100644 --- a/scrypto/src/component/kv_store.rs +++ b/scrypto/src/component/kv_store.rs @@ -47,7 +47,8 @@ impl KeyValu /// 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(); @@ -65,7 +66,8 @@ impl KeyValu 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(); @@ -84,14 +86,15 @@ impl KeyValu /// 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(); } @@ -156,17 +159,20 @@ impl TypeId< } } -impl Encode - for KeyValueStore +impl< + 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()) } } 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 a1f43796380..4466969e59c 100644 --- a/scrypto/src/engine/scrypto_env.rs +++ b/scrypto/src/engine/scrypto_env.rs @@ -22,7 +22,7 @@ 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) } 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/runtime/data.rs b/scrypto/src/runtime/data.rs index 25ec2b909c2..b3c02cb4d05 100644 --- a/scrypto/src/runtime/data.rs +++ b/scrypto/src/runtime/data.rs @@ -67,13 +67,13 @@ impl 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), }; 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/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 66654ae31d4..0f9db073ce0 100644 --- a/transaction/src/builder/manifest_builder.rs +++ b/transaction/src/builder/manifest_builder.rs @@ -36,7 +36,7 @@ macro_rules! args_from_bytes_vec { fields.push(::scrypto::data::scrypto_decode(&arg).unwrap()); } let input_struct = ::scrypto::data::ScryptoValue::Struct { fields }; - ::scrypto::data::scrypto_encode(&input_struct) + ::scrypto::data::scrypto_encode(&input_struct).unwrap() }}; } @@ -334,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 @@ -407,7 +407,7 @@ impl ManifestBuilder { fields.push(scrypto_decode(&arg).unwrap()); } let input_struct = ScryptoValue::Struct { fields }; - let bytes = scrypto_encode(&input_struct); + let bytes = scrypto_encode(&input_struct).unwrap(); Ok(self .add_instruction(Instruction::CallFunction { @@ -501,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); @@ -650,7 +650,8 @@ impl ManifestBuilder { args: scrypto_encode(&ResourceManagerMintInvocation { receiver: resource_address, mint_params: MintParams::Fungible { amount }, - }), + }) + .unwrap(), }); self } @@ -667,7 +668,8 @@ impl ManifestBuilder { args: scrypto_encode(&ResourceManagerBurnInvocation { receiver: resource_address, bucket: Bucket(bucket_id), - }), + }) + .unwrap(), }) .0 }) @@ -691,7 +693,8 @@ impl ManifestBuilder { args: scrypto_encode(&ResourceManagerBurnInvocation { receiver: non_fungible_address.resource_address(), bucket: Bucket(bucket_id), - }), + }) + .unwrap(), }) .0 }, @@ -958,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 @@ -973,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 @@ -982,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 @@ -991,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) @@ -1042,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) @@ -1079,7 +1082,7 @@ impl ManifestBuilder { } } }; - Ok(scrypto_encode(&Proof(proof_id))) + Ok(scrypto_encode(&Proof(proof_id)).unwrap()) } _ => Err(BuildArgsError::UnsupportedType(i, t.clone())), }; @@ -1106,7 +1109,7 @@ 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()) } } 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 7c6ca6b68d9..26231025eae 100644 --- a/transaction/src/manifest/decompiler.rs +++ b/transaction/src/manifest/decompiler.rs @@ -5,12 +5,13 @@ use radix_engine_interface::api::types::{ }; use radix_engine_interface::core::NetworkDefinition; use radix_engine_interface::data::{ - scrypto_decode, scrypto_encode, IndexedScryptoValue, ValueFormattingContext, + scrypto_decode, scrypto_encode, IndexedScryptoValue, ScryptoValueDecodeError, + ValueFormattingContext, }; use radix_engine_interface::model::*; use sbor::rust::collections::*; use sbor::rust::fmt; -use sbor::SborValue; +use sbor::{EncodeError, SborValue}; use utils::ContextualDisplay; use crate::errors::*; @@ -21,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) @@ -477,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 = scrypto_encode(&field); + let bytes = scrypto_encode(&field)?; let arg = IndexedScryptoValue::from_slice(&bytes) .map_err(|_| DecompileError::InvalidArguments)?; f.write_char(' ')?; @@ -559,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 97113783ad8..2802ef1935f 100644 --- a/transaction/src/manifest/generator.rs +++ b/transaction/src/manifest/generator.rs @@ -32,7 +32,7 @@ use crate::validation::*; macro_rules! args_from_value_vec { ($args: expr) => {{ let input_struct = ::sbor::SborValue::Struct { fields: $args }; - ::radix_engine_interface::data::scrypto_encode(&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 { @@ -532,7 +534,7 @@ fn generate_args( for v in values { let value = generate_value(v, None, resolver, bech32_decoder, blobs)?; - result.push(scrypto_encode(&value)); + result.push(scrypto_encode(&value).map_err(|err| GeneratorError::SborEncodeError(err))?); } Ok(result) } 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 0644153e5a7..e062b6590fd 100644 --- a/transaction/src/validation/transaction_validator.rs +++ b/transaction/src/validation/transaction_validator.rs @@ -1,5 +1,5 @@ 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}; @@ -68,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; @@ -117,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(); @@ -162,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); } @@ -313,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)?; @@ -332,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, From 31e64c0dfc2b0ddaaec3ea0897165fef88f777d7 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 01:51:10 +0000 Subject: [PATCH 07/20] fix: Fix tests --- radix-engine-interface/src/data/mod.rs | 2 +- radix-engine/src/model/package/substates.rs | 2 +- radix-engine/src/state_manager/state_diff.rs | 8 ++++++-- sbor/src/basic.rs | 2 +- sbor/src/encoder.rs | 1 + 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/radix-engine-interface/src/data/mod.rs b/radix-engine-interface/src/data/mod.rs index e0f4476bec2..35c98d12a4e 100644 --- a/radix-engine-interface/src/data/mod.rs +++ b/radix-engine-interface/src/data/mod.rs @@ -24,7 +24,7 @@ pub use schema_matcher::*; pub use schema_path::*; pub use value_formatter::*; -pub const MAX_SCRYPTO_SBOR_DEPTH: u8 = 32; +pub const MAX_SCRYPTO_SBOR_DEPTH: u8 = 64; pub type ScryptoEncoder<'a> = VecEncoder<'a, ScryptoCustomTypeId, MAX_SCRYPTO_SBOR_DEPTH>; pub type ScryptoDecoder<'a> = VecDecoder<'a, ScryptoCustomTypeId, MAX_SCRYPTO_SBOR_DEPTH>; diff --git a/radix-engine/src/model/package/substates.rs b/radix-engine/src/model/package/substates.rs index a1d9d2f96bc..6e595cd2de3 100644 --- a/radix-engine/src/model/package/substates.rs +++ b/radix-engine/src/model/package/substates.rs @@ -11,7 +11,7 @@ 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/state_manager/state_diff.rs b/radix-engine/src/state_manager/state_diff.rs index c709fbc0e4c..87f6cbfdfe6 100644 --- a/radix-engine/src/state_manager/state_diff.rs +++ b/radix-engine/src/state_manager/state_diff.rs @@ -30,8 +30,12 @@ impl StateDiff { let output_id = OutputId { substate_id: substate_id.clone(), substate_hash: hash( - scrypto_encode(&output_value.substate) - .expect("Could not encode newly-committed substate"), + 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, }; diff --git a/sbor/src/basic.rs b/sbor/src/basic.rs index 29520e8a521..b5defd6bbaa 100644 --- a/sbor/src/basic.rs +++ b/sbor/src/basic.rs @@ -17,7 +17,7 @@ pub enum NoCustomTypeId {} #[derive(Debug, Clone, PartialEq, Eq)] pub enum NoCustomValue {} -pub const DEFAULT_BASIC_MAX_DEPTH: u8 = 32; +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; diff --git a/sbor/src/encoder.rs b/sbor/src/encoder.rs index f1154fa6057..0c2be8cecb8 100644 --- a/sbor/src/encoder.rs +++ b/sbor/src/encoder.rs @@ -188,6 +188,7 @@ mod tests { 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); From 6edd47c37ba69f204ca0ba6d2ef8f065577619d0 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 03:20:10 +0000 Subject: [PATCH 08/20] fix: Fix some formatting --- radix-engine/src/model/package/substates.rs | 4 +++- radix-engine/tests/blueprints/data_access/src/lib.rs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/radix-engine/src/model/package/substates.rs b/radix-engine/src/model/package/substates.rs index 6e595cd2de3..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").field("blueprint_abis", &self.blueprint_abis).finish() + f.debug_struct("PackageSubstate") + .field("blueprint_abis", &self.blueprint_abis) + .finish() } } diff --git a/radix-engine/tests/blueprints/data_access/src/lib.rs b/radix-engine/tests/blueprints/data_access/src/lib.rs index 1f444c74cd3..d8bfaba3b40 100644 --- a/radix-engine/tests/blueprints/data_access/src/lib.rs +++ b/radix-engine/tests/blueprints/data_access/src/lib.rs @@ -24,7 +24,7 @@ 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 +45,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) } } From b12cca2eddb24888217b2f312d2cb5611bec4767 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 04:47:04 +0000 Subject: [PATCH 09/20] fix: Increase WASM stack size to 1024 to permit encoding deep object --- radix-engine/benches/radix_engine.rs | 2 +- radix-engine/src/ledger/bootstrap.rs | 4 ++-- radix-engine/src/model/package_extractor.rs | 2 +- radix-engine/src/wasm/wasm_validator.rs | 2 +- radix-engine/tests/fuzz_transactions.rs | 2 +- radix-engine/tests/transaction_executor.rs | 2 +- scrypto-unit/src/test_runner.rs | 2 +- simulator/src/resim/mod.rs | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) 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/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_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/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/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/transaction_executor.rs b/radix-engine/tests/transaction_executor.rs index 14118b56e69..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, ), }; diff --git a/scrypto-unit/src/test_runner.rs b/scrypto-unit/src/test_runner.rs index 13ecbc4bb30..5f95f75e57d 100644 --- a/scrypto-unit/src/test_runner.rs +++ b/scrypto-unit/src/test_runner.rs @@ -47,7 +47,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(), 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, ), }; From 7d6771e07c47396cbe6c6470964f11a86031c99b Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 05:02:22 +0000 Subject: [PATCH 10/20] fix: Fix a few test blueprints --- radix-engine/tests/blueprints/kernel/src/lib.rs | 4 ++-- .../tests/blueprints/kv_store/src/cyclic_map.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) 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 32f0ddd6aa9..f090bc24d6e 100644 --- a/radix-engine/tests/blueprints/kv_store/src/cyclic_map.rs +++ b/radix-engine/tests/blueprints/kv_store/src/cyclic_map.rs @@ -24,17 +24,17 @@ blueprint! { let node_id = RENodeId::KeyValueStore(kv_store1_id); let offset = - SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(&0u32))); + 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() @@ -46,17 +46,17 @@ blueprint! { let node_id = RENodeId::KeyValueStore(kv_store_id.clone()); let offset = - SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(&0u32))); + 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() From 6e1d210eee6a13f6b748d62a70dedc17c24b9d9f Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 05:30:28 +0000 Subject: [PATCH 11/20] fix: Formatting fix --- .../tests/blueprints/data_access/src/lib.rs | 5 +++- .../blueprints/kv_store/src/cyclic_map.rs | 26 ++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/radix-engine/tests/blueprints/data_access/src/lib.rs b/radix-engine/tests/blueprints/data_access/src/lib.rs index d8bfaba3b40..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(&()).unwrap())) + call_engine(RadixEngineInput::Write( + lock_handle, + scrypto_encode(&()).unwrap(), + )) } pub fn create_component_and_read_info() -> ComponentInfoSubstate { 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 f090bc24d6e..fe1916ea2f7 100644 --- a/radix-engine/tests/blueprints/kv_store/src/cyclic_map.rs +++ b/radix-engine/tests/blueprints/kv_store/src/cyclic_map.rs @@ -23,14 +23,17 @@ blueprint! { }; let node_id = RENodeId::KeyValueStore(kv_store1_id); - let offset = - SubstateOffset::KeyValueStore(KeyValueStoreOffset::Entry(scrypto_encode(&0u32).unwrap())); - 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())); + }) + .unwrap(), + )); let input = RadixEngineInput::LockSubstate(node_id, offset, true); let lock_handle: LockHandle = call_engine(input); @@ -45,14 +48,17 @@ 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).unwrap())); - 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())); + }) + .unwrap(), + )); let input = RadixEngineInput::LockSubstate(node_id, offset, true); let lock_handle: LockHandle = call_engine(input); From c654fc7feb04438296037ec1b08fc2c95de4a08f Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 05:31:17 +0000 Subject: [PATCH 12/20] refactor: Add more #[inline] attributes which somehow decreases WASM code size --- sbor-derive/src/decode.rs | 9 +++++++++ sbor/src/codec/array.rs | 2 ++ sbor/src/codec/boolean.rs | 2 ++ sbor/src/codec/collection.rs | 5 +++++ sbor/src/codec/integer.rs | 9 +++++++++ sbor/src/codec/misc.rs | 4 ++++ sbor/src/codec/option.rs | 1 + sbor/src/codec/result.rs | 1 + sbor/src/codec/string.rs | 1 + sbor/src/codec/tuple.rs | 1 + sbor/src/codec/unit.rs | 1 + sbor/src/decoder.rs | 5 +++++ sbor/src/encoder.rs | 4 ++++ sbor/src/value.rs | 3 +++ 14 files changed, 48 insertions(+) diff --git a/sbor-derive/src/decode.rs b/sbor-derive/src/decode.rs index b0048914564..16e2cb4568e 100644 --- a/sbor-derive/src/decode.rs +++ b/sbor-derive/src/decode.rs @@ -38,6 +38,7 @@ pub fn handle_decode(input: TokenStream) -> Result { let s_types = s.iter().map(|f| &f.ty); quote! { 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)?; @@ -64,6 +65,7 @@ pub fn handle_decode(input: TokenStream) -> Result { Index::from(unnamed.iter().filter(|f| !is_decoding_skipped(f)).count()); quote! { 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)?; @@ -78,6 +80,7 @@ pub fn handle_decode(input: TokenStream) -> Result { syn::Fields::Unit => { quote! { 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)?; @@ -148,6 +151,7 @@ pub fn handle_decode(input: TokenStream) -> Result { quote! { 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)?; @@ -192,6 +196,7 @@ mod tests { output, quote! { 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)?; @@ -217,6 +222,7 @@ mod tests { output, quote! { 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)?; @@ -239,6 +245,7 @@ mod tests { output, quote! { 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)?; @@ -261,6 +268,7 @@ mod tests { output, quote! { 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)?; @@ -297,6 +305,7 @@ mod tests { output, quote! { 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)?; diff --git a/sbor/src/codec/array.rs b/sbor/src/codec/array.rs index a38aafb52c7..2697b24681c 100644 --- a/sbor/src/codec/array.rs +++ b/sbor/src/codec/array.rs @@ -7,6 +7,7 @@ impl, T: Encode + TypeId> Encode f fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_type_id(Self::type_id()) } + #[inline] fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_type_id(T::type_id())?; @@ -40,6 +41,7 @@ impl, T: Encode + TypeId, const N: usize impl, T: Decode + TypeId, const N: usize> Decode for [T; N] { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, diff --git a/sbor/src/codec/boolean.rs b/sbor/src/codec/boolean.rs index 1fe2aee1e76..f7aa3a229bf 100644 --- a/sbor/src/codec/boolean.rs +++ b/sbor/src/codec/boolean.rs @@ -6,6 +6,7 @@ impl> Encode for bool { fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_type_id(Self::type_id()) } + #[inline] fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_byte(if *self { 1u8 } else { 0u8 }) @@ -13,6 +14,7 @@ impl> Encode for bool { } impl> Decode for bool { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, diff --git a/sbor/src/codec/collection.rs b/sbor/src/codec/collection.rs index 8518cfb8e84..2b7b82d5b4a 100644 --- a/sbor/src/codec/collection.rs +++ b/sbor/src/codec/collection.rs @@ -102,6 +102,7 @@ impl< } impl, T: Decode + TypeId> Decode for Vec { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, @@ -131,6 +132,7 @@ impl, T: Decode + TypeId> Decode f impl, T: Decode + TypeId + Ord> Decode for BTreeSet { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, @@ -144,6 +146,7 @@ impl, T: Decode + TypeId + Ord> Decode, T: Decode + TypeId + Hash + Eq> Decode for HashSet { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, @@ -161,6 +164,7 @@ impl< V: Decode + TypeId, > Decode for BTreeMap { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, @@ -178,6 +182,7 @@ impl< V: Decode + TypeId, > Decode for HashMap { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, diff --git a/sbor/src/codec/integer.rs b/sbor/src/codec/integer.rs index 090a6c8c850..2b14efcf3ed 100644 --- a/sbor/src/codec/integer.rs +++ b/sbor/src/codec/integer.rs @@ -6,6 +6,7 @@ impl> Encode for i8 { fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_type_id(Self::type_id()) } + #[inline] fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_byte(*self as u8) @@ -17,6 +18,7 @@ impl> Encode for u8 { fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_type_id(Self::type_id()) } + #[inline] fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_byte(*self) @@ -30,6 +32,7 @@ macro_rules! encode_int { fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_type_id(Self::type_id()) } + #[inline] fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_slice(&(*self).to_le_bytes()) @@ -64,6 +67,7 @@ impl> Encode for usize { fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { encoder.write_type_id(Self::type_id()) } + #[inline] fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { (*self as u64).encode_body(encoder) @@ -71,6 +75,7 @@ impl> Encode for usize { } impl> Decode for i8 { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, @@ -82,6 +87,7 @@ impl> Decode for i8 { } impl> Decode for u8 { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, @@ -95,6 +101,7 @@ impl> Decode for u8 { macro_rules! decode_int { ($type:ident, $type_id:ident, $n:expr) => { impl> Decode for $type { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, @@ -119,6 +126,7 @@ decode_int!(u64, TYPE_U64, 8); decode_int!(u128, TYPE_U128, 16); impl> Decode for isize { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, @@ -129,6 +137,7 @@ impl> Decode for isize { } impl> Decode for usize { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, diff --git a/sbor/src/codec/misc.rs b/sbor/src/codec/misc.rs index a6be3719bc3..9a955b2357c 100644 --- a/sbor/src/codec/misc.rs +++ b/sbor/src/codec/misc.rs @@ -59,6 +59,7 @@ impl, T: Encode + TypeId> Encode f 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 D, type_id: SborTypeId, @@ -68,6 +69,7 @@ impl<'a, X: CustomTypeId, D: Decoder, B: ?Sized + 'a + ToOwned, O: } impl, T: Decode> Decode for Box { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, @@ -77,6 +79,7 @@ impl, T: Decode> Decode for Box { } impl, T: Decode> Decode for Rc { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, @@ -86,6 +89,7 @@ impl, T: Decode> Decode for Rc { } impl, T: Decode + TypeId> Decode for RefCell { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, diff --git a/sbor/src/codec/option.rs b/sbor/src/codec/option.rs index ed25d508388..cc6e9acb0ec 100644 --- a/sbor/src/codec/option.rs +++ b/sbor/src/codec/option.rs @@ -26,6 +26,7 @@ impl, T: Encode + TypeId> Encode f } impl, T: Decode> Decode for Option { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, diff --git a/sbor/src/codec/result.rs b/sbor/src/codec/result.rs index 92453ba0341..b80d11be49e 100644 --- a/sbor/src/codec/result.rs +++ b/sbor/src/codec/result.rs @@ -31,6 +31,7 @@ impl, T: Encode, E: Encode> Enc impl, T: Decode + TypeId, E: Decode + TypeId> Decode for Result { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, diff --git a/sbor/src/codec/string.rs b/sbor/src/codec/string.rs index 71f190d1c0a..76ec0766166 100644 --- a/sbor/src/codec/string.rs +++ b/sbor/src/codec/string.rs @@ -43,6 +43,7 @@ impl> Encode for String { } impl> Decode for String { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, diff --git a/sbor/src/codec/tuple.rs b/sbor/src/codec/tuple.rs index 40d487c58e7..48ab5bb3788 100644 --- a/sbor/src/codec/tuple.rs +++ b/sbor/src/codec/tuple.rs @@ -32,6 +32,7 @@ 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, $($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)?; diff --git a/sbor/src/codec/unit.rs b/sbor/src/codec/unit.rs index 403504e9e5b..b23727e4c3d 100644 --- a/sbor/src/codec/unit.rs +++ b/sbor/src/codec/unit.rs @@ -14,6 +14,7 @@ impl> Encode for () { } impl> Decode for () { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, diff --git a/sbor/src/decoder.rs b/sbor/src/decoder.rs index d192a3c4c3d..e515c4f5646 100644 --- a/sbor/src/decoder.rs +++ b/sbor/src/decoder.rs @@ -34,6 +34,7 @@ pub enum DecodeError { } pub trait Decoder: Sized { + #[inline] fn decode_payload>(mut self) -> Result { let value = self.decode()?; self.check_end()?; @@ -55,6 +56,7 @@ pub trait Decoder: Sized { Ok(decoded) } + #[inline] fn read_type_id(&mut self) -> Result, DecodeError> { let id = self.read_byte()?; SborTypeId::from_u8(id).ok_or(DecodeError::UnknownTypeId(id)) @@ -84,6 +86,7 @@ pub trait Decoder: Sized { Ok(size) } + #[inline] fn check_preloaded_type_id( &self, type_id: SborTypeId, @@ -99,6 +102,7 @@ pub trait Decoder: Sized { } } + #[inline] fn read_and_check_type_id( &mut self, expected: SborTypeId, @@ -107,6 +111,7 @@ pub trait Decoder: Sized { 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 { diff --git a/sbor/src/encoder.rs b/sbor/src/encoder.rs index 0c2be8cecb8..6445fa11496 100644 --- a/sbor/src/encoder.rs +++ b/sbor/src/encoder.rs @@ -10,6 +10,7 @@ pub enum EncodeError { } pub trait Encoder: Sized { + #[inline] fn encode_payload + ?Sized>(mut self, value: &T) -> Result<(), EncodeError> { self.encode(value) } @@ -25,6 +26,7 @@ pub trait Encoder: Sized { self.track_stack_depth_decrease() } + #[inline] fn write_type_id(&mut self, ty: SborTypeId) -> Result<(), EncodeError> { self.write_byte(ty.as_u8()) } @@ -77,11 +79,13 @@ impl<'a, X: CustomTypeId, const MAX_DEPTH: u8> VecEncoder<'a, X, MAX_DEPTH> { } impl<'a, X: CustomTypeId, const MAX_DEPTH: u8> Encoder for VecEncoder<'a, X, MAX_DEPTH> { + #[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(()) diff --git a/sbor/src/value.rs b/sbor/src/value.rs index e98bb65e1a3..f7d68acdae1 100644 --- a/sbor/src/value.rs +++ b/sbor/src/value.rs @@ -74,6 +74,7 @@ pub enum SborValue { } impl, CV: 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), @@ -97,6 +98,7 @@ impl, CV: Encode> Encode for SborValu } } + #[inline] fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { match self { SborValue::Unit => { @@ -180,6 +182,7 @@ impl, CV: Encode> Encode for SborValu } impl, CV: Decode> Decode for SborValue { + #[inline] fn decode_body_with_type_id( decoder: &mut D, type_id: SborTypeId, From 907b144d319a2f8b5e0ad90b8ae8ee2fd0650c12 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 05:49:39 +0000 Subject: [PATCH 13/20] fix: Fix recursion test for doubling stack limit --- radix-engine/tests/metering.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radix-engine/tests/metering.rs b/radix-engine/tests/metering.rs index 47e0b911097..ff04e592619 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()) From c6b1c8c41f20456157cfd7bc6e2570539f6fc649 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 15:06:21 +0000 Subject: [PATCH 14/20] fix: If size is too large, now returns EncodeError instead of panicking --- sbor/src/encoder.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/sbor/src/encoder.rs b/sbor/src/encoder.rs index 6445fa11496..e25590c63a4 100644 --- a/sbor/src/encoder.rs +++ b/sbor/src/encoder.rs @@ -38,7 +38,13 @@ pub trait Encoder: Sized { fn write_size(&mut self, mut size: usize) -> Result<(), EncodeError> { // LEB128 and 4 bytes max - assert!(size <= 0x0FFFFFFF); // 268,435,455 + // 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; @@ -188,6 +194,21 @@ mod tests { ); } + #[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(); From 1a5ce3c2fd704d4814c3b782619056b61ad27af6 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 15:52:15 +0000 Subject: [PATCH 15/20] refactor: Move track stack depth out of the traits for better hiding --- sbor/src/decoder.rs | 51 +++++++++++++++++++++++---------------------- sbor/src/encoder.rs | 42 ++++++++++++++++++------------------- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/sbor/src/decoder.rs b/sbor/src/decoder.rs index e515c4f5646..810ff2bf544 100644 --- a/sbor/src/decoder.rs +++ b/sbor/src/decoder.rs @@ -49,12 +49,7 @@ pub trait Decoder: Sized { fn decode_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) - } + ) -> Result; #[inline] fn read_type_id(&mut self) -> Result, DecodeError> { @@ -126,10 +121,6 @@ pub trait Decoder: Sized { fn check_end(&self) -> Result<(), DecodeError>; - fn track_stack_depth_increase(&mut self) -> Result<(), DecodeError>; - - fn track_stack_depth_decrease(&mut self) -> Result<(), DecodeError>; - fn read_byte(&mut self) -> Result; fn read_slice(&mut self, n: usize) -> Result<&[u8], DecodeError>; @@ -169,9 +160,34 @@ impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> VecDecoder<'de, X, MAX_DEPTH> { 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_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)?; @@ -197,21 +213,6 @@ impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> Decoder for VecDecoder<'de, X Ok(()) } } - - #[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(()) - } } #[cfg(test)] diff --git a/sbor/src/encoder.rs b/sbor/src/encoder.rs index e25590c63a4..e9459c67f99 100644 --- a/sbor/src/encoder.rs +++ b/sbor/src/encoder.rs @@ -20,11 +20,7 @@ pub trait Encoder: Sized { self.encode_body(value) } - fn encode_body + ?Sized>(&mut self, value: &T) -> Result<(), EncodeError> { - self.track_stack_depth_increase()?; - value.encode_body(self)?; - self.track_stack_depth_decrease() - } + fn encode_body + ?Sized>(&mut self, value: &T) -> Result<(), EncodeError>; #[inline] fn write_type_id(&mut self, ty: SborTypeId) -> Result<(), EncodeError> { @@ -61,10 +57,6 @@ pub trait Encoder: Sized { fn write_byte(&mut self, n: u8) -> Result<(), EncodeError>; fn write_slice(&mut self, slice: &[u8]) -> Result<(), EncodeError>; - - fn track_stack_depth_increase(&mut self) -> Result<(), EncodeError>; - - fn track_stack_depth_decrease(&mut self) -> Result<(), EncodeError>; } /// An `Encoder` abstracts the logic for writing core types into a byte buffer. @@ -82,33 +74,39 @@ impl<'a, X: CustomTypeId, const MAX_DEPTH: u8> VecEncoder<'a, X, MAX_DEPTH> { phantom: PhantomData, } } -} -impl<'a, X: CustomTypeId, const MAX_DEPTH: u8> Encoder for VecEncoder<'a, X, MAX_DEPTH> { #[inline] - fn write_byte(&mut self, n: u8) -> Result<(), EncodeError> { - self.buf.push(n); + 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 write_slice(&mut self, slice: &[u8]) -> Result<(), EncodeError> { - self.buf.extend(slice); + 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_body + ?Sized>(&mut self, value: &T) -> Result<(), EncodeError> { + self.track_stack_depth_increase()?; + value.encode_body(self)?; + self.track_stack_depth_decrease() + } #[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)); - } + fn write_byte(&mut self, n: u8) -> Result<(), EncodeError> { + self.buf.push(n); Ok(()) } #[inline] - fn track_stack_depth_decrease(&mut self) -> Result<(), EncodeError> { - self.stack_depth -= 1; + fn write_slice(&mut self, slice: &[u8]) -> Result<(), EncodeError> { + self.buf.extend(slice); Ok(()) } } From 1132184bcd527fa3b7100242231c63756072cd52 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 20 Nov 2022 16:28:40 +0000 Subject: [PATCH 16/20] docs: Improve docs on Encode/Decode/Encoder/Decoder --- sbor/src/decode.rs | 23 ++++++++++++++++++++++- sbor/src/decoder.rs | 26 ++++++++++++++++++++++++++ sbor/src/encode.rs | 24 ++++++++++++++++++++++++ sbor/src/encoder.rs | 26 ++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 1 deletion(-) diff --git a/sbor/src/decode.rs b/sbor/src/decode.rs index e19c614fc0f..1d176a84a79 100644 --- a/sbor/src/decode.rs +++ b/sbor/src/decode.rs @@ -3,7 +3,28 @@ use crate::type_id::*; /// 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, with a preloaded type id. + /// Decodes the type from the decoder, using a preloaded type id. + /// + /// You likely want to call `decoder.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. + /// + /// 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 D, type_id: SborTypeId, diff --git a/sbor/src/decoder.rs b/sbor/src/decoder.rs index 810ff2bf544..03c041846c5 100644 --- a/sbor/src/decoder.rs +++ b/sbor/src/decoder.rs @@ -34,6 +34,7 @@ pub enum DecodeError { } 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()?; @@ -41,11 +42,36 @@ pub trait Decoder: Sized { 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_body_with_type_id(type_id) } + /// Decodes the SBOR body of the value as part of a larger payload. + /// + /// In some 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. + /// + /// 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>( &mut self, type_id: SborTypeId, diff --git a/sbor/src/encode.rs b/sbor/src/encode.rs index 9292a528473..3f77678a5a0 100644 --- a/sbor/src/encode.rs +++ b/sbor/src/encode.rs @@ -3,6 +3,30 @@ use crate::type_id::*; /// A data structure that can be serialized into a byte array using SBOR. 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 likely want to call `encoder.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. + /// + /// 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 index e9459c67f99..2c7f130fff8 100644 --- a/sbor/src/encoder.rs +++ b/sbor/src/encoder.rs @@ -10,16 +10,42 @@ pub enum EncodeError { } 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_body(value) } + /// Encodes the SBOR body of the value as part of a larger payload. + /// + /// In some 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. + /// + /// 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 + ?Sized>(&mut self, value: &T) -> Result<(), EncodeError>; #[inline] From 585cc2e24468dff5c6b4d25da1244697d839617c Mon Sep 17 00:00:00 2001 From: David Edey Date: Thu, 24 Nov 2022 03:18:38 +0000 Subject: [PATCH 17/20] fix: Various SBOR implementation fixes --- sbor/src/codec/array.rs | 2 +- sbor/src/codec/collection.rs | 38 +++++---------- sbor/src/codec/misc.rs | 30 ++++++++---- sbor/src/codec/string.rs | 16 +------ sbor/src/codec/tuple.rs | 4 +- sbor/src/type_id.rs | 1 + sbor/src/value.rs | 93 ++++++++++++++++++------------------ 7 files changed, 85 insertions(+), 99 deletions(-) diff --git a/sbor/src/codec/array.rs b/sbor/src/codec/array.rs index 2697b24681c..ff30b23920f 100644 --- a/sbor/src/codec/array.rs +++ b/sbor/src/codec/array.rs @@ -34,7 +34,7 @@ impl, T: Encode + TypeId, const N: usize } #[inline] fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.encode_body(self.as_slice()) + self.as_slice().encode_body(encoder) } } diff --git a/sbor/src/codec/collection.rs b/sbor/src/codec/collection.rs index 2b7b82d5b4a..e8a55cefd2a 100644 --- a/sbor/src/codec/collection.rs +++ b/sbor/src/codec/collection.rs @@ -13,7 +13,7 @@ impl, T: Encode + TypeId> Encode f #[inline] fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.encode_body(self.as_slice())?; + self.as_slice().encode_body(encoder)?; Ok(()) } } @@ -54,8 +54,8 @@ impl, T: Encode + TypeId + Ord + Hash> E } } -impl, K: Encode + TypeId, V: Encode + TypeId> - Encode for BTreeMap +impl, K: Encode, V: Encode> Encode + for BTreeMap { #[inline] fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -67,20 +67,14 @@ impl, K: Encode + TypeId, V: Encode::type_id())?; encoder.write_size(self.len())?; for (k, v) in self { - encoder.write_size(2)?; - encoder.encode(k)?; - encoder.encode(v)?; + encoder.encode_body(&(k, v))?; } Ok(()) } } -impl< - X: CustomTypeId, - E: Encoder, - K: Encode + TypeId + Ord + Hash, - V: Encode + TypeId, - > Encode for HashMap +impl, K: Encode + Ord + Hash, V: Encode> Encode + for HashMap { #[inline] fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -93,9 +87,7 @@ impl< encoder.write_size(self.len())?; let keys: BTreeSet<&K> = self.keys().collect(); for key in keys { - encoder.write_size(2)?; - encoder.encode(key)?; - encoder.encode(self.get(key).unwrap())?; + encoder.encode_body(&(key, self.get(key).unwrap()))?; } Ok(()) } @@ -157,12 +149,8 @@ impl, T: Decode + TypeId + Hash + Eq> De } } -impl< - X: CustomTypeId, - D: Decoder, - K: Decode + TypeId + Ord, - V: Decode + TypeId, - > Decode for BTreeMap +impl, K: Decode + Ord, V: Decode> Decode + for BTreeMap { #[inline] fn decode_body_with_type_id( @@ -175,12 +163,8 @@ impl< } } -impl< - X: CustomTypeId, - D: Decoder, - K: Decode + TypeId + Hash + Eq, - V: Decode + TypeId, - > Decode for HashMap +impl, K: Decode + Hash + Eq, V: Decode> Decode + for HashMap { #[inline] fn decode_body_with_type_id( diff --git a/sbor/src/codec/misc.rs b/sbor/src/codec/misc.rs index 9a955b2357c..68c151f99b1 100644 --- a/sbor/src/codec/misc.rs +++ b/sbor/src/codec/misc.rs @@ -6,12 +6,24 @@ use crate::rust::rc::Rc; use crate::type_id::*; use crate::*; -impl<'a, X: CustomTypeId, E: Encoder, B: ?Sized + 'a + ToOwned + Encode + TypeId> - Encode for Cow<'a, B> +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 E) -> Result<(), EncodeError> { - encoder.write_type_id(B::type_id()) + self.as_ref().encode_type_id(encoder) } #[inline] @@ -20,10 +32,10 @@ impl<'a, X: CustomTypeId, E: Encoder, B: ?Sized + 'a + ToOwned + Encode } } -impl, T: Encode + TypeId> Encode for Box { +impl, T: Encode> Encode for Box { #[inline] fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.write_type_id(T::type_id()) + self.as_ref().encode_type_id(encoder) } #[inline] @@ -32,10 +44,10 @@ impl, T: Encode + TypeId> Encode f } } -impl, T: Encode + TypeId> Encode for Rc { +impl, T: Encode> Encode for Rc { #[inline] fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.write_type_id(T::type_id()) + self.as_ref().encode_type_id(encoder) } #[inline] @@ -44,10 +56,10 @@ impl, T: Encode + TypeId> Encode f } } -impl, T: Encode + TypeId> Encode for RefCell { +impl, T: Encode> Encode for RefCell { #[inline] fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.write_type_id(T::type_id()) + self.borrow().encode_type_id(encoder) } #[inline] diff --git a/sbor/src/codec/string.rs b/sbor/src/codec/string.rs index 76ec0766166..8ef0245ccf4 100644 --- a/sbor/src/codec/string.rs +++ b/sbor/src/codec/string.rs @@ -16,20 +16,6 @@ impl> Encode for str { } } -impl> Encode for &str { - #[inline] - fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.write_type_id(Self::type_id()) - } - - #[inline] - 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 { #[inline] fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { @@ -38,7 +24,7 @@ impl> Encode for String { #[inline] fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.encode_body(self.as_str()) + self.as_str().encode_body(encoder) } } diff --git a/sbor/src/codec/tuple.rs b/sbor/src/codec/tuple.rs index 48ab5bb3788..11377f6e7b2 100644 --- a/sbor/src/codec/tuple.rs +++ b/sbor/src/codec/tuple.rs @@ -19,6 +19,7 @@ macro_rules! encode_tuple { }; } +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 } @@ -37,12 +38,13 @@ macro_rules! decode_tuple { decoder.check_preloaded_type_id(type_id, Self::type_id())?; decoder.read_and_check_size($n)?; - Ok(($(decoder.decode::<$name>()?),+)) + 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/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 f7d68acdae1..f1ab579f9eb 100644 --- a/sbor/src/value.rs +++ b/sbor/src/value.rs @@ -8,14 +8,15 @@ use crate::rust::string::String; use crate::rust::vec::Vec; use crate::type_id::*; -/// CV is CustomValue +/// 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, @@ -55,25 +56,25 @@ pub enum SborValue { }, Struct { - fields: Vec>, + fields: Vec>, }, Enum { discriminator: String, - fields: Vec>, + fields: Vec>, }, Array { element_type_id: SborTypeId, - elements: Vec>, + elements: Vec>, }, Tuple { - elements: Vec>, + elements: Vec>, }, Custom { - value: CV, + value: Y, }, } -impl, CV: Encode> Encode for SborValue { +impl, Y: Encode> Encode for SborValue { #[inline] fn encode_type_id(&self, encoder: &mut E) -> Result<(), EncodeError> { match self { @@ -102,43 +103,43 @@ impl, CV: Encode> Encode for SborValu fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { match self { SborValue::Unit => { - encoder.encode_body(&())?; + (()).encode_body(encoder)?; } SborValue::Bool { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::I8 { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::I16 { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::I32 { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::I64 { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::I128 { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::U8 { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::U16 { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::U32 { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::U64 { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::U128 { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::String { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } SborValue::Struct { fields } => { encoder.write_size(fields.len())?; @@ -174,14 +175,14 @@ impl, CV: Encode> Encode for SborValu } // custom SborValue::Custom { value } => { - encoder.encode_body(value)?; + value.encode_body(encoder)?; } } Ok(()) } } -impl, CV: Decode> Decode for SborValue { +impl, Y: Decode> Decode for SborValue { #[inline] fn decode_body_with_type_id( decoder: &mut D, @@ -190,51 +191,51 @@ impl, CV: Decode> Decode for SborValu match type_id { // primitive types SborTypeId::Unit => { - decoder.decode_body_with_type_id::<()>(type_id)?; + <()>::decode_body_with_type_id(decoder, type_id)?; Ok(SborValue::Unit) } SborTypeId::Bool => Ok(SborValue::Bool { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::I8 => Ok(SborValue::I8 { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::I16 => Ok(SborValue::I16 { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::I32 => Ok(SborValue::I32 { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::I64 => Ok(SborValue::I64 { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::I128 => Ok(SborValue::I128 { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::U8 => Ok(SborValue::U8 { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::U16 => Ok(SborValue::U16 { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::U32 => Ok(SborValue::U32 { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::U64 => Ok(SborValue::U64 { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::U128 => Ok(SborValue::U128 { - value: decoder.decode_body_with_type_id::(type_id)?, + value: ::decode_body_with_type_id(decoder, type_id)?, }), SborTypeId::String => Ok(SborValue::String { - value: decoder.decode_body_with_type_id::(type_id)?, + 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(); + let mut fields = Vec::with_capacity(if len <= 1024 { len } else { 1024 }); for _ in 0..len { fields.push(decoder.decode()?); } @@ -242,11 +243,11 @@ impl, CV: Decode> Decode for SborValu } SborTypeId::Enum => { // discriminator - let discriminator = decoder.decode_body_with_type_id::(String::type_id())?; + let discriminator = decoder.read_discriminator()?; // number of fields let len = decoder.read_size()?; // fields - let mut fields = Vec::new(); + let mut fields = Vec::with_capacity(if len <= 1024 { len } else { 1024 }); for _ in 0..len { fields.push(decoder.decode()?); } @@ -262,7 +263,7 @@ impl, CV: Decode> Decode for SborValu // length let len = decoder.read_size()?; // values - let mut elements = Vec::new(); + let mut elements = Vec::with_capacity(if len <= 1024 { len } else { 1024 }); for _ in 0..len { elements.push(decoder.decode_body_with_type_id(element_type_id)?); } @@ -275,22 +276,22 @@ impl, CV: Decode> Decode for SborValu //length let len = decoder.read_size()?; // values - let mut elements = Vec::new(); + 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: decoder.decode_body_with_type_id(type_id)?, + value: Y::decode_body_with_type_id(decoder, type_id)?, }), } } } -pub fn traverse_any, E>( +pub fn traverse_any, E>( path: &mut SborPathBuf, - value: &SborValue, + value: &SborValue, visitor: &mut V, ) -> Result<(), E> { match value { @@ -340,10 +341,10 @@ pub fn traverse_any, E>( Ok(()) } -pub trait CustomValueVisitor { +pub trait CustomValueVisitor { type Err; - fn visit(&mut self, path: &mut SborPathBuf, value: &CV) -> Result<(), Self::Err>; + fn visit(&mut self, path: &mut SborPathBuf, value: &Y) -> Result<(), Self::Err>; } #[cfg(test)] From 69ca5606891a090d4db26ba5d8cb9d7ca9875450 Mon Sep 17 00:00:00 2001 From: David Edey Date: Thu, 24 Nov 2022 03:19:12 +0000 Subject: [PATCH 18/20] tests: Add many SBOR depth tests; other markups --- radix-engine-interface/src/data/mod.rs | 385 ++++++++++++++++++++++++- sbor/src/basic.rs | 13 +- 2 files changed, 394 insertions(+), 4 deletions(-) diff --git a/radix-engine-interface/src/data/mod.rs b/radix-engine-interface/src/data/mod.rs index 35c98d12a4e..d459af2e914 100644 --- a/radix-engine-interface/src/data/mod.rs +++ b/radix-engine-interface/src/data/mod.rs @@ -31,8 +31,17 @@ pub type ScryptoDecoder<'a> = VecDecoder<'a, ScryptoCustomTypeId, MAX_SCRYPTO_SB pub type ScryptoSborTypeId = SborTypeId; pub type ScryptoValue = SborValue; -// These trait "aliases" should only be used for parameters, never implementations -// Implementations should implement the underlying traits (TypeId/Encode/Decode) +// 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 {} @@ -86,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] @@ -112,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/sbor/src/basic.rs b/sbor/src/basic.rs index b5defd6bbaa..ae187092792 100644 --- a/sbor/src/basic.rs +++ b/sbor/src/basic.rs @@ -23,8 +23,17 @@ pub type BasicDecoder<'a> = VecDecoder<'a, NoCustomTypeId, DEFAULT_BASIC_MAX_DEP pub type BasicSborValue = SborValue; pub type BasicSborTypeId = SborTypeId; -// These trait "aliases" should only be used for parameters, never implementations -// Implementations should implement the underlying traits (TypeId/Encode/Decode) +// 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 {} From 706e26d354248af16660c2c2410657ed44994d6a Mon Sep 17 00:00:00 2001 From: David Edey Date: Thu, 24 Nov 2022 03:30:43 +0000 Subject: [PATCH 19/20] fix: Fix compilation to not choke on 64 vecs --- radix-engine-interface/src/lib.rs | 1 + 1 file changed, 1 insertion(+) 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."); From 7f407d489247e96de30065caf2b4b3119c1c7858 Mon Sep 17 00:00:00 2001 From: David Edey Date: Thu, 24 Nov 2022 03:34:26 +0000 Subject: [PATCH 20/20] refactor: Renamed encoder/decoder body methods This clarifies in the name a distinction from the more standard direct calls which can be made against a type/value. --- sbor/src/codec/array.rs | 4 ++-- sbor/src/codec/collection.rs | 10 +++++----- sbor/src/decode.rs | 4 +++- sbor/src/decoder.rs | 14 ++++++++------ sbor/src/encode.rs | 4 +++- sbor/src/encoder.rs | 14 ++++++++------ sbor/src/value.rs | 4 ++-- 7 files changed, 31 insertions(+), 23 deletions(-) diff --git a/sbor/src/codec/array.rs b/sbor/src/codec/array.rs index ff30b23920f..34c3a4121fd 100644 --- a/sbor/src/codec/array.rs +++ b/sbor/src/codec/array.rs @@ -18,7 +18,7 @@ impl, T: Encode + TypeId> Encode f encoder.write_slice(slice)?; } else { for v in self { - encoder.encode_body(v)?; + encoder.encode_deeper_body(v)?; } } Ok(()) @@ -61,7 +61,7 @@ impl, T: Decode + TypeId, const N: usize // Decode element by element for elem in &mut data[..] { - elem.write(decoder.decode_body_with_type_id(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/collection.rs b/sbor/src/codec/collection.rs index e8a55cefd2a..63f9a33a3ea 100644 --- a/sbor/src/codec/collection.rs +++ b/sbor/src/codec/collection.rs @@ -29,7 +29,7 @@ impl, T: Encode + TypeId> Encode f encoder.write_type_id(T::type_id())?; encoder.write_size(self.len())?; for v in self { - encoder.encode_body(v)?; + encoder.encode_deeper_body(v)?; } Ok(()) } @@ -48,7 +48,7 @@ impl, T: Encode + TypeId + Ord + Hash> E encoder.write_type_id(T::type_id())?; encoder.write_size(self.len())?; for v in self { - encoder.encode_body(v)?; + encoder.encode_deeper_body(v)?; } Ok(()) } @@ -67,7 +67,7 @@ impl, K: Encode, V: Encode> Encode::type_id())?; encoder.write_size(self.len())?; for (k, v) in self { - encoder.encode_body(&(k, v))?; + encoder.encode_deeper_body(&(k, v))?; } Ok(()) } @@ -87,7 +87,7 @@ impl, K: Encode + Ord + Hash, V: Encode = self.keys().collect(); for key in keys { - encoder.encode_body(&(key, self.get(key).unwrap()))?; + encoder.encode_deeper_body(&(key, self.get(key).unwrap()))?; } Ok(()) } @@ -114,7 +114,7 @@ impl, T: Decode + TypeId> Decode f } else { let mut result = Vec::::with_capacity(if len <= 1024 { len } else { 1024 }); for _ in 0..len { - result.push(decoder.decode_body_with_type_id(element_type_id)?); + result.push(decoder.decode_deeper_body_with_type_id(element_type_id)?); } Ok(result) } diff --git a/sbor/src/decode.rs b/sbor/src/decode.rs index 1d176a84a79..4aa27745f63 100644 --- a/sbor/src/decode.rs +++ b/sbor/src/decode.rs @@ -5,7 +5,7 @@ use crate::type_id::*; pub trait Decode>: Sized { /// Decodes the type from the decoder, using a preloaded type id. /// - /// You likely want to call `decoder.decode_body_with_type_id` instead of this method. See + /// 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 @@ -14,6 +14,8 @@ pub trait Decode>: Sized { /// 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. diff --git a/sbor/src/decoder.rs b/sbor/src/decoder.rs index 03c041846c5..6d2b9ba7018 100644 --- a/sbor/src/decoder.rs +++ b/sbor/src/decoder.rs @@ -47,12 +47,12 @@ pub trait Decoder: Sized { /// 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_body_with_type_id(type_id) + self.decode_deeper_body_with_type_id(type_id) } - /// Decodes the SBOR body of the value as part of a larger payload. + /// Decodes the SBOR body of a child value as part of a larger payload. /// - /// In some cases, you may wish to directly call `T::decode_body_with_type_id` instead of this method. + /// 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 @@ -61,18 +61,20 @@ pub trait Decoder: Sized { /// 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 + /// 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_body_with_type_id>( + fn decode_deeper_body_with_type_id>( &mut self, type_id: SborTypeId, ) -> Result; @@ -204,7 +206,7 @@ impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> VecDecoder<'de, X, MAX_DEPTH> { } impl<'de, X: CustomTypeId, const MAX_DEPTH: u8> Decoder for VecDecoder<'de, X, MAX_DEPTH> { - fn decode_body_with_type_id>( + fn decode_deeper_body_with_type_id>( &mut self, type_id: SborTypeId, ) -> Result { diff --git a/sbor/src/encode.rs b/sbor/src/encode.rs index 3f77678a5a0..12e2a0979ba 100644 --- a/sbor/src/encode.rs +++ b/sbor/src/encode.rs @@ -8,7 +8,7 @@ pub trait Encode> { /// Encodes the SBOR body of the type to the encoder. /// - /// You likely want to call `encoder.encode_body` instead of this method. See + /// You may want to call `encoder.encode_deeper_body` instead of this method. See /// the below section for details. /// /// ## Direct calls and SBOR Depth @@ -17,6 +17,8 @@ pub trait Encode> { /// 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. diff --git a/sbor/src/encoder.rs b/sbor/src/encoder.rs index 2c7f130fff8..c095af2ee18 100644 --- a/sbor/src/encoder.rs +++ b/sbor/src/encoder.rs @@ -21,12 +21,12 @@ pub trait Encoder: Sized { /// 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_body(value) + self.encode_deeper_body(value) } - /// Encodes the SBOR body of the value as part of a larger payload. + /// Encodes the SBOR body of a child value as part of a larger payload. /// - /// In some cases, you may wish to directly call `value.encode_body` instead of this method. See + /// 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 @@ -35,18 +35,20 @@ pub trait Encoder: Sized { /// 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 + /// 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_body + ?Sized>(&mut self, value: &T) -> Result<(), EncodeError>; + fn encode_deeper_body + ?Sized>(&mut self, value: &T) -> Result<(), EncodeError>; #[inline] fn write_type_id(&mut self, ty: SborTypeId) -> Result<(), EncodeError> { @@ -118,7 +120,7 @@ impl<'a, X: CustomTypeId, const MAX_DEPTH: u8> VecEncoder<'a, X, MAX_DEPTH> { } impl<'a, X: CustomTypeId, const MAX_DEPTH: u8> Encoder for VecEncoder<'a, X, MAX_DEPTH> { - fn encode_body + ?Sized>(&mut self, value: &T) -> Result<(), EncodeError> { + 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() diff --git a/sbor/src/value.rs b/sbor/src/value.rs index f1ab579f9eb..0e90885ff35 100644 --- a/sbor/src/value.rs +++ b/sbor/src/value.rs @@ -164,7 +164,7 @@ impl, Y: Encode> Encode for SborValue encoder.write_type_id(*element_type_id)?; encoder.write_size(elements.len())?; for item in elements { - encoder.encode_body(item)?; + encoder.encode_deeper_body(item)?; } } SborValue::Tuple { elements } => { @@ -265,7 +265,7 @@ impl, Y: Decode> Decode for SborValue // values let mut elements = Vec::with_capacity(if len <= 1024 { len } else { 1024 }); for _ in 0..len { - elements.push(decoder.decode_body_with_type_id(element_type_id)?); + elements.push(decoder.decode_deeper_body_with_type_id(element_type_id)?); } Ok(SborValue::Array { element_type_id,