Skip to content

Commit

Permalink
chore(avm): split up AVM test contract as it was growing too large (#…
Browse files Browse the repository at this point in the history
…5702)

Attempted to add new test functions for nested contract calls and the contract grew too large (all tests began failing on deployment).

This is prep for #4293

The only "new" code in this PR is flagged as new and just adds test cases that exemplify how the kernel fails to silo side-effects by the right contract address when nested calls are made to different contracts.
  • Loading branch information
dbanks12 authored Apr 11, 2024
1 parent 3f870b9 commit 5b8e812
Show file tree
Hide file tree
Showing 10 changed files with 490 additions and 351 deletions.
2 changes: 1 addition & 1 deletion noir-projects/aztec-nr/aztec/src/context/avm_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,4 @@ fn call_static<ARGS_COUNT, RET_SIZE>(
// TODO(5110): consider passing in calldata directly
temporary_function_selector: Field
) -> ([Field; RET_SIZE], u8) {}
// ^ return data ^ success
// ^ return data ^ success
2 changes: 2 additions & 0 deletions noir-projects/noir-contracts/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ members = [
"contracts/auth_contract",
"contracts/avm_initializer_test_contract",
"contracts/avm_test_contract",
"contracts/avm_nested_calls_test_contract",
"contracts/avm_acvm_interop_test_contract",
"contracts/fpc_contract",
"contracts/benchmarking_contract",
"contracts/card_game_contract",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "avm_acvm_interop_test_contract"
authors = [""]
compiler_version = ">=0.25.0"
type = "contract"

[dependencies]
aztec = { path = "../../../aztec-nr/aztec" }
authwit = { path = "../../../aztec-nr/authwit" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use dep::aztec::protocol_types::traits::{Serialize, Deserialize};

contract AvmAcvmInteropTest {
// Libs
use dep::aztec::protocol_types::address::AztecAddress;
use dep::aztec::context::gas::GasOpts;
use dep::aztec::context::public_context::FunctionReturns;
use dep::aztec::protocol_types::abis::function_selector::FunctionSelector;
use dep::authwit::{auth::{assert_current_call_valid_authwit, assert_current_call_valid_authwit_public}};

// Use the standard context interface to emit a new nullifier
#[aztec(public-vm)]
fn new_nullifier(nullifier: Field) {
context.push_new_nullifier(nullifier, 0);
}

/************************************************************************
* ACVM interoperability
************************************************************************/
#[aztec(public)]
fn constant_field_acvm() -> pub Field {
123456
}

#[aztec(public-vm)]
fn constant_field_avm() -> pub Field {
123456
}

#[aztec(public)]
fn new_nullifier_acvm(nullifier: Field) -> pub Field {
context.push_new_nullifier(nullifier, 0);
}

#[aztec(public)]
fn assert_unsiloed_nullifier_acvm(unsiloed_nullifier: Field) {
assert(context.nullifier_exists(unsiloed_nullifier, context.this_address()));
}

#[aztec(public-vm)]
fn call_acvm_from_avm() -> pub Field {
context.call_public_function(
context.this_address(),
FunctionSelector::from_signature("constant_field_acvm()"),
[],
GasOpts::default()
).deserialize_into()
}

#[aztec(public)]
fn call_avm_from_acvm() -> pub Field {
context.call_public_function(
context.this_address(),
FunctionSelector::from_signature("constant_field_avm()"),
[],
GasOpts::default()
).deserialize_into()
}

#[aztec(public-vm)]
fn avm_to_acvm_call(selector: FunctionSelector, args: Field) {
context.call_public_function(context.this_address(), selector, [args], GasOpts::default()).assert_empty();
}

/************************************************************************
* Authwit functions
************************************************************************/
#[aztec(public-vm)]
fn test_authwit_send_money(from: AztecAddress, _to: AztecAddress, _amount: Field) {
assert_current_call_valid_authwit_public(&mut context, from);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "avm_nested_calls_test_contract"
authors = [""]
compiler_version = ">=0.25.0"
type = "contract"

[dependencies]
aztec = { path = "../../../aztec-nr/aztec" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use dep::aztec::protocol_types::traits::{Serialize, Deserialize};

contract AvmNestedCallsTest {
// Libs
use dep::aztec::state_vars::PublicMutable;
use dep::aztec::protocol_types::address::AztecAddress;
use dep::aztec::context::gas::GasOpts;
use dep::aztec::context::public_context::FunctionReturns;
use dep::aztec::protocol_types::abis::function_selector::FunctionSelector;

#[aztec(storage)]
struct Storage {
single: PublicMutable<Field>,
}

/************************************************************************
* Storage
************************************************************************/
#[aztec(public-vm)]
fn set_storage_single(a: Field) {
storage.single.write(a);
}

#[aztec(public-vm)]
fn add_args_return(arg_a: Field, arg_b: Field) -> pub Field {
arg_a + arg_b
}

// Use the standard context interface to emit a new nullifier
#[aztec(public-vm)]
fn new_nullifier(nullifier: Field) {
context.push_new_nullifier(nullifier, 0);
}

// Directly call the external call opcode to initiate a nested call to the add function
#[aztec(public-vm)]
fn raw_nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field {
let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field();

// Nested call
let results = context.call_public_function_raw(
GasOpts::default(),
context.this_address(),
selector,
[arg_a, arg_b]
);
let data_to_return: [Field; 1] = results.0;
// this explicit size is necessary to ensure that ret_size is compile-time
// (ensure the data_to_return is in a HeapArray not a HeapVector)
let success: u8 = results.1;

assert(success == 1, "Call failed");

let add_result = data_to_return[0];
add_result
}

// Directly call the external call opcode to initiate a nested call to the add function with user-specified gas
#[aztec(public-vm)]
fn raw_nested_call_to_add_with_gas(
arg_a: Field,
arg_b: Field,
l1_gas: Field,
l2_gas: Field,
da_gas: Field
) -> pub Field {
let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field();

// Nested call
let results = context.call_public_function_raw(
GasOpts::new(l1_gas, l2_gas, da_gas),
context.this_address(),
selector,
[arg_a, arg_b]
);
let data_to_return: [Field; 1] = results.0;
// this explicit size is necessary to ensure that ret_size is compile-time
// (ensure the data_to_return is in a HeapArray not a HeapVector)
let _success: u8 = results.1;

let add_result = data_to_return[0];
add_result
}

// Use the `call_public_function` wrapper to initiate a nested call to the add function
#[aztec(public-vm)]
fn nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field {
let selector = FunctionSelector::from_signature("add_args_return(Field,Field)");

// Nested call using standard context interface function
context.call_public_function(
context.this_address(),
selector,
[arg_a, arg_b],
GasOpts::default()
).deserialize_into()
}

// Directly call_static the external call opcode to initiate a nested call to the add function
#[aztec(public-vm)]
fn raw_nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub (Field, u8) {
let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field();

let (result_data, success): ([Field; 1], u8) = context.static_call_public_function_raw(
GasOpts::default(),
context.this_address(),
selector,
[arg_a, arg_b]
);

(result_data[0], success)
}

// Directly call_static `set_storage_single`. Should fail since it's accessing storage.
#[aztec(public-vm)]
fn raw_nested_static_call_to_set_storage() -> pub u8 {
let selector = FunctionSelector::from_signature("set_storage_single(Field)").to_field();
let calldata: [Field; 1] = [20];

let (_data_to_return, success): ([Field; 0], u8) = context.static_call_public_function_raw(GasOpts::default(), context.this_address(), selector, calldata);

success
}

// Indirectly call_static the external call opcode to initiate a nested call to the add function
#[aztec(public-vm)]
fn nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub Field {
let selector = FunctionSelector::from_signature("add_args_return(Field,Field)");

context.static_call_public_function(
context.this_address(),
selector,
[arg_a, arg_b],
GasOpts::default()
).deserialize_into()
}

// Indirectly call_static `set_storage_single`. Should revert since it's accessing storage.
#[aztec(public-vm)]
fn nested_static_call_to_set_storage() {
let selector = FunctionSelector::from_signature("set_storage_single(Field)");
let calldata: [Field; 1] = [20];

context.static_call_public_function(context.this_address(), selector, calldata, GasOpts::default()).assert_empty();
}

#[aztec(public-vm)]
fn create_same_nullifier_in_nested_call(nestedAddress: AztecAddress, nullifier: Field) {
context.push_new_nullifier(nullifier, 0);

let selector = FunctionSelector::from_signature("new_nullifier(Field)");
let calldata: [Field; 1] = [nullifier];
let _ : FunctionReturns<0> = context.call_public_function(nestedAddress, selector, calldata, GasOpts::default());
}

#[aztec(public-vm)]
fn create_different_nullifier_in_nested_call(nestedAddress: AztecAddress, nullifier: Field) {
context.push_new_nullifier(nullifier, 0);

let selector = FunctionSelector::from_signature("new_nullifier(Field)");
let calldata: [Field; 1] = [nullifier + 1];
let _ : FunctionReturns<0> = context.call_public_function(nestedAddress, selector, calldata, GasOpts::default());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ type = "contract"
[dependencies]
aztec = { path = "../../../aztec-nr/aztec" }
compressed_string = { path = "../../../aztec-nr/compressed-string" }
authwit = { path = "../../../aztec-nr/authwit" }
Loading

0 comments on commit 5b8e812

Please sign in to comment.