Skip to content

Commit

Permalink
Merge 1eaec2c into 5085545
Browse files Browse the repository at this point in the history
  • Loading branch information
esdrubal committed Jul 22, 2024
2 parents 5085545 + 1eaec2c commit 9770299
Show file tree
Hide file tree
Showing 251 changed files with 5,188 additions and 6,384 deletions.
29 changes: 10 additions & 19 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ fuel-tx = "0.55.0"
fuel-vm = "0.55.0"

# Dependencies from the `fuels-rs` repository:
fuels-core = "0.65.1"
fuels-accounts = "0.65.1"
fuels-core = { git = "https://github.com/FuelLabs/fuels-rs", branch = "esdrubal/abi_changes2" }
fuels-accounts = { git = "https://github.com/FuelLabs/fuels-rs", branch = "esdrubal/abi_changes2" }

# Dependencies from the `forc-wallet` repository:
forc-wallet = "0.8.2"
forc-wallet = { git = "https://github.com/FuelLabs/forc-wallet", branch = "esdrubal/abi_changes" }

# Dependencies from the `fuel-abi-types` repository:
fuel-abi-types = "0.5.2"
fuel-abi-types = { git = "https://github.com/FuelLabs/fuel-abi-types", branch = "esdrubal/abi_changes2" }

