Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(avm): Set gas allowance in public calls #5567

Merged
merged 4 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions avm-transpiler/src/transpile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,9 @@ fn handle_getter_instruction(
"avmOpcodeVersion" => AvmOpcode::VERSION,
"avmOpcodeBlockNumber" => AvmOpcode::BLOCKNUMBER,
"avmOpcodeTimestamp" => AvmOpcode::TIMESTAMP,
"avmOpcodeL1GasLeft" => AvmOpcode::L1GASLEFT,
"avmOpcodeL2GasLeft" => AvmOpcode::L2GASLEFT,
"avmOpcodeDaGasLeft" => AvmOpcode::DAGASLEFT,
// "callStackDepth" => AvmOpcode::CallStackDepth,
_ => panic!(
"Transpiler doesn't know how to process ForeignCall function {:?}",
Expand Down
1 change: 1 addition & 0 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ library Constants {
uint256 internal constant INITIALIZATION_SLOT_SEPARATOR = 1000_000_000;
uint256 internal constant INITIAL_L2_BLOCK_NUM = 1;
uint256 internal constant BLOB_SIZE_IN_BYTES = 126976;
uint256 internal constant NESTED_CALL_L2_GAS_BUFFER = 20000;
uint256 internal constant MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 15000;
uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000;
uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000;
Expand Down
9 changes: 7 additions & 2 deletions noir-projects/aztec-nr/authwit/src/auth.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use dep::aztec::protocol_types::{
abis::function_selector::FunctionSelector, address::AztecAddress,
constants::{GENERATOR_INDEX__AUTHWIT_INNER, GENERATOR_INDEX__AUTHWIT_OUTER}, hash::pedersen_hash
};
use dep::aztec::{context::{PrivateContext, PublicContext, Context}, hash::hash_args_array};
use dep::aztec::{context::{PrivateContext, PublicContext, Context, gas::GasOpts}, hash::hash_args_array};

global IS_VALID_SELECTOR = 0xabf64ad4; // 4 first bytes of keccak256("IS_VALID()")

Expand All @@ -21,7 +21,12 @@ pub fn assert_current_call_valid_authwit(context: &mut PrivateContext, on_behalf
pub fn assert_current_call_valid_authwit_public(context: &mut PublicContext, on_behalf_of: AztecAddress) {
let function_selector = FunctionSelector::from_signature("spend_public_authwit(Field)");
let inner_hash = compute_inner_authwit_hash([context.msg_sender().to_field(), context.selector().to_field(), context.args_hash]);
let result = context.call_public_function(on_behalf_of, function_selector, [inner_hash])[0];
let result = context.call_public_function(
on_behalf_of,
function_selector,
[inner_hash],
GasOpts::default()
)[0];
assert(result == IS_VALID_SELECTOR, "Message not authorized by account");
}
// docs:end:assert_current_call_valid_authwit_public
Expand Down
1 change: 1 addition & 0 deletions noir-projects/aztec-nr/aztec/src/context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod private_context;
mod public_context;
mod avm_context;
mod interface;
mod gas;

use interface::ContextInterface;
use private_context::PrivateContext;
Expand Down
58 changes: 44 additions & 14 deletions noir-projects/aztec-nr/aztec/src/context/avm_context.nr
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use dep::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH, header::Header};
use dep::protocol_types::{
address::{AztecAddress, EthAddress},
constants::{L1_TO_L2_MESSAGE_LENGTH, NESTED_CALL_L2_GAS_BUFFER, RETURN_VALUES_LENGTH},
header::Header
};
use dep::protocol_types::traits::Serialize;
use dep::protocol_types::abis::function_selector::FunctionSelector;
use dep::protocol_types::abis::public_circuit_public_inputs::PublicCircuitPublicInputs;
use dep::protocol_types::constants::RETURN_VALUES_LENGTH;
use crate::context::inputs::avm_context_inputs::AvmContextInputs;
use crate::context::interface::ContextInterface;
use crate::context::interface::PublicContextInterface;
use crate::context::gas::GasOpts;

struct AvmContext {
inputs: AvmContextInputs,
Expand Down Expand Up @@ -54,22 +58,32 @@ impl AvmContext {

fn call_public_function_raw<ARGS_COUNT, RET_COUNT>(
self: &mut Self,
gas: [Field; 3],
gas: GasOpts,
contract_address: AztecAddress,
temporary_function_selector: Field,
args: [Field; ARGS_COUNT]
) -> ([Field; RET_COUNT], u8) {
call(gas, contract_address, args, temporary_function_selector)
call(
gas_for_call(gas),
contract_address,
args,
temporary_function_selector
)
}

fn static_call_public_function_raw<ARGS_COUNT, RET_COUNT>(
self: &mut Self,
gas: [Field; 3],
gas: GasOpts,
contract_address: AztecAddress,
temporary_function_selector: Field,
args: [Field; ARGS_COUNT]
) -> ([Field; RET_COUNT], u8) {
call_static(gas, contract_address, args, temporary_function_selector)
call_static(
gas_for_call(gas),
contract_address,
args,
temporary_function_selector
)
}
}

Expand Down Expand Up @@ -121,12 +135,11 @@ impl PublicContextInterface for AvmContext {
self: &mut Self,
contract_address: AztecAddress,
temporary_function_selector: FunctionSelector,
args: [Field; ARGS_COUNT]
args: [Field; ARGS_COUNT],
gas_opts: GasOpts
) -> [Field; RETURN_VALUES_LENGTH] {
let gas = [/*l1_gas*/10000, /*l2_gas*/10000, /*da_gas*/10000];

let results = call(
gas,
gas_for_call(gas_opts),
contract_address,
args,
temporary_function_selector.to_field()
Expand All @@ -142,12 +155,11 @@ impl PublicContextInterface for AvmContext {
self: &mut Self,
contract_address: AztecAddress,
temporary_function_selector: FunctionSelector,
args: [Field; ARGS_COUNT]
args: [Field; ARGS_COUNT],
gas_opts: GasOpts
) -> [Field; RETURN_VALUES_LENGTH] {
let gas = [/*l1_gas*/10000, /*l2_gas*/10000, /*da_gas*/10000];

let (data_to_return, success): ([Field; RETURN_VALUES_LENGTH], u8) = call_static(
gas,
gas_for_call(gas_opts),
contract_address,
args,
temporary_function_selector.to_field()
Expand Down Expand Up @@ -203,6 +215,15 @@ impl ContextInterface for AvmContext {
}
}

// Helper functions
fn gas_for_call(user_gas: GasOpts) -> [Field; 3] {
[
user_gas.l1_gas.unwrap_or_else(|| l1_gas_left()),
user_gas.l2_gas.unwrap_or_else(|| l2_gas_left() - NESTED_CALL_L2_GAS_BUFFER),
user_gas.da_gas.unwrap_or_else(|| da_gas_left())
]
}

// AVM oracles (opcodes) follow, do not use directly.
#[oracle(avmOpcodeAddress)]
fn address() -> AztecAddress {}
Expand Down Expand Up @@ -240,6 +261,15 @@ fn block_number() -> Field {}
#[oracle(avmOpcodeTimestamp)]
fn timestamp() -> u64 {}

#[oracle(avmOpcodeL1GasLeft)]
fn l1_gas_left() -> Field {}

#[oracle(avmOpcodeL2GasLeft)]
fn l2_gas_left() -> Field {}

#[oracle(avmOpcodeDaGasLeft)]
fn da_gas_left() -> Field {}

#[oracle(avmOpcodeNoteHashExists)]
fn note_hash_exists(note_hash: Field, leaf_index: Field) -> u8 {}

Expand Down
15 changes: 15 additions & 0 deletions noir-projects/aztec-nr/aztec/src/context/gas.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
struct GasOpts {
l1_gas: Option<Field>,
l2_gas: Option<Field>,
da_gas: Option<Field>,
}

impl GasOpts {
pub fn default() -> Self {
GasOpts { l1_gas: Option::none(), l2_gas: Option::none(), da_gas: Option::none() }
}

pub fn new(l1_gas: Field, l2_gas: Field, da_gas: Field) -> Self {
GasOpts { l1_gas: Option::some(l1_gas), l2_gas: Option::some(l2_gas), da_gas: Option::some(da_gas) }
}
}
8 changes: 6 additions & 2 deletions noir-projects/aztec-nr/aztec/src/context/interface.nr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use dep::protocol_types::{
constants::RETURN_VALUES_LENGTH
};

use crate::context::gas::GasOpts;

trait ContextInterface {
fn push_new_note_hash(&mut self, note_hash: Field);
fn push_new_nullifier(&mut self, nullifier: Field, nullified_commitment: Field);
Expand Down Expand Up @@ -34,13 +36,15 @@ trait PublicContextInterface {
self: &mut Self,
contract_address: AztecAddress,
function_selector: FunctionSelector,
args: [Field; ARGS_COUNT]
args: [Field; ARGS_COUNT],
gas_opts: GasOpts
) -> [Field; RETURN_VALUES_LENGTH];
fn static_call_public_function<ARGS_COUNT>(
self: &mut Self,
contract_address: AztecAddress,
function_selector: FunctionSelector,
args: [Field; ARGS_COUNT]
args: [Field; ARGS_COUNT],
gas_opts: GasOpts
) -> [Field; RETURN_VALUES_LENGTH];
fn delegate_call_public_function<ARGS_COUNT>(
self: &mut Self,
Expand Down
11 changes: 8 additions & 3 deletions noir-projects/aztec-nr/aztec/src/context/public_context.nr
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::{
context::{inputs::PublicContextInputs, interface::ContextInterface, interface::PublicContextInterface},
context::{
inputs::PublicContextInputs, interface::ContextInterface, interface::PublicContextInterface,
gas::GasOpts
},
messaging::process_l1_to_l2_message,
oracle::{arguments, public_call::call_public_function_internal}, hash::hash_args_array
};
Expand Down Expand Up @@ -268,7 +271,8 @@ impl PublicContextInterface for PublicContext {
self: &mut Self,
contract_address: AztecAddress,
function_selector: FunctionSelector,
args: [Field; ARGS_COUNT]
args: [Field; ARGS_COUNT],
_gas: GasOpts
) -> [Field; RETURN_VALUES_LENGTH] {
let args_hash = hash_args_array(args);
assert(args_hash == arguments::pack_arguments(args));
Expand All @@ -279,7 +283,8 @@ impl PublicContextInterface for PublicContext {
self: &mut Self,
contract_address: AztecAddress,
function_selector: FunctionSelector,
args: [Field; ARGS_COUNT]
args: [Field; ARGS_COUNT],
_gas: GasOpts
) -> [Field; RETURN_VALUES_LENGTH] {
let args_hash = hash_args_array(args);
assert(args_hash == arguments::pack_arguments(args));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ contract AvmTest {
address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH,
contract_instance::ContractInstance
};
use dep::aztec::context::gas::GasOpts;
use dep::aztec::oracle::get_contract_instance::{get_contract_instance_avm, get_contract_instance_internal_avm};
use dep::aztec::protocol_types::abis::function_selector::FunctionSelector;
use dep::aztec::protocol_types::traits::ToField;
Expand Down Expand Up @@ -340,12 +341,16 @@ contract AvmTest {
#[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();
let gas = [/*l1_gas*/10000, /*l2_gas*/10000, /*da_gas*/10000];

// Nested call
let results = context.call_public_function_raw(gas, context.this_address(), selector, [arg_a, arg_b]);
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
// 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;

Expand All @@ -355,14 +360,46 @@ contract AvmTest {
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
let data_to_return: [Field; RETURN_VALUES_LENGTH] = context.call_public_function(context.this_address(), selector, [arg_a, arg_b]);
// this explicit size ^ is necessary to ensure that ret_size is compile-time
let data_to_return: [Field; RETURN_VALUES_LENGTH] = context.call_public_function(
context.this_address(),
selector,
[arg_a, arg_b],
GasOpts::default()
);
// this explicit size in the return variable is necessary to ensure that ret_size is compile-time
// (ensure the data_to_return is in a HeapArray not a HeapVector)

let add_result = data_to_return[0];
Expand All @@ -373,9 +410,13 @@ contract AvmTest {
#[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 gas = [/*l1_gas*/10000, /*l2_gas*/10000, /*da_gas*/10000];

let (result_data, success): ([Field; 1], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, [arg_a, arg_b]);
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)
}
Expand All @@ -384,10 +425,9 @@ contract AvmTest {
#[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 gas = [/*l1_gas*/10000, /*l2_gas*/10000, /*da_gas*/10000];
let calldata: [Field; 1] = [20];

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

success
}
Expand All @@ -397,7 +437,12 @@ contract AvmTest {
fn nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub Field {
let selector = FunctionSelector::from_signature("add_args_return(Field,Field)");

let result_data: [Field; RETURN_VALUES_LENGTH] = context.static_call_public_function(context.this_address(), selector, [arg_a, arg_b]);
let result_data: [Field; RETURN_VALUES_LENGTH] = context.static_call_public_function(
context.this_address(),
selector,
[arg_a, arg_b],
GasOpts::default()
);

result_data[0]
}
Expand All @@ -408,6 +453,6 @@ contract AvmTest {
let selector = FunctionSelector::from_signature("set_storage_single(Field)");
let calldata: [Field; 1] = [20];

let _resultData: [Field; RETURN_VALUES_LENGTH] = context.static_call_public_function(context.this_address(), selector, calldata);
let _resultData: [Field; RETURN_VALUES_LENGTH] = context.static_call_public_function(context.this_address(), selector, calldata, GasOpts::default());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ contract Benchmarking {
};
use dep::value_note::{utils::{increment, decrement}, value_note::ValueNote};

use dep::aztec::{context::Context};
use dep::aztec::{context::{Context, gas::GasOpts}};

#[aztec(storage)]
struct Storage {
Expand Down Expand Up @@ -47,7 +47,8 @@ contract Benchmarking {
let _callStackItem1 = context.call_public_function(
context.this_address(),
FunctionSelector::from_signature("broadcast((Field))"),
[owner.to_field()]
[owner.to_field()],
GasOpts::default()
);
}

Expand Down
Loading
Loading