From 201072b3e22884465451c47247fcddb754ab4ed6 Mon Sep 17 00:00:00 2001 From: superstar0402 Date: Mon, 14 Aug 2023 08:13:54 -0300 Subject: [PATCH] feat(noir): autogenerate contract interface for calling from external contracts (#1487) Builds on @iAmMichaelConnor work to generate a contract interface for simplifying calling function in other contracts. Uses only information present in the ABI. For each function in the target contract, creates a wrapper function that receives the same arguments, serialises them based on the standard ABI encoding format (see [here](https://github.com/AztecProtocol/aztec-packages/blob/49d272159f1b27521ad34081c7f1622ccac19dff/yarn-project/foundation/src/abi/encoder.ts)), and uses the `call_private_function` from the `context` to call into them. To handle custom structs, we're re-defining them in the contract interface. Until we get struct type names in the ABI (see https://github.com/noir-lang/noir/issues/2238), we are autogenerating the name as well, based on the function name and param name where they are used. Serialisation is done manually in the code, but we may want to replace it with a Noir intrinsic when available (see https://github.com/noir-lang/noir/issues/2240). See [this file](https://github.com/AztecProtocol/aztec-packages/blob/49d272159f1b27521ad34081c7f1622ccac19dff/yarn-project/noir-contracts/src/contracts/test_contract/src/test_contract_interface.nr) for example output. Fixes #1237 --------- Co-authored-by: iAmMichaelConnor --- yarn-project/noir-libs/noir-aztec/src/abi.nr | 30 +++++++++++-------- .../noir-libs/noir-aztec/src/context.nr | 8 ++--- .../noir-libs/noir-aztec/src/state_vars.nr | 1 - .../noir-aztec/src/state_vars/public_state.nr | 2 +- .../noir-libs/noir-aztec/src/types.nr | 3 +- .../noir-libs/noir-aztec/src/types/point.nr | 22 +++++++++++++- .../type_serialisation.nr | 1 + .../type_serialisation/bool_serialisation.nr | 16 ++++++++++ .../type_serialisation/field_serialisation.nr | 2 +- .../type_serialisation/u32_serialisation.nr | 2 +- 10 files changed, 63 insertions(+), 24 deletions(-) rename yarn-project/noir-libs/noir-aztec/src/{state_vars => types}/type_serialisation.nr (92%) create mode 100644 yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/bool_serialisation.nr rename yarn-project/noir-libs/noir-aztec/src/{state_vars => types}/type_serialisation/field_serialisation.nr (82%) rename yarn-project/noir-libs/noir-aztec/src/{state_vars => types}/type_serialisation/u32_serialisation.nr (82%) diff --git a/yarn-project/noir-libs/noir-aztec/src/abi.nr b/yarn-project/noir-libs/noir-aztec/src/abi.nr index b2a4240..be4fbfc 100644 --- a/yarn-project/noir-libs/noir-aztec/src/abi.nr +++ b/yarn-project/noir-libs/noir-aztec/src/abi.nr @@ -358,21 +358,25 @@ global ARGS_HASH_CHUNK_LENGTH: u32 = 32; global ARGS_HASH_CHUNK_COUNT: u32 = 16; fn hash_args(args: [Field; N]) -> Field { - let mut chunks_hashes = [0; ARGS_HASH_CHUNK_COUNT]; - for i in 0..ARGS_HASH_CHUNK_COUNT { - let mut chunk_hash = 0; - let start_chunk_index = i * ARGS_HASH_CHUNK_LENGTH; - if start_chunk_index < (args.len() as u32) { - let mut chunk_args = [0; ARGS_HASH_CHUNK_LENGTH]; - for j in 0..ARGS_HASH_CHUNK_LENGTH { - let item_index = i * ARGS_HASH_CHUNK_LENGTH + j; - if item_index < (args.len() as u32) { - chunk_args[j] = args[item_index]; + if args.len() == 0 { + 0 + } else { + let mut chunks_hashes = [0; ARGS_HASH_CHUNK_COUNT]; + for i in 0..ARGS_HASH_CHUNK_COUNT { + let mut chunk_hash = 0; + let start_chunk_index = i * ARGS_HASH_CHUNK_LENGTH; + if start_chunk_index < (args.len() as u32) { + let mut chunk_args = [0; ARGS_HASH_CHUNK_LENGTH]; + for j in 0..ARGS_HASH_CHUNK_LENGTH { + let item_index = i * ARGS_HASH_CHUNK_LENGTH + j; + if item_index < (args.len() as u32) { + chunk_args[j] = args[item_index]; + } } + chunk_hash = dep::std::hash::pedersen_with_separator(chunk_args, GENERATOR_INDEX__FUNCTION_ARGS)[0]; } - chunk_hash = dep::std::hash::pedersen_with_separator(chunk_args, GENERATOR_INDEX__FUNCTION_ARGS)[0]; + chunks_hashes[i] = chunk_hash; } - chunks_hashes[i] = chunk_hash; + dep::std::hash::pedersen_with_separator(chunks_hashes, GENERATOR_INDEX__FUNCTION_ARGS)[0] } - dep::std::hash::pedersen_with_separator(chunks_hashes, GENERATOR_INDEX__FUNCTION_ARGS)[0] } diff --git a/yarn-project/noir-libs/noir-aztec/src/context.nr b/yarn-project/noir-libs/noir-aztec/src/context.nr index 8c20f03..82c7b90 100644 --- a/yarn-project/noir-libs/noir-aztec/src/context.nr +++ b/yarn-project/noir-libs/noir-aztec/src/context.nr @@ -296,7 +296,7 @@ impl Context { contract_address: Field, function_selector: Field, args: [Field; ARGS_COUNT] - ) -> [Field; RETURN_VALUES_LENGTH] { + ) { let args_hash = hash_args(args); assert(args_hash == arguments::pack_arguments(args)); self.call_public_function_with_packed_args(contract_address, function_selector, args_hash) @@ -306,7 +306,7 @@ impl Context { &mut self, contract_address: Field, function_selector: Field, - ) -> [Field; RETURN_VALUES_LENGTH] { + ) { self.call_public_function_with_packed_args(contract_address, function_selector, 0) } @@ -315,7 +315,7 @@ impl Context { contract_address: Field, function_selector: Field, args_hash: Field - ) -> [Field; RETURN_VALUES_LENGTH] { + ) { let fields = enqueue_public_function_call_internal( contract_address, function_selector, @@ -372,7 +372,5 @@ impl Context { assert(item.public_inputs.call_context.storage_contract_address == contract_address); self.public_call_stack.push(item.hash()); - - item.public_inputs.return_values } } diff --git a/yarn-project/noir-libs/noir-aztec/src/state_vars.nr b/yarn-project/noir-libs/noir-aztec/src/state_vars.nr index 0148c8a..b35df03 100644 --- a/yarn-project/noir-libs/noir-aztec/src/state_vars.nr +++ b/yarn-project/noir-libs/noir-aztec/src/state_vars.nr @@ -1,6 +1,5 @@ mod immutable_singleton; mod map; mod public_state; -mod type_serialisation; mod set; mod singleton; \ No newline at end of file diff --git a/yarn-project/noir-libs/noir-aztec/src/state_vars/public_state.nr b/yarn-project/noir-libs/noir-aztec/src/state_vars/public_state.nr index b4cae24..900255b 100644 --- a/yarn-project/noir-libs/noir-aztec/src/state_vars/public_state.nr +++ b/yarn-project/noir-libs/noir-aztec/src/state_vars/public_state.nr @@ -1,6 +1,6 @@ use crate::oracle::storage::storage_read; use crate::oracle::storage::storage_write; -use crate::state_vars::type_serialisation::TypeSerialisationInterface; +use crate::types::type_serialisation::TypeSerialisationInterface; struct PublicState { storage_slot: Field, diff --git a/yarn-project/noir-libs/noir-aztec/src/types.nr b/yarn-project/noir-libs/noir-aztec/src/types.nr index 4614a0c..babc0a6 100644 --- a/yarn-project/noir-libs/noir-aztec/src/types.nr +++ b/yarn-project/noir-libs/noir-aztec/src/types.nr @@ -1,3 +1,4 @@ +mod option; // This can/should be moved out into an official noir library mod point; mod vec; // This can/should be moved out into an official noir library -mod option; // This can/should be moved out into an official noir library \ No newline at end of file +mod type_serialisation; \ No newline at end of file diff --git a/yarn-project/noir-libs/noir-aztec/src/types/point.nr b/yarn-project/noir-libs/noir-aztec/src/types/point.nr index 81e4842..47ea73f 100644 --- a/yarn-project/noir-libs/noir-aztec/src/types/point.nr +++ b/yarn-project/noir-libs/noir-aztec/src/types/point.nr @@ -1,3 +1,5 @@ +use crate::types::type_serialisation::TypeSerialisationInterface; + struct Point { x: Field, y: Field, @@ -7,4 +9,22 @@ impl Point { fn new(x: Field, y: Field) -> Self { Point { x, y } } -} \ No newline at end of file +} + +global POINT_SERIALISED_LEN: Field = 2; + +fn deserialisePoint(fields: [Field; POINT_SERIALISED_LEN]) -> Point { + Point { + x: fields[0], + y: fields[1], + } +} + +fn serialisePoint(point: Point) -> [Field; POINT_SERIALISED_LEN] { + [point.x, point.y] +} + +global PointSerialisationMethods = TypeSerialisationInterface { + deserialise: deserialisePoint, + serialise: serialisePoint, +}; \ No newline at end of file diff --git a/yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation.nr b/yarn-project/noir-libs/noir-aztec/src/types/type_serialisation.nr similarity index 92% rename from yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation.nr rename to yarn-project/noir-libs/noir-aztec/src/types/type_serialisation.nr index d76e521..dfe738d 100644 --- a/yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation.nr +++ b/yarn-project/noir-libs/noir-aztec/src/types/type_serialisation.nr @@ -1,3 +1,4 @@ +mod bool_serialisation; mod field_serialisation; mod u32_serialisation; diff --git a/yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/bool_serialisation.nr b/yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/bool_serialisation.nr new file mode 100644 index 0000000..734f725 --- /dev/null +++ b/yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/bool_serialisation.nr @@ -0,0 +1,16 @@ +use crate::types::type_serialisation::TypeSerialisationInterface; + +global BOOL_SERIALISED_LEN: Field = 1; + +fn deserialiseBool(fields: [Field; BOOL_SERIALISED_LEN]) -> bool { + fields[0] as bool +} + +fn serialiseBool(value: bool) -> [Field; BOOL_SERIALISED_LEN] { + [value as Field] +} + +global BoolSerialisationMethods = TypeSerialisationInterface { + deserialise: deserialiseBool, + serialise: serialiseBool, +}; \ No newline at end of file diff --git a/yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation/field_serialisation.nr b/yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/field_serialisation.nr similarity index 82% rename from yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation/field_serialisation.nr rename to yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/field_serialisation.nr index 5352d0e..5fcaf37 100644 --- a/yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation/field_serialisation.nr +++ b/yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/field_serialisation.nr @@ -1,4 +1,4 @@ -use crate::state_vars::type_serialisation::TypeSerialisationInterface; +use crate::types::type_serialisation::TypeSerialisationInterface; global FIELD_SERIALISED_LEN: Field = 1; diff --git a/yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation/u32_serialisation.nr b/yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/u32_serialisation.nr similarity index 82% rename from yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation/u32_serialisation.nr rename to yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/u32_serialisation.nr index 21178a1..dd00ebf 100644 --- a/yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation/u32_serialisation.nr +++ b/yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/u32_serialisation.nr @@ -1,4 +1,4 @@ -use crate::state_vars::type_serialisation::TypeSerialisationInterface; +use crate::types::type_serialisation::TypeSerialisationInterface; global U32_SERIALISED_LEN: Field = 1;