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: return Enums containing heap types at depth 1 #1106

Merged
merged 41 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
cf30752
first draft
iqdecay Aug 28, 2023
512975f
add test project
iqdecay Aug 28, 2023
871d3d6
wip
iqdecay Aug 28, 2023
a6df54d
feat: cut the supplementary ReturnData receipt to 0
iqdecay Aug 29, 2023
eeef19c
fix call instructions length
iqdecay Aug 29, 2023
f2ced6d
add test
iqdecay Aug 29, 2023
575da0d
add test for options
iqdecay Aug 29, 2023
cc81c0e
test: add enum variants lib test
iqdecay Aug 30, 2023
1d7a61a
add docs
iqdecay Aug 30, 2023
003cf41
style: appease clippy and all formatting gods
iqdecay Aug 30, 2023
dc5d5dd
dedupe uses_heap_type function
iqdecay Aug 30, 2023
c5bf0e9
Merge branch 'master' into iqdecay/feat-wrapped-bytes-output
iqdecay Aug 30, 2023
cc8c5db
add test for the discriminant
iqdecay Aug 30, 2023
c13b581
fix naming
iqdecay Aug 30, 2023
8a3ed33
style: appease clippy and all formatting gods
iqdecay Aug 31, 2023
59d7e84
Merge branch 'master' into iqdecay/feat-wrapped-bytes-output
iqdecay Aug 31, 2023
52730bb
Update packages/fuels-core/src/types/enum_variants.rs
iqdecay Sep 7, 2023
5f6fedc
style: improve skipping bytes
iqdecay Sep 7, 2023
40e75e1
fix: fix potential buffer overflow error
iqdecay Sep 7, 2023
2c530a9
style: remove unused imports
iqdecay Sep 7, 2023
52f5ab2
style: rename function
iqdecay Sep 7, 2023
4347558
refactor: improve filtering in call utils
iqdecay Sep 7, 2023
073e995
fix
iqdecay Sep 8, 2023
9ddc3b9
fix: disallow multiple heap types in variants only in return types
iqdecay Sep 8, 2023
527f95e
Merge branch 'master' into iqdecay/feat-wrapped-bytes-output
iqdecay Sep 11, 2023
05c69bf
feat: improve with segfault suggestion
iqdecay Sep 13, 2023
45ce512
test: improve testing for return type validation
iqdecay Sep 13, 2023
ba5955c
reinstate tests
iqdecay Sep 13, 2023
e322450
Merge branch 'master' into iqdecay/feat-wrapped-bytes-output
iqdecay Sep 14, 2023
efe0270
fix test for deep heap types
iqdecay Sep 14, 2023
c92c53a
style: appease clippy and all formatting gods
iqdecay Sep 14, 2023
14789b4
style
iqdecay Sep 14, 2023
3063c18
test: fix tests
iqdecay Sep 14, 2023
0228bff
Merge branch 'master' into iqdecay/feat-wrapped-bytes-output
iqdecay Oct 3, 2023
6b138f5
Update packages/fuels-core/src/types/enum_variants.rs
iqdecay Oct 3, 2023
3869d08
Update packages/fuels-core/src/types/param_types.rs
iqdecay Oct 3, 2023
67183c0
Merge branch 'master' into iqdecay/feat-wrapped-bytes-output
MujkicA Oct 4, 2023
7d43a1b
Merge branch 'master' into iqdecay/feat-wrapped-bytes-output
segfault-magnet Oct 4, 2023
d85b0a7
Merge branch 'master' into iqdecay/feat-wrapped-bytes-output
iqdecay Oct 4, 2023
02d07ca
rename function for extra receipts to avoid sounding like a setter
iqdecay Oct 4, 2023
b33ca17
Merge branch 'master' into iqdecay/feat-wrapped-bytes-output
hal3e Oct 6, 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
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
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
Loading