Skip to content

Commit

Permalink
Merge branch 'master' into hal3e/bug-precompute-after-add-witness
Browse files Browse the repository at this point in the history
  • Loading branch information
hal3e authored Oct 9, 2023
2 parents f0cf16e + 22f10db commit d22d449
Show file tree
Hide file tree
Showing 41 changed files with 872 additions and 331 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ env:
DASEL_VERSION: https://github.com/TomWright/dasel/releases/download/v1.24.3/dasel_linux_amd64
RUSTFLAGS: "-D warnings"
FUEL_CORE_VERSION: 0.20.4
RUST_VERSION: 1.71.1
FORC_VERSION: 0.45.0
RUST_VERSION: 1.72.0
FORC_VERSION: 0.46.0
FORC_PATCH_BRANCH: ""
FORC_PATCH_REVISION: ""

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ homepage = "https://fuel.network/"
readme = "README.md"
license = "Apache-2.0"
repository = "https://github.com/FuelLabs/fuels-rs"
rust-version = "1.71.1"
rust-version = "1.72.0"
version = "0.48.0"

[workspace.dependencies]
Expand Down
2 changes: 2 additions & 0 deletions docs/src/calling-contracts/logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ You can use the `decode_logs()` function to retrieve a `LogResult` struct contai
```

Due to possible performance hits, it is not recommended to use `decode_logs()` outside of a debugging scenario.

> **Note:** String slices can not be logged directly. Use the `__to_str_array()` function to convert it to a `str[N]` first.
6 changes: 3 additions & 3 deletions examples/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ mod tests {
.await?;
// ANCHOR_END: contract_call_cost_estimation

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

Ok(())
}
Expand Down Expand Up @@ -364,7 +364,7 @@ mod tests {
let response = contract_methods.mint_coins(1_000_000).call().await?;
// ANCHOR: variable_outputs
let address = wallet.address();
let asset_id = contract_id.asset_id(&Bits256::zeroed()).into();
let asset_id = contract_id.asset_id(&Bits256::zeroed());

// withdraw some tokens to wallet
let response = contract_methods
Expand Down Expand Up @@ -657,7 +657,7 @@ mod tests {
.await?;
// ANCHOR_END: multi_call_cost_estimation

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

Ok(())
}
Expand Down
1 change: 1 addition & 0 deletions packages/fuels-code-gen/src/program_bindings/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ mod tests {
pub(crate) fn sdk_provided_custom_types_lookup() -> HashMap<TypePath, TypePath> {
[
("std::address::Address", "::fuels::types::Address"),
("std::contract_id::AssetId", "::fuels::types::AssetId"),
("std::b512::B512", "::fuels::types::B512"),
("std::bytes::Bytes", "::fuels::types::Bytes"),
("std::contract_id::ContractId", "::fuels::types::ContractId"),
Expand Down
67 changes: 67 additions & 0 deletions packages/fuels-core/src/codec/abi_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,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
23 changes: 19 additions & 4 deletions packages/fuels-core/src/codec/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use fuel_tx::{ContractId, Receipt};
use crate::{
codec::{try_from_bytes, DecoderConfig},
traits::{Parameterize, Tokenizable},
types::errors::{error, Error, Result},
types::{
errors::{error, Error, Result},
param_types::ParamType,
},
};

#[derive(Clone)]
Expand All @@ -31,9 +34,22 @@ impl LogFormatter {
decoder_config: DecoderConfig,
bytes: &[u8],
) -> Result<String> {
Self::can_decode_log_with_type::<T>()?;
Ok(format!("{:?}", try_from_bytes::<T>(bytes, decoder_config)?))
}

fn can_decode_log_with_type<T: Parameterize>() -> Result<()> {
match T::param_type() {
// 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
ParamType::StringSlice => Err(error!(
InvalidData,
"String slices can not be decoded from logs. Convert the slice to `str[N]` with `__to_str_array`"
)),
_ => Ok(()),
}
}

pub fn can_handle_type<T: Tokenizable + Parameterize + 'static>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
Expand Down Expand Up @@ -162,9 +178,8 @@ impl LogDecoder {
let target_ids: HashSet<LogId> = self
.log_formatters
.iter()
.filter_map(|(log_id, log_formatter)| {
log_formatter.can_handle_type::<T>().then(|| log_id.clone())
})
.filter(|(_, log_formatter)| log_formatter.can_handle_type::<T>())
.map(|(log_id, _)| log_id.clone())
.collect();

receipts
Expand Down
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 d22d449

Please sign in to comment.