From 7b88bacb734ba263ced43e79d9d579a791418e6f Mon Sep 17 00:00:00 2001 From: Gregorio Juliana Date: Tue, 9 Apr 2024 09:14:26 +0200 Subject: [PATCH] feat: add return values to aztec fns (#5389) Leverages the `#[abi(tag)]` feature from https://github.com/AztecProtocol/aztec-packages/pull/5386 to output the aztec functions abi *before* macro transformation, so that values can be decoded in https://github.com/AztecProtocol/aztec-packages/pull/5551 --------- Co-authored-by: esau <152162806+sklppy88@users.noreply.github.com> --- .../src/core/libraries/ConstantsGen.sol | 2 +- .../crates/types/src/constants.nr | 2 +- noir/noir-repo/aztec_macros/src/lib.rs | 3 +- .../aztec_macros/src/transforms/functions.rs | 94 ++++++++++++++++++- .../aztec_macros/src/utils/errors.rs | 6 ++ yarn-project/circuits.js/src/constants.gen.ts | 2 +- .../src/contract/artifact_hash.test.ts | 2 +- 7 files changed, 102 insertions(+), 9 deletions(-) diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index c86086125bd..bac287e95a5 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -83,7 +83,7 @@ library Constants { uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; uint256 internal constant DEPLOYER_CONTRACT_ADDRESS = - 0x12bcd3e09e8d8559c75d59552db47471f63c72fbbc9decb59c517b4e58634a72; + 0x1b628eeb6349f2a4c000b703942eb8a625bfe5e6ee34ccc210748cf9ae05af98; uint256 internal constant L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17; uint256 internal constant MAX_NOTE_FIELDS_LENGTH = 20; uint256 internal constant GET_NOTE_ORACLE_RETURN_LENGTH = 23; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index f89bbe8dfb0..c95d6654430 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -117,7 +117,7 @@ global REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af8166354 // CONTRACT INSTANCE CONSTANTS // sha224sum 'struct ContractInstanceDeployed' global DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; -global DEPLOYER_CONTRACT_ADDRESS = 0x12bcd3e09e8d8559c75d59552db47471f63c72fbbc9decb59c517b4e58634a72; +global DEPLOYER_CONTRACT_ADDRESS = 0x1b628eeb6349f2a4c000b703942eb8a625bfe5e6ee34ccc210748cf9ae05af98; // NOIR CONSTANTS - constants used only in yarn-packages/noir-contracts // Some are defined here because Noir doesn't yet support globals referencing other globals yet. diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 1aafda1d093..48c30ab6ffa 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -4,7 +4,7 @@ mod utils; use transforms::{ compute_note_hash_and_nullifier::inject_compute_note_hash_and_nullifier, events::{generate_selector_impl, transform_events}, - functions::{transform_function, transform_unconstrained}, + functions::{export_fn_abi, transform_function, transform_unconstrained}, note_interface::{generate_note_interface_impl, inject_note_exports}, storage::{ assign_storage_slots, check_for_storage_definition, check_for_storage_implementation, @@ -129,6 +129,7 @@ fn transform_module(module: &mut SortedModule) -> Result // Apply transformations to the function based on collected attributes if is_private || is_public || is_public_vm { + export_fn_abi(&mut module.types, func)?; transform_function( if is_private { "Private" diff --git a/noir/noir-repo/aztec_macros/src/transforms/functions.rs b/noir/noir-repo/aztec_macros/src/transforms/functions.rs index 30c14f53e62..a3064ecdd01 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/functions.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/functions.rs @@ -1,10 +1,10 @@ use convert_case::{Case, Casing}; use noirc_errors::Span; use noirc_frontend::{ - macros_api::FieldElement, BlockExpression, ConstrainKind, ConstrainStatement, Distinctness, - Expression, ExpressionKind, ForLoopStatement, ForRange, FunctionReturnType, Ident, Literal, - NoirFunction, Param, PathKind, Pattern, Signedness, Statement, StatementKind, UnresolvedType, - UnresolvedTypeData, Visibility, + macros_api::FieldElement, parse_program, BlockExpression, ConstrainKind, ConstrainStatement, + Distinctness, Expression, ExpressionKind, ForLoopStatement, ForRange, FunctionReturnType, + Ident, Literal, NoirFunction, NoirStruct, Param, PathKind, Pattern, Signedness, Statement, + StatementKind, UnresolvedType, UnresolvedTypeData, Visibility, }; use crate::{ @@ -113,6 +113,92 @@ pub fn transform_function( Ok(()) } +// Generates a global struct containing the original (before transform_function gets executed) function abi that gets exported +// in the contract artifact after compilation. The abi will be later used to decode the function return values in the simulator. +pub fn export_fn_abi( + types: &mut Vec, + func: &NoirFunction, +) -> Result<(), AztecMacroError> { + let mut parameters_struct_source: Option<&str> = None; + + let struct_source = format!( + " + struct {}_parameters {{ + {} + }} + ", + func.name(), + func.parameters() + .iter() + .map(|param| { + let param_name = match param.pattern.clone() { + Pattern::Identifier(ident) => Ok(ident.0.contents), + _ => Err(AztecMacroError::CouldNotExportFunctionAbi { + span: Some(param.span), + secondary_message: Some( + "Only identifier patterns are supported".to_owned(), + ), + }), + }; + + format!( + "{}: {}", + param_name.unwrap(), + param.typ.typ.to_string().replace("plain::", "") + ) + }) + .collect::>() + .join(",\n"), + ); + + if !func.parameters().is_empty() { + parameters_struct_source = Some(&struct_source); + } + + let mut program = String::new(); + + let parameters = if let Some(parameters_struct_source) = parameters_struct_source { + program.push_str(parameters_struct_source); + format!("parameters: {}_parameters,\n", func.name()) + } else { + "".to_string() + }; + + let return_type_str = func.return_type().typ.to_string().replace("plain::", ""); + let return_type = if return_type_str != "()" { + format!("return_type: {},\n", return_type_str) + } else { + "".to_string() + }; + + let export_struct_source = format!( + " + #[abi(functions)] + struct {}_abi {{ + {}{} + }}", + func.name(), + parameters, + return_type + ); + + program.push_str(&export_struct_source); + + let (ast, errors) = parse_program(&program); + if !errors.is_empty() { + return Err(AztecMacroError::CouldNotExportFunctionAbi { + span: None, + secondary_message: Some( + format!("Failed to parse Noir macro code (struct {}_abi). This is either a bug in the compiler or the Noir macro code", func.name()) + ) + }); + } + + let sorted_ast = ast.into_sorted(); + types.extend(sorted_ast.types); + Ok(()) +} + /// Transform Unconstrained /// /// Inserts the following code at the beginning of an unconstrained function diff --git a/noir/noir-repo/aztec_macros/src/utils/errors.rs b/noir/noir-repo/aztec_macros/src/utils/errors.rs index e3a3db87a3d..9aead1756f9 100644 --- a/noir/noir-repo/aztec_macros/src/utils/errors.rs +++ b/noir/noir-repo/aztec_macros/src/utils/errors.rs @@ -13,6 +13,7 @@ pub enum AztecMacroError { CouldNotImplementNoteInterface { span: Option, secondary_message: Option }, MultipleStorageDefinitions { span: Option }, CouldNotExportStorageLayout { span: Option, secondary_message: Option }, + CouldNotExportFunctionAbi { span: Option, secondary_message: Option }, EventError { span: Span, message: String }, UnsupportedAttributes { span: Span, secondary_message: Option }, } @@ -60,6 +61,11 @@ impl From for MacroError { secondary_message, span, }, + AztecMacroError::CouldNotExportFunctionAbi { secondary_message, span } => MacroError { + primary_message: "Could not generate and export function abi".to_string(), + secondary_message, + span, + }, AztecMacroError::EventError { span, message } => MacroError { primary_message: message, secondary_message: None, diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 77e588276ed..d48c426d72b 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -68,7 +68,7 @@ export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d99n; export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631n; -export const DEPLOYER_CONTRACT_ADDRESS = 0x12bcd3e09e8d8559c75d59552db47471f63c72fbbc9decb59c517b4e58634a72n; +export const DEPLOYER_CONTRACT_ADDRESS = 0x1b628eeb6349f2a4c000b703942eb8a625bfe5e6ee34ccc210748cf9ae05af98n; export const L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17; export const MAX_NOTE_FIELDS_LENGTH = 20; export const GET_NOTE_ORACLE_RETURN_LENGTH = 23; diff --git a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts index e01b9484f21..b7dbf493fd7 100644 --- a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts +++ b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts @@ -5,7 +5,7 @@ describe('ArtifactHash', () => { it('calculates the artifact hash', () => { const artifact = getBenchmarkContractArtifact(); expect(computeArtifactHash(artifact).toString()).toMatchInlineSnapshot( - `"0x011603d7f02ebec628e8f1b2458edff811648ea3af5399cec32302aab6217b26"`, + `"0x2000991c126ffc45142660f7c3ad26f65aeb853a3b9c7e5906ba8205a2556128"`, ); }); });