[workspace.package]
edition = "2021"
Expand Down
157 changes: 15 additions & 142 deletions forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use forc_util::{
default_output_directory, find_file_name, kebab_to_snake_case, print_compiling,
print_on_failure, print_warnings,
};
use fuel_abi_types::abi::program as program_abi;
use petgraph::{
self, dot,
visit::{Bfs, Dfs, EdgeRef, Walker},
Expand Down Expand Up @@ -1832,29 +1831,38 @@ pub fn compile(
metrics
);

const OLD_ENCODING_VERSION: &str = "0";
const NEW_ENCODING_VERSION: &str = "1";
const SPEC_VERSION: &str = "1";

let mut program_abi = match pkg.target {
BuildTarget::Fuel => {
let mut types = vec![];
ProgramABI::Fuel(time_expr!(
let program_abi_res = time_expr!(
"generate JSON ABI program",
"generate_json_abi",
fuel_abi::generate_program_abi(
&handler,
&mut AbiContext {
program: typed_program,
abi_with_callpaths: profile.json_abi_with_callpaths,
type_ids_to_full_type_str: HashMap::<String, String>::new(),
},
engines,
&mut types,
profile
.experimental
.new_encoding
.then(|| NEW_ENCODING_VERSION.into()),
.then(|| NEW_ENCODING_VERSION.into())
.unwrap_or(OLD_ENCODING_VERSION.into()),
SPEC_VERSION.into(),
),
Some(sway_build_config.clone()),
metrics
))
);
let program_abi = match program_abi_res {
Err(_) => return fail(handler),
Ok(program_abi) => program_abi,
};
ProgramABI::Fuel(program_abi)
}
BuildTarget::EVM => {
// Merge the ABI output of ASM gen with ABI gen to handle internal constructors
Expand Down Expand Up @@ -2460,7 +2468,7 @@ pub fn build(
}
};

let mut compiled = compile(
let compiled = compile(
&descriptor,
&profile,
&engines,
Expand All @@ -2480,11 +2488,6 @@ pub fn build(
}
source_map.insert_dependency(descriptor.manifest_file.dir());

// TODO: This should probably be in `fuel_abi_json::generate_json_abi_program`?
if let ProgramABI::Fuel(ref mut program_abi) = compiled.program_abi {
standardize_json_abi_types(program_abi);
}

let built_pkg = BuiltPackage {
descriptor,
program_abi: compiled.program_abi,
Expand All @@ -2504,136 +2507,6 @@ pub fn build(
Ok(built_packages)
}

/// Standardize the JSON ABI data structure by eliminating duplicate types. This is an iterative
/// process because every time two types are merged, new opportunities for more merging arise.
fn standardize_json_abi_types(json_abi_program: &mut program_abi::ProgramABI) {
loop {
// If type with id_1 is a duplicate of type with id_2, then keep track of the mapping
// between id_1 and id_2 in the HashMap below.
let mut old_to_new_id: HashMap<usize, usize> = HashMap::new();

// A vector containing unique `program_abi::TypeDeclaration`s.
//
// Two `program_abi::TypeDeclaration` are deemed the same if the have the same
// `type_field`, `components`, and `type_parameters` (even if their `type_id`s are
// different).
let mut deduped_types: Vec<program_abi::TypeDeclaration> = Vec::new();

// Insert values in `deduped_types` if they haven't been inserted before. Otherwise, create
// an appropriate mapping between type IDs in the HashMap `old_to_new_id`.
for decl in &json_abi_program.types {
if let Some(ty) = deduped_types.iter().find(|d| {
d.type_field == decl.type_field
&& d.components == decl.components
&& d.type_parameters == decl.type_parameters
}) {
old_to_new_id.insert(decl.type_id, ty.type_id);
} else {
deduped_types.push(decl.clone());
}
}

// Nothing to do if the hash map is empty as there are not merge opportunities. We can now
// exit the loop.
if old_to_new_id.is_empty() {
break;
}

json_abi_program.types = deduped_types;

// Update all `program_abi::TypeApplication`s and all `program_abi::TypeDeclaration`s
update_all_types(json_abi_program, &old_to_new_id);
}

// Sort the `program_abi::TypeDeclaration`s
json_abi_program
.types
.sort_by(|t1, t2| t1.type_field.cmp(&t2.type_field));

// Standardize IDs (i.e. change them to 0,1,2,... according to the alphabetical order above
let mut old_to_new_id: HashMap<usize, usize> = HashMap::new();
for (ix, decl) in json_abi_program.types.iter_mut().enumerate() {
old_to_new_id.insert(decl.type_id, ix);
decl.type_id = ix;
}

// Update all `program_abi::TypeApplication`s and all `program_abi::TypeDeclaration`s
update_all_types(json_abi_program, &old_to_new_id);
}

/// Recursively updates the type IDs used in a program_abi::ProgramABI
fn update_all_types(
json_abi_program: &mut program_abi::ProgramABI,
old_to_new_id: &HashMap<usize, usize>,
) {
// Update all `program_abi::TypeApplication`s in every function
for func in &mut json_abi_program.functions {
for input in &mut func.inputs {
update_json_type_application(input, old_to_new_id);
}

update_json_type_application(&mut func.output, old_to_new_id);
}

// Update all `program_abi::TypeDeclaration`
for decl in &mut json_abi_program.types {
update_json_type_declaration(decl, old_to_new_id);
}
if let Some(logged_types) = &mut json_abi_program.logged_types {
for logged_type in logged_types {
update_json_type_application(&mut logged_type.application, old_to_new_id);
}
}
if let Some(messages_types) = &mut json_abi_program.messages_types {
for logged_type in messages_types {
update_json_type_application(&mut logged_type.application, old_to_new_id);
}
}
if let Some(configurables) = &mut json_abi_program.configurables {
for logged_type in configurables {
update_json_type_application(&mut logged_type.application, old_to_new_id);
}
}
}

/// Recursively updates the type IDs used in a `program_abi::TypeApplication` given a HashMap from
/// old to new IDs
fn update_json_type_application(
type_application: &mut program_abi::TypeApplication,
old_to_new_id: &HashMap<usize, usize>,
) {
if let Some(new_id) = old_to_new_id.get(&type_application.type_id) {
type_application.type_id = *new_id;
}

if let Some(args) = &mut type_application.type_arguments {
for arg in args.iter_mut() {
update_json_type_application(arg, old_to_new_id);
}
}
}

/// Recursively updates the type IDs used in a `program_abi::TypeDeclaration` given a HashMap from
/// old to new IDs
fn update_json_type_declaration(
type_declaration: &mut program_abi::TypeDeclaration,
old_to_new_id: &HashMap<usize, usize>,
) {
if let Some(params) = &mut type_declaration.type_parameters {
for param in params.iter_mut() {
if let Some(new_id) = old_to_new_id.get(param) {
*param = *new_id;
}
}
}

if let Some(components) = &mut type_declaration.components {
for component in components.iter_mut() {
update_json_type_application(component, old_to_new_id);
}
}
}

/// Compile the entire forc package and return the lexed, parsed and typed programs
/// of the dependencies and project.
/// The final item in the returned vector is the project.
Expand Down
36 changes: 12 additions & 24 deletions forc-plugins/forc-client/src/op/run/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,17 @@ impl ScriptCallHandler {
mod tests {
use super::{ScriptCallHandler, Type};

const TEST_JSON_ABI: &str = r#"{"concreteTypes":[{"concreteTypeId":"2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d",
"type":"()"},{"concreteTypeId":"b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903","type":"bool"},
{"concreteTypeId":"c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b","type":"u8"}],
"functions":[{"inputs":[{"name":"test_u8","concreteTypeId":"c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b"},
{"name":"test_bool","concreteTypeId":"b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903"}],"name":"main",
"output":"2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d"}],"loggedTypes":[],
"messagesTypes":[],"configurables":[]}"#;

#[test]
fn test_script_call_handler_generation_success() {
let test_json_abi = r#"{"types":[{"typeId":0,"type":"()","components":[],"typeParameters":null},
{"typeId":1,"type":"bool","components":null,"typeParameters":null},{"typeId":2,"type":"u8","components":null,
"typeParameters":null}],"functions":[{"inputs":[{"name":"test_u8","type":2,"typeArguments":null},{"name":"test_bool",
"type":1,"typeArguments":null}],"name":"main","output":{"name":"","type":0,"typeArguments":null},"attributes":null}],
"loggedTypes":[],"messagesTypes":[],"configurables":[]}"#;
let generated_call_handler = ScriptCallHandler::from_json_abi_str(test_json_abi).unwrap();
let generated_call_handler = ScriptCallHandler::from_json_abi_str(TEST_JSON_ABI).unwrap();

let expected_call_handler = ScriptCallHandler {
main_arg_types: vec![Type::U8, Type::Bool],
Expand All @@ -88,12 +91,7 @@ mod tests {

#[test]
fn test_main_encoding_success() {
let test_json_abi = r#"{"types":[{"typeId":0,"type":"()","components":[],"typeParameters":null},
{"typeId":1,"type":"bool","components":null,"typeParameters":null},{"typeId":2,"type":"u8","components":null,
"typeParameters":null}],"functions":[{"inputs":[{"name":"test_u8","type":2,"typeArguments":null},{"name":"test_bool",
"type":1,"typeArguments":null}],"name":"main","output":{"name":"","type":0,"typeArguments":null},"attributes":null}],
"loggedTypes":[],"messagesTypes":[],"configurables":[]}"#;
let call_handler = ScriptCallHandler::from_json_abi_str(test_json_abi).unwrap();
let call_handler = ScriptCallHandler::from_json_abi_str(TEST_JSON_ABI).unwrap();
let values = ["2", "true"];

let encoded_bytes = call_handler.encode_arguments(&values).unwrap();
Expand All @@ -104,12 +102,7 @@ mod tests {
#[test]
#[should_panic]
fn test_main_encoding_fail_arg_type_mismatch() {
let test_json_abi = r#"{"types":[{"typeId":0,"type":"()","components":[],"typeParameters":null},
{"typeId":1,"type":"bool","components":null,"typeParameters":null},{"typeId":2,"type":"u8","components":null,
"typeParameters":null}],"functions":[{"inputs":[{"name":"test_u8","type":2,"typeArguments":null},{"name":"test_bool",
"type":1,"typeArguments":null}],"name":"main","output":{"name":"","type":0,"typeArguments":null},"attributes":null}],
"loggedTypes":[],"messagesTypes":[],"configurables":[]}"#;
let call_handler = ScriptCallHandler::from_json_abi_str(test_json_abi).unwrap();
let call_handler = ScriptCallHandler::from_json_abi_str(TEST_JSON_ABI).unwrap();
// The abi describes the following main function:
// - fn main(test_u8: u8, test_bool: bool)
// Providing a bool to u8 field should return an error.
Expand All @@ -120,12 +113,7 @@ mod tests {
#[test]
#[should_panic(expected = "main function takes 2 arguments, 1 provided")]
fn test_main_encoding_fail_arg_count_mismatch() {
let test_json_abi = r#"{"types":[{"typeId":0,"type":"()","components":[],"typeParameters":null},
{"typeId":1,"type":"bool","components":null,"typeParameters":null},{"typeId":2,"type":"u8","components":null,
"typeParameters":null}],"functions":[{"inputs":[{"name":"test_u8","type":2,"typeArguments":null},{"name":"test_bool",
"type":1,"typeArguments":null}],"name":"main","output":{"name":"","type":0,"typeArguments":null},"attributes":null}],
"loggedTypes":[],"messagesTypes":[],"configurables":[]}"#;
let call_handler = ScriptCallHandler::from_json_abi_str(test_json_abi).unwrap();
let call_handler = ScriptCallHandler::from_json_abi_str(TEST_JSON_ABI).unwrap();
// The abi describes the following main function:
// - fn main(test_u8: u8, test_bool: bool)
// Providing only 1 value should return an error as function requires 2 args.
Expand Down
4 changes: 3 additions & 1 deletion forc-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,9 @@ pub fn decode_log_data(
program_abi: &ProgramABI,
) -> anyhow::Result<DecodedLog> {
let program_abi = match program_abi {
ProgramABI::Fuel(fuel_abi) => Some(fuel_abi),
ProgramABI::Fuel(fuel_abi) => Some(
fuel_abi_types::abi::unified_program::UnifiedProgramABI::from_counterpart(fuel_abi)?,
),
_ => None,
}
.ok_or_else(|| anyhow::anyhow!("only fuelvm is supported for log decoding"))?;
Expand Down
Loading

0 comments on commit 9770299

Please sign in to comment.