Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: represent small values as single bytes #1163

Merged
merged 29 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift click to select a range
b339dca
updating codecs to new sway
xunilrj Oct 24, 2023
f6b9af4
forc fmt issues
xunilrj Oct 24, 2023
c021498
updating CI to forc new version
xunilrj Nov 8, 2023
6e3fabf
fixing forc fmt issues
xunilrj Nov 8, 2023
f215452
fix ci implicit std branch
xunilrj Nov 8, 2023
9feaafe
fix implicit std tag
xunilrj Nov 8, 2023
988e5be
removing std env vars
xunilrj Nov 9, 2023
13f1f1a
testing forc fixed implicit vard
xunilrj Nov 9, 2023
c5deae3
verbose diagnostics
xunilrj Nov 9, 2023
4b51665
removing hardcoded std
xunilrj Nov 9, 2023
ba6c23b
std pointing to a fixed branch
xunilrj Nov 9, 2023
558eeda
allow deprecated on U256
xunilrj Nov 9, 2023
5e2ca52
allow deprecated on U256
xunilrj Nov 9, 2023
6a30c6b
allow deprecated on U256
xunilrj Nov 9, 2023
fa7120d
fix warninngs
xunilrj Nov 9, 2023
ea3eb04
fmt and clippy issues
xunilrj Nov 9, 2023
2614c8a
fmt and clippy issues
xunilrj Nov 9, 2023
ef014c3
fix fee estimation
xunilrj Nov 9, 2023
1aa1aa9
fixing witness test
xunilrj Nov 9, 2023
b8e0608
clippy and fmt issues
xunilrj Nov 9, 2023
dad0821
fixing gas estimates
xunilrj Nov 9, 2023
29d012a
fix test and remove enum limitation
xunilrj Nov 10, 2023
15994b1
rebase issues and uncommenting tests
xunilrj Nov 10, 2023
5ff50bd
Uncomment and fix tests
Br1ght0ne Nov 10, 2023
6cc4ac0
Fix bool decoding
Br1ght0ne Nov 10, 2023
bc5f72f
Fix bool decoding (for real this time)
Br1ght0ne Nov 10, 2023
6d1ee58
Make tx of wrapper pub(crate)
Br1ght0ne Nov 10, 2023
fec1c54
Fix typos
Br1ght0ne Nov 10, 2023
5880140
fix doc test
xunilrj Nov 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 19,9 @@ env:
FUEL_CORE_VERSION: 0.20.6
RUST_VERSION: 1.72.1
FORC_VERSION: 0.46.0
FORC_PATCH_BRANCH: ""
FORC_PATCH_BRANCH: "xunilrj/fix-implicit-std-env-vars"
FORC_PATCH_REVISION: ""
FORC_IMPLICIT_STD_GIT_BRANCH: "xunilrj/fix-implicit-std-env-vars"

