Skip to content

Commit

Permalink
feat: static call support in aztec.nr and acir-simulator (#4106)
Browse files Browse the repository at this point in the history
Closes #4036,
#2872

Added support for static calls, making sure callcontext is properly
forwarded and checked in the simulator before reaching the kernel
circuits.
  • Loading branch information
Thunkar authored Feb 14, 2024
1 parent 5f5bf16 commit 5f9546a
Show file tree
Hide file tree
Showing 27 changed files with 413 additions and 42 deletions.
13 changes: 13 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,17 @@ jobs:
name: "Test"
command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_nested_contract.test.ts

e2e-static-calls:
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small
steps:
- *checkout
- *setup_env
- run:
name: "Test"
command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_static_calls.test.ts

e2e-non-contract-account:
docker:
- image: aztecprotocol/alpine-build-image
Expand Down Expand Up @@ -1308,6 +1319,7 @@ workflows:
- e2e-state-vars: *e2e_test
- e2e-block-building: *e2e_test
- e2e-nested-contract: *e2e_test
- e2e-static-calls: *e2e_test
- e2e-non-contract-account: *e2e_test
- e2e-multiple-accounts-1-enc-key: *e2e_test
- e2e-cli: *e2e_test
Expand Down Expand Up @@ -1349,6 +1361,7 @@ workflows:
- e2e-state-vars
- e2e-block-building
- e2e-nested-contract
- e2e-static-calls
- e2e-non-contract-account
- e2e-multiple-accounts-1-enc-key
- e2e-cli
Expand Down
14 changes: 12 additions & 2 deletions noir-projects/aztec-nr/authwit/src/entrypoint/app.nr
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,19 @@ impl AppPayload {
for call in self.function_calls {
if !call.target_address.is_zero() {
if call.is_public {
context.call_public_function_with_packed_args(call.target_address, call.function_selector, call.args_hash);
context.call_public_function_with_packed_args(
call.target_address,
call.function_selector,
call.args_hash,
false
);
} else {
let _result = context.call_private_function_with_packed_args(call.target_address, call.function_selector, call.args_hash);
let _result = context.call_private_function_with_packed_args(
call.target_address,
call.function_selector,
call.args_hash,
false
);
}
}
}
Expand Down
14 changes: 12 additions & 2 deletions noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,19 @@ impl FeePayload {
for call in self.function_calls {
if !call.target_address.is_zero() {
if call.is_public {
context.call_public_function_with_packed_args(call.target_address, call.function_selector, call.args_hash);
context.call_public_function_with_packed_args(
call.target_address,
call.function_selector,
call.args_hash,
false
);
} else {
let _result = context.call_private_function_with_packed_args(call.target_address, call.function_selector, call.args_hash);
let _result = context.call_private_function_with_packed_args(
call.target_address,
call.function_selector,
call.args_hash,
false
);
}
}
}
Expand Down
64 changes: 53 additions & 11 deletions noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -249,28 +249,49 @@ impl PrivateContext {
) -> [Field; RETURN_VALUES_LENGTH] {
let args_hash = hash_args(args);
assert(args_hash == arguments::pack_arguments(args));
self.call_private_function_with_packed_args(contract_address, function_selector, args_hash)
self.call_private_function_with_packed_args(contract_address, function_selector, args_hash, false)
}

pub fn call_private_function_static<ARGS_COUNT>(
&mut self,
contract_address: AztecAddress,
function_selector: FunctionSelector,
args: [Field; ARGS_COUNT]
) -> [Field; RETURN_VALUES_LENGTH] {
let args_hash = hash_args(args);
assert(args_hash == arguments::pack_arguments(args));
self.call_private_function_with_packed_args(contract_address, function_selector, args_hash, true)
}

pub fn call_private_function_no_args(
&mut self,
contract_address: AztecAddress,
function_selector: FunctionSelector
) -> [Field; RETURN_VALUES_LENGTH] {
self.call_private_function_with_packed_args(contract_address, function_selector, 0)
self.call_private_function_with_packed_args(contract_address, function_selector, 0, false)
}

pub fn call_private_function_no_args_static(
&mut self,
contract_address: AztecAddress,
function_selector: FunctionSelector
) -> [Field; RETURN_VALUES_LENGTH] {
self.call_private_function_with_packed_args(contract_address, function_selector, 0, true)
}

pub fn call_private_function_with_packed_args(
fn call_private_function_with_packed_args(
&mut self,
contract_address: AztecAddress,
function_selector: FunctionSelector,
args_hash: Field
args_hash: Field,
is_static_call: bool
) -> [Field; RETURN_VALUES_LENGTH] {
let item = call_private_function_internal(
contract_address,
function_selector,
args_hash,
self.side_effect_counter
self.side_effect_counter,
is_static_call
);

assert_eq(item.public_inputs.call_context.start_side_effect_counter, self.side_effect_counter);
Expand All @@ -286,7 +307,7 @@ impl PrivateContext {
// the msg_sender in the nested call to be equal to our address, and the execution context address
// for the nested call to be equal to the address we actually called.
assert(item.public_inputs.call_context.is_delegate_call == false);
assert(item.public_inputs.call_context.is_static_call == false);
assert(item.public_inputs.call_context.is_static_call == is_static_call);
assert(item.public_inputs.call_context.is_contract_deployment == false);
assert(
item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address)
Expand All @@ -306,28 +327,49 @@ impl PrivateContext {
) {
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)
self.call_public_function_with_packed_args(contract_address, function_selector, args_hash, false)
}

pub fn call_public_function_static<ARGS_COUNT>(
&mut self,
contract_address: AztecAddress,
function_selector: FunctionSelector,
args: [Field; ARGS_COUNT]
) {
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, true)
}

pub fn call_public_function_no_args(
&mut self,
contract_address: AztecAddress,
function_selector: FunctionSelector
) {
self.call_public_function_with_packed_args(contract_address, function_selector, 0)
self.call_public_function_with_packed_args(contract_address, function_selector, 0, false)
}

pub fn call_public_function_no_args_static(
&mut self,
contract_address: AztecAddress,
function_selector: FunctionSelector
) {
self.call_public_function_with_packed_args(contract_address, function_selector, 0, true)
}

pub fn call_public_function_with_packed_args(
&mut self,
contract_address: AztecAddress,
function_selector: FunctionSelector,
args_hash: Field
args_hash: Field,
is_static_call: bool
) {
let fields = enqueue_public_function_call_internal(
contract_address,
function_selector,
args_hash,
self.side_effect_counter
self.side_effect_counter,
is_static_call
);

let mut reader = Reader::new(fields);
Expand Down Expand Up @@ -370,7 +412,7 @@ impl PrivateContext {
// the msg_sender in the nested call to be equal to our address, and the execution context address
// for the nested call to be equal to the address we actually called.
assert(item.public_inputs.call_context.is_delegate_call == false);
assert(item.public_inputs.call_context.is_static_call == false);
assert(item.public_inputs.call_context.is_static_call == is_static_call);
assert(item.public_inputs.call_context.is_contract_deployment == false);
assert(
item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address)
Expand Down
43 changes: 41 additions & 2 deletions noir-projects/aztec-nr/aztec/src/context/public_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,53 @@ impl PublicContext {
) -> [Field; RETURN_VALUES_LENGTH] {
let args_hash = hash_args(args);
assert(args_hash == arguments::pack_arguments(args));
call_public_function_internal(contract_address, function_selector, args_hash)
call_public_function_internal(
contract_address,
function_selector,
args_hash,
false
)
}

pub fn call_public_function_static<ARGS_COUNT>(
_self: Self,
contract_address: AztecAddress,
function_selector: FunctionSelector,
args: [Field; ARGS_COUNT],
) -> [Field; RETURN_VALUES_LENGTH] {
let args_hash = hash_args(args);
assert(args_hash == arguments::pack_arguments(args));
call_public_function_internal(
contract_address,
function_selector,
args_hash,
true
)
}

pub fn call_public_function_no_args(
_self: Self,
contract_address: AztecAddress,
function_selector: FunctionSelector
) -> [Field; RETURN_VALUES_LENGTH] {
call_public_function_internal(contract_address, function_selector, 0)
call_public_function_internal(
contract_address,
function_selector,
0,
false,
)
}

pub fn call_public_function_no_args_static(
_self: Self,
contract_address: AztecAddress,
function_selector: FunctionSelector,
) -> [Field; RETURN_VALUES_LENGTH] {
call_public_function_internal(
contract_address,
function_selector,
0,
true,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,23 @@ fn call_private_function_oracle(
_contract_address: AztecAddress,
_function_selector: FunctionSelector,
_args_hash: Field,
_start_side_effect_counter: u32
_start_side_effect_counter: u32,
_is_static_call: bool
) -> [Field; PRIVATE_CALL_STACK_ITEM_LENGTH] {}

unconstrained pub fn call_private_function_internal(
contract_address: AztecAddress,
function_selector: FunctionSelector,
args_hash: Field,
start_side_effect_counter: u32
start_side_effect_counter: u32,
is_static_call: bool
) -> PrivateCallStackItem {
let fields = call_private_function_oracle(
contract_address,
function_selector,
args_hash,
start_side_effect_counter
start_side_effect_counter,
is_static_call
);

PrivateCallStackItem::deserialize(fields)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@ fn enqueue_public_function_call_oracle(
_contract_address: AztecAddress,
_function_selector: FunctionSelector,
_args_hash: Field,
_side_effect_counter: u32
_side_effect_counter: u32,
_is_static_call: bool
) -> [Field; ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_SIZE] {}

unconstrained pub fn enqueue_public_function_call_internal(
contract_address: AztecAddress,
function_selector: FunctionSelector,
args_hash: Field,
side_effect_counter: u32
side_effect_counter: u32,
is_static_call: bool
) -> [Field; ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_SIZE] {
enqueue_public_function_call_oracle(
contract_address,
function_selector,
args_hash,
side_effect_counter
side_effect_counter,
is_static_call
)
}
8 changes: 5 additions & 3 deletions noir-projects/aztec-nr/aztec/src/oracle/public_call.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ use dep::protocol_types::{abis::function_selector::FunctionSelector, address::Az
fn call_public_function_oracle(
_contract_address: AztecAddress,
_function_selector: FunctionSelector,
_args_hash: Field
_args_hash: Field,
_is_static_call: bool
) -> [Field; RETURN_VALUES_LENGTH] {}

unconstrained pub fn call_public_function_internal(
contract_address: AztecAddress,
function_selector: FunctionSelector,
args_hash: Field
args_hash: Field,
is_static_call: bool
) -> [Field; RETURN_VALUES_LENGTH] {
call_public_function_oracle(contract_address, function_selector, args_hash)
call_public_function_oracle(contract_address, function_selector, args_hash, is_static_call)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ type = "contract"

[dependencies]
aztec = { path = "../../../aztec-nr/aztec" }
value_note = { path = "../../../aztec-nr/value-note" }

35 changes: 32 additions & 3 deletions noir-projects/noir-contracts/contracts/child_contract/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,28 @@ contract Child {
use dep::std::option::Option;

use dep::aztec::{
context::{PrivateContext, PublicContext, Context}, log::emit_unencrypted_log,
state_vars::public_state::PublicState
context::{PrivateContext, PublicContext, Context},
log::emit_unencrypted_log,
state_vars::{
public_state::PublicState,
set::Set
},
protocol_types::{
abis::{
function_selector::FunctionSelector,
call_context::CallContext
},
address::AztecAddress,
},
note::{
note_getter_options::NoteGetterOptions,
}
};
use dep::aztec::protocol_types::{abis::{call_context::CallContext, function_selector::FunctionSelector}, address::AztecAddress};
use dep::value_note::value_note::ValueNote;

struct Storage {
current_value: PublicState<Field>,
a_private_value: Set<ValueNote>,
}

#[aztec(private)]
Expand Down Expand Up @@ -56,6 +71,20 @@ contract Child {
new_value
}

#[aztec(private)]
fn privateSetValue(new_value: Field, owner: AztecAddress) -> Field {
let mut note = ValueNote::new(new_value, owner);
storage.a_private_value.insert(&mut note, true);
new_value
}

#[aztec(private)]
fn privateGetValue(amount: Field, owner: AztecAddress) -> Field {
let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, owner.to_field(), Option::none()).set_limit(1);
let notes = storage.a_private_value.get_notes(options);
notes[0].unwrap_unchecked().value
}

// Increments `current_value` by `new_value`
#[aztec(public)]
fn pubIncValue(new_value: Field) -> Field {
Expand Down
Loading

0 comments on commit 5f9546a

Please sign in to comment.