Skip to content

Commit

Permalink
feat!: add decode_as_debug_str to ABIDecoder (#1291)
Browse files Browse the repository at this point in the history
PR: #690 updated `ParamType`
and added names for `struct` and `enum` types and their fields/variants.
This was later removed in PR:
#885 as we completely changed
how log decoding is done.

This PR returns struct and enum names (also fields/variants) so that
users can use `ParamTypes` at runtime to debug log or return receipts.
In addition, users are able to go directly from `ProgramABI` and some
data to decoded debug. Here is an example how this is used:

BREAKING CHANGE: `EnumVariants` are now imported through
`param_types::EnumVariants`
  • Loading branch information
hal3e authored Mar 12, 2024
1 parent fa17c52 commit dde493c
Show file tree
Hide file tree
Showing 24 changed files with 2,756 additions and 2,116 deletions.
102 changes: 101 additions & 1 deletion examples/debugging/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ mod tests {
use fuel_abi_types::abi::program::ProgramABI;
use fuels::{
core::{
codec::{calldata, fn_selector, resolve_fn_selector},
codec::{calldata, fn_selector, resolve_fn_selector, ABIDecoder},
traits::Parameterize,
},
macros::abigen,
types::{errors::Result, param_types::ParamType, SizedAsciiString},
};

Expand Down Expand Up @@ -69,4 +70,103 @@ mod tests {

Ok(())
}

#[test]
fn decoded_debug_matches_rust_debug() -> Result<()> {
abigen!(Contract(
name = "MyContract",
abi = "packages/fuels/tests/types/contracts/generics/out/debug/generics-abi.json"
));

let json_abi_file =
"../../packages/fuels/tests/types/contracts/generics/out/debug/generics-abi.json";
let abi_file_contents = std::fs::read_to_string(json_abi_file)?;

let parsed_abi: ProgramABI = serde_json::from_str(&abi_file_contents)?;

let type_lookup = parsed_abi
.types
.into_iter()
.map(|decl| (decl.type_id, decl))
.collect::<HashMap<_, _>>();

let get_first_fn_argument = |fn_name: &str| {
parsed_abi
.functions
.iter()
.find(|abi_fun| abi_fun.name == fn_name)
.expect("should be there")
.inputs
.first()
.expect("should be there")
};
let decoder = ABIDecoder::default();

{
// simple struct with a single generic parameter
let type_application = get_first_fn_argument("struct_w_generic");
let param_type = ParamType::try_from_type_application(type_application, &type_lookup)?;

let expected_struct = SimpleGeneric {
single_generic_param: 123u64,
};

assert_eq!(
format!("{expected_struct:?}"),
decoder.decode_as_debug_str(&param_type, &[0, 0, 0, 0, 0, 0, 0, 123])?
);
}
{
// struct that delegates the generic param internally
let type_application = get_first_fn_argument("struct_delegating_generic");
let param_type = ParamType::try_from_type_application(type_application, &type_lookup)?;

let expected_struct = PassTheGenericOn {
one: SimpleGeneric {
single_generic_param: SizedAsciiString::<3>::try_from("abc")?,
},
};

assert_eq!(
format!("{expected_struct:?}"),
decoder.decode_as_debug_str(&param_type, &[97, 98, 99])?
);
}
{
// enum with generic in variant
let type_application = get_first_fn_argument("enum_w_generic");
let param_type = ParamType::try_from_type_application(type_application, &type_lookup)?;

let expected_enum = EnumWGeneric::B(10u64);

assert_eq!(
format!("{expected_enum:?}"),
decoder.decode_as_debug_str(
&param_type,
&[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10]
)?
);
}
{
// logged type
let logged_type = parsed_abi
.logged_types
.as_ref()
.expect("has logs")
.first()
.expect("has log");

let param_type =
ParamType::try_from_type_application(&logged_type.application, &type_lookup)?;

let expected_u8 = 1;

assert_eq!(
format!("{expected_u8}"),
decoder.decode_as_debug_str(&param_type, &[0, 0, 0, 0, 0, 0, 0, 1])?
);
}

Ok(())
}
}
Loading

0 comments on commit dde493c

Please sign in to comment.