Skip to content

Commit d8704e1

Browse files
authored
feat!: represent small values as single bytes (#1163)
1 parent 4b0aa6b commit d8704e1

File tree

54 files changed

+593
-629
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+593
-629
lines changed

.github/workflows/ci.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ env:
1919
FUEL_CORE_VERSION: 0.20.6
2020
RUST_VERSION: 1.72.1
2121
FORC_VERSION: 0.46.0
22-
FORC_PATCH_BRANCH: ""
22+
FORC_PATCH_BRANCH: "xunilrj/fix-implicit-std-env-vars"
2323
FORC_PATCH_REVISION: ""
24+
FORC_IMPLICIT_STD_GIT_BRANCH: "xunilrj/fix-implicit-std-env-vars"
2425

2526
jobs:
2627
setup-test-projects:

examples/contracts/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ mod tests {
103103
.await?;
104104
// ANCHOR_END: contract_call_cost_estimation
105105

106-
assert_eq!(transaction_cost.gas_used, 397);
106+
assert_eq!(transaction_cost.gas_used, 470);
107107

108108
Ok(())
109109
}
@@ -649,7 +649,7 @@ mod tests {
649649
.await?;
650650
// ANCHOR_END: multi_call_cost_estimation
651651

652-
assert_eq!(transaction_cost.gas_used, 618);
652+
assert_eq!(transaction_cost.gas_used, 693);
653653

654654
Ok(())
655655
}

packages/fuels-accounts/src/accounts_utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use fuels_core::{
44
constants::BASE_ASSET_ID,
55
types::{
66
bech32::Bech32Address,
7-
errors::{error, Error, Result},
7+
errors::{error, Result},
88
input::Input,
99
transaction_builders::TransactionBuilder,
1010
},

packages/fuels-accounts/src/provider/retry_util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{fmt::Debug, future::Future, num::NonZeroU32, time::Duration};
22

3-
use fuels_core::types::errors::{error, Error, Result as SdkResult};
3+
use fuels_core::types::errors::{error, Result as SdkResult};
44

55
/// A set of strategies to control retry intervals between attempts.
66
///

packages/fuels-accounts/src/provider/retryable_client.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ use fuel_core_client::client::{
88
};
99
use fuel_tx::{Receipt, Transaction, TxId, UtxoId};
1010
use fuel_types::{Address, AssetId, BlockHeight, ContractId, MessageId, Nonce};
11-
use fuels_core::{
12-
error,
13-
types::errors::{Error, Result},
14-
};
11+
use fuels_core::{error, types::errors::Result};
1512

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

packages/fuels-core/src/codec/abi_decoder.rs

+29-45
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,19 @@ impl ABIDecoder {
5252
///
5353
/// let decoder = ABIDecoder::default();
5454
///
55-
/// let token = decoder.decode(&ParamType::U8, &[0, 0, 0, 0, 0, 0, 0, 7]).unwrap();
55+
/// let token = decoder.decode(&ParamType::U64, &[0, 0, 0, 0, 0, 0, 0, 7]).unwrap();
5656
///
57-
/// assert_eq!(u8::from_token(token).unwrap(), 7u8);
57+
/// assert_eq!(u64::from_token(token).unwrap(), 7u64);
5858
/// ```
5959
pub fn decode(&self, param_type: &ParamType, bytes: &[u8]) -> Result<Token> {
6060
BoundedDecoder::new(self.config).decode(param_type, bytes)
6161
}
6262

63+
/// Decode data from one of the receipt returns.
64+
pub fn decode_receipt_return(&self, param_type: &ParamType, bytes: &[u8]) -> Result<Token> {
65+
BoundedDecoder::new(self.config).decode(param_type, bytes)
66+
}
67+
6368
/// Same as `decode` but decodes multiple `ParamType`s in one go.
6469
/// # Examples
6570
/// ```
@@ -68,7 +73,7 @@ impl ABIDecoder {
6873
/// use fuels_core::types::Token;
6974
///
7075
/// let decoder = ABIDecoder::default();
71-
/// let data: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8];
76+
/// let data: &[u8] = &[7, 8];
7277
///
7378
/// let tokens = decoder.decode_multiple(&[ParamType::U8, ParamType::U8], &data).unwrap();
7479
///
@@ -114,7 +119,7 @@ mod tests {
114119
];
115120
let data = [
116121
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, // u32
117-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, // u8
122+
0xff, // u8
118123
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, // u16
119124
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // u64
120125
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -141,9 +146,7 @@ mod tests {
141146
#[test]
142147
fn decode_bool() -> Result<()> {
143148
let types = vec![ParamType::Bool, ParamType::Bool];
144-
let data = [
145-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00,
146-
];
149+
let data = [0x01, 0x0];
147150

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

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

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

@@ -234,7 +235,7 @@ mod tests {
234235
// }
235236

236237
let data = [
237-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
238+
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
238239
];
239240
let param_type = ParamType::Struct {
240241
fields: vec![ParamType::U8, ParamType::Bool],
@@ -366,8 +367,8 @@ mod tests {
366367
};
367368

368369
let data = [
369-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0,
370-
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
370+
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
371+
0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
371372
];
372373

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

417418
let u8_arr = ParamType::Array(Box::new(ParamType::U8), 2);
418419
let b256 = ParamType::B256;
419-
let s = ParamType::StringArray(3);
420-
let ss = ParamType::StringSlice;
421420

422-
let types = [nested_struct, u8_arr, b256, s, ss];
421+
let types = [nested_struct, u8_arr, b256];
423422

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

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

460-
let ss = Token::StringSlice(StaticStringToken::new(
461-
"This is a full sentence".into(),
462-
None,
463-
));
464-
465-
let s = Token::StringArray(StaticStringToken::new("foo".into(), Some(3)));
466-
467-
let expected: Vec<Token> = vec![foo, u8_arr, b256, s, ss];
458+
let expected: Vec<Token> = vec![foo, u8_arr, b256];
468459

469460
assert_eq!(decoded, expected);
470461
Ok(())
@@ -555,13 +546,6 @@ mod tests {
555546
assert!(matches!(result, Err(Error::InvalidType(_))));
556547
}
557548

558-
#[test]
559-
pub fn multiply_overflow_vector() {
560-
let param_type = Vec::<[(); usize::MAX]>::param_type();
561-
let result = ABIDecoder::default().decode(&param_type, &[]);
562-
assert!(matches!(result, Err(Error::InvalidData(_))));
563-
}
564-
565549
#[test]
566550
pub fn multiply_overflow_arith() {
567551
let mut param_type: ParamType = U16;

packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs

+64-30
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use std::{convert::TryInto, str};
22

3-
use fuel_types::bytes::padded_len_usize;
4-
53
use crate::{
64
codec::DecoderConfig,
75
constants::WORD_SIZE,
6+
round_up_to_word_alignment,
87
traits::Tokenizable,
98
types::{
109
enum_variants::EnumVariants,
11-
errors::{error, Error, Result},
10+
errors::{error, Result},
1211
param_types::ParamType,
1312
StaticStringToken, Token, U256,
1413
},
@@ -37,9 +36,25 @@ impl BoundedDecoder {
3736
}
3837
}
3938

40-
pub(crate) fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result<Token> {
39+
pub fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result<Token> {
4140
param_type.validate_is_decodable(self.config.max_depth)?;
42-
Ok(self.decode_param(param_type, bytes)?.token)
41+
match param_type {
42+
// Unit, U8 and Bool are returned as u64 from receipt "Return"
43+
ParamType::Unit => Ok(Token::Unit),
44+
ParamType::U8 => Self::decode_u64(bytes).map(|r| {
45+
Token::U8(match r.token {
46+
Token::U64(v) => v as u8,
47+
_ => unreachable!("decode_u64 returning unexpected token"),
48+
})
49+
}),
50+
ParamType::Bool => Self::decode_u64(bytes).map(|r| {
51+
Token::Bool(match r.token {
52+
Token::U64(v) => v != 0,
53+
_ => unreachable!("decode_u64 returning unexpected token"),
54+
})
55+
}),
56+
_ => self.decode_param(param_type, bytes).map(|x| x.token),
57+
}
4358
}
4459

4560
pub(crate) fn decode_multiple(
@@ -130,7 +145,17 @@ impl BoundedDecoder {
130145
}
131146

132147
fn decode_tuple(&mut self, param_types: &[ParamType], bytes: &[u8]) -> Result<Decoded> {
133-
let (tokens, bytes_read) = self.decode_params(param_types, bytes)?;
148+
let mut tokens = vec![];
149+
150+
let mut bytes_read = 0;
151+
152+
for param_type in param_types.iter() {
153+
// padding has to be taken into account
154+
bytes_read = round_up_to_word_alignment(bytes_read);
155+
let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?;
156+
bytes_read += res.bytes_read;
157+
tokens.push(res.token);
158+
}
134159

135160
Ok(Decoded {
136161
token: Token::Tuple(tokens),
@@ -139,7 +164,17 @@ impl BoundedDecoder {
139164
}
140165

141166
fn decode_struct(&mut self, param_types: &[ParamType], bytes: &[u8]) -> Result<Decoded> {
142-
let (tokens, bytes_read) = self.decode_params(param_types, bytes)?;
167+
let mut tokens = vec![];
168+
169+
let mut bytes_read = 0;
170+
171+
for param_type in param_types.iter() {
172+
// padding has to be taken into account
173+
bytes_read = round_up_to_word_alignment(bytes_read);
174+
let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?;
175+
bytes_read += res.bytes_read;
176+
tokens.push(res.token);
177+
}
143178

144179
Ok(Decoded {
145180
token: Token::Struct(tokens),
@@ -209,13 +244,12 @@ impl BoundedDecoder {
209244
}
210245

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

215-
let decoded = str::from_utf8(&encoded_str[..length])?;
249+
let decoded = str::from_utf8(encoded_str)?;
216250
let result = Decoded {
217251
token: Token::StringArray(StaticStringToken::new(decoded.into(), Some(length))),
218-
bytes_read: encoded_len,
252+
bytes_read: round_up_to_word_alignment(length),
219253
};
220254
Ok(result)
221255
}
@@ -233,7 +267,7 @@ impl BoundedDecoder {
233267

234268
let result = Decoded {
235269
token: Token::Bool(b),
236-
bytes_read: WORD_SIZE,
270+
bytes_read: 1,
237271
};
238272

239273
Ok(result)
@@ -277,17 +311,17 @@ impl BoundedDecoder {
277311
fn decode_u8(bytes: &[u8]) -> Result<Decoded> {
278312
Ok(Decoded {
279313
token: Token::U8(peek_u8(bytes)?),
280-
bytes_read: WORD_SIZE,
314+
bytes_read: 1,
281315
})
282316
}
283317

284318
fn decode_unit(bytes: &[u8]) -> Result<Decoded> {
285319
// We don't need the data, we're doing this purely as a bounds
286320
// check.
287-
peek_fixed::<WORD_SIZE>(bytes)?;
321+
peek_fixed::<1>(bytes)?;
288322
Ok(Decoded {
289323
token: Token::Unit,
290-
bytes_read: WORD_SIZE,
324+
bytes_read: 1,
291325
})
292326
}
293327

@@ -299,33 +333,33 @@ impl BoundedDecoder {
299333
/// * `data`: slice of encoded data on whose beginning we're expecting an encoded enum
300334
/// * `variants`: all types that this particular enum type could hold
301335
fn decode_enum(&mut self, bytes: &[u8], variants: &EnumVariants) -> Result<Decoded> {
302-
let enum_width = variants.compute_encoding_width_of_enum()?;
336+
let enum_width_in_bytes = variants
337+
.compute_enum_width_in_bytes()
338+
.ok_or(error!(InvalidData, "Error calculating enum width in bytes"))?;
303339

304-
let discriminant = peek_u32(bytes)? as u8;
340+
let discriminant = peek_u64(bytes)?;
305341
let selected_variant = variants.param_type_of_variant(discriminant)?;
306342

307-
let skip_extra = variants
343+
let skip_extra_in_bytes = variants
308344
.heap_type_variant()
309345
.and_then(|(heap_discriminant, heap_type)| {
310-
(heap_discriminant == discriminant).then_some(heap_type.compute_encoding_width())
346+
(heap_discriminant == discriminant).then_some(heap_type.compute_encoding_in_bytes())
311347
})
312-
.transpose()?
348+
.unwrap_or_default()
313349
.unwrap_or_default();
350+
let bytes_to_skip = enum_width_in_bytes
351+
- selected_variant
352+
.compute_encoding_in_bytes()
353+
.ok_or(error!(InvalidData, "Error calculating enum width in bytes"))?
354+
+ skip_extra_in_bytes;
314355

315-
let words_to_skip = enum_width - selected_variant.compute_encoding_width()? + skip_extra;
316-
let bytes_to_skip = words_to_skip.checked_mul(WORD_SIZE).ok_or_else(|| {
317-
error!(
318-
InvalidData,
319-
"Overflow error while decoding enum {variants:?}"
320-
)
321-
})?;
322356
let enum_content_bytes = skip(bytes, bytes_to_skip)?;
323357
let result = self.decode_token_in_enum(enum_content_bytes, variants, selected_variant)?;
324358

325359
let selector = Box::new((discriminant, result.token, variants.clone()));
326360
Ok(Decoded {
327361
token: Token::Enum(selector),
328-
bytes_read: enum_width * WORD_SIZE,
362+
bytes_read: enum_width_in_bytes,
329363
})
330364
}
331365

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

429-
let slice = peek_fixed::<WORD_SIZE>(bytes)?;
430-
let bytes = slice[WORD_SIZE - BYTES..]
463+
let slice = peek_fixed::<1>(bytes)?;
464+
let bytes = slice[1 - BYTES..]
431465
.try_into()
432466
.expect("peek_u8: You must use a slice containing exactly 1B.");
433467
Ok(u8::from_be_bytes(bytes))

0 commit comments

Comments
 (0)