jobs:
setup-test-projects:
Expand Down
4 changes: 2 additions & 2 deletions examples/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 103,7 @@ mod tests {
.await?;
// ANCHOR_END: contract_call_cost_estimation

assert_eq!(transaction_cost.gas_used, 397);
assert_eq!(transaction_cost.gas_used, 470);

Ok(())
}
Expand Down Expand Up @@ -649,7 649,7 @@ mod tests {
.await?;
// ANCHOR_END: multi_call_cost_estimation

assert_eq!(transaction_cost.gas_used, 618);
assert_eq!(transaction_cost.gas_used, 693);

Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion packages/fuels-accounts/src/accounts_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 4,7 @@ use fuels_core::{
constants::BASE_ASSET_ID,
types::{
bech32::Bech32Address,
errors::{error, Error, Result},
errors::{error, Result},
input::Input,
transaction_builders::TransactionBuilder,
},
Expand Down
2 changes: 1 addition & 1 deletion packages/fuels-accounts/src/provider/retry_util.rs
Original file line number Diff line number Diff line change
@@ -1,6 1,6 @@
use std::{fmt::Debug, future::Future, num::NonZeroU32, time::Duration};

use fuels_core::types::errors::{error, Error, Result as SdkResult};
use fuels_core::types::errors::{error, Result as SdkResult};

/// A set of strategies to control retry intervals between attempts.
///
Expand Down
5 changes: 1 addition & 4 deletions packages/fuels-accounts/src/provider/retryable_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 8,7 @@ use fuel_core_client::client::{
};
use fuel_tx::{Receipt, Transaction, TxId, UtxoId};
use fuel_types::{Address, AssetId, BlockHeight, ContractId, MessageId, Nonce};
use fuels_core::{
error,
types::errors::{Error, Result},
};
use fuels_core::{error, types::errors::Result};

use crate::provider::{retry_util, RetryConfig};

Expand Down
74 changes: 29 additions & 45 deletions packages/fuels-core/src/codec/abi_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 52,19 @@ impl ABIDecoder {
///
/// let decoder = ABIDecoder::default();
///
/// let token = decoder.decode(&ParamType::U8, &[0, 0, 0, 0, 0, 0, 0, 7]).unwrap();
/// let token = decoder.decode(&ParamType::U64, &[0, 0, 0, 0, 0, 0, 0, 7]).unwrap();
///
/// assert_eq!(u8::from_token(token).unwrap(), 7u8);
/// assert_eq!(u64::from_token(token).unwrap(), 7u64);
/// ```
pub fn decode(&self, param_type: &ParamType, bytes: &[u8]) -> Result<Token> {
BoundedDecoder::new(self.config).decode(param_type, bytes)
}

/// Decode data from one of the receipt returns.
pub fn decode_receipt_return(&self, param_type: &ParamType, bytes: &[u8]) -> Result<Token> {
BoundedDecoder::new(self.config).decode(param_type, bytes)
}

/// Same as `decode` but decodes multiple `ParamType`s in one go.
/// # Examples
/// ```
Expand All @@ -68,7 73,7 @@ impl ABIDecoder {
/// use fuels_core::types::Token;
///
/// let decoder = ABIDecoder::default();
/// let data: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8];
/// let data: &[u8] = &[7, 8];
///
/// let tokens = decoder.decode_multiple(&[ParamType::U8, ParamType::U8], &data).unwrap();
///
Expand Down Expand Up @@ -114,7 119,7 @@ mod tests {
];
let data = [
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, // u32
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, // u8
0xff, // u8
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, // u16
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // u64
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Expand All @@ -141,9 146,7 @@ mod tests {
#[test]
fn decode_bool() -> Result<()> {
let types = vec![ParamType::Bool, ParamType::Bool];
let data = [
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00,
];
let data = [0x01, 0x0];

let decoded = ABIDecoder::default().decode_multiple(&types, &data)?;

Expand Down Expand Up @@ -215,9 218,7 @@ mod tests {
fn decode_array() -> Result<()> {
// Create a parameter type for u8[2].
let types = vec![ParamType::Array(Box::new(ParamType::U8), 2)];
let data = [
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a,
];
let data = [0xff, 0x2a];

let decoded = ABIDecoder::default().decode_multiple(&types, &data)?;

Expand All @@ -234,7 235,7 @@ mod tests {
// }

let data = [
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
];
let param_type = ParamType::Struct {
fields: vec![ParamType::U8, ParamType::Bool],
Expand Down Expand Up @@ -366,8 367,8 @@ mod tests {
};

let data = [
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
];

let decoded = ABIDecoder::default().decode(&nested_struct, &data)?;
Expand Down Expand Up @@ -416,26 417,23 @@ mod tests {

let u8_arr = ParamType::Array(Box::new(ParamType::U8), 2);
let b256 = ParamType::B256;
let s = ParamType::StringArray(3);
let ss = ParamType::StringSlice;

let types = [nested_struct, u8_arr, b256, s, ss];
let types = [nested_struct, u8_arr, b256];

let bytes = [
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, // foo.x == 10u16
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // foo.y.a == true
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // foo.b.0 == 1u8
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, // foo.b.1 == 2u8
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // u8[2].0 == 1u8
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, // u8[2].0 == 2u8
0xd5, 0x57, 0x9c, 0x46, 0xdf, 0xcc, 0x7f, 0x18, // b256
0x20, 0x70, 0x13, 0xe6, 0x5b, 0x44, 0xe4, 0xcb, // b256
0x4e, 0x2c, 0x22, 0x98, 0xf4, 0xac, 0x45, 0x7b, // b256
0xa8, 0xf8, 0x27, 0x43, 0xf3, 0x1e, 0x93, 0xb, // b256
0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, // str[3]
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, // str data
0x61, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x73, // str data
0x65, 0x6e, 0x74, 0x65, 0x6e, 0x63, 0x65, // str data
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, // u16
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // bool
0x1, 0x2, // array[u8]
0x1, 0x2, // array[u8]
0xd5, 0x57, 0x9c, 0x46, 0xdf, 0xcc, 0x7f, 0x18, // b256 start
0x20, 0x70, 0x13, 0xe6, 0x5b, 0x44, 0xe4, 0xcb, //
0x4e, 0x2c, 0x22, 0x98, 0xf4, 0xac, 0x45, 0x7b, //
0xa8, 0xf8, 0x27, 0x43, 0xf3, 0x1e, 0x93,
0xb, // b256 end
// 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, // "foo"
// 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, //
// 0x61, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x73, //
// 0x65, 0x6e, 0x74, 0x65, 0x6e, 0x63, 0x65, //
];

let decoded = ABIDecoder::default().decode_multiple(&types, &bytes)?;
Expand All @@ -457,14 455,7 @@ mod tests {
0xf3, 0x1e, 0x93, 0xb,
]);

let ss = Token::StringSlice(StaticStringToken::new(
"This is a full sentence".into(),
None,
));

let s = Token::StringArray(StaticStringToken::new("foo".into(), Some(3)));

let expected: Vec<Token> = vec![foo, u8_arr, b256, s, ss];
let expected: Vec<Token> = vec![foo, u8_arr, b256];

assert_eq!(decoded, expected);
Ok(())
Expand Down Expand Up @@ -555,13 546,6 @@ mod tests {
assert!(matches!(result, Err(Error::InvalidType(_))));
}

#[test]
pub fn multiply_overflow_vector() {
let param_type = Vec::<[(); usize::MAX]>::param_type();
let result = ABIDecoder::default().decode(&param_type, &[]);
assert!(matches!(result, Err(Error::InvalidData(_))));
}

#[test]
pub fn multiply_overflow_arith() {
let mut param_type: ParamType = U16;
Expand Down
94 changes: 64 additions & 30 deletions packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs
Original file line number Diff line number Diff line change
@@ -1,14 1,13 @@
use std::{convert::TryInto, str};

use fuel_types::bytes::padded_len_usize;

use crate::{
codec::DecoderConfig,
constants::WORD_SIZE,
round_up_to_word_alignment,
traits::Tokenizable,
types::{
enum_variants::EnumVariants,
errors::{error, Error, Result},
errors::{error, Result},
param_types::ParamType,
StaticStringToken, Token, U256,
},
Expand Down Expand Up @@ -37,9 36,25 @@ impl BoundedDecoder {
}
}

pub(crate) fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result<Token> {
pub fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result<Token> {
param_type.validate_is_decodable(self.config.max_depth)?;
Ok(self.decode_param(param_type, bytes)?.token)
match param_type {
// Unit, U8 and Bool are returned as u64 from receipt "Return"
ParamType::Unit => Ok(Token::Unit),
ParamType::U8 => Self::decode_u64(bytes).map(|r| {
Token::U8(match r.token {
Token::U64(v) => v as u8,
_ => unreachable!("decode_u64 returning unexpected token"),
})
}),
ParamType::Bool => Self::decode_u64(bytes).map(|r| {
Token::Bool(match r.token {
Token::U64(v) => v != 0,
_ => unreachable!("decode_u64 returning unexpected token"),
})
}),
_ => self.decode_param(param_type, bytes).map(|x| x.token),
}
}

pub(crate) fn decode_multiple(
Expand Down Expand Up @@ -130,7 145,17 @@ impl BoundedDecoder {
}

fn decode_tuple(&mut self, param_types: &[ParamType], bytes: &[u8]) -> Result<Decoded> {
let (tokens, bytes_read) = self.decode_params(param_types, bytes)?;
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 = 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),
Expand All @@ -139,7 164,17 @@ impl BoundedDecoder {
}

fn decode_struct(&mut self, param_types: &[ParamType], bytes: &[u8]) -> Result<Decoded> {
let (tokens, bytes_read) = self.decode_params(param_types, bytes)?;
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 = 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::Struct(tokens),
Expand Down Expand Up @@ -209,13 244,12 @@ impl BoundedDecoder {
}

fn decode_string_array(bytes: &[u8], length: usize) -> Result<Decoded> {
let encoded_len = padded_len_usize(length);
let encoded_str = peek(bytes, encoded_len)?;
let encoded_str = peek(bytes, length)?;

let decoded = str::from_utf8(&encoded_str[..length])?;
let decoded = str::from_utf8(encoded_str)?;
let result = Decoded {
token: Token::StringArray(StaticStringToken::new(decoded.into(), Some(length))),
bytes_read: encoded_len,
bytes_read: round_up_to_word_alignment(length),
};
Ok(result)
}
Expand All @@ -233,7 267,7 @@ impl BoundedDecoder {

let result = Decoded {
token: Token::Bool(b),
bytes_read: WORD_SIZE,
bytes_read: 1,
};

Ok(result)
Expand Down Expand Up @@ -277,17 311,17 @@ impl BoundedDecoder {
fn decode_u8(bytes: &[u8]) -> Result<Decoded> {
Ok(Decoded {
token: Token::U8(peek_u8(bytes)?),
bytes_read: WORD_SIZE,
bytes_read: 1,
})
}

fn decode_unit(bytes: &[u8]) -> Result<Decoded> {
// We don't need the data, we're doing this purely as a bounds
// check.
peek_fixed::<WORD_SIZE>(bytes)?;
peek_fixed::<1>(bytes)?;
Ok(Decoded {
token: Token::Unit,
bytes_read: WORD_SIZE,
bytes_read: 1,
})
}

Expand All @@ -299,33 333,33 @@ impl BoundedDecoder {
/// * `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<Decoded> {
let enum_width = variants.compute_encoding_width_of_enum()?;
let enum_width_in_bytes = variants
.compute_enum_width_in_bytes()
.ok_or(error!(InvalidData, "Error calculating enum width in bytes"))?;

let discriminant = peek_u32(bytes)? as u8;
let discriminant = peek_u64(bytes)?;
let selected_variant = variants.param_type_of_variant(discriminant)?;

let skip_extra = variants
let skip_extra_in_bytes = variants
.heap_type_variant()
.and_then(|(heap_discriminant, heap_type)| {
(heap_discriminant == discriminant).then_some(heap_type.compute_encoding_width())
(heap_discriminant == discriminant).then_some(heap_type.compute_encoding_in_bytes())
})
.transpose()?
.unwrap_or_default()
.unwrap_or_default();
let bytes_to_skip = enum_width_in_bytes
- selected_variant
.compute_encoding_in_bytes()
.ok_or(error!(InvalidData, "Error calculating enum width in bytes"))?
skip_extra_in_bytes;

let words_to_skip = enum_width - selected_variant.compute_encoding_width()? skip_extra;
let bytes_to_skip = words_to_skip.checked_mul(WORD_SIZE).ok_or_else(|| {
error!(
InvalidData,
"Overflow error while decoding enum {variants:?}"
)
})?;
let enum_content_bytes = skip(bytes, bytes_to_skip)?;
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: enum_width * WORD_SIZE,
bytes_read: enum_width_in_bytes,
})
}

Expand Down Expand Up @@ -426,8 460,8 @@ fn peek_u16(bytes: &[u8]) -> Result<u16> {
fn peek_u8(bytes: &[u8]) -> Result<u8> {
const BYTES: usize = std::mem::size_of::<u8>();

let slice = peek_fixed::<WORD_SIZE>(bytes)?;
let bytes = slice[WORD_SIZE - BYTES..]
let slice = peek_fixed::<1>(bytes)?;
let bytes = slice[1 - BYTES..]
digorithm marked this conversation as resolved.
Show resolved Hide resolved
.try_into()
.expect("peek_u8: You must use a slice containing exactly 1B.");
Ok(u8::from_be_bytes(bytes))
Expand Down
Loading
Loading