From 60d2f70009f1f52da59d71b1792fbf0fe112cb13 Mon Sep 17 00:00:00 2001 From: hal3e Date: Mon, 15 Jan 2024 16:32:18 +0100 Subject: [PATCH 01/16] make it compile --- packages/fuels-code-gen/src/program_bindings/utils.rs | 2 +- packages/fuels/Forc.toml | 4 +++- .../fuels/tests/contracts/lib_contract/src/main.sw | 2 +- .../tests/contracts/lib_contract_caller/src/main.sw | 2 +- .../fuels/tests/contracts/liquidity_pool/src/main.sw | 2 +- .../tests/contracts/needs_custom_decoder/src/main.sw | 11 +++++++++++ packages/fuels/tests/contracts/require/src/main.sw | 4 ++-- packages/fuels/tests/contracts/token_ops/src/main.sw | 2 +- packages/fuels/tests/logs.rs | 2 +- packages/fuels/tests/logs/contract_logs/src/main.sw | 2 +- .../script_needs_custom_decoder_logging/Forc.toml | 7 ------- .../script_needs_custom_decoder_logging/src/main.sw | 8 -------- .../tests/logs/script_with_contract_logs/src/main.sw | 2 +- .../scripts/script_needs_custom_decoder/src/main.sw | 11 +++++++++++ .../fuels/tests/scripts/script_require/src/main.sw | 4 ++-- .../fuels/tests/scripts/transfer_script/src/main.sw | 2 +- 16 files changed, 38 insertions(+), 29 deletions(-) delete mode 100644 packages/fuels/tests/logs/script_needs_custom_decoder_logging/Forc.toml delete mode 100644 packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw diff --git a/packages/fuels-code-gen/src/program_bindings/utils.rs b/packages/fuels-code-gen/src/program_bindings/utils.rs index 56671a371b..75b81d8edb 100644 --- a/packages/fuels-code-gen/src/program_bindings/utils.rs +++ b/packages/fuels-code-gen/src/program_bindings/utils.rs @@ -141,7 +141,7 @@ pub(crate) fn tokenize_generics(generics: &[Ident]) -> (TokenStream, TokenStream pub(crate) fn sdk_provided_custom_types_lookup() -> HashMap { [ ("std::address::Address", "::fuels::types::Address"), - ("std::contract_id::AssetId", "::fuels::types::AssetId"), + ("std::asset_id::AssetId", "::fuels::types::AssetId"), ("std::b512::B512", "::fuels::types::B512"), ("std::bytes::Bytes", "::fuels::types::Bytes"), ("std::contract_id::ContractId", "::fuels::types::ContractId"), diff --git a/packages/fuels/Forc.toml b/packages/fuels/Forc.toml index 10518eb26f..ed648aefd4 100644 --- a/packages/fuels/Forc.toml +++ b/packages/fuels/Forc.toml @@ -31,7 +31,6 @@ members = [ 'tests/logs/contract_logs_abi', 'tests/logs/contract_with_contract_logs', 'tests/logs/script_logs', - 'tests/logs/script_needs_custom_decoder_logging', 'tests/logs/script_with_contract_logs', 'tests/predicates/basic_predicate', 'tests/predicates/swap', @@ -103,3 +102,6 @@ members = [ 'tests/types/scripts/script_u256', 'tests/types/scripts/script_vectors', ] + +[patch.'https://github.com/fuellabs/sway'] +std = { git = "https://github.com/fuellabs/sway", branch = "hal3e/trait-auto-impl" } diff --git a/packages/fuels/tests/contracts/lib_contract/src/main.sw b/packages/fuels/tests/contracts/lib_contract/src/main.sw index bedcd0610f..2a51679eb6 100644 --- a/packages/fuels/tests/contracts/lib_contract/src/main.sw +++ b/packages/fuels/tests/contracts/lib_contract/src/main.sw @@ -8,6 +8,6 @@ impl LibContract for Contract { } fn require() -> () { - require(false, __to_str_array("require from contract")); + require(false, "require from contract"); } } diff --git a/packages/fuels/tests/contracts/lib_contract_caller/src/main.sw b/packages/fuels/tests/contracts/lib_contract_caller/src/main.sw index c517b41090..f041f48226 100644 --- a/packages/fuels/tests/contracts/lib_contract_caller/src/main.sw +++ b/packages/fuels/tests/contracts/lib_contract_caller/src/main.sw @@ -1,7 +1,7 @@ contract; use lib_contract::LibContract; -use std::token::mint_to_address; +use std::asset::mint_to_address; use std::constants::ZERO_B256; abi ContractCaller { diff --git a/packages/fuels/tests/contracts/liquidity_pool/src/main.sw b/packages/fuels/tests/contracts/liquidity_pool/src/main.sw index c923f56bf5..5ef6d6049f 100644 --- a/packages/fuels/tests/contracts/liquidity_pool/src/main.sw +++ b/packages/fuels/tests/contracts/liquidity_pool/src/main.sw @@ -6,7 +6,7 @@ use std::{ msg_asset_id, }, context::msg_amount, - token::{ + asset::{ mint_to_address, transfer_to_address, }, diff --git a/packages/fuels/tests/contracts/needs_custom_decoder/src/main.sw b/packages/fuels/tests/contracts/needs_custom_decoder/src/main.sw index 2d7280fc47..5365d5e358 100644 --- a/packages/fuels/tests/contracts/needs_custom_decoder/src/main.sw +++ b/packages/fuels/tests/contracts/needs_custom_decoder/src/main.sw @@ -1,5 +1,16 @@ contract; +impl AbiEncode for [u8; 1000] +{ + fn abi_encode(self, ref mut buffer: Buffer) { + let mut i = 0; + while i < 1000 { + self[i].abi_encode(buffer); + i += 1; + } + } +} + abi MyContract { fn i_return_a_1k_el_array() -> [u8; 1000]; fn i_log_a_1k_el_array(); diff --git a/packages/fuels/tests/contracts/require/src/main.sw b/packages/fuels/tests/contracts/require/src/main.sw index 6f33644caf..ea242fe291 100644 --- a/packages/fuels/tests/contracts/require/src/main.sw +++ b/packages/fuels/tests/contracts/require/src/main.sw @@ -33,7 +33,7 @@ impl TestContract for Contract { } fn require_string() { - require(false, __to_str_array("fuel")); + require(false, "fuel"); } fn require_custom_generic() { @@ -54,7 +54,7 @@ impl TestContract for Contract { fn require_with_additional_logs() { log(42); - log(__to_str_array("fuel")); + log("fuel"); require(false, 64); } } diff --git a/packages/fuels/tests/contracts/token_ops/src/main.sw b/packages/fuels/tests/contracts/token_ops/src/main.sw index 542c666fe4..641d59be70 100644 --- a/packages/fuels/tests/contracts/token_ops/src/main.sw +++ b/packages/fuels/tests/contracts/token_ops/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::{bytes::Bytes, context::balance_of, context::msg_amount, message::send_message, token::*}; +use std::{bytes::Bytes, context::balance_of, context::msg_amount, message::send_message, asset::*}; use std::constants::ZERO_B256; abi TestFuelCoin { diff --git a/packages/fuels/tests/logs.rs b/packages/fuels/tests/logs.rs index a2ea577cef..cd82d6d0b5 100644 --- a/packages/fuels/tests/logs.rs +++ b/packages/fuels/tests/logs.rs @@ -1399,7 +1399,7 @@ async fn can_configure_decoder_for_script_log_decoding() -> Result<()> { Wallets("wallet"), Abigen(Script( name = "LogScript", - project = "packages/fuels/tests/logs/script_needs_custom_decoder_logging" + project = "packages/fuels/tests/scripts/script_needs_custom_decoder" )), LoadScript( name = "script_instance", diff --git a/packages/fuels/tests/logs/contract_logs/src/main.sw b/packages/fuels/tests/logs/contract_logs/src/main.sw index 5c88e1901f..ca90f1f9b0 100644 --- a/packages/fuels/tests/logs/contract_logs/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs/src/main.sw @@ -52,7 +52,7 @@ impl ContractLogs for Contract { fn produce_logs_variables() { let f: u64 = 64; let u: b256 = 0xef86afa9696cf0dc6385e2c407a6e159a1103cefb7e2ae0636fb33d3cb2a9e4a; - let e: str[4] = __to_str_array("Fuel"); + let e: str = "Fuel"; let l: [u8; 3] = [1u8, 2u8, 3u8]; log(f); diff --git a/packages/fuels/tests/logs/script_needs_custom_decoder_logging/Forc.toml b/packages/fuels/tests/logs/script_needs_custom_decoder_logging/Forc.toml deleted file mode 100644 index eb0a1a82b9..0000000000 --- a/packages/fuels/tests/logs/script_needs_custom_decoder_logging/Forc.toml +++ /dev/null @@ -1,7 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "script_needs_custom_decoder_logging" - -[dependencies] diff --git a/packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw b/packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw deleted file mode 100644 index 65c9daa56f..0000000000 --- a/packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw +++ /dev/null @@ -1,8 +0,0 @@ -script; - -fn main() { - // TODO: This file can be made obsolete once - // [retry](`https://github.com/FuelLabs/fuels-rs/issues/1020`) lands. - let arr: [u8; 1000] = [0; 1000]; - log(arr); -} diff --git a/packages/fuels/tests/logs/script_with_contract_logs/src/main.sw b/packages/fuels/tests/logs/script_with_contract_logs/src/main.sw index 89644ee5de..581845fb5f 100644 --- a/packages/fuels/tests/logs/script_with_contract_logs/src/main.sw +++ b/packages/fuels/tests/logs/script_with_contract_logs/src/main.sw @@ -10,7 +10,7 @@ fn main(contract_id: ContractId) { let f: bool = true; let u: u64 = 42; - let e: str[4] = __to_str_array("Fuel"); + let e: str = "Fuel"; let l: [u8; 3] = [1u8, 2u8, 3u8]; log(f); log(u); diff --git a/packages/fuels/tests/scripts/script_needs_custom_decoder/src/main.sw b/packages/fuels/tests/scripts/script_needs_custom_decoder/src/main.sw index 9e0ba87709..cb7b8f342b 100644 --- a/packages/fuels/tests/scripts/script_needs_custom_decoder/src/main.sw +++ b/packages/fuels/tests/scripts/script_needs_custom_decoder/src/main.sw @@ -1,5 +1,16 @@ script; +impl AbiEncode for [u8; 1000] +{ + fn abi_encode(self, ref mut buffer: Buffer) { + let mut i = 0; + while i < 1000 { + self[i].abi_encode(buffer); + i += 1; + } + } +} + fn main() -> [u8; 1000] { let arr: [u8; 1000] = [0; 1000]; log(arr); diff --git a/packages/fuels/tests/scripts/script_require/src/main.sw b/packages/fuels/tests/scripts/script_require/src/main.sw index 62afeb88ae..fdd9b33caa 100644 --- a/packages/fuels/tests/scripts/script_require/src/main.sw +++ b/packages/fuels/tests/scripts/script_require/src/main.sw @@ -32,7 +32,7 @@ fn main(match_enum: MatchEnum) { if let MatchEnum::RequirePrimitive = match_enum { require(false, 42); } else if let MatchEnum::RequireString = match_enum { - require(false, __to_str_array("fuel")); + require(false, "fuel"); } else if let MatchEnum::RequireCustomGeneric = match_enum { let l: [u8; 3] = [1u8, 2u8, 3u8]; @@ -49,7 +49,7 @@ fn main(match_enum: MatchEnum) { require(false, test_deeply_nested_generic); } else if let MatchEnum::RequireWithAdditionalLogs = match_enum { log(42); - log(__to_str_array("fuel")); + log("fuel"); require(false, 64); } } diff --git a/packages/fuels/tests/scripts/transfer_script/src/main.sw b/packages/fuels/tests/scripts/transfer_script/src/main.sw index 2366121d2d..332ed88c39 100644 --- a/packages/fuels/tests/scripts/transfer_script/src/main.sw +++ b/packages/fuels/tests/scripts/transfer_script/src/main.sw @@ -1,6 +1,6 @@ script; -use std::token::transfer_to_address; +use std::asset::transfer_to_address; fn main(amount: u64, asset: AssetId, receiver: Address) -> () { transfer_to_address(receiver, asset, amount); From 1564aafb0b41b01820f9918c457235c9b21b0fa0 Mon Sep 17 00:00:00 2001 From: hal3e Date: Wed, 17 Jan 2024 17:04:46 +0100 Subject: [PATCH 02/16] make current tests work --- packages/fuels-core/src/codec/abi_decoder.rs | 19 + .../experimental_bounded_decoder.rs | 437 ++++++++++++++++++ packages/fuels-core/src/codec/logs.rs | 18 +- .../fuels-core/src/types/enum_variants.rs | 17 + packages/fuels-core/src/types/param_types.rs | 40 ++ packages/fuels/Cargo.toml | 1 + packages/fuels/Forc.toml | 1 + packages/fuels/tests/logs.rs | 38 +- .../tests/logs/contract_logs/src/main.sw | 2 +- .../Forc.toml | 7 + .../src/main.sw | 20 + .../script_with_contract_logs/src/main.sw | 2 +- .../script_needs_custom_decoder/src/main.sw | 12 - 13 files changed, 594 insertions(+), 20 deletions(-) create mode 100644 packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs create mode 100644 packages/fuels/tests/logs/script_needs_custom_decoder_logging/Forc.toml create mode 100644 packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw diff --git a/packages/fuels-core/src/codec/abi_decoder.rs b/packages/fuels-core/src/codec/abi_decoder.rs index 6b7434af87..0693c4f694 100644 --- a/packages/fuels-core/src/codec/abi_decoder.rs +++ b/packages/fuels-core/src/codec/abi_decoder.rs @@ -1,10 +1,15 @@ mod bounded_decoder; +#[cfg(not(experimental))] +mod experimental_bounded_decoder; use crate::{ codec::abi_decoder::bounded_decoder::BoundedDecoder, types::{errors::Result, param_types::ParamType, Token}, }; +#[cfg(not(experimental))] +use crate::codec::abi_decoder::experimental_bounded_decoder::ExperimentalBoundedDecoder; + #[derive(Debug, Clone, Copy)] pub struct DecoderConfig { /// Entering a struct, array, tuple, enum or vector increases the depth. Decoding will fail if @@ -77,6 +82,20 @@ impl ABIDecoder { pub fn decode_multiple(&self, param_types: &[ParamType], bytes: &[u8]) -> Result> { BoundedDecoder::new(self.config).decode_multiple(param_types, bytes) } + + #[cfg(not(experimental))] + pub fn experimental_decode(&self, param_type: &ParamType, bytes: &[u8]) -> Result { + ExperimentalBoundedDecoder::new(self.config).decode(param_type, bytes) + } + + #[cfg(not(experimental))] + pub fn experimental_decode_multiple( + &self, + param_types: &[ParamType], + bytes: &[u8], + ) -> Result> { + ExperimentalBoundedDecoder::new(self.config).decode_multiple(param_types, bytes) + } } #[cfg(test)] diff --git a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs new file mode 100644 index 0000000000..7207cc7f38 --- /dev/null +++ b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs @@ -0,0 +1,437 @@ +use std::str; + +use crate::{ + checked_round_up_to_word_alignment, + codec::DecoderConfig, + constants::WORD_SIZE, + traits::Tokenizable, + types::{ + enum_variants::EnumVariants, + errors::{error, Result}, + param_types::ParamType, + StaticStringToken, Token, U256, + }, +}; + +/// Is used to decode bytes into `Token`s from which types implementing `Tokenizable` can be +/// instantiated. Implements decoding limits to control resource usage. +pub(crate) struct ExperimentalBoundedDecoder { + depth_tracker: CounterWithLimit, + token_tracker: CounterWithLimit, +} + +const U128_BYTES_SIZE: usize = 2 * WORD_SIZE; +const U256_BYTES_SIZE: usize = 4 * WORD_SIZE; +const B256_BYTES_SIZE: usize = 4 * WORD_SIZE; + +impl ExperimentalBoundedDecoder { + pub(crate) fn new(config: DecoderConfig) -> Self { + let depth_tracker = CounterWithLimit::new(config.max_depth, "Depth"); + let token_tracker = CounterWithLimit::new(config.max_tokens, "Token"); + Self { + depth_tracker, + token_tracker, + } + } + + pub fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { + match param_type { + ParamType::Unit => Ok(Token::Unit), + _ => self.decode_param(param_type, bytes).map(|x| x.token), + } + } + + pub(crate) fn decode_multiple( + &mut self, + param_types: &[ParamType], + bytes: &[u8], + ) -> Result> { + let (tokens, _) = self.decode_params(param_types, bytes)?; + + Ok(tokens) + } + + fn run_w_depth_tracking( + &mut self, + decoder: impl FnOnce(&mut Self) -> Result, + ) -> Result { + self.depth_tracker.increase()?; + + let res = decoder(self); + + self.depth_tracker.decrease(); + res + } + + fn decode_param(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { + self.token_tracker.increase()?; + match param_type { + ParamType::Unit => unreachable!(), // `Unit` already handled in `decode` + ParamType::U8 => Self::decode_u8(bytes), // ok + ParamType::U16 => Self::decode_u16(bytes), // ok + ParamType::U32 => Self::decode_u32(bytes), // ok + ParamType::U64 => Self::decode_u64(bytes), // ok + ParamType::U128 => Self::decode_u128(bytes), // ok + ParamType::U256 => Self::decode_u256(bytes), // ok + ParamType::Bool => Self::decode_bool(bytes), // ok + ParamType::B256 => Self::decode_b256(bytes), // ok + ParamType::RawSlice => self.decode_raw_slice(bytes), // nok + ParamType::StringSlice => Self::decode_string_slice(bytes), // nok + ParamType::StringArray(len) => Self::decode_string_array(bytes, *len), // ok + ParamType::Array(ref t, length) => { + self.run_w_depth_tracking(|ctx| ctx.decode_array(t, bytes, *length)) + } // ok + ParamType::Struct { fields, .. } => { + self.run_w_depth_tracking(|ctx| ctx.decode_struct(fields, bytes)) + } // ok + ParamType::Enum { variants, .. } => { + self.run_w_depth_tracking(|ctx| ctx.decode_enum(bytes, variants)) + } // ok + ParamType::Tuple(types) => { + self.run_w_depth_tracking(|ctx| ctx.decode_tuple(types, bytes)) + } // nok + ParamType::Vector(param_type) => { + // although nested vectors cannot be decoded yet, depth tracking still occurs for future + // proofing + self.run_w_depth_tracking(|ctx| ctx.decode_vector(param_type, bytes)) + } // nok + ParamType::Bytes => Self::decode_bytes(bytes), // check + ParamType::String => Self::decode_std_string(bytes), // check + } + } + + fn decode_bytes(bytes: &[u8]) -> Result { + Ok(Decoded { + token: Token::Bytes(bytes.to_vec()), + bytes_read: bytes.len(), + }) + } + + fn decode_std_string(bytes: &[u8]) -> Result { + Ok(Decoded { + token: Token::String(str::from_utf8(bytes)?.to_string()), + bytes_read: bytes.len(), + }) + } + + fn decode_vector(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { + let num_of_elements = ParamType::calculate_num_of_elements(param_type, bytes.len())?; + let (tokens, bytes_read) = + self.decode_params(std::iter::repeat(param_type).take(num_of_elements), bytes)?; + + Ok(Decoded { + token: Token::Vector(tokens), + bytes_read, + }) + } + + fn decode_tuple(&mut self, param_types: &[ParamType], bytes: &[u8]) -> Result { + let mut tokens = vec![]; + + let mut bytes_read = 0; + + for param_type in param_types.iter() { + // padding has to be taken into account + bytes_read = checked_round_up_to_word_alignment(bytes_read)?; + let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?; + bytes_read += res.bytes_read; + tokens.push(res.token); + } + + Ok(Decoded { + token: Token::Tuple(tokens), + bytes_read, + }) + } + + fn decode_struct(&mut self, param_types: &[ParamType], bytes: &[u8]) -> Result { + let mut tokens = vec![]; + + let mut bytes_read = 0; + + for param_type in param_types.iter() { + let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?; + bytes_read += res.bytes_read; + tokens.push(res.token); + } + + Ok(Decoded { + token: Token::Struct(tokens), + bytes_read, + }) + } + + fn decode_params<'a>( + &mut self, + param_types: impl IntoIterator, + bytes: &[u8], + ) -> Result<(Vec, usize)> { + let mut results = vec![]; + + let mut bytes_read = 0; + + for param_type in param_types { + let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?; + bytes_read += res.bytes_read; + results.push(res.token); + } + + Ok((results, bytes_read)) + } + + fn decode_array( + &mut self, + param_type: &ParamType, + bytes: &[u8], + length: usize, + ) -> Result { + let (tokens, bytes_read) = + self.decode_params(std::iter::repeat(param_type).take(length), bytes)?; + + Ok(Decoded { + token: Token::Array(tokens), + bytes_read, + }) + } + + fn decode_raw_slice(&mut self, bytes: &[u8]) -> Result { + let raw_slice_element = ParamType::U64; + let num_of_elements = + ParamType::calculate_num_of_elements(&raw_slice_element, bytes.len())?; + let param_type = ParamType::U64; + let (tokens, bytes_read) = + self.decode_params(std::iter::repeat(¶m_type).take(num_of_elements), bytes)?; + let elements = tokens + .into_iter() + .map(u64::from_token) + .collect::>>() + .map_err(|e| error!(InvalidData, "{e}"))?; + + Ok(Decoded { + token: Token::RawSlice(elements), + bytes_read, + }) + } + + fn decode_string_slice(bytes: &[u8]) -> Result { + let size = peek_u64(bytes)? as usize; + let bytes = peek(skip(bytes, WORD_SIZE)?, size)?; + let decoded = str::from_utf8(bytes)?; + + Ok(Decoded { + token: Token::StringSlice(StaticStringToken::new(decoded.into(), None)), + bytes_read: decoded.len(), + }) + } + + fn decode_string_array(bytes: &[u8], length: usize) -> Result { + let encoded_str = peek(bytes, length)?; + + let decoded = str::from_utf8(encoded_str)?; + let result = Decoded { + token: Token::StringArray(StaticStringToken::new(decoded.into(), Some(length))), + bytes_read: checked_round_up_to_word_alignment(length)?, + }; + Ok(result) + } + + fn decode_b256(bytes: &[u8]) -> Result { + Ok(Decoded { + token: Token::B256(*peek_fixed::(bytes)?), + bytes_read: B256_BYTES_SIZE, + }) + } + + fn decode_bool(bytes: &[u8]) -> Result { + // Grab last byte of the word and compare it to 0x00 + let b = peek_u8(bytes)? != 0u8; + + let result = Decoded { + token: Token::Bool(b), + bytes_read: 1, + }; + + Ok(result) + } + + fn decode_u128(bytes: &[u8]) -> Result { + Ok(Decoded { + token: Token::U128(peek_u128(bytes)?), + bytes_read: U128_BYTES_SIZE, + }) + } + + fn decode_u256(bytes: &[u8]) -> Result { + Ok(Decoded { + token: Token::U256(peek_u256(bytes)?), + bytes_read: U256_BYTES_SIZE, + }) + } + + fn decode_u64(bytes: &[u8]) -> Result { + Ok(Decoded { + token: Token::U64(peek_u64(bytes)?), + bytes_read: WORD_SIZE, + }) + } + + fn decode_u32(bytes: &[u8]) -> Result { + Ok(Decoded { + token: Token::U32(peek_u32(bytes)?), + bytes_read: WORD_SIZE, + }) + } + + fn decode_u16(bytes: &[u8]) -> Result { + Ok(Decoded { + token: Token::U16(peek_u16(bytes)?), + bytes_read: WORD_SIZE, + }) + } + + fn decode_u8(bytes: &[u8]) -> Result { + Ok(Decoded { + token: Token::U8(peek_u8(bytes)?), + bytes_read: 1, + }) + } + + /// The encoding follows the ABI specs defined + /// [here](https://github.com/FuelLabs/fuel-specs/blob/1be31f70c757d8390f74b9e1b3beb096620553eb/specs/protocol/abi.md) + /// + /// # Arguments + /// + /// * `data`: slice of encoded data on whose beginning we're expecting an encoded enum + /// * `variants`: all types that this particular enum type could hold + fn decode_enum(&mut self, bytes: &[u8], variants: &EnumVariants) -> Result { + let discriminant = peek_u64(bytes)?; + let selected_variant = variants.param_type_of_variant(discriminant)?; + + let enum_content_bytes = skip(bytes, 8)?; + let result = self.decode_token_in_enum(enum_content_bytes, variants, selected_variant)?; + + let selector = Box::new((discriminant, result.token, variants.clone())); + Ok(Decoded { + token: Token::Enum(selector), + bytes_read: 8 + result.bytes_read, + }) + } + + fn decode_token_in_enum( + &mut self, + bytes: &[u8], + variants: &EnumVariants, + selected_variant: &ParamType, + ) -> Result { + // Enums that contain only Units as variants have only their discriminant encoded. + // Because of this we construct the Token::Unit rather than calling `decode_param` + if variants.only_units_inside() { + Ok(Decoded { + token: Token::Unit, + bytes_read: 0, + }) + } else { + self.decode_param(selected_variant, bytes) + } + } +} + +#[derive(Debug, Clone)] +struct Decoded { + token: Token, + bytes_read: usize, +} + +struct CounterWithLimit { + count: usize, + max: usize, + name: String, +} + +impl CounterWithLimit { + fn new(max: usize, name: impl Into) -> Self { + Self { + count: 0, + max, + name: name.into(), + } + } + + fn increase(&mut self) -> Result<()> { + self.count += 1; + if self.count > self.max { + Err(error!( + InvalidType, + "{} limit ({}) reached while decoding. Try increasing it.", self.name, self.max + )) + } else { + Ok(()) + } + } + + fn decrease(&mut self) { + if self.count > 0 { + self.count -= 1; + } + } +} + +fn peek_u128(bytes: &[u8]) -> Result { + let slice = peek_fixed::(bytes)?; + Ok(u128::from_be_bytes(*slice)) +} + +fn peek_u256(bytes: &[u8]) -> Result { + let slice = peek_fixed::(bytes)?; + Ok(U256::from(*slice)) +} + +fn peek_u64(bytes: &[u8]) -> Result { + let slice = peek_fixed::(bytes)?; + Ok(u64::from_be_bytes(*slice)) +} + +fn peek_u32(bytes: &[u8]) -> Result { + let slice = peek_fixed::<4>(bytes)?; + Ok(u32::from_be_bytes(*slice)) +} + +fn peek_u16(bytes: &[u8]) -> Result { + let slice = peek_fixed::<2>(bytes)?; + Ok(u16::from_be_bytes(*slice)) +} + +fn peek_u8(bytes: &[u8]) -> Result { + let slice = peek_fixed::<1>(bytes)?; + Ok(u8::from_be_bytes(*slice)) +} + +fn peek_fixed(data: &[u8]) -> Result<&[u8; LEN]> { + let slice_w_correct_length = peek(data, LEN)?; + Ok(<&[u8; LEN]>::try_from(slice_w_correct_length) + .expect("peek(data,len) must return a slice of length `len` or error out")) +} + +fn peek(data: &[u8], len: usize) -> Result<&[u8]> { + if len > data.len() { + Err(error!( + InvalidData, + "tried to read {len} bytes from response but only had {} remaining!", + data.len() + )) + } else { + Ok(&data[..len]) + } +} + +fn skip(slice: &[u8], num_bytes: usize) -> Result<&[u8]> { + if num_bytes > slice.len() { + Err(error!( + InvalidData, + "tried to consume {num_bytes} bytes from response but only had {} remaining!", + slice.len() + )) + } else { + Ok(&slice[num_bytes..]) + } +} diff --git a/packages/fuels-core/src/codec/logs.rs b/packages/fuels-core/src/codec/logs.rs index 1daae05ed5..6581b9aef4 100644 --- a/packages/fuels-core/src/codec/logs.rs +++ b/packages/fuels-core/src/codec/logs.rs @@ -10,12 +10,12 @@ use fuel_tx::{ContractId, Receipt}; use crate::{ codec::{ABIDecoder, DecoderConfig}, traits::{Parameterize, Tokenizable}, - types::{ - errors::{error, Error, Result}, - param_types::ParamType, - }, + types::errors::{error, Error, Result}, }; +#[cfg(experimental)] +use crate::types::param_types::ParamType; + #[derive(Clone)] pub struct LogFormatter { formatter: fn(DecoderConfig, &[u8]) -> Result, @@ -34,11 +34,17 @@ impl LogFormatter { decoder_config: DecoderConfig, bytes: &[u8], ) -> Result { + #[cfg(experimental)] Self::can_decode_log_with_type::()?; + #[cfg(experimental)] let token = ABIDecoder::new(decoder_config).decode(&T::param_type(), bytes)?; + + #[cfg(not(experimental))] + let token = ABIDecoder::new(decoder_config).experimental_decode(&T::param_type(), bytes)?; Ok(format!("{:?}", T::from_token(token)?)) } + #[cfg(experimental)] fn can_decode_log_with_type() -> Result<()> { match T::param_type() { // String slices can not be decoded from logs as they are encoded as ptr, len @@ -188,6 +194,10 @@ impl LogDecoder { .extract_log_id_and_data() .filter_map(|(log_id, bytes)| { target_ids.contains(&log_id).then(|| { + #[cfg(not(experimental))] + let token = ABIDecoder::new(self.decoder_config) + .experimental_decode(&T::param_type(), &bytes)?; + #[cfg(experimental)] let token = ABIDecoder::new(self.decoder_config).decode(&T::param_type(), &bytes)?; T::from_token(token) diff --git a/packages/fuels-core/src/types/enum_variants.rs b/packages/fuels-core/src/types/enum_variants.rs index fc2f9d0a58..0a7c4c9360 100644 --- a/packages/fuels-core/src/types/enum_variants.rs +++ b/packages/fuels-core/src/types/enum_variants.rs @@ -63,6 +63,23 @@ impl EnumVariants { .ok_or_else(|| error!(InvalidType, "Enum variants are too wide")) } + /// Calculates how many bytes are needed to encode an enum. + #[cfg(not(experimental))] + pub fn experimental_compute_enum_width_in_bytes(&self) -> Result { + if self.only_units_inside() { + return Ok(ENUM_DISCRIMINANT_BYTE_WIDTH); + } + + let width = self.param_types().iter().try_fold(0, |a, p| -> Result<_> { + let size = p.experimental_compute_encoding_in_bytes()?; + Ok(a.max(size)) + })?; + + checked_round_up_to_word_alignment(width)? + .checked_add(ENUM_DISCRIMINANT_BYTE_WIDTH) + .ok_or_else(|| error!(InvalidType, "Enum variants are too wide")) + } + /// Determines the padding needed for the provided enum variant (based on the width of the /// biggest variant) and returns it. pub fn compute_padding_amount_in_bytes(&self, variant_param_type: &ParamType) -> Result { diff --git a/packages/fuels-core/src/types/param_types.rs b/packages/fuels-core/src/types/param_types.rs index e23b13203e..37ae274b11 100644 --- a/packages/fuels-core/src/types/param_types.rs +++ b/packages/fuels-core/src/types/param_types.rs @@ -212,6 +212,46 @@ impl ParamType { } } + /// Calculates the number of bytes the VM expects this parameter to be encoded in. + #[cfg(not(experimental))] + pub fn experimental_compute_encoding_in_bytes(&self) -> Result { + let overflow_error = || { + error!( + InvalidType, + "Reached overflow while computing encoding size for {:?}", self + ) + }; + match &self { + ParamType::Unit => Ok(0), + ParamType::U8 | ParamType::Bool => Ok(1), + ParamType::U16 => Ok(2), + ParamType::U32 => Ok(4), + ParamType::U64 => Ok(8), + // TODO: @hal3e fix StringSlice, RawSlice, Vec + ParamType::U128 | ParamType::RawSlice | ParamType::StringSlice => Ok(16), + ParamType::U256 | ParamType::B256 => Ok(32), + ParamType::Vector(_) | ParamType::Bytes | ParamType::String => Ok(24), + ParamType::Array(param, count) => param + .compute_encoding_in_bytes()? + .checked_mul(*count) + .ok_or_else(overflow_error), + ParamType::StringArray(len) => { + checked_round_up_to_word_alignment(*len).map_err(|_| overflow_error()) + } + ParamType::Tuple(fields) | ParamType::Struct { fields, .. } => { + fields.iter().try_fold(0, |a: usize, param_type| { + let size = checked_round_up_to_word_alignment( + param_type.compute_encoding_in_bytes()?, + )?; + a.checked_add(size).ok_or_else(overflow_error) + }) + } + ParamType::Enum { variants, .. } => variants + .compute_enum_width_in_bytes() + .map_err(|_| overflow_error()), + } + } + /// For when you need to convert a ABI JSON's TypeApplication into a ParamType. /// /// # Arguments diff --git a/packages/fuels/Cargo.toml b/packages/fuels/Cargo.toml index 4a213e9a64..b74852afc1 100644 --- a/packages/fuels/Cargo.toml +++ b/packages/fuels/Cargo.toml @@ -36,6 +36,7 @@ sha2 = { workspace = true } tempfile = { workspace = true } tokio = { workspace = true, features = ["time", "test-util"] } tai64 = { workspace = true } +pretty_assertions = "1.4.0" [features] default = ["std", "fuels-test-helpers?/fuels-accounts", "coin-cache"] diff --git a/packages/fuels/Forc.toml b/packages/fuels/Forc.toml index ed648aefd4..767efa6782 100644 --- a/packages/fuels/Forc.toml +++ b/packages/fuels/Forc.toml @@ -31,6 +31,7 @@ members = [ 'tests/logs/contract_logs_abi', 'tests/logs/contract_with_contract_logs', 'tests/logs/script_logs', + 'tests/logs/script_needs_custom_decoder_logging', 'tests/logs/script_with_contract_logs', 'tests/predicates/basic_predicate', 'tests/predicates/swap', diff --git a/packages/fuels/tests/logs.rs b/packages/fuels/tests/logs.rs index cd82d6d0b5..5d6e58376b 100644 --- a/packages/fuels/tests/logs.rs +++ b/packages/fuels/tests/logs.rs @@ -218,7 +218,9 @@ async fn test_decode_logs() -> Result<()> { format!("{expected_generic_struct:?}"), ]; - assert_eq!(logs.filter_succeeded(), expected_logs); + dbg!(&logs); + use pretty_assertions::assert_eq; + assert_eq!(expected_logs, logs.filter_succeeded()); Ok(()) } @@ -1399,7 +1401,7 @@ async fn can_configure_decoder_for_script_log_decoding() -> Result<()> { Wallets("wallet"), Abigen(Script( name = "LogScript", - project = "packages/fuels/tests/scripts/script_needs_custom_decoder" + project = "packages/fuels/tests/logs/script_needs_custom_decoder_logging" )), LoadScript( name = "script_instance", @@ -1452,6 +1454,7 @@ async fn can_configure_decoder_for_script_log_decoding() -> Result<()> { // String slices can not be decoded from logs as they are encoded as ptr, len // TODO: Once https://github.com/FuelLabs/sway/issues/5110 is resolved we can remove this #[tokio::test] +#[cfg(experimental)] async fn test_string_slice_log() -> Result<()> { setup_program_test!( Wallets("wallet"), @@ -1482,3 +1485,34 @@ async fn test_string_slice_log() -> Result<()> { Ok(()) } + +#[tokio::test] +#[cfg(not(experimental))] +async fn test_string_slice_log() -> Result<()> { + use fuels_core::types::AsciiString; + + setup_program_test!( + Wallets("wallet"), + Abigen(Contract( + name = "MyContract", + project = "packages/fuels/tests/logs/contract_logs" + ),), + Deploy( + contract = "MyContract", + name = "contract_instance", + wallet = "wallet" + ) + ); + + let response = contract_instance + .methods() + .produce_string_slice_log() + .call() + .await?; + + let logs = response.decode_logs_with_type::()?; + + assert_eq!(logs.first().unwrap().to_string(), "string_slice"); + + Ok(()) +} diff --git a/packages/fuels/tests/logs/contract_logs/src/main.sw b/packages/fuels/tests/logs/contract_logs/src/main.sw index ca90f1f9b0..5c88e1901f 100644 --- a/packages/fuels/tests/logs/contract_logs/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs/src/main.sw @@ -52,7 +52,7 @@ impl ContractLogs for Contract { fn produce_logs_variables() { let f: u64 = 64; let u: b256 = 0xef86afa9696cf0dc6385e2c407a6e159a1103cefb7e2ae0636fb33d3cb2a9e4a; - let e: str = "Fuel"; + let e: str[4] = __to_str_array("Fuel"); let l: [u8; 3] = [1u8, 2u8, 3u8]; log(f); diff --git a/packages/fuels/tests/logs/script_needs_custom_decoder_logging/Forc.toml b/packages/fuels/tests/logs/script_needs_custom_decoder_logging/Forc.toml new file mode 100644 index 0000000000..eb0a1a82b9 --- /dev/null +++ b/packages/fuels/tests/logs/script_needs_custom_decoder_logging/Forc.toml @@ -0,0 +1,7 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "script_needs_custom_decoder_logging" + +[dependencies] diff --git a/packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw b/packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw new file mode 100644 index 0000000000..d42f71cfda --- /dev/null +++ b/packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw @@ -0,0 +1,20 @@ +script; + +impl AbiEncode for [u8; 1000] +{ + #[allow(dead_code)] + fn abi_encode(self, ref mut buffer: Buffer) { + let mut i = 0; + while i < 1000 { + self[i].abi_encode(buffer); + i += 1; + } + } +} + +fn main() { + // TODO: This file can be made obsolete once + // [retry](`https://github.com/FuelLabs/fuels-rs/issues/1020`) lands. + let arr: [u8; 1000] = [0; 1000]; + log(arr); +} diff --git a/packages/fuels/tests/logs/script_with_contract_logs/src/main.sw b/packages/fuels/tests/logs/script_with_contract_logs/src/main.sw index 581845fb5f..89644ee5de 100644 --- a/packages/fuels/tests/logs/script_with_contract_logs/src/main.sw +++ b/packages/fuels/tests/logs/script_with_contract_logs/src/main.sw @@ -10,7 +10,7 @@ fn main(contract_id: ContractId) { let f: bool = true; let u: u64 = 42; - let e: str = "Fuel"; + let e: str[4] = __to_str_array("Fuel"); let l: [u8; 3] = [1u8, 2u8, 3u8]; log(f); log(u); diff --git a/packages/fuels/tests/scripts/script_needs_custom_decoder/src/main.sw b/packages/fuels/tests/scripts/script_needs_custom_decoder/src/main.sw index cb7b8f342b..ec83b54faa 100644 --- a/packages/fuels/tests/scripts/script_needs_custom_decoder/src/main.sw +++ b/packages/fuels/tests/scripts/script_needs_custom_decoder/src/main.sw @@ -1,18 +1,6 @@ script; -impl AbiEncode for [u8; 1000] -{ - fn abi_encode(self, ref mut buffer: Buffer) { - let mut i = 0; - while i < 1000 { - self[i].abi_encode(buffer); - i += 1; - } - } -} - fn main() -> [u8; 1000] { let arr: [u8; 1000] = [0; 1000]; - log(arr); arr } From 6decd9d21f2238a6388263039d653ae2abbd063f Mon Sep 17 00:00:00 2001 From: hal3e Date: Thu, 18 Jan 2024 09:46:29 +0100 Subject: [PATCH 03/16] add new tests --- .../experimental_bounded_decoder.rs | 61 ++++++++++--------- packages/fuels/Cargo.toml | 1 - packages/fuels/tests/logs.rs | 37 +++++++++-- .../tests/logs/contract_logs/src/main.sw | 24 ++++++++ .../tests/logs/contract_logs_abi/src/main.sw | 1 + 5 files changed, 91 insertions(+), 33 deletions(-) diff --git a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs index 7207cc7f38..0474a85fbf 100644 --- a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs +++ b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs @@ -35,10 +35,7 @@ impl ExperimentalBoundedDecoder { } pub fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { - match param_type { - ParamType::Unit => Ok(Token::Unit), - _ => self.decode_param(param_type, bytes).map(|x| x.token), - } + self.decode_param(param_type, bytes).map(|x| x.token) } pub(crate) fn decode_multiple( @@ -66,37 +63,37 @@ impl ExperimentalBoundedDecoder { fn decode_param(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { self.token_tracker.increase()?; match param_type { - ParamType::Unit => unreachable!(), // `Unit` already handled in `decode` - ParamType::U8 => Self::decode_u8(bytes), // ok - ParamType::U16 => Self::decode_u16(bytes), // ok - ParamType::U32 => Self::decode_u32(bytes), // ok - ParamType::U64 => Self::decode_u64(bytes), // ok - ParamType::U128 => Self::decode_u128(bytes), // ok - ParamType::U256 => Self::decode_u256(bytes), // ok - ParamType::Bool => Self::decode_bool(bytes), // ok - ParamType::B256 => Self::decode_b256(bytes), // ok - ParamType::RawSlice => self.decode_raw_slice(bytes), // nok - ParamType::StringSlice => Self::decode_string_slice(bytes), // nok - ParamType::StringArray(len) => Self::decode_string_array(bytes, *len), // ok + ParamType::Unit => Self::decode_unit(), + ParamType::U8 => Self::decode_u8(bytes), + ParamType::U16 => Self::decode_u16(bytes), + ParamType::U32 => Self::decode_u32(bytes), + ParamType::U64 => Self::decode_u64(bytes), + ParamType::U128 => Self::decode_u128(bytes), + ParamType::U256 => Self::decode_u256(bytes), + ParamType::Bool => Self::decode_bool(bytes), + ParamType::B256 => Self::decode_b256(bytes), + ParamType::RawSlice => self.decode_raw_slice(bytes), // FIX: + ParamType::StringSlice => Self::decode_string_slice(bytes), // FIX: + ParamType::StringArray(len) => Self::decode_string_array(bytes, *len), ParamType::Array(ref t, length) => { self.run_w_depth_tracking(|ctx| ctx.decode_array(t, bytes, *length)) - } // ok + } ParamType::Struct { fields, .. } => { self.run_w_depth_tracking(|ctx| ctx.decode_struct(fields, bytes)) - } // ok + } ParamType::Enum { variants, .. } => { self.run_w_depth_tracking(|ctx| ctx.decode_enum(bytes, variants)) - } // ok + } ParamType::Tuple(types) => { self.run_w_depth_tracking(|ctx| ctx.decode_tuple(types, bytes)) - } // nok + } // FIX: ParamType::Vector(param_type) => { // although nested vectors cannot be decoded yet, depth tracking still occurs for future // proofing self.run_w_depth_tracking(|ctx| ctx.decode_vector(param_type, bytes)) - } // nok - ParamType::Bytes => Self::decode_bytes(bytes), // check - ParamType::String => Self::decode_std_string(bytes), // check + } + ParamType::Bytes => Self::decode_bytes(bytes), // TODO: + ParamType::String => Self::decode_std_string(bytes), // TODO: } } @@ -115,13 +112,14 @@ impl ExperimentalBoundedDecoder { } fn decode_vector(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { - let num_of_elements = ParamType::calculate_num_of_elements(param_type, bytes.len())?; + let num_of_elements = peek_u64(bytes)? as usize; + let bytes = skip(bytes, WORD_SIZE)?; let (tokens, bytes_read) = self.decode_params(std::iter::repeat(param_type).take(num_of_elements), bytes)?; Ok(Decoded { token: Token::Vector(tokens), - bytes_read, + bytes_read: WORD_SIZE + bytes_read, }) } @@ -278,14 +276,14 @@ impl ExperimentalBoundedDecoder { fn decode_u32(bytes: &[u8]) -> Result { Ok(Decoded { token: Token::U32(peek_u32(bytes)?), - bytes_read: WORD_SIZE, + bytes_read: 4, }) } fn decode_u16(bytes: &[u8]) -> Result { Ok(Decoded { token: Token::U16(peek_u16(bytes)?), - bytes_read: WORD_SIZE, + bytes_read: 2, }) } @@ -296,6 +294,13 @@ impl ExperimentalBoundedDecoder { }) } + fn decode_unit() -> Result { + Ok(Decoded { + token: Token::Unit, + bytes_read: 0, + }) + } + /// The encoding follows the ABI specs defined /// [here](https://github.com/FuelLabs/fuel-specs/blob/1be31f70c757d8390f74b9e1b3beb096620553eb/specs/protocol/abi.md) /// @@ -307,7 +312,7 @@ impl ExperimentalBoundedDecoder { let discriminant = peek_u64(bytes)?; let selected_variant = variants.param_type_of_variant(discriminant)?; - let enum_content_bytes = skip(bytes, 8)?; + let enum_content_bytes = skip(bytes, WORD_SIZE)?; let result = self.decode_token_in_enum(enum_content_bytes, variants, selected_variant)?; let selector = Box::new((discriminant, result.token, variants.clone())); diff --git a/packages/fuels/Cargo.toml b/packages/fuels/Cargo.toml index b74852afc1..4a213e9a64 100644 --- a/packages/fuels/Cargo.toml +++ b/packages/fuels/Cargo.toml @@ -36,7 +36,6 @@ sha2 = { workspace = true } tempfile = { workspace = true } tokio = { workspace = true, features = ["time", "test-util"] } tai64 = { workspace = true } -pretty_assertions = "1.4.0" [features] default = ["std", "fuels-test-helpers?/fuels-accounts", "coin-cache"] diff --git a/packages/fuels/tests/logs.rs b/packages/fuels/tests/logs.rs index 5d6e58376b..a2265c2279 100644 --- a/packages/fuels/tests/logs.rs +++ b/packages/fuels/tests/logs.rs @@ -218,8 +218,6 @@ async fn test_decode_logs() -> Result<()> { format!("{expected_generic_struct:?}"), ]; - dbg!(&logs); - use pretty_assertions::assert_eq; assert_eq!(expected_logs, logs.filter_succeeded()); Ok(()) @@ -1455,7 +1453,7 @@ async fn can_configure_decoder_for_script_log_decoding() -> Result<()> { // TODO: Once https://github.com/FuelLabs/sway/issues/5110 is resolved we can remove this #[tokio::test] #[cfg(experimental)] -async fn test_string_slice_log() -> Result<()> { +async fn string_slice_log() -> Result<()> { setup_program_test!( Wallets("wallet"), Abigen(Contract( @@ -1488,7 +1486,7 @@ async fn test_string_slice_log() -> Result<()> { #[tokio::test] #[cfg(not(experimental))] -async fn test_string_slice_log() -> Result<()> { +async fn string_slice_log() -> Result<()> { use fuels_core::types::AsciiString; setup_program_test!( @@ -1516,3 +1514,34 @@ async fn test_string_slice_log() -> Result<()> { Ok(()) } + +#[tokio::test] +#[cfg(not(experimental))] +async fn contract_vec_log() -> Result<()> { + setup_program_test!( + Wallets("wallet"), + Abigen(Contract( + name = "MyContract", + project = "packages/fuels/tests/logs/contract_logs" + ),), + Deploy( + contract = "MyContract", + name = "contract_instance", + wallet = "wallet" + ) + ); + + let v = [1u16, 2, 3].to_vec(); + let some_enum = EnumWithGeneric::VariantOne(v); + let other_enum = EnumWithGeneric::VariantTwo; + let v1 = vec![some_enum.clone(), other_enum, some_enum]; + let expected_vec = vec![vec![v1.clone(), v1]]; + + let response = contract_instance.methods().produce_vec_log().call().await?; + + let logs = response.decode_logs_with_type::>>>>>()?; + + assert_eq!(vec![expected_vec], logs); + + Ok(()) +} diff --git a/packages/fuels/tests/logs/contract_logs/src/main.sw b/packages/fuels/tests/logs/contract_logs/src/main.sw index 5c88e1901f..598751f56f 100644 --- a/packages/fuels/tests/logs/contract_logs/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs/src/main.sw @@ -141,4 +141,28 @@ impl ContractLogs for Contract { fn produce_string_slice_log() { log("string_slice"); } + + fn produce_vec_log() { + let mut v = Vec::new(); + v.push(1u16); + v.push(2u16); + v.push(3u16); + + let some_enum = EnumWithGeneric::VariantOne(v); + let other_enum = EnumWithGeneric::VariantTwo; + + let mut v1 = Vec::new(); + v1.push(some_enum); + v1.push(other_enum); + v1.push(some_enum); + + let mut v2 = Vec::new(); + v2.push(v1); + v2.push(v1); + + let mut v3 = Vec::new(); + v3.push(v2); + + log(v3); + } } diff --git a/packages/fuels/tests/logs/contract_logs_abi/src/main.sw b/packages/fuels/tests/logs/contract_logs_abi/src/main.sw index 831826d0dc..77495998d0 100644 --- a/packages/fuels/tests/logs/contract_logs_abi/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs_abi/src/main.sw @@ -10,4 +10,5 @@ abi ContractLogs { fn produce_multiple_logs(); fn produce_bad_logs(); fn produce_string_slice_log(); + fn produce_vec_log(); } From cca73fc70364e70d2ccf14c3a6ff2edc5178c9d2 Mon Sep 17 00:00:00 2001 From: hal3e Date: Thu, 18 Jan 2024 16:57:37 +0100 Subject: [PATCH 04/16] add String, Bytes --- .github/workflows/ci.yml | 2 +- .../src/codec/abi_decoder/bounded_decoder.rs | 2 +- .../experimental_bounded_decoder.rs | 22 +++++----- packages/fuels/Forc.toml | 2 +- packages/fuels/tests/logs.rs | 41 ++++++++++++++----- .../tests/logs/contract_logs/src/main.sw | 20 +++++++++ .../tests/logs/contract_logs_abi/src/main.sw | 2 + .../fuels/tests/logs/script_logs/src/main.sw | 12 ++++++ 8 files changed, 79 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3982b92a03..02d2cc8ebb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ env: FUEL_CORE_VERSION: 0.22.0 FUEL_CORE_PATCH_BRANCH: RUST_VERSION: 1.74.0 - FORC_VERSION: 0.48.0 + FORC_VERSION: 0.49.0 FORC_PATCH_BRANCH: "" FORC_PATCH_REVISION: "" diff --git a/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs b/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs index 3ad13d0cc9..f53307675b 100644 --- a/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs +++ b/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs @@ -36,7 +36,7 @@ impl BoundedDecoder { } } - pub fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { + pub(crate) fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { param_type.validate_is_decodable(self.config.max_depth)?; match param_type { // Unit, U8 and Bool are returned as u64 from receipt "Return" diff --git a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs index 0474a85fbf..6175b34db6 100644 --- a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs +++ b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs @@ -34,7 +34,7 @@ impl ExperimentalBoundedDecoder { } } - pub fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { + pub(crate) fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { self.decode_param(param_type, bytes).map(|x| x.token) } @@ -72,8 +72,8 @@ impl ExperimentalBoundedDecoder { ParamType::U256 => Self::decode_u256(bytes), ParamType::Bool => Self::decode_bool(bytes), ParamType::B256 => Self::decode_b256(bytes), - ParamType::RawSlice => self.decode_raw_slice(bytes), // FIX: - ParamType::StringSlice => Self::decode_string_slice(bytes), // FIX: + ParamType::RawSlice => self.decode_raw_slice(bytes), // FIX:@halre sway first + ParamType::StringSlice => Self::decode_string_slice(bytes), ParamType::StringArray(len) => Self::decode_string_array(bytes, *len), ParamType::Array(ref t, length) => { self.run_w_depth_tracking(|ctx| ctx.decode_array(t, bytes, *length)) @@ -86,28 +86,32 @@ impl ExperimentalBoundedDecoder { } ParamType::Tuple(types) => { self.run_w_depth_tracking(|ctx| ctx.decode_tuple(types, bytes)) - } // FIX: + } ParamType::Vector(param_type) => { // although nested vectors cannot be decoded yet, depth tracking still occurs for future // proofing self.run_w_depth_tracking(|ctx| ctx.decode_vector(param_type, bytes)) } - ParamType::Bytes => Self::decode_bytes(bytes), // TODO: - ParamType::String => Self::decode_std_string(bytes), // TODO: + ParamType::Bytes => Self::decode_bytes(bytes), + ParamType::String => Self::decode_std_string(bytes), } } fn decode_bytes(bytes: &[u8]) -> Result { + let num_of_elements = peek_u64(bytes)? as usize; + let bytes = peek(skip(bytes, WORD_SIZE)?, num_of_elements)?; Ok(Decoded { token: Token::Bytes(bytes.to_vec()), - bytes_read: bytes.len(), + bytes_read: WORD_SIZE + bytes.len(), }) } fn decode_std_string(bytes: &[u8]) -> Result { + let num_of_elements = peek_u64(bytes)? as usize; + let bytes = peek(skip(bytes, WORD_SIZE)?, num_of_elements)?; Ok(Decoded { token: Token::String(str::from_utf8(bytes)?.to_string()), - bytes_read: bytes.len(), + bytes_read: WORD_SIZE + bytes.len(), }) } @@ -129,8 +133,6 @@ impl ExperimentalBoundedDecoder { let mut bytes_read = 0; for param_type in param_types.iter() { - // padding has to be taken into account - bytes_read = checked_round_up_to_word_alignment(bytes_read)?; let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?; bytes_read += res.bytes_read; tokens.push(res.token); diff --git a/packages/fuels/Forc.toml b/packages/fuels/Forc.toml index 767efa6782..0148393ce2 100644 --- a/packages/fuels/Forc.toml +++ b/packages/fuels/Forc.toml @@ -105,4 +105,4 @@ members = [ ] [patch.'https://github.com/fuellabs/sway'] -std = { git = "https://github.com/fuellabs/sway", branch = "hal3e/trait-auto-impl" } +std = { git = "https://github.com/fuellabs/sway", branch = "hal3e/abiencoder-impls" } diff --git a/packages/fuels/tests/logs.rs b/packages/fuels/tests/logs.rs index a2265c2279..c31d4278eb 100644 --- a/packages/fuels/tests/logs.rs +++ b/packages/fuels/tests/logs.rs @@ -99,6 +99,7 @@ async fn test_parse_logs_custom_types() -> Result<()> { let log_test_struct = response.decode_logs_with_type::()?; let log_test_enum = response.decode_logs_with_type::()?; + let log_tuple = response.decode_logs_with_type::<(TestStruct, TestEnum)>()?; let expected_bits256 = Bits256([ 239, 134, 175, 169, 105, 108, 240, 220, 99, 133, 226, 196, 7, 166, 225, 89, 161, 16, 60, @@ -111,8 +112,9 @@ async fn test_parse_logs_custom_types() -> Result<()> { }; let expected_enum = TestEnum::VariantTwo; - assert_eq!(log_test_struct, vec![expected_struct]); - assert_eq!(log_test_enum, vec![expected_enum]); + assert_eq!(log_test_struct, vec![expected_struct.clone()]); + assert_eq!(log_test_enum, vec![expected_enum.clone()]); + assert_eq!(log_tuple, vec![(expected_struct, expected_enum)]); Ok(()) } @@ -638,6 +640,7 @@ async fn test_script_decode_logs() -> Result<()> { field_3: 64, }; let expected_enum = TestEnum::VariantTwo; + let expected_tuple = (expected_struct.clone(), expected_enum.clone()); let expected_generic_struct = StructWithGeneric { field_1: expected_struct.clone(), field_2: 64, @@ -663,6 +666,7 @@ async fn test_script_decode_logs() -> Result<()> { format!("{:?}", [1, 2, 3]), format!("{expected_struct:?}"), format!("{expected_enum:?}"), + format!("{expected_tuple:?}"), format!("{expected_generic_struct:?}"), format!("{expected_generic_enum:?}"), format!("{expected_nested_struct:?}"), @@ -1517,7 +1521,7 @@ async fn string_slice_log() -> Result<()> { #[tokio::test] #[cfg(not(experimental))] -async fn contract_vec_log() -> Result<()> { +async fn contract_heap_types_log() -> Result<()> { setup_program_test!( Wallets("wallet"), Abigen(Contract( @@ -1530,18 +1534,33 @@ async fn contract_vec_log() -> Result<()> { wallet = "wallet" ) ); + let contract_methods = contract_instance.methods(); + { + let v = [1u16, 2, 3].to_vec(); + let some_enum = EnumWithGeneric::VariantOne(v); + let other_enum = EnumWithGeneric::VariantTwo; + let v1 = vec![some_enum.clone(), other_enum, some_enum]; + let expected_vec = vec![vec![v1.clone(), v1]]; - let v = [1u16, 2, 3].to_vec(); - let some_enum = EnumWithGeneric::VariantOne(v); - let other_enum = EnumWithGeneric::VariantTwo; - let v1 = vec![some_enum.clone(), other_enum, some_enum]; - let expected_vec = vec![vec![v1.clone(), v1]]; + let response = contract_methods.produce_vec_log().call().await?; + let logs = response.decode_logs_with_type::>>>>>()?; - let response = contract_instance.methods().produce_vec_log().call().await?; + assert_eq!(vec![expected_vec], logs); + } + { + let response = contract_methods.produce_string_log().call().await?; + let logs = response.decode_logs_with_type::()?; - let logs = response.decode_logs_with_type::>>>>>()?; + assert_eq!(vec!["fuel".to_string()], logs); + } + { + let response = contract_methods.produce_bytes_log().call().await?; + let logs = response.decode_logs_with_type::()?; - assert_eq!(vec![expected_vec], logs); + assert_eq!(vec![Bytes("fuel".as_bytes().to_vec())], logs); + } Ok(()) } + +//TODO: @hal3e add heat types logs for script diff --git a/packages/fuels/tests/logs/contract_logs/src/main.sw b/packages/fuels/tests/logs/contract_logs/src/main.sw index 598751f56f..3c574e92a5 100644 --- a/packages/fuels/tests/logs/contract_logs/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs/src/main.sw @@ -1,8 +1,19 @@ contract; use std::logging::log; +use std::string::String; use contract_logs::ContractLogs; +impl AbiEncode for (TestStruct, TestEnum) +{ + #[allow(dead_code)] + fn abi_encode(self, ref mut buffer: Buffer) { + let (test_struct, test_enum) = self; + test_struct.abi_encode(buffer); + test_enum.abi_encode(buffer); + } +} + #[allow(dead_code)] struct TestStruct { field_1: bool, @@ -74,6 +85,7 @@ impl ContractLogs for Contract { log(test_struct); log(test_enum); + log((test_struct, test_enum)); } fn produce_logs_generic_types() { @@ -165,4 +177,12 @@ impl ContractLogs for Contract { log(v3); } + + fn produce_heap_types_logs() { + log(String::from_ascii_str("fuel")); + } + + fn produce_bytes_log() { + log(String::from_ascii_str("fuel").as_bytes()); + } } diff --git a/packages/fuels/tests/logs/contract_logs_abi/src/main.sw b/packages/fuels/tests/logs/contract_logs_abi/src/main.sw index 77495998d0..0f022867c6 100644 --- a/packages/fuels/tests/logs/contract_logs_abi/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs_abi/src/main.sw @@ -11,4 +11,6 @@ abi ContractLogs { fn produce_bad_logs(); fn produce_string_slice_log(); fn produce_vec_log(); + fn produce_string_log(); + fn produce_bytes_logs(); } diff --git a/packages/fuels/tests/logs/script_logs/src/main.sw b/packages/fuels/tests/logs/script_logs/src/main.sw index cd44620ec9..fd4fd877fb 100644 --- a/packages/fuels/tests/logs/script_logs/src/main.sw +++ b/packages/fuels/tests/logs/script_logs/src/main.sw @@ -2,6 +2,16 @@ script; use std::logging::log; +impl AbiEncode for (TestStruct, TestEnum) +{ + #[allow(dead_code)] + fn abi_encode(self, ref mut buffer: Buffer) { + let (test_struct, test_enum) = self; + test_struct.abi_encode(buffer); + test_enum.abi_encode(buffer); + } +} + #[allow(dead_code)] struct TestStruct { field_1: bool, @@ -44,6 +54,7 @@ fn main() { let u: b256 = 0xef86afa9696cf0dc6385e2c407a6e159a1103cefb7e2ae0636fb33d3cb2a9e4a; let e: str[4] = __to_str_array("Fuel"); let l: [u8; 3] = [1u8, 2u8, 3u8]; + let test_struct = TestStruct { field_1: true, field_2: u, @@ -75,6 +86,7 @@ fn main() { log(l); log(test_struct); log(test_enum); + log((test_struct, test_enum)); log(test_generic_struct); log(test_generic_enum); log(test_struct_nested); From 1e407410dc75da43263e0991121eca2cab82a2eb Mon Sep 17 00:00:00 2001 From: hal3e Date: Fri, 19 Jan 2024 10:11:44 +0100 Subject: [PATCH 05/16] add `RawSlice` --- .../src/codec/abi_decoder/bounded_decoder.rs | 17 ++------- .../experimental_bounded_decoder.rs | 23 ++++-------- packages/fuels-core/src/codec/abi_encoder.rs | 35 +++++++++---------- packages/fuels-core/src/types.rs | 2 +- .../fuels-core/src/types/core/raw_slice.rs | 12 +++---- .../tests/contracts/lib_contract/src/main.sw | 18 +++++++++- .../fuels/tests/contracts/require/src/main.sw | 4 +-- packages/fuels/tests/logs.rs | 6 ++++ .../tests/logs/contract_logs/src/main.sw | 6 +++- .../tests/logs/contract_logs_abi/src/main.sw | 3 +- .../tests/scripts/script_require/src/main.sw | 4 +-- .../types/contracts/raw_slice/src/main.sw | 8 ++--- .../predicate_raw_slice/src/main.sw | 2 +- packages/fuels/tests/types_contracts.rs | 4 +-- 14 files changed, 72 insertions(+), 72 deletions(-) diff --git a/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs b/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs index f53307675b..4f14240e01 100644 --- a/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs +++ b/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs @@ -4,7 +4,6 @@ use crate::{ checked_round_up_to_word_alignment, codec::DecoderConfig, constants::WORD_SIZE, - traits::Tokenizable, types::{ enum_variants::EnumVariants, errors::{error, Result}, @@ -216,21 +215,9 @@ impl BoundedDecoder { } fn decode_raw_slice(&mut self, bytes: &[u8]) -> Result { - let raw_slice_element = ParamType::U64; - let num_of_elements = - ParamType::calculate_num_of_elements(&raw_slice_element, bytes.len())?; - let param_type = ParamType::U64; - let (tokens, bytes_read) = - self.decode_params(std::iter::repeat(¶m_type).take(num_of_elements), bytes)?; - let elements = tokens - .into_iter() - .map(u64::from_token) - .collect::>>() - .map_err(|e| error!(InvalidData, "{e}"))?; - Ok(Decoded { - token: Token::RawSlice(elements), - bytes_read, + token: Token::RawSlice(bytes.to_vec()), + bytes_read: bytes.len(), }) } diff --git a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs index 6175b34db6..6e69ded1f4 100644 --- a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs +++ b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs @@ -4,7 +4,6 @@ use crate::{ checked_round_up_to_word_alignment, codec::DecoderConfig, constants::WORD_SIZE, - traits::Tokenizable, types::{ enum_variants::EnumVariants, errors::{error, Result}, @@ -72,7 +71,7 @@ impl ExperimentalBoundedDecoder { ParamType::U256 => Self::decode_u256(bytes), ParamType::Bool => Self::decode_bool(bytes), ParamType::B256 => Self::decode_b256(bytes), - ParamType::RawSlice => self.decode_raw_slice(bytes), // FIX:@halre sway first + ParamType::RawSlice => self.decode_raw_slice(bytes), ParamType::StringSlice => Self::decode_string_slice(bytes), ParamType::StringArray(len) => Self::decode_string_array(bytes, *len), ParamType::Array(ref t, length) => { @@ -195,21 +194,11 @@ impl ExperimentalBoundedDecoder { } fn decode_raw_slice(&mut self, bytes: &[u8]) -> Result { - let raw_slice_element = ParamType::U64; - let num_of_elements = - ParamType::calculate_num_of_elements(&raw_slice_element, bytes.len())?; - let param_type = ParamType::U64; - let (tokens, bytes_read) = - self.decode_params(std::iter::repeat(¶m_type).take(num_of_elements), bytes)?; - let elements = tokens - .into_iter() - .map(u64::from_token) - .collect::>>() - .map_err(|e| error!(InvalidData, "{e}"))?; - + let num_of_elements = peek_u64(bytes)? as usize; + let bytes = peek(skip(bytes, WORD_SIZE)?, num_of_elements)?; Ok(Decoded { - token: Token::RawSlice(elements), - bytes_read, + token: Token::RawSlice(bytes.to_vec()), + bytes_read: WORD_SIZE + bytes.len(), }) } @@ -320,7 +309,7 @@ impl ExperimentalBoundedDecoder { let selector = Box::new((discriminant, result.token, variants.clone())); Ok(Decoded { token: Token::Enum(selector), - bytes_read: 8 + result.bytes_read, + bytes_read: WORD_SIZE + result.bytes_read, }) } diff --git a/packages/fuels-core/src/codec/abi_encoder.rs b/packages/fuels-core/src/codec/abi_encoder.rs index 3585a52499..b20e2795cc 100644 --- a/packages/fuels-core/src/codec/abi_encoder.rs +++ b/packages/fuels-core/src/codec/abi_encoder.rs @@ -2,7 +2,6 @@ use fuel_types::bytes::padded_len_usize; use crate::{ checked_round_up_to_word_alignment, - constants::WORD_SIZE, types::{ errors::Result, pad_u16, pad_u32, @@ -83,7 +82,7 @@ impl ABIEncoder { Token::Enum(arg_enum) => Self::encode_enum(arg_enum)?, Token::Tuple(arg_tuple) => Self::encode_tuple(arg_tuple)?, Token::Unit => vec![Self::encode_unit()], - Token::RawSlice(data) => Self::encode_raw_slice(data)?, + Token::RawSlice(data) => Self::encode_raw_slice(data.to_vec())?, Token::Bytes(data) => Self::encode_bytes(data.to_vec())?, // `String` in Sway has the same memory layout as the bytes type Token::String(string) => Self::encode_bytes(string.clone().into_bytes())?, @@ -190,16 +189,17 @@ impl ABIEncoder { ]) } - fn encode_raw_slice(data: &[u64]) -> Result> { - let encoded_data = data - .iter() - .map(|&word| Self::encode_u64(word)) - .collect::>(); + fn encode_raw_slice(mut data: Vec) -> Result> { + let len = data.len(); - let num_bytes = data.len() * WORD_SIZE; - let len = Self::encode_u64(num_bytes as u64); + zeropad_to_word_alignment(&mut data); - Ok(vec![Data::Dynamic(encoded_data), len]) + let encoded_data = vec![Data::Inline(data)]; + + Ok(vec![ + Data::Dynamic(encoded_data), + Self::encode_u64(len as u64), + ]) } fn encode_string_slice(arg_string: &StaticStringToken) -> Result> { @@ -248,6 +248,7 @@ mod tests { use super::*; use crate::{ codec::first_four_bytes_of_sha256_hash, + constants::WORD_SIZE, types::{enum_variants::EnumVariants, param_types::ParamType}, }; @@ -1202,16 +1203,12 @@ mod tests { let encoded_bytes = ABIEncoder::encode(&[token])?.resolve(offset); // assert - let ptr = vec![0, 0, 0, 0, 0, 0, 0, 56]; - let len = vec![0, 0, 0, 0, 0, 0, 0, 24]; - let data = [ - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 0, 2], - [0, 0, 0, 0, 0, 0, 0, 3], - ] - .concat(); + let ptr = [0, 0, 0, 0, 0, 0, 0, 56].to_vec(); + let len = [0, 0, 0, 0, 0, 0, 0, 3].to_vec(); + let data = [1, 2, 3].to_vec(); + let padding = [0, 0, 0, 0, 0].to_vec(); - let expected_encoded_bytes = [ptr, len, data].concat(); + let expected_encoded_bytes = [ptr, len, data, padding].concat(); assert_eq!(expected_encoded_bytes, encoded_bytes); diff --git a/packages/fuels-core/src/types.rs b/packages/fuels-core/src/types.rs index a20d7cdcc1..60e7f57a4e 100644 --- a/packages/fuels-core/src/types.rs +++ b/packages/fuels-core/src/types.rs @@ -91,7 +91,7 @@ pub enum Token { Struct(Vec), Enum(Box), Tuple(Vec), - RawSlice(Vec), + RawSlice(Vec), Bytes(Vec), String(String), } diff --git a/packages/fuels-core/src/types/core/raw_slice.rs b/packages/fuels-core/src/types/core/raw_slice.rs index d4e0b0cd62..0eb37a8fe7 100644 --- a/packages/fuels-core/src/types/core/raw_slice.rs +++ b/packages/fuels-core/src/types/core/raw_slice.rs @@ -1,21 +1,21 @@ #[derive(Debug, PartialEq, Clone, Eq)] // `RawSlice` is a mapping of the contract type "untyped raw slice" -- currently the only way of // returning dynamically sized data from a script. -pub struct RawSlice(pub Vec); +pub struct RawSlice(pub Vec); -impl From for Vec { - fn from(raw_slice: RawSlice) -> Vec { +impl From for Vec { + fn from(raw_slice: RawSlice) -> Vec { raw_slice.0 } } -impl PartialEq> for RawSlice { - fn eq(&self, other: &Vec) -> bool { +impl PartialEq> for RawSlice { + fn eq(&self, other: &Vec) -> bool { self.0 == *other } } -impl PartialEq for Vec { +impl PartialEq for Vec { fn eq(&self, other: &RawSlice) -> bool { *self == other.0 } diff --git a/packages/fuels/tests/contracts/lib_contract/src/main.sw b/packages/fuels/tests/contracts/lib_contract/src/main.sw index 2a51679eb6..ae4cf896e4 100644 --- a/packages/fuels/tests/contracts/lib_contract/src/main.sw +++ b/packages/fuels/tests/contracts/lib_contract/src/main.sw @@ -2,12 +2,28 @@ contract; use lib_contract::LibContract; +impl AbiEncode for str[21] { + fn abi_encode(self, ref mut buffer: Buffer) { + let s = from_str_array(self); + + let len = s.len(); + let ptr = s.as_ptr(); + + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} + impl LibContract for Contract { fn increment(value: u64) -> u64 { value + 1 } fn require() -> () { - require(false, "require from contract"); + require(false, __to_str_array("require from contract")); } } diff --git a/packages/fuels/tests/contracts/require/src/main.sw b/packages/fuels/tests/contracts/require/src/main.sw index ea242fe291..6f33644caf 100644 --- a/packages/fuels/tests/contracts/require/src/main.sw +++ b/packages/fuels/tests/contracts/require/src/main.sw @@ -33,7 +33,7 @@ impl TestContract for Contract { } fn require_string() { - require(false, "fuel"); + require(false, __to_str_array("fuel")); } fn require_custom_generic() { @@ -54,7 +54,7 @@ impl TestContract for Contract { fn require_with_additional_logs() { log(42); - log("fuel"); + log(__to_str_array("fuel")); require(false, 64); } } diff --git a/packages/fuels/tests/logs.rs b/packages/fuels/tests/logs.rs index c31d4278eb..1b40e1060e 100644 --- a/packages/fuels/tests/logs.rs +++ b/packages/fuels/tests/logs.rs @@ -1559,6 +1559,12 @@ async fn contract_heap_types_log() -> Result<()> { assert_eq!(vec![Bytes("fuel".as_bytes().to_vec())], logs); } + { + let response = contract_methods.produce_raw_slice_log().call().await?; + let logs = response.decode_logs_with_type::()?; + + assert_eq!(vec![RawSlice("fuel".as_bytes().to_vec())], logs); + } Ok(()) } diff --git a/packages/fuels/tests/logs/contract_logs/src/main.sw b/packages/fuels/tests/logs/contract_logs/src/main.sw index 3c574e92a5..452f074888 100644 --- a/packages/fuels/tests/logs/contract_logs/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs/src/main.sw @@ -178,11 +178,15 @@ impl ContractLogs for Contract { log(v3); } - fn produce_heap_types_logs() { + fn produce_string_log() { log(String::from_ascii_str("fuel")); } fn produce_bytes_log() { log(String::from_ascii_str("fuel").as_bytes()); } + + fn produce_raw_slice_log() { + log(String::from_ascii_str("fuel").as_raw_slice()); + } } diff --git a/packages/fuels/tests/logs/contract_logs_abi/src/main.sw b/packages/fuels/tests/logs/contract_logs_abi/src/main.sw index 0f022867c6..228b57116b 100644 --- a/packages/fuels/tests/logs/contract_logs_abi/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs_abi/src/main.sw @@ -12,5 +12,6 @@ abi ContractLogs { fn produce_string_slice_log(); fn produce_vec_log(); fn produce_string_log(); - fn produce_bytes_logs(); + fn produce_bytes_log(); + fn produce_raw_slice_log(); } diff --git a/packages/fuels/tests/scripts/script_require/src/main.sw b/packages/fuels/tests/scripts/script_require/src/main.sw index fdd9b33caa..62afeb88ae 100644 --- a/packages/fuels/tests/scripts/script_require/src/main.sw +++ b/packages/fuels/tests/scripts/script_require/src/main.sw @@ -32,7 +32,7 @@ fn main(match_enum: MatchEnum) { if let MatchEnum::RequirePrimitive = match_enum { require(false, 42); } else if let MatchEnum::RequireString = match_enum { - require(false, "fuel"); + require(false, __to_str_array("fuel")); } else if let MatchEnum::RequireCustomGeneric = match_enum { let l: [u8; 3] = [1u8, 2u8, 3u8]; @@ -49,7 +49,7 @@ fn main(match_enum: MatchEnum) { require(false, test_deeply_nested_generic); } else if let MatchEnum::RequireWithAdditionalLogs = match_enum { log(42); - log("fuel"); + log(__to_str_array("fuel")); require(false, 64); } } diff --git a/packages/fuels/tests/types/contracts/raw_slice/src/main.sw b/packages/fuels/tests/types/contracts/raw_slice/src/main.sw index 04084fef65..2d2d87f1eb 100644 --- a/packages/fuels/tests/types/contracts/raw_slice/src/main.sw +++ b/packages/fuels/tests/types/contracts/raw_slice/src/main.sw @@ -12,13 +12,13 @@ struct Wrapper { } abi RawSliceContract { - fn return_raw_slice(length: u64) -> raw_slice; + fn return_raw_slice(length: u8) -> raw_slice; fn accept_raw_slice(slice: raw_slice); fn accept_nested_raw_slice(wrapper: Wrapper>); } fn validate_raw_slice(input: raw_slice) { - let vec: Vec = Vec::from(input); + let vec: Vec = Vec::from(input); require(vec.len() == 3, "raw slice len is not 3"); require( vec @@ -47,9 +47,9 @@ fn validate_vec(vec: Vec) { } impl RawSliceContract for Contract { - fn return_raw_slice(length: u64) -> raw_slice { + fn return_raw_slice(length: u8) -> raw_slice { let mut vec = Vec::new(); - let mut counter = 0; + let mut counter = 0u8; while counter < length { vec.push(counter); counter = counter + 1; diff --git a/packages/fuels/tests/types/predicates/predicate_raw_slice/src/main.sw b/packages/fuels/tests/types/predicates/predicate_raw_slice/src/main.sw index 19ba59de2c..a63409b911 100644 --- a/packages/fuels/tests/types/predicates/predicate_raw_slice/src/main.sw +++ b/packages/fuels/tests/types/predicates/predicate_raw_slice/src/main.sw @@ -12,7 +12,7 @@ struct Wrapper { } fn valid_raw_slice(slice: raw_slice) -> bool { - let vec: Vec = Vec::from(slice); + let vec: Vec = Vec::from(slice); vec.len() == 3 && vec.get(0).unwrap() == 40 && vec.get(1).unwrap() == 41 && vec.get(2).unwrap() == 42 } diff --git a/packages/fuels/tests/types_contracts.rs b/packages/fuels/tests/types_contracts.rs index 1043d9d595..ad3470d9a6 100644 --- a/packages/fuels/tests/types_contracts.rs +++ b/packages/fuels/tests/types_contracts.rs @@ -1973,9 +1973,9 @@ async fn test_contract_raw_slice() -> Result<()> { let contract_methods = contract_instance.methods(); { - for length in 0..=10 { + for length in 0u8..=10 { let response = contract_methods.return_raw_slice(length).call().await?; - assert_eq!(response.value, (0..length).collect::>()); + assert_eq!(response.value, (0u8..length).collect::>()); } } { From ce4dee106d2452572a427c2481480ead346cfc2d Mon Sep 17 00:00:00 2001 From: hal3e Date: Mon, 22 Jan 2024 11:36:13 +0100 Subject: [PATCH 06/16] forc fmt --- .../contracts/liquidity_pool/src/main.sw | 12 ++--- .../needs_custom_decoder/src/main.sw | 3 +- .../tests/contracts/token_ops/src/main.sw | 2 +- .../tests/logs/contract_logs/src/main.sw | 5 +- .../fuels/tests/logs/script_logs/src/main.sw | 3 +- .../src/main.sw | 3 +- .../fuels/tests/predicates/swap/src/main.sw | 4 +- .../types/contracts/evm_address/src/main.sw | 8 +--- .../contracts/heap_type_in_enums/src/main.sw | 4 +- .../tests/types/contracts/tuples/src/main.sw | 4 +- .../tests/types/contracts/u256/src/main.sw | 4 +- .../types/predicates/address/src/main.sw | 4 +- .../predicates/predicate_tuples/src/main.sw | 3 +- .../predicates/predicate_vectors/src/main.sw | 36 +++++--------- .../types/scripts/script_vectors/src/main.sw | 48 +++++++------------ 15 files changed, 48 insertions(+), 95 deletions(-) diff --git a/packages/fuels/tests/contracts/liquidity_pool/src/main.sw b/packages/fuels/tests/contracts/liquidity_pool/src/main.sw index 5ef6d6049f..187a89fc4d 100644 --- a/packages/fuels/tests/contracts/liquidity_pool/src/main.sw +++ b/packages/fuels/tests/contracts/liquidity_pool/src/main.sw @@ -1,15 +1,15 @@ contract; use std::{ + asset::{ + mint_to_address, + transfer_to_address, + }, call_frames::{ contract_id, msg_asset_id, }, context::msg_amount, - asset::{ - mint_to_address, - transfer_to_address, - }, }; use std::constants::ZERO_B256; @@ -20,9 +20,7 @@ abi LiquidityPool { fn withdraw(recipient: Address); } -const BASE_TOKEN: AssetId = AssetId::from( - 0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c, -); +const BASE_TOKEN: AssetId = AssetId::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c); impl LiquidityPool for Contract { #[payable] diff --git a/packages/fuels/tests/contracts/needs_custom_decoder/src/main.sw b/packages/fuels/tests/contracts/needs_custom_decoder/src/main.sw index 5365d5e358..fdec65b4f4 100644 --- a/packages/fuels/tests/contracts/needs_custom_decoder/src/main.sw +++ b/packages/fuels/tests/contracts/needs_custom_decoder/src/main.sw @@ -1,7 +1,6 @@ contract; -impl AbiEncode for [u8; 1000] -{ +impl AbiEncode for [u8; 1000] { fn abi_encode(self, ref mut buffer: Buffer) { let mut i = 0; while i < 1000 { diff --git a/packages/fuels/tests/contracts/token_ops/src/main.sw b/packages/fuels/tests/contracts/token_ops/src/main.sw index 641d59be70..1b943d667e 100644 --- a/packages/fuels/tests/contracts/token_ops/src/main.sw +++ b/packages/fuels/tests/contracts/token_ops/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::{bytes::Bytes, context::balance_of, context::msg_amount, message::send_message, asset::*}; +use std::{asset::*, bytes::Bytes, context::balance_of, context::msg_amount, message::send_message}; use std::constants::ZERO_B256; abi TestFuelCoin { diff --git a/packages/fuels/tests/logs/contract_logs/src/main.sw b/packages/fuels/tests/logs/contract_logs/src/main.sw index 452f074888..9328964bf1 100644 --- a/packages/fuels/tests/logs/contract_logs/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs/src/main.sw @@ -4,8 +4,7 @@ use std::logging::log; use std::string::String; use contract_logs::ContractLogs; -impl AbiEncode for (TestStruct, TestEnum) -{ +impl AbiEncode for (TestStruct, TestEnum) { #[allow(dead_code)] fn abi_encode(self, ref mut buffer: Buffer) { let (test_struct, test_enum) = self; @@ -144,7 +143,7 @@ impl ContractLogs for Contract { // produce a custom log with log id 128 // this log id will not be present in abi JSON asm(r1: 0, r2: 128, r3: 0, r4: 0) { - log r1 r2 r3 r4; + log r1 r2 r3 r4; } log(123); diff --git a/packages/fuels/tests/logs/script_logs/src/main.sw b/packages/fuels/tests/logs/script_logs/src/main.sw index fd4fd877fb..d59768188c 100644 --- a/packages/fuels/tests/logs/script_logs/src/main.sw +++ b/packages/fuels/tests/logs/script_logs/src/main.sw @@ -2,8 +2,7 @@ script; use std::logging::log; -impl AbiEncode for (TestStruct, TestEnum) -{ +impl AbiEncode for (TestStruct, TestEnum) { #[allow(dead_code)] fn abi_encode(self, ref mut buffer: Buffer) { let (test_struct, test_enum) = self; diff --git a/packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw b/packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw index d42f71cfda..b5265d7c46 100644 --- a/packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw +++ b/packages/fuels/tests/logs/script_needs_custom_decoder_logging/src/main.sw @@ -1,7 +1,6 @@ script; -impl AbiEncode for [u8; 1000] -{ +impl AbiEncode for [u8; 1000] { #[allow(dead_code)] fn abi_encode(self, ref mut buffer: Buffer) { let mut i = 0; diff --git a/packages/fuels/tests/predicates/swap/src/main.sw b/packages/fuels/tests/predicates/swap/src/main.sw index 3d79de95e5..0538cb188d 100644 --- a/packages/fuels/tests/predicates/swap/src/main.sw +++ b/packages/fuels/tests/predicates/swap/src/main.sw @@ -11,9 +11,7 @@ use std::{ }; fn main() -> bool { - let receiver = Address::from( - 0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db, - ); + let receiver = Address::from(0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db); let ask_amount = 100; let output_index = 0; diff --git a/packages/fuels/tests/types/contracts/evm_address/src/main.sw b/packages/fuels/tests/types/contracts/evm_address/src/main.sw index 278686f085..6abd15413f 100644 --- a/packages/fuels/tests/types/contracts/evm_address/src/main.sw +++ b/packages/fuels/tests/types/contracts/evm_address/src/main.sw @@ -10,17 +10,13 @@ abi EvmTest { impl EvmTest for Contract { fn evm_address_as_input(evm_addr: EvmAddress) -> bool { - let evm_addr2 = EvmAddress::from( - 0x1616060606060606060606060606060606060606060606060606060606060606, - ); + let evm_addr2 = EvmAddress::from(0x1616060606060606060606060606060606060606060606060606060606060606); evm_addr == evm_addr2 } fn evm_address_from_literal() -> EvmAddress { - EvmAddress::from( - 0x0606060606060606060606060606060606060606060606060606060606060606, - ) + EvmAddress::from(0x0606060606060606060606060606060606060606060606060606060606060606) } fn evm_address_from_argument(raw_address: b256) -> EvmAddress { diff --git a/packages/fuels/tests/types/contracts/heap_type_in_enums/src/main.sw b/packages/fuels/tests/types/contracts/heap_type_in_enums/src/main.sw index 5c329c6332..941d637f97 100644 --- a/packages/fuels/tests/types/contracts/heap_type_in_enums/src/main.sw +++ b/packages/fuels/tests/types/contracts/heap_type_in_enums/src/main.sw @@ -115,9 +115,7 @@ impl MyContract for Contract { } fn would_raise_a_memory_overflow() -> Result { - Result::Err( - 0x1111111111111111111111111111111111111111111111111111111111111111, - ) + Result::Err(0x1111111111111111111111111111111111111111111111111111111111111111) } fn returns_a_heap_type_too_deep() -> Result { diff --git a/packages/fuels/tests/types/contracts/tuples/src/main.sw b/packages/fuels/tests/types/contracts/tuples/src/main.sw index 0b8ffebd8d..14e7a70f57 100644 --- a/packages/fuels/tests/types/contracts/tuples/src/main.sw +++ b/packages/fuels/tests/types/contracts/tuples/src/main.sw @@ -42,9 +42,7 @@ impl MyContract for Contract { name: __to_str_array("Jane"), }); assert(input.0 == expected.0); - assert( - sha256(from_str_array(input.1.name)) == sha256(from_str_array(expected.1.name)), - ); + assert(sha256(from_str_array(input.1.name)) == sha256(from_str_array(expected.1.name))); expected } diff --git a/packages/fuels/tests/types/contracts/u256/src/main.sw b/packages/fuels/tests/types/contracts/u256/src/main.sw index 5a1bd9955b..e0b8ab0bec 100644 --- a/packages/fuels/tests/types/contracts/u256/src/main.sw +++ b/packages/fuels/tests/types/contracts/u256/src/main.sw @@ -18,9 +18,7 @@ impl MyContract for Contract { } fn u256_in_enum_output() -> SomeEnum { - SomeEnum::B( - 0x0000000000000001000000000000000200000000000000030000000000000004u256, - ) + SomeEnum::B(0x0000000000000001000000000000000200000000000000030000000000000004u256) } fn u256_in_enum_input(some_enum: SomeEnum) { diff --git a/packages/fuels/tests/types/predicates/address/src/main.sw b/packages/fuels/tests/types/predicates/address/src/main.sw index 1d2275732f..c431b853e0 100644 --- a/packages/fuels/tests/types/predicates/address/src/main.sw +++ b/packages/fuels/tests/types/predicates/address/src/main.sw @@ -1,9 +1,7 @@ predicate; fn main(input: Address) -> bool { - let expected_addr = Address::from( - 0xef86afa9696cf0dc6385e2c407a6e159a1103cefb7e2ae0636fb33d3cb2a9e4a, - ); + let expected_addr = Address::from(0xef86afa9696cf0dc6385e2c407a6e159a1103cefb7e2ae0636fb33d3cb2a9e4a); input == expected_addr } diff --git a/packages/fuels/tests/types/predicates/predicate_tuples/src/main.sw b/packages/fuels/tests/types/predicates/predicate_tuples/src/main.sw index d4d2e6dfa4..3426226ce6 100644 --- a/packages/fuels/tests/types/predicates/predicate_tuples/src/main.sw +++ b/packages/fuels/tests/types/predicates/predicate_tuples/src/main.sw @@ -14,8 +14,7 @@ fn main(input_tuple: (u64, TestStruct, TestEnum), number: u64) -> bool { let (u64_number, test_struct, test_enum) = input_tuple; if let TestEnum::Value(enum_value) = test_enum { - return u64_number == 16 && test_struct - .value == 32u32 && enum_value == 64 && number == 128; + return u64_number == 16 && test_struct.value == 32u32 && enum_value == 64 && number == 128; } false diff --git a/packages/fuels/tests/types/predicates/predicate_vectors/src/main.sw b/packages/fuels/tests/types/predicates/predicate_vectors/src/main.sw index ceb9650aa1..861fc618d2 100644 --- a/packages/fuels/tests/types/predicates/predicate_vectors/src/main.sw +++ b/packages/fuels/tests/types/predicates/predicate_vectors/src/main.sw @@ -26,25 +26,16 @@ fn main( result = result && (u32_vec.get(1).unwrap() == 4u32); - result = result && (vec_in_vec - .get(0) - .unwrap() - .get(1) - .unwrap() == 2u32); + result = result && (vec_in_vec.get(0).unwrap().get(1).unwrap() == 2u32); result = result && (struct_in_vec.get(0).unwrap().a == 8u32); - result = result && (vec_in_struct - .a - .get(1) - .unwrap() == 16u32); + result = result && (vec_in_struct.a.get(1).unwrap() == 16u32); let array: [u64; 2] = array_in_vec.get(1).unwrap(); result = result && (array[0] == 32u64); - result = result && (vec_in_array[0] - .get(1) - .unwrap() == 64u32); + result = result && (vec_in_array[0].get(1).unwrap() == 64u32); if let SomeEnum::A(some_vec) = vec_in_enum { result = result && (some_vec.get(2).unwrap() == 128u32); @@ -59,21 +50,20 @@ fn main( result = false; } - result = result && (tuple_in_vec - .get(1) - .unwrap().0 == 128u32); + result = result && (tuple_in_vec.get(1).unwrap().0 == 128u32); let (tuple_a, _) = vec_in_tuple; result = result && (tuple_a.get(1).unwrap() == 64u32); - result = result && (vec_in_a_vec_in_a_struct_in_a_vec - .get(1) - .unwrap() - .a - .get(1) - .unwrap() - .get(1) - .unwrap() == 32u32); + result = result + && (vec_in_a_vec_in_a_struct_in_a_vec + .get(1) + .unwrap() + .a + .get(1) + .unwrap() + .get(1) + .unwrap() == 32u32); result } diff --git a/packages/fuels/tests/types/scripts/script_vectors/src/main.sw b/packages/fuels/tests/types/scripts/script_vectors/src/main.sw index 5bc99a0735..7e3a126b50 100644 --- a/packages/fuels/tests/types/scripts/script_vectors/src/main.sw +++ b/packages/fuels/tests/types/scripts/script_vectors/src/main.sw @@ -28,19 +28,15 @@ fn main( } { let mut exp_vec_in_vec = Vec::new(); - exp_vec_in_vec - .push(vec_from([0u32, 1u32, 2u32])); - exp_vec_in_vec - .push(vec_from([0u32, 1u32, 2u32])); + exp_vec_in_vec.push(vec_from([0u32, 1u32, 2u32])); + exp_vec_in_vec.push(vec_from([0u32, 1u32, 2u32])); require(vec_in_vec == exp_vec_in_vec, "vec_in_vec err"); } { let mut exp_struct_in_vec = Vec::new(); - exp_struct_in_vec - .push(SomeStruct { a: 0u32 }); - exp_struct_in_vec - .push(SomeStruct { a: 1u32 }); + exp_struct_in_vec.push(SomeStruct { a: 0u32 }); + exp_struct_in_vec.push(SomeStruct { a: 1u32 }); require(struct_in_vec == exp_struct_in_vec, "struct_in_vec err"); } @@ -53,10 +49,8 @@ fn main( } { let mut exp_array_in_vec = Vec::new(); - exp_array_in_vec - .push([0, 1]); - exp_array_in_vec - .push([0, 1]); + exp_array_in_vec.push([0, 1]); + exp_array_in_vec.push([0, 1]); require(array_in_vec == exp_array_in_vec, "array_in_vec err"); } @@ -73,19 +67,15 @@ fn main( } { let mut exp_enum_in_vec = Vec::new(); - exp_enum_in_vec - .push(SomeEnum::a(0u32)); - exp_enum_in_vec - .push(SomeEnum::a(1u32)); + exp_enum_in_vec.push(SomeEnum::a(0u32)); + exp_enum_in_vec.push(SomeEnum::a(1u32)); require(enum_in_vec == exp_enum_in_vec, "enum_in_vec err"); } { let mut exp_tuple_in_vec = Vec::new(); - exp_tuple_in_vec - .push((0u32, 0u32)); - exp_tuple_in_vec - .push((1u32, 1u32)); + exp_tuple_in_vec.push((0u32, 0u32)); + exp_tuple_in_vec.push((1u32, 1u32)); require(tuple_in_vec == exp_tuple_in_vec, "tuple_in_vec err"); } @@ -100,28 +90,22 @@ fn main( let mut inner_vec_1 = Vec::new(); let inner_inner_vec_1 = vec_from([0u32, 1u32, 2u32]); - inner_vec_1 - .push(inner_inner_vec_1); + inner_vec_1.push(inner_inner_vec_1); let inner_inner_vec_2 = vec_from([3u32, 4u32, 5u32]); - inner_vec_1 - .push(inner_inner_vec_2); + inner_vec_1.push(inner_inner_vec_2); - exp_vec_in_a_vec_in_a_struct_in_a_vec - .push(SomeStruct { a: inner_vec_1 }); + exp_vec_in_a_vec_in_a_struct_in_a_vec.push(SomeStruct { a: inner_vec_1 }); let mut inner_vec_2 = Vec::new(); let inner_inner_vec_3 = vec_from([6u32, 7u32, 8u32]); - inner_vec_2 - .push(inner_inner_vec_3); + inner_vec_2.push(inner_inner_vec_3); let inner_inner_vec_4 = vec_from([9u32, 10u32, 11u32]); - inner_vec_2 - .push(inner_inner_vec_4); + inner_vec_2.push(inner_inner_vec_4); - exp_vec_in_a_vec_in_a_struct_in_a_vec - .push(SomeStruct { a: inner_vec_2 }); + exp_vec_in_a_vec_in_a_struct_in_a_vec.push(SomeStruct { a: inner_vec_2 }); require( vec_in_a_vec_in_a_struct_in_a_vec == exp_vec_in_a_vec_in_a_struct_in_a_vec, From 66a402dcb828a8191785625e85078a9e5196e0bf Mon Sep 17 00:00:00 2001 From: hal3e Date: Mon, 22 Jan 2024 16:58:24 +0100 Subject: [PATCH 07/16] refactor --- .../src/codec/abi_decoder/bounded_decoder.rs | 4 +- .../experimental_bounded_decoder.rs | 378 ++++++++---------- packages/fuels-core/src/codec/logs.rs | 9 +- .../fuels-core/src/types/enum_variants.rs | 17 - packages/fuels-core/src/types/param_types.rs | 56 +-- 5 files changed, 189 insertions(+), 275 deletions(-) diff --git a/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs b/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs index 4f14240e01..d7556c2ff6 100644 --- a/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs +++ b/packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs @@ -93,7 +93,7 @@ impl BoundedDecoder { ParamType::U256 => Self::decode_u256(bytes), ParamType::Bool => Self::decode_bool(bytes), ParamType::B256 => Self::decode_b256(bytes), - ParamType::RawSlice => self.decode_raw_slice(bytes), + ParamType::RawSlice => Self::decode_raw_slice(bytes), ParamType::StringSlice => Self::decode_string_slice(bytes), ParamType::StringArray(len) => Self::decode_string_array(bytes, *len), ParamType::Array(ref t, length) => { @@ -214,7 +214,7 @@ impl BoundedDecoder { }) } - fn decode_raw_slice(&mut self, bytes: &[u8]) -> Result { + fn decode_raw_slice(bytes: &[u8]) -> Result { Ok(Decoded { token: Token::RawSlice(bytes.to_vec()), bytes_read: bytes.len(), diff --git a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs index 6e69ded1f4..b358ba2189 100644 --- a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs +++ b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs @@ -1,7 +1,6 @@ -use std::str; +use std::{iter::repeat, str}; use crate::{ - checked_round_up_to_word_alignment, codec::DecoderConfig, constants::WORD_SIZE, types::{ @@ -19,9 +18,15 @@ pub(crate) struct ExperimentalBoundedDecoder { token_tracker: CounterWithLimit, } +const U8_BYTES_SIZE: usize = 1; +const U16_BYTES_SIZE: usize = 2; +const U32_BYTES_SIZE: usize = 4; +const U64_BYTES_SIZE: usize = WORD_SIZE; const U128_BYTES_SIZE: usize = 2 * WORD_SIZE; const U256_BYTES_SIZE: usize = 4 * WORD_SIZE; const B256_BYTES_SIZE: usize = 4 * WORD_SIZE; +const LENGTH_BYTES_SIZE: usize = WORD_SIZE; +const DISCRIMINANT_BYTES_SIZE: usize = WORD_SIZE; impl ExperimentalBoundedDecoder { pub(crate) fn new(config: DecoderConfig) -> Self { @@ -63,167 +68,98 @@ impl ExperimentalBoundedDecoder { self.token_tracker.increase()?; match param_type { ParamType::Unit => Self::decode_unit(), + ParamType::Bool => Self::decode_bool(bytes), ParamType::U8 => Self::decode_u8(bytes), ParamType::U16 => Self::decode_u16(bytes), ParamType::U32 => Self::decode_u32(bytes), ParamType::U64 => Self::decode_u64(bytes), ParamType::U128 => Self::decode_u128(bytes), ParamType::U256 => Self::decode_u256(bytes), - ParamType::Bool => Self::decode_bool(bytes), ParamType::B256 => Self::decode_b256(bytes), - ParamType::RawSlice => self.decode_raw_slice(bytes), + ParamType::Bytes => Self::decode_bytes(bytes), + ParamType::String => Self::decode_std_string(bytes), + ParamType::RawSlice => Self::decode_raw_slice(bytes), + ParamType::StringArray(length) => Self::decode_string_array(bytes, *length), ParamType::StringSlice => Self::decode_string_slice(bytes), - ParamType::StringArray(len) => Self::decode_string_array(bytes, *len), - ParamType::Array(ref t, length) => { - self.run_w_depth_tracking(|ctx| ctx.decode_array(t, bytes, *length)) - } - ParamType::Struct { fields, .. } => { - self.run_w_depth_tracking(|ctx| ctx.decode_struct(fields, bytes)) - } - ParamType::Enum { variants, .. } => { - self.run_w_depth_tracking(|ctx| ctx.decode_enum(bytes, variants)) + ParamType::Tuple(param_types) => { + self.run_w_depth_tracking(|ctx| ctx.decode_tuple(param_types, bytes)) } - ParamType::Tuple(types) => { - self.run_w_depth_tracking(|ctx| ctx.decode_tuple(types, bytes)) + ParamType::Array(param_type, length) => { + self.run_w_depth_tracking(|ctx| ctx.decode_array(param_type, bytes, *length)) } ParamType::Vector(param_type) => { // although nested vectors cannot be decoded yet, depth tracking still occurs for future // proofing self.run_w_depth_tracking(|ctx| ctx.decode_vector(param_type, bytes)) } - ParamType::Bytes => Self::decode_bytes(bytes), - ParamType::String => Self::decode_std_string(bytes), + + ParamType::Struct { fields, .. } => { + self.run_w_depth_tracking(|ctx| ctx.decode_struct(fields, bytes)) + } + ParamType::Enum { variants, .. } => { + self.run_w_depth_tracking(|ctx| ctx.decode_enum(bytes, variants)) + } } } - fn decode_bytes(bytes: &[u8]) -> Result { - let num_of_elements = peek_u64(bytes)? as usize; - let bytes = peek(skip(bytes, WORD_SIZE)?, num_of_elements)?; + fn decode_unit() -> Result { Ok(Decoded { - token: Token::Bytes(bytes.to_vec()), - bytes_read: WORD_SIZE + bytes.len(), + token: Token::Unit, + bytes_read: 0, }) } - fn decode_std_string(bytes: &[u8]) -> Result { - let num_of_elements = peek_u64(bytes)? as usize; - let bytes = peek(skip(bytes, WORD_SIZE)?, num_of_elements)?; + fn decode_bool(bytes: &[u8]) -> Result { + let value = peek_u8(bytes)? != 0u8; + Ok(Decoded { - token: Token::String(str::from_utf8(bytes)?.to_string()), - bytes_read: WORD_SIZE + bytes.len(), + token: Token::Bool(value), + bytes_read: U8_BYTES_SIZE, }) } - fn decode_vector(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { - let num_of_elements = peek_u64(bytes)? as usize; - let bytes = skip(bytes, WORD_SIZE)?; - let (tokens, bytes_read) = - self.decode_params(std::iter::repeat(param_type).take(num_of_elements), bytes)?; - + fn decode_u8(bytes: &[u8]) -> Result { Ok(Decoded { - token: Token::Vector(tokens), - bytes_read: WORD_SIZE + bytes_read, + token: Token::U8(peek_u8(bytes)?), + bytes_read: U8_BYTES_SIZE, }) } - fn decode_tuple(&mut self, param_types: &[ParamType], bytes: &[u8]) -> Result { - let mut tokens = vec![]; - - let mut bytes_read = 0; - - for param_type in param_types.iter() { - let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?; - bytes_read += res.bytes_read; - tokens.push(res.token); - } - + fn decode_u16(bytes: &[u8]) -> Result { Ok(Decoded { - token: Token::Tuple(tokens), - bytes_read, + token: Token::U16(peek_u16(bytes)?), + bytes_read: U16_BYTES_SIZE, }) } - fn decode_struct(&mut self, param_types: &[ParamType], bytes: &[u8]) -> Result { - let mut tokens = vec![]; - - let mut bytes_read = 0; - - for param_type in param_types.iter() { - let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?; - bytes_read += res.bytes_read; - tokens.push(res.token); - } - + fn decode_u32(bytes: &[u8]) -> Result { Ok(Decoded { - token: Token::Struct(tokens), - bytes_read, + token: Token::U32(peek_u32(bytes)?), + bytes_read: U32_BYTES_SIZE, }) } - fn decode_params<'a>( - &mut self, - param_types: impl IntoIterator, - bytes: &[u8], - ) -> Result<(Vec, usize)> { - let mut results = vec![]; - - let mut bytes_read = 0; - - for param_type in param_types { - let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?; - bytes_read += res.bytes_read; - results.push(res.token); - } - - Ok((results, bytes_read)) - } - - fn decode_array( - &mut self, - param_type: &ParamType, - bytes: &[u8], - length: usize, - ) -> Result { - let (tokens, bytes_read) = - self.decode_params(std::iter::repeat(param_type).take(length), bytes)?; - + fn decode_u64(bytes: &[u8]) -> Result { Ok(Decoded { - token: Token::Array(tokens), - bytes_read, + token: Token::U64(peek_u64(bytes)?), + bytes_read: U64_BYTES_SIZE, }) } - fn decode_raw_slice(&mut self, bytes: &[u8]) -> Result { - let num_of_elements = peek_u64(bytes)? as usize; - let bytes = peek(skip(bytes, WORD_SIZE)?, num_of_elements)?; + fn decode_u128(bytes: &[u8]) -> Result { Ok(Decoded { - token: Token::RawSlice(bytes.to_vec()), - bytes_read: WORD_SIZE + bytes.len(), + token: Token::U128(peek_u128(bytes)?), + bytes_read: U128_BYTES_SIZE, }) } - fn decode_string_slice(bytes: &[u8]) -> Result { - let size = peek_u64(bytes)? as usize; - let bytes = peek(skip(bytes, WORD_SIZE)?, size)?; - let decoded = str::from_utf8(bytes)?; - + fn decode_u256(bytes: &[u8]) -> Result { Ok(Decoded { - token: Token::StringSlice(StaticStringToken::new(decoded.into(), None)), - bytes_read: decoded.len(), + token: Token::U256(peek_u256(bytes)?), + bytes_read: U256_BYTES_SIZE, }) } - fn decode_string_array(bytes: &[u8], length: usize) -> Result { - let encoded_str = peek(bytes, length)?; - - let decoded = str::from_utf8(encoded_str)?; - let result = Decoded { - token: Token::StringArray(StaticStringToken::new(decoded.into(), Some(length))), - bytes_read: checked_round_up_to_word_alignment(length)?, - }; - Ok(result) - } - fn decode_b256(bytes: &[u8]) -> Result { Ok(Decoded { token: Token::B256(*peek_fixed::(bytes)?), @@ -231,104 +167,128 @@ impl ExperimentalBoundedDecoder { }) } - fn decode_bool(bytes: &[u8]) -> Result { - // Grab last byte of the word and compare it to 0x00 - let b = peek_u8(bytes)? != 0u8; + fn decode_bytes(bytes: &[u8]) -> Result { + let length = peek_length(bytes)?; + let bytes = peek(skip(bytes, LENGTH_BYTES_SIZE)?, length)?; - let result = Decoded { - token: Token::Bool(b), - bytes_read: 1, - }; + Ok(Decoded { + token: Token::Bytes(bytes.to_vec()), + bytes_read: LENGTH_BYTES_SIZE + bytes.len(), + }) + } + + fn decode_std_string(bytes: &[u8]) -> Result { + let length = peek_length(bytes)?; + let bytes = peek(skip(bytes, LENGTH_BYTES_SIZE)?, length)?; - Ok(result) + Ok(Decoded { + token: Token::String(str::from_utf8(bytes)?.to_string()), + bytes_read: LENGTH_BYTES_SIZE + bytes.len(), + }) } - fn decode_u128(bytes: &[u8]) -> Result { + fn decode_raw_slice(bytes: &[u8]) -> Result { + let length = peek_length(bytes)?; + let bytes = peek(skip(bytes, LENGTH_BYTES_SIZE)?, length)?; + Ok(Decoded { - token: Token::U128(peek_u128(bytes)?), - bytes_read: U128_BYTES_SIZE, + token: Token::RawSlice(bytes.to_vec()), + bytes_read: LENGTH_BYTES_SIZE + bytes.len(), }) } - fn decode_u256(bytes: &[u8]) -> Result { + fn decode_string_array(bytes: &[u8], length: usize) -> Result { + let bytes = peek(bytes, length)?; + let decoded = str::from_utf8(bytes)?.to_string(); + Ok(Decoded { - token: Token::U256(peek_u256(bytes)?), - bytes_read: U256_BYTES_SIZE, + token: Token::StringArray(StaticStringToken::new(decoded, Some(length))), + bytes_read: length, }) } - fn decode_u64(bytes: &[u8]) -> Result { + fn decode_string_slice(bytes: &[u8]) -> Result { + let length = peek_length(bytes)?; + let bytes = peek(skip(bytes, LENGTH_BYTES_SIZE)?, length)?; + let decoded = str::from_utf8(bytes)?.to_string(); + Ok(Decoded { - token: Token::U64(peek_u64(bytes)?), - bytes_read: WORD_SIZE, + token: Token::StringSlice(StaticStringToken::new(decoded, None)), + bytes_read: bytes.len(), }) } - fn decode_u32(bytes: &[u8]) -> Result { + fn decode_tuple(&mut self, param_types: &[ParamType], bytes: &[u8]) -> Result { + let (tokens, bytes_read) = self.decode_params(param_types, bytes)?; + Ok(Decoded { - token: Token::U32(peek_u32(bytes)?), - bytes_read: 4, + token: Token::Tuple(tokens), + bytes_read, }) } - fn decode_u16(bytes: &[u8]) -> Result { + fn decode_array( + &mut self, + param_type: &ParamType, + bytes: &[u8], + length: usize, + ) -> Result { + let (tokens, bytes_read) = self.decode_params(repeat(param_type).take(length), bytes)?; + Ok(Decoded { - token: Token::U16(peek_u16(bytes)?), - bytes_read: 2, + token: Token::Array(tokens), + bytes_read, }) } - fn decode_u8(bytes: &[u8]) -> Result { + fn decode_vector(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result { + let length = peek_length(bytes)?; + let bytes = skip(bytes, LENGTH_BYTES_SIZE)?; + let (tokens, bytes_read) = self.decode_params(repeat(param_type).take(length), bytes)?; + Ok(Decoded { - token: Token::U8(peek_u8(bytes)?), - bytes_read: 1, + token: Token::Vector(tokens), + bytes_read: LENGTH_BYTES_SIZE + bytes_read, }) } - fn decode_unit() -> Result { + fn decode_struct(&mut self, param_types: &[ParamType], bytes: &[u8]) -> Result { + let (tokens, bytes_read) = self.decode_params(param_types, bytes)?; + Ok(Decoded { - token: Token::Unit, - bytes_read: 0, + token: Token::Struct(tokens), + bytes_read, }) } - /// The encoding follows the ABI specs defined - /// [here](https://github.com/FuelLabs/fuel-specs/blob/1be31f70c757d8390f74b9e1b3beb096620553eb/specs/protocol/abi.md) - /// - /// # Arguments - /// - /// * `data`: slice of encoded data on whose beginning we're expecting an encoded enum - /// * `variants`: all types that this particular enum type could hold fn decode_enum(&mut self, bytes: &[u8], variants: &EnumVariants) -> Result { - let discriminant = peek_u64(bytes)?; + let discriminant = peek_discriminant(bytes)?; + let variant_bytes = skip(bytes, DISCRIMINANT_BYTES_SIZE)?; let selected_variant = variants.param_type_of_variant(discriminant)?; - let enum_content_bytes = skip(bytes, WORD_SIZE)?; - let result = self.decode_token_in_enum(enum_content_bytes, variants, selected_variant)?; + let decoded = self.decode_param(selected_variant, variant_bytes)?; - let selector = Box::new((discriminant, result.token, variants.clone())); Ok(Decoded { - token: Token::Enum(selector), - bytes_read: WORD_SIZE + result.bytes_read, + token: Token::Enum(Box::new((discriminant, decoded.token, variants.clone()))), + bytes_read: DISCRIMINANT_BYTES_SIZE + decoded.bytes_read, }) } - fn decode_token_in_enum( + fn decode_params<'a>( &mut self, + param_types: impl IntoIterator, bytes: &[u8], - variants: &EnumVariants, - selected_variant: &ParamType, - ) -> Result { - // Enums that contain only Units as variants have only their discriminant encoded. - // Because of this we construct the Token::Unit rather than calling `decode_param` - if variants.only_units_inside() { - Ok(Decoded { - token: Token::Unit, - bytes_read: 0, - }) - } else { - self.decode_param(selected_variant, bytes) + ) -> Result<(Vec, usize)> { + let mut tokens = vec![]; + let mut bytes_read = 0; + + for param_type in param_types { + let decoded = self.decode_param(param_type, skip(bytes, bytes_read)?)?; + tokens.push(decoded.token); + bytes_read += decoded.bytes_read; } + + Ok((tokens, bytes_read)) } } @@ -356,13 +316,13 @@ impl CounterWithLimit { fn increase(&mut self) -> Result<()> { self.count += 1; if self.count > self.max { - Err(error!( + return Err(error!( InvalidType, "{} limit ({}) reached while decoding. Try increasing it.", self.name, self.max - )) - } else { - Ok(()) + )); } + + Ok(()) } fn decrease(&mut self) { @@ -372,6 +332,26 @@ impl CounterWithLimit { } } +fn peek_u8(bytes: &[u8]) -> Result { + let slice = peek_fixed::(bytes)?; + Ok(u8::from_be_bytes(*slice)) +} + +fn peek_u16(bytes: &[u8]) -> Result { + let slice = peek_fixed::(bytes)?; + Ok(u16::from_be_bytes(*slice)) +} + +fn peek_u32(bytes: &[u8]) -> Result { + let slice = peek_fixed::(bytes)?; + Ok(u32::from_be_bytes(*slice)) +} + +fn peek_u64(bytes: &[u8]) -> Result { + let slice = peek_fixed::(bytes)?; + Ok(u64::from_be_bytes(*slice)) +} + fn peek_u128(bytes: &[u8]) -> Result { let slice = peek_fixed::(bytes)?; Ok(u128::from_be_bytes(*slice)) @@ -382,52 +362,40 @@ fn peek_u256(bytes: &[u8]) -> Result { Ok(U256::from(*slice)) } -fn peek_u64(bytes: &[u8]) -> Result { - let slice = peek_fixed::(bytes)?; - Ok(u64::from_be_bytes(*slice)) -} +fn peek_length(bytes: &[u8]) -> Result { + let slice = peek_fixed::(bytes)?; -fn peek_u32(bytes: &[u8]) -> Result { - let slice = peek_fixed::<4>(bytes)?; - Ok(u32::from_be_bytes(*slice)) + u64::from_be_bytes(*slice) + .try_into() + .map_err(|_| error!(InvalidData, "could not convert `u64` to `usize`")) } -fn peek_u16(bytes: &[u8]) -> Result { - let slice = peek_fixed::<2>(bytes)?; - Ok(u16::from_be_bytes(*slice)) +fn peek_discriminant(bytes: &[u8]) -> Result { + let slice = peek_fixed::(bytes)?; + Ok(u64::from_be_bytes(*slice)) } -fn peek_u8(bytes: &[u8]) -> Result { - let slice = peek_fixed::<1>(bytes)?; - Ok(u8::from_be_bytes(*slice)) +fn peek(data: &[u8], len: usize) -> Result<&[u8]> { + (len <= data.len()).then_some(&data[..len]).ok_or(error!( + InvalidData, + "tried to read `{len}` bytes but only had `{}` remaining!", + data.len() + )) } fn peek_fixed(data: &[u8]) -> Result<&[u8; LEN]> { let slice_w_correct_length = peek(data, LEN)?; - Ok(<&[u8; LEN]>::try_from(slice_w_correct_length) - .expect("peek(data,len) must return a slice of length `len` or error out")) -} - -fn peek(data: &[u8], len: usize) -> Result<&[u8]> { - if len > data.len() { - Err(error!( - InvalidData, - "tried to read {len} bytes from response but only had {} remaining!", - data.len() - )) - } else { - Ok(&data[..len]) - } + Ok(slice_w_correct_length + .try_into() + .expect("peek(data, len) must return a slice of length `len` or error out")) } fn skip(slice: &[u8], num_bytes: usize) -> Result<&[u8]> { - if num_bytes > slice.len() { - Err(error!( + (num_bytes <= slice.len()) + .then_some(&slice[num_bytes..]) + .ok_or(error!( InvalidData, - "tried to consume {num_bytes} bytes from response but only had {} remaining!", + "tried to consume `{num_bytes}` bytes but only had `{}` remaining!", slice.len() )) - } else { - Ok(&slice[num_bytes..]) - } } diff --git a/packages/fuels-core/src/codec/logs.rs b/packages/fuels-core/src/codec/logs.rs index 6581b9aef4..1a63843543 100644 --- a/packages/fuels-core/src/codec/logs.rs +++ b/packages/fuels-core/src/codec/logs.rs @@ -35,12 +35,14 @@ impl LogFormatter { bytes: &[u8], ) -> Result { #[cfg(experimental)] - Self::can_decode_log_with_type::()?; - #[cfg(experimental)] - let token = ABIDecoder::new(decoder_config).decode(&T::param_type(), bytes)?; + let toxken = { + Self::can_decode_log_with_type::()?; + ABIDecoder::new(decoder_config).decode(&T::param_type(), bytes)? + }; #[cfg(not(experimental))] let token = ABIDecoder::new(decoder_config).experimental_decode(&T::param_type(), bytes)?; + Ok(format!("{:?}", T::from_token(token)?)) } @@ -200,6 +202,7 @@ impl LogDecoder { #[cfg(experimental)] let token = ABIDecoder::new(self.decoder_config).decode(&T::param_type(), &bytes)?; + T::from_token(token) }) }) diff --git a/packages/fuels-core/src/types/enum_variants.rs b/packages/fuels-core/src/types/enum_variants.rs index 0a7c4c9360..fc2f9d0a58 100644 --- a/packages/fuels-core/src/types/enum_variants.rs +++ b/packages/fuels-core/src/types/enum_variants.rs @@ -63,23 +63,6 @@ impl EnumVariants { .ok_or_else(|| error!(InvalidType, "Enum variants are too wide")) } - /// Calculates how many bytes are needed to encode an enum. - #[cfg(not(experimental))] - pub fn experimental_compute_enum_width_in_bytes(&self) -> Result { - if self.only_units_inside() { - return Ok(ENUM_DISCRIMINANT_BYTE_WIDTH); - } - - let width = self.param_types().iter().try_fold(0, |a, p| -> Result<_> { - let size = p.experimental_compute_encoding_in_bytes()?; - Ok(a.max(size)) - })?; - - checked_round_up_to_word_alignment(width)? - .checked_add(ENUM_DISCRIMINANT_BYTE_WIDTH) - .ok_or_else(|| error!(InvalidType, "Enum variants are too wide")) - } - /// Determines the padding needed for the provided enum variant (based on the width of the /// biggest variant) and returns it. pub fn compute_padding_amount_in_bytes(&self, variant_param_type: &ParamType) -> Result { diff --git a/packages/fuels-core/src/types/param_types.rs b/packages/fuels-core/src/types/param_types.rs index 37ae274b11..c2bff0e2f8 100644 --- a/packages/fuels-core/src/types/param_types.rs +++ b/packages/fuels-core/src/types/param_types.rs @@ -16,19 +16,23 @@ use crate::{ #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum ParamType { + Unit, + Bool, U8, U16, U32, U64, U128, U256, - Bool, B256, - Unit, + Bytes, + String, + RawSlice, + StringArray(usize), + StringSlice, + Tuple(Vec), Array(Box, usize), Vector(Box), - StringSlice, - StringArray(usize), Struct { fields: Vec, generics: Vec, @@ -37,10 +41,6 @@ pub enum ParamType { variants: EnumVariants, generics: Vec, }, - Tuple(Vec), - RawSlice, - Bytes, - String, } pub enum ReturnLocation { @@ -212,46 +212,6 @@ impl ParamType { } } - /// Calculates the number of bytes the VM expects this parameter to be encoded in. - #[cfg(not(experimental))] - pub fn experimental_compute_encoding_in_bytes(&self) -> Result { - let overflow_error = || { - error!( - InvalidType, - "Reached overflow while computing encoding size for {:?}", self - ) - }; - match &self { - ParamType::Unit => Ok(0), - ParamType::U8 | ParamType::Bool => Ok(1), - ParamType::U16 => Ok(2), - ParamType::U32 => Ok(4), - ParamType::U64 => Ok(8), - // TODO: @hal3e fix StringSlice, RawSlice, Vec - ParamType::U128 | ParamType::RawSlice | ParamType::StringSlice => Ok(16), - ParamType::U256 | ParamType::B256 => Ok(32), - ParamType::Vector(_) | ParamType::Bytes | ParamType::String => Ok(24), - ParamType::Array(param, count) => param - .compute_encoding_in_bytes()? - .checked_mul(*count) - .ok_or_else(overflow_error), - ParamType::StringArray(len) => { - checked_round_up_to_word_alignment(*len).map_err(|_| overflow_error()) - } - ParamType::Tuple(fields) | ParamType::Struct { fields, .. } => { - fields.iter().try_fold(0, |a: usize, param_type| { - let size = checked_round_up_to_word_alignment( - param_type.compute_encoding_in_bytes()?, - )?; - a.checked_add(size).ok_or_else(overflow_error) - }) - } - ParamType::Enum { variants, .. } => variants - .compute_enum_width_in_bytes() - .map_err(|_| overflow_error()), - } - } - /// For when you need to convert a ABI JSON's TypeApplication into a ParamType. /// /// # Arguments From a124b72250bce586c444ffb6aa24aba6ad5a9fa5 Mon Sep 17 00:00:00 2001 From: hal3e Date: Tue, 23 Jan 2024 12:32:25 +0100 Subject: [PATCH 08/16] add experimental log test for Script --- packages/fuels/Forc.toml | 3 +- packages/fuels/tests/logs.rs | 100 +++++++++++------- .../tests/logs/contract_logs/src/main.sw | 29 +++-- .../tests/logs/contract_logs_abi/src/main.sw | 2 +- .../logs/script_experimental_logs/Forc.toml | 5 + .../logs/script_experimental_logs/src/main.sw | 46 ++++++++ 6 files changed, 130 insertions(+), 55 deletions(-) create mode 100644 packages/fuels/tests/logs/script_experimental_logs/Forc.toml create mode 100644 packages/fuels/tests/logs/script_experimental_logs/src/main.sw diff --git a/packages/fuels/Forc.toml b/packages/fuels/Forc.toml index 0148393ce2..ff25dc0b76 100644 --- a/packages/fuels/Forc.toml +++ b/packages/fuels/Forc.toml @@ -30,14 +30,15 @@ members = [ 'tests/logs/contract_logs', 'tests/logs/contract_logs_abi', 'tests/logs/contract_with_contract_logs', + 'tests/logs/script_experimental_logs', 'tests/logs/script_logs', 'tests/logs/script_needs_custom_decoder_logging', 'tests/logs/script_with_contract_logs', 'tests/predicates/basic_predicate', - 'tests/predicates/swap', 'tests/predicates/predicate_configurables', 'tests/predicates/predicate_witnesses', 'tests/predicates/signatures', + 'tests/predicates/swap', 'tests/scripts/arguments', 'tests/scripts/basic_script', 'tests/scripts/require_from_contract', diff --git a/packages/fuels/tests/logs.rs b/packages/fuels/tests/logs.rs index 1b40e1060e..0a43b217e3 100644 --- a/packages/fuels/tests/logs.rs +++ b/packages/fuels/tests/logs.rs @@ -5,7 +5,7 @@ use fuels::{ tx::Receipt, types::{Bits256, SizedAsciiString}, }; -use fuels_core::codec::DecoderConfig; +use fuels_core::{codec::DecoderConfig, types::AsciiString}; #[tokio::test] async fn test_parse_logged_variables() -> Result<()> { @@ -1421,8 +1421,7 @@ async fn can_configure_decoder_for_script_log_decoding() -> Result<()> { ..Default::default() }) .call() - .await - .unwrap(); + .await?; response .decode_logs_with_type::<[u8; 1000]>() @@ -1440,10 +1439,9 @@ async fn can_configure_decoder_for_script_log_decoding() -> Result<()> { ..Default::default() }) .call() - .await - .unwrap(); + .await?; - let logs = response.decode_logs_with_type::<[u8; 1000]>().unwrap(); + let logs = response.decode_logs_with_type::<[u8; 1000]>()?; assert_eq!(logs, vec![[0u8; 1000]]); let logs = response.decode_logs(); @@ -1490,9 +1488,7 @@ async fn string_slice_log() -> Result<()> { #[tokio::test] #[cfg(not(experimental))] -async fn string_slice_log() -> Result<()> { - use fuels_core::types::AsciiString; - +async fn contract_experimental_log() -> Result<()> { setup_program_test!( Wallets("wallet"), Abigen(Contract( @@ -1505,36 +1501,14 @@ async fn string_slice_log() -> Result<()> { wallet = "wallet" ) ); + let contract_methods = contract_instance.methods(); - let response = contract_instance - .methods() - .produce_string_slice_log() - .call() - .await?; - - let logs = response.decode_logs_with_type::()?; - - assert_eq!(logs.first().unwrap().to_string(), "string_slice"); - - Ok(()) -} + { + let response = contract_methods.produce_string_slice_log().call().await?; + let logs = response.decode_logs_with_type::()?; -#[tokio::test] -#[cfg(not(experimental))] -async fn contract_heap_types_log() -> Result<()> { - setup_program_test!( - Wallets("wallet"), - Abigen(Contract( - name = "MyContract", - project = "packages/fuels/tests/logs/contract_logs" - ),), - Deploy( - contract = "MyContract", - name = "contract_instance", - wallet = "wallet" - ) - ); - let contract_methods = contract_instance.methods(); + assert_eq!("fuel".to_string(), logs.first().unwrap().to_string()); + } { let v = [1u16, 2, 3].to_vec(); let some_enum = EnumWithGeneric::VariantOne(v); @@ -1569,4 +1543,54 @@ async fn contract_heap_types_log() -> Result<()> { Ok(()) } -//TODO: @hal3e add heat types logs for script +#[tokio::test] +#[cfg(not(experimental))] +async fn script_experimental_log() -> Result<()> { + setup_program_test!( + Wallets("wallet"), + Abigen(Script( + name = "LogScript", + project = "packages/fuels/tests/logs/script_experimental_logs" + )), + LoadScript( + name = "script_instance", + script = "LogScript", + wallet = "wallet" + ) + ); + let response = script_instance.main().call().await?; + + { + let logs = response.decode_logs_with_type::()?; + + assert_eq!("fuel".to_string(), logs.first().unwrap().to_string()); + } + { + let logs = response.decode_logs_with_type::()?; + + assert_eq!(vec!["fuel".to_string()], logs); + } + { + let logs = response.decode_logs_with_type::()?; + + assert_eq!(vec![Bytes("fuel".as_bytes().to_vec())], logs); + } + { + let logs = response.decode_logs_with_type::()?; + + assert_eq!(vec![RawSlice("fuel".as_bytes().to_vec())], logs); + } + { + let v = [1u16, 2, 3].to_vec(); + let some_enum = EnumWithGeneric::VariantOne(v); + let other_enum = EnumWithGeneric::VariantTwo; + let v1 = vec![some_enum.clone(), other_enum, some_enum]; + let expected_vec = vec![vec![v1.clone(), v1]]; + + let logs = response.decode_logs_with_type::>>>>>()?; + + assert_eq!(vec![expected_vec], logs); + } + + Ok(()) +} diff --git a/packages/fuels/tests/logs/contract_logs/src/main.sw b/packages/fuels/tests/logs/contract_logs/src/main.sw index 9328964bf1..3691b3ced3 100644 --- a/packages/fuels/tests/logs/contract_logs/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs/src/main.sw @@ -1,7 +1,6 @@ contract; -use std::logging::log; -use std::string::String; +use std::{logging::log, string::String}; use contract_logs::ContractLogs; impl AbiEncode for (TestStruct, TestEnum) { @@ -150,7 +149,19 @@ impl ContractLogs for Contract { } fn produce_string_slice_log() { - log("string_slice"); + log("fuel"); + } + + fn produce_string_log() { + log(String::from_ascii_str("fuel")); + } + + fn produce_bytes_log() { + log(String::from_ascii_str("fuel").as_bytes()); + } + + fn produce_raw_slice_log() { + log(String::from_ascii_str("fuel").as_raw_slice()); } fn produce_vec_log() { @@ -176,16 +187,4 @@ impl ContractLogs for Contract { log(v3); } - - fn produce_string_log() { - log(String::from_ascii_str("fuel")); - } - - fn produce_bytes_log() { - log(String::from_ascii_str("fuel").as_bytes()); - } - - fn produce_raw_slice_log() { - log(String::from_ascii_str("fuel").as_raw_slice()); - } } diff --git a/packages/fuels/tests/logs/contract_logs_abi/src/main.sw b/packages/fuels/tests/logs/contract_logs_abi/src/main.sw index 228b57116b..074a16c5cb 100644 --- a/packages/fuels/tests/logs/contract_logs_abi/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs_abi/src/main.sw @@ -10,8 +10,8 @@ abi ContractLogs { fn produce_multiple_logs(); fn produce_bad_logs(); fn produce_string_slice_log(); - fn produce_vec_log(); fn produce_string_log(); fn produce_bytes_log(); fn produce_raw_slice_log(); + fn produce_vec_log(); } diff --git a/packages/fuels/tests/logs/script_experimental_logs/Forc.toml b/packages/fuels/tests/logs/script_experimental_logs/Forc.toml new file mode 100644 index 0000000000..3cffec9495 --- /dev/null +++ b/packages/fuels/tests/logs/script_experimental_logs/Forc.toml @@ -0,0 +1,5 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "script_experimental_logs" diff --git a/packages/fuels/tests/logs/script_experimental_logs/src/main.sw b/packages/fuels/tests/logs/script_experimental_logs/src/main.sw new file mode 100644 index 0000000000..3280342462 --- /dev/null +++ b/packages/fuels/tests/logs/script_experimental_logs/src/main.sw @@ -0,0 +1,46 @@ +script; + +use std::{logging::log, string::String}; + +#[allow(dead_code)] +enum EnumWithGeneric { + VariantOne: D, + VariantTwo: (), +} + +fn main() { + // String slice + log("fuel"); + + // String + log(String::from_ascii_str("fuel")); + + // Bytes + log(String::from_ascii_str("fuel").as_bytes()); + + // RawSlice + log(String::from_ascii_str("fuel").as_raw_slice()); + + // Vector + let mut v = Vec::new(); + v.push(1u16); + v.push(2u16); + v.push(3u16); + + let some_enum = EnumWithGeneric::VariantOne(v); + let other_enum = EnumWithGeneric::VariantTwo; + + let mut v1 = Vec::new(); + v1.push(some_enum); + v1.push(other_enum); + v1.push(some_enum); + + let mut v2 = Vec::new(); + v2.push(v1); + v2.push(v1); + + let mut v3 = Vec::new(); + v3.push(v2); + + log(v3); +} From 3b64baa5ad8cc5c286c4e637975e4e61b637b4ce Mon Sep 17 00:00:00 2001 From: hal3e Date: Tue, 23 Jan 2024 12:34:40 +0100 Subject: [PATCH 09/16] forc fmt --- packages/fuels/tests/logs.rs | 24 ++++----- .../logs/script_experimental_logs/src/main.sw | 50 +++++++++---------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/packages/fuels/tests/logs.rs b/packages/fuels/tests/logs.rs index 0a43b217e3..6e57f3628e 100644 --- a/packages/fuels/tests/logs.rs +++ b/packages/fuels/tests/logs.rs @@ -1509,18 +1509,6 @@ async fn contract_experimental_log() -> Result<()> { assert_eq!("fuel".to_string(), logs.first().unwrap().to_string()); } - { - let v = [1u16, 2, 3].to_vec(); - let some_enum = EnumWithGeneric::VariantOne(v); - let other_enum = EnumWithGeneric::VariantTwo; - let v1 = vec![some_enum.clone(), other_enum, some_enum]; - let expected_vec = vec![vec![v1.clone(), v1]]; - - let response = contract_methods.produce_vec_log().call().await?; - let logs = response.decode_logs_with_type::>>>>>()?; - - assert_eq!(vec![expected_vec], logs); - } { let response = contract_methods.produce_string_log().call().await?; let logs = response.decode_logs_with_type::()?; @@ -1539,6 +1527,18 @@ async fn contract_experimental_log() -> Result<()> { assert_eq!(vec![RawSlice("fuel".as_bytes().to_vec())], logs); } + { + let v = [1u16, 2, 3].to_vec(); + let some_enum = EnumWithGeneric::VariantOne(v); + let other_enum = EnumWithGeneric::VariantTwo; + let v1 = vec![some_enum.clone(), other_enum, some_enum]; + let expected_vec = vec![vec![v1.clone(), v1]]; + + let response = contract_methods.produce_vec_log().call().await?; + let logs = response.decode_logs_with_type::>>>>>()?; + + assert_eq!(vec![expected_vec], logs); + } Ok(()) } diff --git a/packages/fuels/tests/logs/script_experimental_logs/src/main.sw b/packages/fuels/tests/logs/script_experimental_logs/src/main.sw index 3280342462..27ac44fd3e 100644 --- a/packages/fuels/tests/logs/script_experimental_logs/src/main.sw +++ b/packages/fuels/tests/logs/script_experimental_logs/src/main.sw @@ -9,38 +9,38 @@ enum EnumWithGeneric { } fn main() { - // String slice - log("fuel"); + // String slice + log("fuel"); - // String - log(String::from_ascii_str("fuel")); + // String + log(String::from_ascii_str("fuel")); - // Bytes - log(String::from_ascii_str("fuel").as_bytes()); + // Bytes + log(String::from_ascii_str("fuel").as_bytes()); - // RawSlice - log(String::from_ascii_str("fuel").as_raw_slice()); + // RawSlice + log(String::from_ascii_str("fuel").as_raw_slice()); - // Vector - let mut v = Vec::new(); - v.push(1u16); - v.push(2u16); - v.push(3u16); + // Vector + let mut v = Vec::new(); + v.push(1u16); + v.push(2u16); + v.push(3u16); - let some_enum = EnumWithGeneric::VariantOne(v); - let other_enum = EnumWithGeneric::VariantTwo; + let some_enum = EnumWithGeneric::VariantOne(v); + let other_enum = EnumWithGeneric::VariantTwo; - let mut v1 = Vec::new(); - v1.push(some_enum); - v1.push(other_enum); - v1.push(some_enum); + let mut v1 = Vec::new(); + v1.push(some_enum); + v1.push(other_enum); + v1.push(some_enum); - let mut v2 = Vec::new(); - v2.push(v1); - v2.push(v1); + let mut v2 = Vec::new(); + v2.push(v1); + v2.push(v1); - let mut v3 = Vec::new(); - v3.push(v2); + let mut v3 = Vec::new(); + v3.push(v2); - log(v3); + log(v3); } From 1340b8a2e1b4b9c114571639da86b492bf862a61 Mon Sep 17 00:00:00 2001 From: hal3e Date: Tue, 23 Jan 2024 16:40:19 +0100 Subject: [PATCH 10/16] add CI step --- .github/workflows/ci.yml | 32 +++++++++++++++++++- packages/fuels-core/src/codec/abi_decoder.rs | 8 ++--- packages/fuels-core/src/codec/logs.rs | 15 ++++----- packages/fuels/tests/logs.rs | 12 +++++--- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 763ead3d5f..8182e3d1f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,7 +80,7 @@ jobs: # TODO: To be removed once https://github.com/FuelLabs/fuels-rs/issues/881 is unblocked. - name: Build Sway test projects w type paths - run: forc build --terse --json-abi-with-callpaths + run: forc build --terse --error-on-warnings --json-abi-with-callpaths working-directory: packages/fuels - uses: actions/upload-artifact@v2 @@ -97,6 +97,25 @@ jobs: !packages/fuels/tests/**/Forc.lock !packages/fuels/tests/.gitignore + # TODO: To be removed once experimental encoding is the default + - name: Build Sway test projects w experimental logs + run: forc build --terse --error-on-warnings --json-abi-with-callpaths --experimental-new-encoding + working-directory: packages/fuels + + - uses: actions/upload-artifact@v2 + with: + retention-days: 2 + name: sway-examples-w-experimental-logs + # cache only the sway build artifacts, skip all src files + path: | + packages/fuels/tests + !packages/fuels/tests/*.rs + !packages/fuels/tests/**/*.rs + !packages/fuels/tests/**/*.sw + !packages/fuels/tests/**/Forc.toml + !packages/fuels/tests/**/Forc.lock + !packages/fuels/tests/.gitignore + get-workspace-members: runs-on: ubuntu-latest outputs: @@ -182,6 +201,11 @@ jobs: args: - command: check_doc_unresolved_links args: + # TODO: To be removed once experimental encoding is the default + - command: test_experimental_logs + args: + download_sway_artifacts: sway-examples-w-experimental-logs + install_fuel_core: true steps: - name: Checkout repository uses: actions/checkout@v3 @@ -257,6 +281,12 @@ jobs: run: | ! cargo doc --document-private-items |& grep -A 6 "warning: unresolved link to" + # TODO: To be removed once experimental encoding is the default + - name: Test experimental logs + if: ${{ matrix.command == 'test_experimental_logs' }} + uses: taiki-e/install-action@nextest + run: RUSTFLAGS='--cfg experimental' cargo nextest run --all-targets --workspace + publish: needs: - cargo-verifications diff --git a/packages/fuels-core/src/codec/abi_decoder.rs b/packages/fuels-core/src/codec/abi_decoder.rs index 0693c4f694..2d7bcbd4ab 100644 --- a/packages/fuels-core/src/codec/abi_decoder.rs +++ b/packages/fuels-core/src/codec/abi_decoder.rs @@ -1,5 +1,5 @@ mod bounded_decoder; -#[cfg(not(experimental))] +#[cfg(experimental)] mod experimental_bounded_decoder; use crate::{ @@ -7,7 +7,7 @@ use crate::{ types::{errors::Result, param_types::ParamType, Token}, }; -#[cfg(not(experimental))] +#[cfg(experimental)] use crate::codec::abi_decoder::experimental_bounded_decoder::ExperimentalBoundedDecoder; #[derive(Debug, Clone, Copy)] @@ -83,12 +83,12 @@ impl ABIDecoder { BoundedDecoder::new(self.config).decode_multiple(param_types, bytes) } - #[cfg(not(experimental))] + #[cfg(experimental)] pub fn experimental_decode(&self, param_type: &ParamType, bytes: &[u8]) -> Result { ExperimentalBoundedDecoder::new(self.config).decode(param_type, bytes) } - #[cfg(not(experimental))] + #[cfg(experimental)] pub fn experimental_decode_multiple( &self, param_types: &[ParamType], diff --git a/packages/fuels-core/src/codec/logs.rs b/packages/fuels-core/src/codec/logs.rs index 1a63843543..920c164c79 100644 --- a/packages/fuels-core/src/codec/logs.rs +++ b/packages/fuels-core/src/codec/logs.rs @@ -13,7 +13,7 @@ use crate::{ types::errors::{error, Error, Result}, }; -#[cfg(experimental)] +#[cfg(not(experimental))] use crate::types::param_types::ParamType; #[derive(Clone)] @@ -34,19 +34,19 @@ impl LogFormatter { decoder_config: DecoderConfig, bytes: &[u8], ) -> Result { - #[cfg(experimental)] - let toxken = { + #[cfg(not(experimental))] + let token = { Self::can_decode_log_with_type::()?; ABIDecoder::new(decoder_config).decode(&T::param_type(), bytes)? }; - #[cfg(not(experimental))] + #[cfg(experimental)] let token = ABIDecoder::new(decoder_config).experimental_decode(&T::param_type(), bytes)?; Ok(format!("{:?}", T::from_token(token)?)) } - #[cfg(experimental)] + #[cfg(not(experimental))] fn can_decode_log_with_type() -> Result<()> { match T::param_type() { // String slices can not be decoded from logs as they are encoded as ptr, len @@ -196,10 +196,11 @@ impl LogDecoder { .extract_log_id_and_data() .filter_map(|(log_id, bytes)| { target_ids.contains(&log_id).then(|| { - #[cfg(not(experimental))] + #[cfg(experimental)] let token = ABIDecoder::new(self.decoder_config) .experimental_decode(&T::param_type(), &bytes)?; - #[cfg(experimental)] + + #[cfg(not(experimental))] let token = ABIDecoder::new(self.decoder_config).decode(&T::param_type(), &bytes)?; diff --git a/packages/fuels/tests/logs.rs b/packages/fuels/tests/logs.rs index 6e57f3628e..fe8fe74a9f 100644 --- a/packages/fuels/tests/logs.rs +++ b/packages/fuels/tests/logs.rs @@ -5,7 +5,7 @@ use fuels::{ tx::Receipt, types::{Bits256, SizedAsciiString}, }; -use fuels_core::{codec::DecoderConfig, types::AsciiString}; +use fuels_core::codec::DecoderConfig; #[tokio::test] async fn test_parse_logged_variables() -> Result<()> { @@ -1454,7 +1454,7 @@ async fn can_configure_decoder_for_script_log_decoding() -> Result<()> { // String slices can not be decoded from logs as they are encoded as ptr, len // TODO: Once https://github.com/FuelLabs/sway/issues/5110 is resolved we can remove this #[tokio::test] -#[cfg(experimental)] +#[cfg(not(experimental))] async fn string_slice_log() -> Result<()> { setup_program_test!( Wallets("wallet"), @@ -1487,8 +1487,10 @@ async fn string_slice_log() -> Result<()> { } #[tokio::test] -#[cfg(not(experimental))] +#[cfg(experimental)] async fn contract_experimental_log() -> Result<()> { + use fuels_core::types::AsciiString; + setup_program_test!( Wallets("wallet"), Abigen(Contract( @@ -1544,8 +1546,10 @@ async fn contract_experimental_log() -> Result<()> { } #[tokio::test] -#[cfg(not(experimental))] +#[cfg(experimental)] async fn script_experimental_log() -> Result<()> { + use fuels_core::types::AsciiString; + setup_program_test!( Wallets("wallet"), Abigen(Script( From 8eb06983002701ba8ac60c66d02b376a6b25665b Mon Sep 17 00:00:00 2001 From: hal3e Date: Tue, 23 Jan 2024 17:24:32 +0100 Subject: [PATCH 11/16] CI step --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8182e3d1f7..4039fc1621 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -281,7 +281,7 @@ jobs: run: | ! cargo doc --document-private-items |& grep -A 6 "warning: unresolved link to" - # TODO: To be removed once experimental encoding is the default + # TODO: To be removed once experimental encoding is the default. - name: Test experimental logs if: ${{ matrix.command == 'test_experimental_logs' }} uses: taiki-e/install-action@nextest From 40f12fc85a2f379136602a59bd88430d79cbf38a Mon Sep 17 00:00:00 2001 From: hal3e Date: Tue, 23 Jan 2024 17:29:04 +0100 Subject: [PATCH 12/16] update CI --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4039fc1621..791b1cb590 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -242,8 +242,9 @@ jobs: name: ${{ matrix.download_sway_artifacts }} path: packages/fuels/tests/ + # TODO: `test_experimental_logs` to be removed once experimental encoding is the default. - name: Install nextest - if: ${{ matrix.cargo_command == 'nextest' }} + if: ${{ matrix.cargo_command == 'nextest' || matrix.command = 'test_experimental_logs' }} uses: taiki-e/install-action@nextest - name: Install cargo-machete @@ -284,7 +285,6 @@ jobs: # TODO: To be removed once experimental encoding is the default. - name: Test experimental logs if: ${{ matrix.command == 'test_experimental_logs' }} - uses: taiki-e/install-action@nextest run: RUSTFLAGS='--cfg experimental' cargo nextest run --all-targets --workspace publish: From 3423c4cc7c4bb3944f616ad5976865a5155b45c8 Mon Sep 17 00:00:00 2001 From: hal3e Date: Tue, 23 Jan 2024 17:29:50 +0100 Subject: [PATCH 13/16] update CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 791b1cb590..50291411f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -244,7 +244,7 @@ jobs: # TODO: `test_experimental_logs` to be removed once experimental encoding is the default. - name: Install nextest - if: ${{ matrix.cargo_command == 'nextest' || matrix.command = 'test_experimental_logs' }} + if: ${{ matrix.cargo_command == 'nextest' || matrix.command == 'test_experimental_logs' }} uses: taiki-e/install-action@nextest - name: Install cargo-machete From 2b810428b2abc7a29c6cb5f4e53acece61763b93 Mon Sep 17 00:00:00 2001 From: hal3e Date: Tue, 23 Jan 2024 17:46:00 +0100 Subject: [PATCH 14/16] update CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50291411f6..26230b7ed5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -285,7 +285,7 @@ jobs: # TODO: To be removed once experimental encoding is the default. - name: Test experimental logs if: ${{ matrix.command == 'test_experimental_logs' }} - run: RUSTFLAGS='--cfg experimental' cargo nextest run --all-targets --workspace + run: RUSTFLAGS='--cfg experimental' cargo nextest run --test logs publish: needs: From ce898ce42d268cb19bb141946bd9bbb4a315b3f7 Mon Sep 17 00:00:00 2001 From: hal3e Date: Thu, 25 Jan 2024 13:33:24 +0100 Subject: [PATCH 15/16] pr comments --- .../src/codec/abi_decoder/experimental_bounded_decoder.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs index b358ba2189..e8728bf08b 100644 --- a/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs +++ b/packages/fuels-core/src/codec/abi_decoder/experimental_bounded_decoder.rs @@ -57,10 +57,9 @@ impl ExperimentalBoundedDecoder { decoder: impl FnOnce(&mut Self) -> Result, ) -> Result { self.depth_tracker.increase()?; - let res = decoder(self); - self.depth_tracker.decrease(); + res } @@ -88,8 +87,6 @@ impl ExperimentalBoundedDecoder { self.run_w_depth_tracking(|ctx| ctx.decode_array(param_type, bytes, *length)) } ParamType::Vector(param_type) => { - // although nested vectors cannot be decoded yet, depth tracking still occurs for future - // proofing self.run_w_depth_tracking(|ctx| ctx.decode_vector(param_type, bytes)) } From d5fd48d3af379bdc44f5fa66d696fca297d5050f Mon Sep 17 00:00:00 2001 From: hal3e Date: Thu, 25 Jan 2024 13:37:29 +0100 Subject: [PATCH 16/16] remove AbiEncode for tuples --- packages/fuels/tests/logs/contract_logs/src/main.sw | 9 --------- packages/fuels/tests/logs/script_logs/src/main.sw | 9 --------- 2 files changed, 18 deletions(-) diff --git a/packages/fuels/tests/logs/contract_logs/src/main.sw b/packages/fuels/tests/logs/contract_logs/src/main.sw index 3691b3ced3..1ddb6c37b9 100644 --- a/packages/fuels/tests/logs/contract_logs/src/main.sw +++ b/packages/fuels/tests/logs/contract_logs/src/main.sw @@ -3,15 +3,6 @@ contract; use std::{logging::log, string::String}; use contract_logs::ContractLogs; -impl AbiEncode for (TestStruct, TestEnum) { - #[allow(dead_code)] - fn abi_encode(self, ref mut buffer: Buffer) { - let (test_struct, test_enum) = self; - test_struct.abi_encode(buffer); - test_enum.abi_encode(buffer); - } -} - #[allow(dead_code)] struct TestStruct { field_1: bool, diff --git a/packages/fuels/tests/logs/script_logs/src/main.sw b/packages/fuels/tests/logs/script_logs/src/main.sw index d59768188c..5f5cec3a62 100644 --- a/packages/fuels/tests/logs/script_logs/src/main.sw +++ b/packages/fuels/tests/logs/script_logs/src/main.sw @@ -2,15 +2,6 @@ script; use std::logging::log; -impl AbiEncode for (TestStruct, TestEnum) { - #[allow(dead_code)] - fn abi_encode(self, ref mut buffer: Buffer) { - let (test_struct, test_enum) = self; - test_struct.abi_encode(buffer); - test_enum.abi_encode(buffer); - } -} - #[allow(dead_code)] struct TestStruct { field_1: bool,