Skip to content

Commit

Permalink
Merge branch 'master' into Salka1988/return_result
Browse files Browse the repository at this point in the history
  • Loading branch information
Salka1988 committed Oct 7, 2023
2 parents 847fd0d + f51e76f commit dab55f3
Show file tree
Hide file tree
Showing 27 changed files with 901 additions and 200 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ jobs:
test:
uses: FuelLabs/github-actions/.github/workflows/mdbook-docs.yml@master
with:
docs-src-path: 'docs/src'

docs-src-path: "docs/src"
pre-command: 'cargo run --package versions-replacer -- ./docs --manifest-path ./Cargo.toml --filename-regex "\.md$"'
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ members = [
"packages/fuels-test-helpers",
"packages/wasm-tests",
"scripts/check-docs",
"scripts/versions-replacer",
]

[workspace.package]
Expand Down
2 changes: 1 addition & 1 deletion docs/src/calling-contracts/call-params.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The parameters for a contract call are:
3. Gas forwarded
<!-- call_params:example:end -->

You can use these to forward coins to a contract. You can configure these parameters by creating an instance of [`CallParameters`](https://docs.rs/fuels/latest/fuels/programs/contract/struct.CallParameters.html) and passing it to a chain method called `call_params`.
You can use these to forward coins to a contract. You can configure these parameters by creating an instance of [`CallParameters`](https://docs.rs/fuels/{{versions.fuels}}/fuels/programs/contract/struct.CallParameters.html) and passing it to a chain method called `call_params`.
<!-- use_call_params:example:end -->

For instance, suppose the following contract that uses Sway's `msg_amount()` to return the amount sent in that transaction.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/connecting/querying.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Querying the blockchain

Once you set up a provider, you can interact with the Fuel blockchain. Here are a few examples of what you can do with a provider; for a more in-depth overview of the API, check the [official provider API documentation](https://docs.rs/fuels/latest/fuels/accounts/provider/struct.Provider.html).
Once you set up a provider, you can interact with the Fuel blockchain. Here are a few examples of what you can do with a provider; for a more in-depth overview of the API, check the [official provider API documentation](https://docs.rs/fuels/{{versions.fuels}}/fuels/accounts/provider/struct.Provider.html).

- [Set up](#set-up)
- [Get all coins from an address](#get-all-coins-from-an-address)
Expand Down
4 changes: 2 additions & 2 deletions docs/src/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ cargo test -- --nocapture
Add these dependencies on your `Cargo.toml`:

```toml
fuels = "0.48"
fuels = "{{versions.fuels}}"
```

> **Note** We're using version `0.48` of the SDK, which is the latest version at the time of this writing.
> **Note** We're using version `{{versions.fuels}}` of the SDK, which is the latest version at the time of this writing.
And then, in your Rust file that's going to make use of the SDK:

Expand Down
2 changes: 1 addition & 1 deletion docs/src/reference.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# API Reference

For a more in-depth look at the APIs provided by the Fuel Rust SDK, head over to the [official documentation](https://docs.rs/fuels/latest/fuels/). In the actual Rust docs, you can see the most up-to-date information about the API, which is synced with the code as it changes.
For a more in-depth look at the APIs provided by the Fuel Rust SDK, head over to the [official documentation](https://docs.rs/fuels/{{versions.fuels}}/fuels/). In the actual Rust docs, you can see the most up-to-date information about the API, which is synced with the code as it changes.
2 changes: 1 addition & 1 deletion docs/src/types/address.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Address

Like `Bytes32`, `Address` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/latest/fuel_types/struct.Address.html)).
Like `Bytes32`, `Address` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuel-types}}/fuel_types/struct.Address.html)).

These are the main ways of creating an `Address`:

Expand Down
2 changes: 1 addition & 1 deletion docs/src/types/asset-id.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AssetId

Like `Bytes32`, `AssetId` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/latest/fuel_types/struct.AssetId.html)).
Like `Bytes32`, `AssetId` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuel-types}}/fuel_types/struct.AssetId.html)).

These are the main ways of creating an `AssetId`:

