Skip to content

Commit

Permalink
feat(noir): autogenerate contract interface for calling from external…
Browse files Browse the repository at this point in the history
… 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
noir-lang/noir#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
noir-lang/noir#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 <[email protected]>
  • Loading branch information
superstar0402 and iAmMichaelConnor committed Aug 14, 2023
1 parent bfc019f commit 201072b
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 24 deletions.
30 changes: 17 additions & 13 deletions yarn-project/noir-libs/noir-aztec/src/abi.nr
Original file line number Diff line number Diff line change
Expand Up @@ -358,21 +358,25 @@ global ARGS_HASH_CHUNK_LENGTH: u32 = 32;
global ARGS_HASH_CHUNK_COUNT: u32 = 16;

fn hash_args<N>(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]
}
8 changes: 3 additions & 5 deletions yarn-project/noir-libs/noir-aztec/src/context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
}

Expand All @@ -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,
Expand Down Expand Up @@ -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
}
}
1 change: 0 additions & 1 deletion yarn-project/noir-libs/noir-aztec/src/state_vars.nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
mod immutable_singleton;
mod map;
mod public_state;
mod type_serialisation;
mod set;
mod singleton;
Original file line number Diff line number Diff line change
@@ -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<T, T_SERIALISED_LEN> {
storage_slot: Field,
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/noir-libs/noir-aztec/src/types.nr
Original file line number Diff line number Diff line change
@@ -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
mod type_serialisation;
22 changes: 21 additions & 1 deletion yarn-project/noir-libs/noir-aztec/src/types/point.nr
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::types::type_serialisation::TypeSerialisationInterface;

struct Point {
x: Field,
y: Field,
Expand All @@ -7,4 +9,22 @@ impl Point {
fn new(x: Field, y: Field) -> Self {
Point { x, y }
}
}
}

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,
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod bool_serialisation;
mod field_serialisation;
mod u32_serialisation;

Expand Down
Original file line number Diff line number Diff line change
@@ -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,
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::state_vars::type_serialisation::TypeSerialisationInterface;
use crate::types::type_serialisation::TypeSerialisationInterface;

global FIELD_SERIALISED_LEN: Field = 1;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::state_vars::type_serialisation::TypeSerialisationInterface;
use crate::types::type_serialisation::TypeSerialisationInterface;

global U32_SERIALISED_LEN: Field = 1;

Expand Down

0 comments on commit 201072b

Please sign in to comment.