Skip to content

Commit 201072b

Browse files
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 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 <mike@aztecprotocol.com>
1 parent bfc019f commit 201072b

File tree

10 files changed

+63
-24
lines changed

10 files changed

+63
-24
lines changed

yarn-project/noir-libs/noir-aztec/src/abi.nr

+17-13
Original file line numberDiff line numberDiff line change
@@ -358,21 +358,25 @@ global ARGS_HASH_CHUNK_LENGTH: u32 = 32;
358358
global ARGS_HASH_CHUNK_COUNT: u32 = 16;
359359

360360
fn hash_args<N>(args: [Field; N]) -> Field {
361-
let mut chunks_hashes = [0; ARGS_HASH_CHUNK_COUNT];
362-
for i in 0..ARGS_HASH_CHUNK_COUNT {
363-
let mut chunk_hash = 0;
364-
let start_chunk_index = i * ARGS_HASH_CHUNK_LENGTH;
365-
if start_chunk_index < (args.len() as u32) {
366-
let mut chunk_args = [0; ARGS_HASH_CHUNK_LENGTH];
367-
for j in 0..ARGS_HASH_CHUNK_LENGTH {
368-
let item_index = i * ARGS_HASH_CHUNK_LENGTH + j;
369-
if item_index < (args.len() as u32) {
370-
chunk_args[j] = args[item_index];
361+
if args.len() == 0 {
362+
0
363+
} else {
364+
let mut chunks_hashes = [0; ARGS_HASH_CHUNK_COUNT];
365+
for i in 0..ARGS_HASH_CHUNK_COUNT {
366+
let mut chunk_hash = 0;
367+
let start_chunk_index = i * ARGS_HASH_CHUNK_LENGTH;
368+
if start_chunk_index < (args.len() as u32) {
369+
let mut chunk_args = [0; ARGS_HASH_CHUNK_LENGTH];
370+
for j in 0..ARGS_HASH_CHUNK_LENGTH {
371+
let item_index = i * ARGS_HASH_CHUNK_LENGTH + j;
372+
if item_index < (args.len() as u32) {
373+
chunk_args[j] = args[item_index];
374+
}
371375
}
376+
chunk_hash = dep::std::hash::pedersen_with_separator(chunk_args, GENERATOR_INDEX__FUNCTION_ARGS)[0];
372377
}
373-
chunk_hash = dep::std::hash::pedersen_with_separator(chunk_args, GENERATOR_INDEX__FUNCTION_ARGS)[0];
378+
chunks_hashes[i] = chunk_hash;
374379
}
375-
chunks_hashes[i] = chunk_hash;
380+
dep::std::hash::pedersen_with_separator(chunks_hashes, GENERATOR_INDEX__FUNCTION_ARGS)[0]
376381
}
377-
dep::std::hash::pedersen_with_separator(chunks_hashes, GENERATOR_INDEX__FUNCTION_ARGS)[0]
378382
}

yarn-project/noir-libs/noir-aztec/src/context.nr

+3-5
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ impl Context {
296296
contract_address: Field,
297297
function_selector: Field,
298298
args: [Field; ARGS_COUNT]
299-
) -> [Field; RETURN_VALUES_LENGTH] {
299+
) {
300300
let args_hash = hash_args(args);
301301
assert(args_hash == arguments::pack_arguments(args));
302302
self.call_public_function_with_packed_args(contract_address, function_selector, args_hash)
@@ -306,7 +306,7 @@ impl Context {
306306
&mut self,
307307
contract_address: Field,
308308
function_selector: Field,
309-
) -> [Field; RETURN_VALUES_LENGTH] {
309+
) {
310310
self.call_public_function_with_packed_args(contract_address, function_selector, 0)
311311
}
312312

@@ -315,7 +315,7 @@ impl Context {
315315
contract_address: Field,
316316
function_selector: Field,
317317
args_hash: Field
318-
) -> [Field; RETURN_VALUES_LENGTH] {
318+
) {
319319
let fields = enqueue_public_function_call_internal(
320320
contract_address,
321321
function_selector,
@@ -372,7 +372,5 @@ impl Context {
372372
assert(item.public_inputs.call_context.storage_contract_address == contract_address);
373373

374374
self.public_call_stack.push(item.hash());
375-
376-
item.public_inputs.return_values
377375
}
378376
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
mod immutable_singleton;
22
mod map;
33
mod public_state;
4-
mod type_serialisation;
54
mod set;
65
mod singleton;

yarn-project/noir-libs/noir-aztec/src/state_vars/public_state.nr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::oracle::storage::storage_read;
22
use crate::oracle::storage::storage_write;
3-
use crate::state_vars::type_serialisation::TypeSerialisationInterface;
3+
use crate::types::type_serialisation::TypeSerialisationInterface;
44

55
struct PublicState<T, T_SERIALISED_LEN> {
66
storage_slot: Field,
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod option; // This can/should be moved out into an official noir library
12
mod point;
23
mod vec; // This can/should be moved out into an official noir library
3-
mod option; // This can/should be moved out into an official noir library
4+
mod type_serialisation;

yarn-project/noir-libs/noir-aztec/src/types/point.nr

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::types::type_serialisation::TypeSerialisationInterface;
2+
13
struct Point {
24
x: Field,
35
y: Field,
@@ -7,4 +9,22 @@ impl Point {
79
fn new(x: Field, y: Field) -> Self {
810
Point { x, y }
911
}
10-
}
12+
}
13+
14+
global POINT_SERIALISED_LEN: Field = 2;
15+
16+
fn deserialisePoint(fields: [Field; POINT_SERIALISED_LEN]) -> Point {
17+
Point {
18+
x: fields[0],
19+
y: fields[1],
20+
}
21+
}
22+
23+
fn serialisePoint(point: Point) -> [Field; POINT_SERIALISED_LEN] {
24+
[point.x, point.y]
25+
}
26+
27+
global PointSerialisationMethods = TypeSerialisationInterface {
28+
deserialise: deserialisePoint,
29+
serialise: serialisePoint,
30+
};

yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation.nr yarn-project/noir-libs/noir-aztec/src/types/type_serialisation.nr

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod bool_serialisation;
12
mod field_serialisation;
23
mod u32_serialisation;
34

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use crate::types::type_serialisation::TypeSerialisationInterface;
2+
3+
global BOOL_SERIALISED_LEN: Field = 1;
4+
5+
fn deserialiseBool(fields: [Field; BOOL_SERIALISED_LEN]) -> bool {
6+
fields[0] as bool
7+
}
8+
9+
fn serialiseBool(value: bool) -> [Field; BOOL_SERIALISED_LEN] {
10+
[value as Field]
11+
}
12+
13+
global BoolSerialisationMethods = TypeSerialisationInterface {
14+
deserialise: deserialiseBool,
15+
serialise: serialiseBool,
16+
};

yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation/field_serialisation.nr yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/field_serialisation.nr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::state_vars::type_serialisation::TypeSerialisationInterface;
1+
use crate::types::type_serialisation::TypeSerialisationInterface;
22

33
global FIELD_SERIALISED_LEN: Field = 1;
44

yarn-project/noir-libs/noir-aztec/src/state_vars/type_serialisation/u32_serialisation.nr yarn-project/noir-libs/noir-aztec/src/types/type_serialisation/u32_serialisation.nr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::state_vars::type_serialisation::TypeSerialisationInterface;
1+
use crate::types::type_serialisation::TypeSerialisationInterface;
22

33
global U32_SERIALISED_LEN: Field = 1;
44

0 commit comments

Comments
 (0)