Expand Down
2 changes: 1 addition & 1 deletion docs/src/types/bytes32.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ These are the main ways of creating a `Bytes32`:
{{#include ../../../examples/types/src/lib.rs:bytes32_format}}
```

For a full list of implemented methods and traits, see the [fuel-types documentation](https://docs.rs/fuel-types/latest/fuel_types/struct.Bytes32.html).
For a full list of implemented methods and traits, see the [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuel-types}}/fuel_types/struct.Bytes32.html).

> **Note:** In Fuel, there's a special type called `b256`, which is similar to `Bytes32`; also used to represent hashes, and it holds a 256-bit value. In Rust, through the SDK, this is represented as `Bits256(value)` where `value` is a `[u8; 32]`. If your contract method takes a `b256` as input, all you need to do is pass a `Bits256([u8; 32])` when calling it from the SDK.
2 changes: 1 addition & 1 deletion docs/src/types/contract-id.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ContractId

Like `Bytes32`, `ContractId` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/latest/fuel_types/struct.ContractId.html)).
Like `Bytes32`, `ContractId` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuel-types}}/fuel_types/struct.ContractId.html)).

These are the main ways of creating a `ContractId`:

Expand Down
84 changes: 81 additions & 3 deletions packages/fuels-core/src/codec/abi_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ mod tests {
use std::vec;

use super::*;
use crate::types::U256;
use crate::{
constants::WORD_SIZE,
types::{enum_variants::EnumVariants, errors::Error, StaticStringToken},
Expand All @@ -106,11 +107,19 @@ mod tests {
ParamType::U8,
ParamType::U16,
ParamType::U64,
ParamType::U128,
ParamType::U256,
];
let data = [
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff,
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, // u32
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 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,
0xff, 0xff, // u128
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, // u256
];

let decoded = ABIDecoder::default().decode_multiple(&types, &data)?;
Expand All @@ -120,6 +129,8 @@ mod tests {
Token::U8(u8::MAX),
Token::U16(u16::MAX),
Token::U64(u64::MAX),
Token::U128(u128::MAX),
Token::U256(U256::MAX),
];
assert_eq!(decoded, expected);
Ok(())
Expand Down Expand Up @@ -510,6 +521,73 @@ mod tests {
Ok(())
}

#[test]
fn decoding_enum_with_more_than_one_heap_type_variant_fails() -> Result<()> {
let mut param_types = vec![
ParamType::U64,
ParamType::Bool,
ParamType::Vector(Box::from(ParamType::U64)),
];
// empty data
let data = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
let variants = EnumVariants::new(param_types.clone())?;
let enum_param_type = ParamType::Enum {
variants,
generics: vec![],
};
// it works if there is only one heap type
let _ = ABIDecoder::default().decode(&enum_param_type, &data)?;

param_types.append(&mut vec![ParamType::Bytes]);
let variants = EnumVariants::new(param_types)?;
let enum_param_type = ParamType::Enum {
variants,
generics: vec![],
};
// fails if there is more than one variant using heap type in the enum
let error = ABIDecoder::default()
.decode(&enum_param_type, &data)
.expect_err("Should fail");
let expected_error =
"Invalid type: Enums currently support only one heap-type variant. Found: 2"
.to_string();
assert_eq!(error.to_string(), expected_error);

Ok(())
}

#[test]
fn enums_w_too_deeply_nested_heap_types_not_allowed() {
let param_types = vec![
ParamType::U8,
ParamType::Struct {
fields: vec![ParamType::RawSlice],
generics: vec![],
},
];
let variants = EnumVariants::new(param_types).unwrap();
let enum_param_type = ParamType::Enum {
variants,
generics: vec![],
};

let err = ABIDecoder::default()
.decode(&enum_param_type, &[])
.expect_err("should have failed");

let Error::InvalidType(msg) = err else {
panic!("Unexpected err: {err}");
};

assert_eq!(
msg,
"Enums currently support only one level deep heap types."
);
}

#[test]
fn max_depth_surpassed() {
const MAX_DEPTH: usize = 2;
Expand Down
23 changes: 8 additions & 15 deletions packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl BoundedDecoder {
}

pub(crate) fn decode(&mut self, param_type: &ParamType, bytes: &[u8]) -> Result<Token> {
Self::is_type_decodable(param_type)?;
param_type.validate_is_decodable()?;
Ok(self.decode_param(param_type, bytes)?.token)
}

Expand All @@ -46,24 +46,13 @@ impl BoundedDecoder {
bytes: &[u8],
) -> Result<Vec<Token>> {
for param_type in param_types {
Self::is_type_decodable(param_type)?;
param_type.validate_is_decodable()?;
}
let (tokens, _) = self.decode_params(param_types, bytes)?;

Ok(tokens)
}

fn is_type_decodable(param_type: &ParamType) -> Result<()> {
if param_type.contains_nested_heap_types() {
Err(error!(
InvalidType,
"Type {param_type:?} contains nested heap types (`Vec` or `Bytes`), this is not supported."
))
} else {
Ok(())
}
}

fn run_w_depth_tracking(
&mut self,
decoder: impl FnOnce(&mut Self) -> Result<Decoded>,
Expand Down Expand Up @@ -312,8 +301,12 @@ impl BoundedDecoder {

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

let words_to_skip = enum_width - selected_variant.compute_encoding_width();
let skip_extra = variants
.heap_type_variant()
.is_some_and(|(heap_discriminant, _)| heap_discriminant == discriminant)
.then_some(3);
let words_to_skip =
enum_width - selected_variant.compute_encoding_width() + skip_extra.unwrap_or_default();
let enum_content_bytes = skip(bytes, words_to_skip * WORD_SIZE)?;
let result = self.decode_token_in_enum(enum_content_bytes, variants, selected_variant)?;

Expand Down
13 changes: 13 additions & 0 deletions packages/fuels-core/src/codec/abi_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1200,4 +1200,17 @@ mod tests {

Ok(())
}

#[test]
fn encoding_large_unsigned_integers() -> Result<()> {
let token = Token::U128(u128::MAX);
let expected_encoding = [255; 16];
let result = ABIEncoder::encode(&[token])?.resolve(0);
assert_eq!(result, expected_encoding);
let token = Token::U256(U256::MAX);
let expected_encoding = [255; 32];
let result = ABIEncoder::encode(&[token])?.resolve(0);
assert_eq!(result, expected_encoding);
Ok(())
}
}
43 changes: 39 additions & 4 deletions packages/fuels-core/src/types/enum_variants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ pub struct EnumVariants {

impl EnumVariants {
pub fn new(param_types: Vec<ParamType>) -> Result<EnumVariants> {
if !param_types.is_empty() {
Ok(EnumVariants { param_types })
} else {
Err(error!(InvalidData, "Enum variants can not be empty!"))
if param_types.is_empty() {
return Err(error!(InvalidData, "Enum variants can not be empty!"));
}
Ok(EnumVariants { param_types })
}

pub fn param_types(&self) -> &[ParamType] {
Expand All @@ -34,6 +33,13 @@ impl EnumVariants {
})
}

pub fn heap_type_variant(&self) -> Option<(u8, &ParamType)> {
self.param_types()
.iter()
.enumerate()
.find_map(|(d, p)| p.is_extra_receipt_needed(false).then_some((d as u8, p)))
}

pub fn only_units_inside(&self) -> bool {
self.param_types
.iter()
Expand Down Expand Up @@ -64,3 +70,32 @@ impl EnumVariants {
(biggest_variant_width - variant_width) * WORD_SIZE
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_get_heap_type_variant_discriminant() -> Result<()> {
let param_types = vec![
ParamType::U64,
ParamType::Bool,
ParamType::Vector(Box::from(ParamType::U64)),
];
let variants = EnumVariants::new(param_types)?;
assert_eq!(variants.heap_type_variant().unwrap().0, 2);

let param_types = vec![
ParamType::Vector(Box::from(ParamType::U64)),
ParamType::U64,
ParamType::Bool,
];
let variants = EnumVariants::new(param_types)?;
assert_eq!(variants.heap_type_variant().unwrap().0, 0);

let param_types = vec![ParamType::U64, ParamType::Bool];
let variants = EnumVariants::new(param_types)?;
assert!(variants.heap_type_variant().is_none());
Ok(())
}
}
Loading

0 comments on commit dab55f3

Please sign in to comment.