Skip to content

Commit

Permalink
feat(avm): Set gas allowance in public calls
Browse files Browse the repository at this point in the history
  • Loading branch information
spalladino committed Apr 4, 2024
1 parent 255ca72 commit 0e28cdc
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 61 deletions.
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 = 1000;
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
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
35 changes: 29 additions & 6 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 @@ -121,9 +125,14 @@ 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 gas = [
gas_opts.l1_gas.unwrap_or_else(|| l1_gas_left()),
gas_opts.l2_gas.unwrap_or_else(|| l2_gas_left() - NESTED_CALL_L2_GAS_BUFFER),
gas_opts.da_gas.unwrap_or_else(|| da_gas_left()),
];

let results = call(
gas,
Expand All @@ -142,9 +151,14 @@ 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 gas = [
gas_opts.l1_gas.unwrap_or_else(|| l1_gas_left()),
gas_opts.l2_gas.unwrap_or_else(|| l2_gas_left() - NESTED_CALL_L2_GAS_BUFFER),
gas_opts.da_gas.unwrap_or_else(|| da_gas_left()),
];

let (data_to_return, success): ([Field; RETURN_VALUES_LENGTH], u8) = call_static(
gas,
Expand Down Expand Up @@ -240,6 +254,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 {
fn empty() -> Self {
GasOpts { l1_gas: Option::none(), l2_gas: Option::none(), da_gas: Option::none() }
}

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 @@ -93,6 +93,8 @@ global INITIALIZATION_SLOT_SEPARATOR: Field = 1000_000_000;
global INITIAL_L2_BLOCK_NUM: Field = 1;
// 126976 = 31 * 4096;
global BLOB_SIZE_IN_BYTES: Field = 126976;
// How much gas is subtracted from L2GASLEFT when making a nested public call by default in the AVM
global NESTED_CALL_L2_GAS_BUFFER = 1000;

// CONTRACT CLASS CONSTANTS
global MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u64 = 15000;
Expand Down
1 change: 1 addition & 0 deletions yarn-project/circuits.js/src/constants.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const ARGS_HASH_CHUNK_COUNT = 64;
export const INITIALIZATION_SLOT_SEPARATOR = 1000_000_000;
export const INITIAL_L2_BLOCK_NUM = 1;
export const BLOB_SIZE_IN_BYTES = 126976;
export const NESTED_CALL_L2_GAS_BUFFER = 1000;
export const MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 15000;
export const MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000;
export const MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000;
Expand Down
32 changes: 32 additions & 0 deletions yarn-project/simulator/src/avm/opcodes/context_getters.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { initContext, initMachineState } from '../fixtures/index.js';
import { DAGasLeft, L1GasLeft, L2GasLeft } from './context_getters.js';

describe.each([
[L1GasLeft, 'l1GasLeft'],
[L2GasLeft, 'l2GasLeft'],
[DAGasLeft, 'daGasLeft'],
] as const)('Context getter instructions for machine state', (clsValue, key) => {
it(`${clsValue.name} should (de)serialize correctly`, () => {
const buf = Buffer.from([
clsValue.opcode, // opcode
0x01, // indirect
...Buffer.from('12345678', 'hex'), // dstOffset
]);
const inst = new clsValue(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678);

expect(clsValue.deserialize(buf)).toEqual(inst);
expect(inst.serialize()).toEqual(buf);
});

it(`${clsValue.name} should read '${key}' correctly`, async () => {
const value = 123456;
const instruction = new clsValue(/*indirect=*/ 0, /*dstOffset=*/ 0);
const context = initContext({ machineState: initMachineState({ [key]: value }) });

await instruction.execute(context);

const actual = context.machineState.memory.get(0).toNumber();
const expected = key === 'l2GasLeft' ? value - 110 : value; // l2gascost decreases when it's executed
expect(actual).toEqual(expected);
});
});
31 changes: 31 additions & 0 deletions yarn-project/simulator/src/avm/opcodes/context_getters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { AvmContext } from '../avm_context.js';
import { type MemoryValue, Uint32 } from '../avm_memory_types.js';
import { Opcode } from '../serialization/instruction_serialization.js';
import { GetterInstruction } from './instruction_impl.js';

export class L2GasLeft extends GetterInstruction {
static type: string = 'L2GASLEFT';
static readonly opcode: Opcode = Opcode.L2GASLEFT;

protected getValue(context: AvmContext): MemoryValue {
return new Uint32(context.machineState.l2GasLeft);
}
}

export class L1GasLeft extends GetterInstruction {
static type: string = 'L1GASLEFT';
static readonly opcode: Opcode = Opcode.L1GASLEFT;

protected getValue(context: AvmContext): MemoryValue {
return new Uint32(context.machineState.l1GasLeft);
}
}

export class DAGasLeft extends GetterInstruction {
static type: string = 'DAGASLEFT';
static readonly opcode: Opcode = Opcode.DAGASLEFT;

protected getValue(context: AvmContext): MemoryValue {
return new Uint32(context.machineState.daGasLeft);
}
}
Loading

0 comments on commit 0e28cdc

Please sign in to comment.