From 442e8baab05ea077fbca9646d56d428d411326d5 Mon Sep 17 00:00:00 2001 From: Marcos Henrich Date: Wed, 10 Jul 2024 10:25:19 +0100 Subject: [PATCH] Updates ABI with program_type and hash based ids. --- Cargo.lock | 31 +++-- Cargo.toml | 2 +- forc-pkg/src/pkg.rs | 140 +---------------------- sway-core/src/abi_generation/fuel_abi.rs | 129 +++++++++++++++------ 4 files changed, 126 insertions(+), 176 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59fdeefec6e..ac61e55d4d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2002,7 +2002,7 @@ dependencies = [ "forc-tx", "forc-util", "forc-wallet", - "fuel-abi-types", + "fuel-abi-types 0.6.0", "fuel-core-client", "fuel-core-types", "fuel-crypto", @@ -2137,7 +2137,7 @@ dependencies = [ "cid", "forc-tracing 0.61.0", "forc-util", - "fuel-abi-types", + "fuel-abi-types 0.6.0", "futures", "git2", "gix-url", @@ -2170,7 +2170,7 @@ version = "0.61.0" dependencies = [ "anyhow", "forc-pkg", - "fuel-abi-types", + "fuel-abi-types 0.6.0", "fuel-tx", "fuel-vm", "fuels-core", @@ -2324,6 +2324,23 @@ dependencies = [ "thiserror", ] +[[package]] +name = "fuel-abi-types" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccb98391d7df3963bc3f30d3c8bfce301573a115fa92a35bed55e4c94b836be2" +dependencies = [ + "itertools 0.10.5", + "lazy_static", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.66", + "thiserror", +] + [[package]] name = "fuel-asm" version = "0.52.0" @@ -2685,7 +2702,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c62cf6bfe69581bf806602c45ade998b7f34fb96bbbfc508819d7ae6c4957aa" dependencies = [ "Inflector", - "fuel-abi-types", + "fuel-abi-types 0.5.2", "itertools 0.12.1", "proc-macro2", "quote", @@ -2703,7 +2720,7 @@ dependencies = [ "async-trait", "bech32", "chrono", - "fuel-abi-types", + "fuel-abi-types 0.5.2", "fuel-asm", "fuel-core-chain-config", "fuel-core-client", @@ -2742,7 +2759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c75f67cf51f7ea66978828a9e2729c69819e1b43865afe372450ba25973c66a" dependencies = [ "async-trait", - "fuel-abi-types", + "fuel-abi-types 0.5.2", "fuel-asm", "fuel-tx", "fuel-types", @@ -6551,7 +6568,7 @@ dependencies = [ "derivative", "dirs 3.0.2", "either", - "fuel-abi-types", + "fuel-abi-types 0.6.0", "fuel-ethabi", "fuel-etk-asm", "fuel-etk-ops", diff --git a/Cargo.toml b/Cargo.toml index 5835ed5779c..982e157ad41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ fuels-accounts = "0.64.0" forc-wallet = "0.8.1" # Dependencies from the `fuel-abi-types` repository: -fuel-abi-types = "0.5.0" +fuel-abi-types = "0.6.0" [workspace.package] edition = "2021" diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 09b00fa5057..04721fdeb2b 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -14,7 +14,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}, @@ -1819,6 +1818,8 @@ pub fn compile( ); const NEW_ENCODING_VERSION: &str = "1"; + const SPEC_VERSION: &str = "1"; + const ABI_VERSION: &str = "1"; let mut program_abi = match pkg.target { BuildTarget::Fuel => { @@ -1837,6 +1838,8 @@ pub fn compile( .experimental .new_encoding .then(|| NEW_ENCODING_VERSION.into()), + SPEC_VERSION.into(), + ABI_VERSION.into() ), Some(sway_build_config.clone()), metrics @@ -2452,11 +2455,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, @@ -2476,136 +2474,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 = 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 = 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 = 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, -) { - // 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, -) { - 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, -) { - 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. diff --git a/sway-core/src/abi_generation/fuel_abi.rs b/sway-core/src/abi_generation/fuel_abi.rs index 1479dd2c155..228e76fd2f3 100644 --- a/sway-core/src/abi_generation/fuel_abi.rs +++ b/sway-core/src/abi_generation/fuel_abi.rs @@ -1,4 +1,5 @@ use fuel_abi_types::abi::program as program_abi; +use sha2::{Digest, Sha256}; use std::collections::HashSet; use crate::{ @@ -33,11 +34,24 @@ impl<'a> AbiContext<'a> { } } +impl TypeId { + fn get_abi_type_id(&self, ctx: &mut AbiContext, engines: &Engines) -> String { + let string = + self.get_abi_type_str(&ctx.to_str_context(engines, true), engines, self.clone()); + let mut hasher = Sha256::new(); + hasher.update(string); + let result = hasher.finalize(); + format!("{:x}", result) + } +} + pub fn generate_program_abi( ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, encoding: Option, + spec_version: program_abi::Version, + abi_version: program_abi::Version, ) -> program_abi::ProgramABI { let decl_engine = engines.de(); match &ctx.program.kind { @@ -53,6 +67,27 @@ pub fn generate_program_abi( let messages_types = generate_messages_types(ctx, engines, types); let configurables = generate_configurables(ctx, engines, types); program_abi::ProgramABI { + program_type: "contract".to_string(), + spec_version, + abi_version, + encoding, + types: types.to_vec(), + functions, + logged_types: Some(logged_types), + messages_types: Some(messages_types), + configurables: Some(configurables), + } + } + TyProgramKind::Script { main_function, .. } => { + let main_function = decl_engine.get_function(main_function); + let functions = vec![main_function.generate_abi_function(ctx, engines, types)]; + let logged_types = generate_logged_types(ctx, engines, types); + let messages_types = generate_messages_types(ctx, engines, types); + let configurables = generate_configurables(ctx, engines, types); + program_abi::ProgramABI { + program_type: "script".to_string(), + spec_version, + abi_version, encoding, types: types.to_vec(), functions, @@ -61,14 +96,16 @@ pub fn generate_program_abi( configurables: Some(configurables), } } - TyProgramKind::Script { main_function, .. } - | TyProgramKind::Predicate { main_function, .. } => { + TyProgramKind::Predicate { main_function, .. } => { let main_function = decl_engine.get_function(main_function); let functions = vec![main_function.generate_abi_function(ctx, engines, types)]; let logged_types = generate_logged_types(ctx, engines, types); let messages_types = generate_messages_types(ctx, engines, types); let configurables = generate_configurables(ctx, engines, types); program_abi::ProgramABI { + program_type: "predicate".to_string(), + spec_version, + abi_version, encoding, types: types.to_vec(), functions, @@ -77,7 +114,10 @@ pub fn generate_program_abi( configurables: Some(configurables), } } - _ => program_abi::ProgramABI { + TyProgramKind::Library { .. } => program_abi::ProgramABI { + program_type: "library".to_string(), + spec_version, + abi_version, encoding, types: vec![], functions: vec![], @@ -99,7 +139,7 @@ fn generate_logged_types( .logged_types .iter() .map(|(_, type_id)| program_abi::TypeDeclaration { - type_id: type_id.index(), + type_id: type_id.get_abi_type_id(ctx, engines), type_field: type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -128,7 +168,7 @@ fn generate_logged_types( log_id: log_id.to_string(), application: program_abi::TypeApplication { name: "".to_string(), - type_id: type_id.index(), + type_id: type_id.get_abi_type_id(ctx, engines), type_arguments: type_id .get_abi_type_arguments(ctx, engines, types, *type_id), }, @@ -149,7 +189,7 @@ fn generate_messages_types( .messages_types .iter() .map(|(_, type_id)| program_abi::TypeDeclaration { - type_id: type_id.index(), + type_id: type_id.get_abi_type_id(ctx, engines), type_field: type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -171,7 +211,7 @@ fn generate_messages_types( message_id: **message_id as u64, application: program_abi::TypeApplication { name: "".to_string(), - type_id: type_id.index(), + type_id: type_id.get_abi_type_id(ctx, engines), type_arguments: type_id.get_abi_type_arguments(ctx, engines, types, *type_id), }, }) @@ -189,7 +229,7 @@ fn generate_configurables( .configurables .iter() .map(|decl| program_abi::TypeDeclaration { - type_id: decl.type_ascription.type_id.index(), + type_id: decl.type_ascription.type_id.get_abi_type_id(ctx, engines), type_field: decl.type_ascription.type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -221,7 +261,7 @@ fn generate_configurables( name: decl.call_path.suffix.to_string(), application: program_abi::TypeApplication { name: "".to_string(), - type_id: decl.type_ascription.type_id.index(), + type_id: decl.type_ascription.type_id.get_abi_type_id(ctx, engines), type_arguments: decl.type_ascription.type_id.get_abi_type_arguments( ctx, engines, @@ -246,7 +286,7 @@ impl TypeId { engines: &Engines, types: &mut Vec, resolved_type_id: TypeId, - ) -> Option> { + ) -> Option> { match self.is_generic_parameter(engines, resolved_type_id) { true => None, false => resolved_type_id.get_type_parameters(engines).map(|v| { @@ -277,7 +317,10 @@ impl TypeId { .variants .iter() .map(|x| program_abi::TypeDeclaration { - type_id: x.type_argument.initial_type_id.index(), + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(ctx, engines), type_field: x.type_argument.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -306,7 +349,10 @@ impl TypeId { .iter() .map(|x| program_abi::TypeApplication { name: x.name.to_string(), - type_id: x.type_argument.initial_type_id.index(), + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(ctx, engines), type_arguments: x.type_argument.initial_type_id.get_abi_type_arguments( ctx, engines, @@ -325,7 +371,10 @@ impl TypeId { .fields .iter() .map(|x| program_abi::TypeDeclaration { - type_id: x.type_argument.initial_type_id.index(), + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(ctx, engines), type_field: x.type_argument.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -354,7 +403,10 @@ impl TypeId { .iter() .map(|x| program_abi::TypeApplication { name: x.name.to_string(), - type_id: x.type_argument.initial_type_id.index(), + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(ctx, engines), type_arguments: x.type_argument.initial_type_id.get_abi_type_arguments( ctx, engines, @@ -369,7 +421,7 @@ impl TypeId { if let TypeInfo::Array(elem_ty, _) = &*type_engine.get(resolved_type_id) { // The `program_abi::TypeDeclaration`s needed for the array element type let elem_abi_ty = program_abi::TypeDeclaration { - type_id: elem_ty.initial_type_id.index(), + type_id: elem_ty.initial_type_id.get_abi_type_id(ctx, engines), type_field: elem_ty.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -394,7 +446,7 @@ impl TypeId { // `program_abi::TypeApplication` for the array element type Some(vec![program_abi::TypeApplication { name: "__array_element".to_string(), - type_id: elem_ty.initial_type_id.index(), + type_id: elem_ty.initial_type_id.get_abi_type_id(ctx, engines), type_arguments: elem_ty.initial_type_id.get_abi_type_arguments( ctx, engines, @@ -412,7 +464,7 @@ impl TypeId { let fields_types = fields .iter() .map(|x| program_abi::TypeDeclaration { - type_id: x.initial_type_id.index(), + type_id: x.initial_type_id.get_abi_type_id(ctx, engines), type_field: x.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -436,7 +488,7 @@ impl TypeId { .iter() .map(|x| program_abi::TypeApplication { name: "__tuple_element".to_string(), - type_id: x.initial_type_id.index(), + type_id: x.initial_type_id.get_abi_type_id(ctx, engines), type_arguments: x .initial_type_id .get_abi_type_arguments(ctx, engines, types, x.type_id), @@ -461,7 +513,7 @@ impl TypeId { .iter(), ) .map(|(v, p)| program_abi::TypeDeclaration { - type_id: v.initial_type_id.index(), + type_id: v.initial_type_id.get_abi_type_id(ctx, engines), type_field: v.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -526,7 +578,7 @@ impl TypeId { .iter() .zip(resolved_params.iter()) .map(|(v, p)| program_abi::TypeDeclaration { - type_id: v.initial_type_id.index(), + type_id: v.initial_type_id.get_abi_type_id(ctx, engines), type_field: v.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -546,7 +598,7 @@ impl TypeId { .iter() .map(|arg| program_abi::TypeApplication { name: "".to_string(), - type_id: arg.initial_type_id.index(), + type_id: arg.initial_type_id.get_abi_type_id(ctx, engines), type_arguments: arg.initial_type_id.get_abi_type_arguments( ctx, engines, @@ -563,7 +615,7 @@ impl TypeId { .type_parameters .iter() .map(|v| program_abi::TypeDeclaration { - type_id: v.type_id.index(), + type_id: v.type_id.get_abi_type_id(ctx, engines), type_field: v.type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -584,7 +636,7 @@ impl TypeId { .iter() .map(|arg| program_abi::TypeApplication { name: "".to_string(), - type_id: arg.type_id.index(), + type_id: arg.type_id.get_abi_type_id(ctx, engines), type_arguments: arg.type_id.get_abi_type_arguments( ctx, engines, @@ -603,7 +655,7 @@ impl TypeId { .type_parameters .iter() .map(|v| program_abi::TypeDeclaration { - type_id: v.type_id.index(), + type_id: v.type_id.get_abi_type_id(ctx, engines), type_field: v.type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -624,7 +676,7 @@ impl TypeId { .iter() .map(|arg| program_abi::TypeApplication { name: "".to_string(), - type_id: arg.type_id.index(), + type_id: arg.type_id.get_abi_type_id(ctx, engines), type_arguments: arg.type_id.get_abi_type_arguments( ctx, engines, @@ -652,7 +704,10 @@ impl TyFunctionDecl { .parameters .iter() .map(|x| program_abi::TypeDeclaration { - type_id: x.type_argument.initial_type_id.index(), + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(ctx, engines), type_field: x.type_argument.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -675,7 +730,10 @@ impl TyFunctionDecl { // The single `program_abi::TypeDeclaration` needed for the output let output_type = program_abi::TypeDeclaration { - type_id: self.return_type.initial_type_id.index(), + type_id: self + .return_type + .initial_type_id + .get_abi_type_id(ctx, engines), type_field: self.return_type.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -707,7 +765,10 @@ impl TyFunctionDecl { .iter() .map(|x| program_abi::TypeApplication { name: x.name.to_string(), - type_id: x.type_argument.initial_type_id.index(), + type_id: x + .type_argument + .initial_type_id + .get_abi_type_id(ctx, engines), type_arguments: x.type_argument.initial_type_id.get_abi_type_arguments( ctx, engines, @@ -718,7 +779,10 @@ impl TyFunctionDecl { .collect(), output: program_abi::TypeApplication { name: "".to_string(), - type_id: self.return_type.initial_type_id.index(), + type_id: self + .return_type + .initial_type_id + .get_abi_type_id(ctx, engines), type_arguments: self.return_type.initial_type_id.get_abi_type_arguments( ctx, engines, @@ -757,9 +821,10 @@ impl TypeParameter { ctx: &mut AbiContext, engines: &Engines, types: &mut Vec, - ) -> usize { + ) -> String { + let type_id = self.initial_type_id.get_abi_type_id(ctx, engines); let type_parameter = program_abi::TypeDeclaration { - type_id: self.initial_type_id.index(), + type_id: type_id.clone(), type_field: self.initial_type_id.get_abi_type_str( &ctx.to_str_context(engines, false), engines, @@ -774,6 +839,6 @@ impl TypeParameter { type_parameters: None, }; types.push(type_parameter); - self.initial_type_id.index() + type_id } }