Skip to content

Commit

Permalink
Merge e8ccd89 into 6e651de
Browse files Browse the repository at this point in the history
  • Loading branch information
dbanks12 authored Oct 10, 2024
2 parents 6e651de + e8ccd89 commit 8722f80
Show file tree
Hide file tree
Showing 15 changed files with 92 additions and 29 deletions.
25 changes: 22 additions & 3 deletions barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1760,11 +1760,30 @@ TEST_F(AvmExecutionTests, daGasLeft)
validate_trace(std::move(trace), public_inputs);
}

TEST_F(AvmExecutionTests, ExecutorThrowsWithTooMuchGasAllocated)
{
std::string bytecode_hex = to_hex(OpCode::GETENVVAR_16) + // opcode GETENVVAR_16(sender)
"00" // Indirect flag
+ to_hex(static_cast<uint8_t>(EnvironmentVariable::SENDER)) + "0007"; // addr 7

std::vector<FF> calldata = {};
std::vector<FF> returndata = {};
std::vector<FF> public_inputs_vec(PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, 0);
public_inputs_vec[L2_START_GAS_LEFT_PCPI_OFFSET] = MAX_L2_GAS_PER_ENQUEUED_CALL + 1;

auto bytecode = hex_to_bytes(bytecode_hex);
auto instructions = Deserialization::parse(bytecode);

EXPECT_THROW_WITH_MESSAGE(
Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec),
"Cannot allocate more than MAX_L2_GAS_PER_ENQUEUED_CALL to the AVM for execution of an enqueued call");
}

// Should throw whenever the wrong number of public inputs are provided
TEST_F(AvmExecutionTests, ExecutorThrowsWithIncorrectNumberOfPublicInputs)
{
std::string bytecode_hex = to_hex(OpCode::GETENVVAR_16) + // opcode SENDER
"00" // Indirect flag
std::string bytecode_hex = to_hex(OpCode::GETENVVAR_16) + // opcode GETENVVAR_16(sender)
"00" // Indirect flag
+ to_hex(static_cast<uint8_t>(EnvironmentVariable::SENDER)) + "0007"; // addr 7

std::vector<FF> calldata = {};
Expand All @@ -1774,7 +1793,7 @@ TEST_F(AvmExecutionTests, ExecutorThrowsWithIncorrectNumberOfPublicInputs)
auto bytecode = hex_to_bytes(bytecode_hex);
auto instructions = Deserialization::parse(bytecode);

EXPECT_THROW_WITH_MESSAGE(Execution::gen_trace(instructions, calldata, returndata, public_inputs_vec),
EXPECT_THROW_WITH_MESSAGE(Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec),
"Public inputs vector is not of PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH");
}

Expand Down
15 changes: 15 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ template <typename FF_> VmPublicInputs<FF_> convert_public_inputs(std::vector<FF
throw_or_abort("Public inputs vector is not of PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH");
}

// WARNING: this must be constrained by the kernel!
// Here this is just a sanity check to prevent generation of proofs that
// will be thrown out by the kernel anyway.
if constexpr (IsAnyOf<FF_, bb::fr>) {
if (public_inputs_vec[L2_START_GAS_LEFT_PCPI_OFFSET] > MAX_L2_GAS_PER_ENQUEUED_CALL) {
throw_or_abort(
"Cannot allocate more than MAX_L2_GAS_PER_ENQUEUED_CALL to the AVM for execution of an enqueued call");
}
} else {
if (public_inputs_vec[L2_START_GAS_LEFT_PCPI_OFFSET].get_value() > MAX_L2_GAS_PER_ENQUEUED_CALL) {
throw_or_abort(
"Cannot allocate more than MAX_L2_GAS_PER_ENQUEUED_CALL to the AVM for execution of an enqueued call");
}
}

std::array<FF_, KERNEL_INPUTS_LENGTH>& kernel_inputs = std::get<KERNEL_INPUTS>(public_inputs);

// Copy items from PublicCircuitPublicInputs vector to public input columns
Expand Down
1 change: 1 addition & 0 deletions barretenberg/cpp/src/barretenberg/vm/aztec_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL 16
#define MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_CALL 16
#define MAX_UNENCRYPTED_LOGS_PER_CALL 4
#define MAX_L2_GAS_PER_ENQUEUED_CALL 6000000
#define AZTEC_ADDRESS_LENGTH 1
#define GAS_FEES_LENGTH 2
#define GAS_LENGTH 2
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 @@ -117,6 +117,7 @@ library Constants {
14061769416655647708490531650437236735160113654556896985372298487345;
uint256 internal constant DEFAULT_GAS_LIMIT = 1000000000;
uint256 internal constant DEFAULT_TEARDOWN_GAS_LIMIT = 100000000;
uint256 internal constant MAX_L2_GAS_PER_ENQUEUED_CALL = 6000000;
uint256 internal constant DEFAULT_MAX_FEE_PER_GAS = 10;
uint256 internal constant DEFAULT_INCLUSION_FEE = 0;
uint256 internal constant DA_BYTES_PER_FIELD = 32;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use dep::types::{
kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, enqueued_call_data::EnqueuedCallData,
public_call_request::PublicCallRequest, validation_requests::PublicValidationRequestArrayLengths
},
utils::arrays::array_length
constants::MAX_L2_GAS_PER_ENQUEUED_CALL, utils::arrays::array_length
};

pub struct EnqueuedCallDataValidator {
Expand Down Expand Up @@ -89,17 +89,23 @@ impl EnqueuedCallDataValidator {
// Validates that the start gas injected into the vm circuit matches the remaining gas.
fn validate_start_gas(self, previous_kernel: PublicKernelCircuitPublicInputs) {
let enqueued_call_start_gas = self.enqueued_call.data.start_gas_left;
// NOTE: the AVM circuit will fail to generate a proof if its "start gas" is > MAX_L2_GAS_PER_ENQUEUED_CALL,
// so the kernel never allocates more than that maximum to one enqueued call.
if self.phase != PublicKernelPhase.TEARDOWN {
// An enqueued call's start gas is the remaining gas left in the transaction after the previous kernel.
let tx_gas_limits = previous_kernel.constants.tx_context.gas_settings.gas_limits;
let computed_start_gas = tx_gas_limits.sub(previous_kernel.end.gas_used).sub(previous_kernel.end_non_revertible.gas_used);
let mut computed_start_gas = tx_gas_limits.sub(previous_kernel.end.gas_used).sub(previous_kernel.end_non_revertible.gas_used);
// Keep L2 gas below max
computed_start_gas.l2_gas = std::cmp::min(computed_start_gas.l2_gas, MAX_L2_GAS_PER_ENQUEUED_CALL);
assert_eq(
enqueued_call_start_gas, computed_start_gas, "Start gas for enqueued call does not match transaction gas left"
enqueued_call_start_gas, computed_start_gas, "Start gas for enqueued call does not match transaction gas left (with MAX_L2_GAS_PER_ENQUEUED_CALL applied)"
);
} else {
let teardown_gas_limit = previous_kernel.constants.tx_context.gas_settings.teardown_gas_limits;
let mut teardown_gas_limit = previous_kernel.constants.tx_context.gas_settings.teardown_gas_limits;
// Keep L2 gas below max
teardown_gas_limit.l2_gas = std::cmp::min(teardown_gas_limit.l2_gas, MAX_L2_GAS_PER_ENQUEUED_CALL);
assert_eq(
enqueued_call_start_gas, teardown_gas_limit, "Start gas for enqueued call does not match teardown gas allocation"
enqueued_call_start_gas, teardown_gas_limit, "Start gas for enqueued call does not match teardown gas allocation (with MAX_L2_GAS_PER_ENQUEUED_CALL applied)"
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ global DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bd
// GAS DEFAULTS
global DEFAULT_GAS_LIMIT: u32 = 1_000_000_000;
global DEFAULT_TEARDOWN_GAS_LIMIT: u32 = 100_000_000;
global MAX_L2_GAS_PER_ENQUEUED_CALL: u32 = 6_000_000;
global DEFAULT_MAX_FEE_PER_GAS: Field = 10;
global DEFAULT_INCLUSION_FEE: Field = 0;
global DA_BYTES_PER_FIELD: u32 = 32;
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 @@ -102,6 +102,7 @@ export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE =
14061769416655647708490531650437236735160113654556896985372298487345n;
export const DEFAULT_GAS_LIMIT = 1000000000;
export const DEFAULT_TEARDOWN_GAS_LIMIT = 100000000;
export const MAX_L2_GAS_PER_ENQUEUED_CALL = 6000000;
export const DEFAULT_MAX_FEE_PER_GAS = 10;
export const DEFAULT_INCLUSION_FEE = 0;
export const DA_BYTES_PER_FIELD = 32;
Expand Down
1 change: 1 addition & 0 deletions yarn-project/circuits.js/src/scripts/constants.in.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const CPP_CONSTANTS = [
'MEM_TAG_U64',
'MEM_TAG_U128',
'MEM_TAG_FF',
'MAX_L2_GAS_PER_ENQUEUED_CALL',
];

const CPP_GENERATORS: string[] = [];
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/circuits.js/src/structs/gas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { type FieldsOf } from '@aztec/foundation/types';

import { inspect } from 'util';

import { MAX_L2_GAS_PER_ENQUEUED_CALL } from '../constants.gen.js';
import { type GasFees } from './gas_fees.js';
import { type UInt32 } from './shared.js';

Expand Down Expand Up @@ -36,7 +37,7 @@ export class Gas {

/** Returns large enough gas amounts for testing purposes. */
static test() {
return new Gas(1e9, 1e9);
return new Gas(1e9, MAX_L2_GAS_PER_ENQUEUED_CALL);
}

isEmpty() {
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/simulator/src/avm/avm_simulator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { MAX_L2_GAS_PER_ENQUEUED_CALL } from '@aztec/circuits.js';
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';

import { strict as assert } from 'assert';
Expand All @@ -21,6 +22,10 @@ export class AvmSimulator {
private bytecode: Buffer | undefined;

constructor(private context: AvmContext) {
assert(
context.machineState.gasLeft.l2Gas <= MAX_L2_GAS_PER_ENQUEUED_CALL,
`Cannot allocate more than ${MAX_L2_GAS_PER_ENQUEUED_CALL} to the AVM for execution of an enqueued call`,
);
this.log = createDebugLogger(`aztec:avm_simulator:core(f:${context.environment.functionSelector.toString()})`);
}

Expand Down
4 changes: 2 additions & 2 deletions yarn-project/simulator/src/avm/fixtures/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isNoirCallStackUnresolved } from '@aztec/circuit-types';
import { GasFees, GlobalVariables } from '@aztec/circuits.js';
import { GasFees, GlobalVariables, MAX_L2_GAS_PER_ENQUEUED_CALL } from '@aztec/circuits.js';
import { FunctionSelector, getFunctionDebugMetadata } from '@aztec/foundation/abi';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { EthAddress } from '@aztec/foundation/eth-address';
Expand Down Expand Up @@ -91,7 +91,7 @@ export function initGlobalVariables(overrides?: Partial<GlobalVariables>): Globa
*/
export function initMachineState(overrides?: Partial<AvmMachineState>): AvmMachineState {
return AvmMachineState.fromState({
l2GasLeft: overrides?.l2GasLeft ?? 1e8,
l2GasLeft: overrides?.l2GasLeft ?? MAX_L2_GAS_PER_ENQUEUED_CALL,
daGasLeft: overrides?.daGasLeft ?? 1e8,
});
}
Expand Down
11 changes: 9 additions & 2 deletions yarn-project/simulator/src/public/enqueued_call_simulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
L2ToL1Message,
LogHash,
MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_CALL,
MAX_L2_GAS_PER_ENQUEUED_CALL,
MAX_L2_TO_L1_MSGS_PER_CALL,
MAX_NOTE_HASHES_PER_CALL,
MAX_NOTE_HASH_READ_REQUESTS_PER_CALL,
Expand Down Expand Up @@ -120,6 +121,12 @@ export class EnqueuedCallSimulator {
transactionFee: Fr,
phase: PublicKernelPhase,
): Promise<EnqueuedCallResult> {
// Gas allocated to an enqueued call can be different from the available gas
// if there is more gas available than the max allocation per enqueued call.
const allocatedGas = new Gas(
/*daGas=*/ availableGas.daGas,
/*l2Gas=*/ Math.min(availableGas.l2Gas, MAX_L2_GAS_PER_ENQUEUED_CALL),
);
const pendingNullifiers = this.getSiloedPendingNullifiers(previousPublicKernelOutput);
const startSideEffectCounter = previousPublicKernelOutput.endSideEffectCounter + 1;

Expand All @@ -140,7 +147,7 @@ export class EnqueuedCallSimulator {
const result = await this.publicExecutor.simulate(
executionRequest,
constants,
availableGas,
allocatedGas,
tx.data.constants.txContext,
pendingNullifiers,
transactionFee,
Expand All @@ -167,7 +174,7 @@ export class EnqueuedCallSimulator {
accumulatedData,
startSideEffectCounter,
startSideEffectCounter,
availableGas,
allocatedGas,
result.transactionFee,
result.reverted,
);
Expand Down
6 changes: 2 additions & 4 deletions yarn-project/simulator/src/public/execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import {
} from '@aztec/circuits.js';
import { computeVarArgsHash } from '@aztec/circuits.js/hash';

import { type Gas as AvmGas } from '../avm/avm_gas.js';

/**
* The public function execution result.
*/
Expand All @@ -36,9 +34,9 @@ export interface PublicExecutionResult {
/** The side effect counter after executing this function call */
endSideEffectCounter: Fr;
/** How much gas was available for this public execution. */
startGasLeft: AvmGas;
startGasLeft: Gas;
/** How much gas was left after this public execution. */
endGasLeft: AvmGas;
endGasLeft: Gas;
/** Transaction fee set for this tx. */
transactionFee: Fr;

Expand Down
10 changes: 5 additions & 5 deletions yarn-project/simulator/src/public/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class PublicExecutor {
* Executes a public execution request.
* @param executionRequest - The execution to run.
* @param constants - The constants (including global variables) to use.
* @param availableGas - The gas available at the start of this enqueued call.
* @param allocatedGas - The gas available at the start of this enqueued call.
* @param txContext - Transaction context.
* @param pendingSiloedNullifiers - The pending nullifier set from earlier parts of this TX.
* @param transactionFee - Fee offered for this TX.
Expand All @@ -55,7 +55,7 @@ export class PublicExecutor {
public async simulate(
executionRequest: PublicExecutionRequest,
constants: CombinedConstantData,
availableGas: Gas,
allocatedGas: Gas,
_txContext: TxContext,
pendingSiloedNullifiers: Nullifier[],
transactionFee: Fr = Fr.ZERO,
Expand Down Expand Up @@ -85,7 +85,7 @@ export class PublicExecutor {

const avmExecutionEnv = createAvmExecutionEnvironment(executionRequest, constants.globalVariables, transactionFee);

const avmMachineState = new AvmMachineState(availableGas);
const avmMachineState = new AvmMachineState(allocatedGas);
const avmContext = new AvmContext(avmPersistableState, avmExecutionEnv, avmMachineState);
const simulator = new AvmSimulator(avmContext);
const avmResult = await simulator.execute();
Expand All @@ -111,7 +111,7 @@ export class PublicExecutor {

const publicExecutionResult = trace.toPublicExecutionResult(
avmExecutionEnv,
/*startGasLeft=*/ availableGas,
/*startGasLeft=*/ allocatedGas,
/*endGasLeft=*/ Gas.from(avmContext.machineState.gasLeft),
bytecode,
avmResult,
Expand All @@ -127,7 +127,7 @@ export class PublicExecutor {
const _vmCircuitPublicInputs = enqueuedCallTrace.toVMCircuitPublicInputs(
constants,
avmExecutionEnv,
/*startGasLeft=*/ availableGas,
/*startGasLeft=*/ allocatedGas,
/*endGasLeft=*/ Gas.from(avmContext.machineState.gasLeft),
avmResult,
);
Expand Down
21 changes: 14 additions & 7 deletions yarn-project/simulator/src/public/public_processor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -724,8 +724,9 @@ describe('public_processor', () => {
const revertibleRequests = tx.getRevertiblePublicExecutionRequests();
const teardownRequest = tx.getPublicTeardownExecutionRequest()!;

const gasLimits = Gas.from({ l2Gas: 1e9, daGas: 1e9 });
const teardownGas = Gas.from({ l2Gas: 1e7, daGas: 1e7 });
// Keep gas numbers MAX_L2_GAS_PER_ENQUEUED_CALL or the logic below has to get weird
const gasLimits = Gas.from({ l2Gas: 1e6, daGas: 1e6 });
const teardownGas = Gas.from({ l2Gas: 1e5, daGas: 1e5 });
tx.data.constants.txContext.gasSettings = GasSettings.from({
gasLimits: gasLimits,
teardownGasLimits: teardownGas,
Expand All @@ -750,20 +751,26 @@ describe('public_processor', () => {

let simulatorCallCount = 0;

// Keep gas numbers below MAX_L2_GAS_PER_ENQUEUED_CALL or we need
// to separately compute available start gas and "effective" start gas
// for each enqueued call after applying that max.
const initialGas = gasLimits.sub(teardownGas);
const setupGasUsed = Gas.from({ l2Gas: 1e6 });
const appGasUsed = Gas.from({ l2Gas: 2e6, daGas: 2e6 });
const teardownGasUsed = Gas.from({ l2Gas: 3e6, daGas: 3e6 });
const setupGasUsed = Gas.from({ l2Gas: 1e4 });
const appGasUsed = Gas.from({ l2Gas: 2e4, daGas: 2e4 });
const teardownGasUsed = Gas.from({ l2Gas: 3e4, daGas: 3e4 });
const afterSetupGas = initialGas.sub(setupGasUsed);
const afterAppGas = afterSetupGas.sub(appGasUsed);
const afterTeardownGas = teardownGas.sub(teardownGasUsed);

// Total gas used is the sum of teardown gas allocation plus all expenditures along the way,
// without including the gas used in the teardown phase (since that's consumed entirely up front).
const expectedTotalGasUsed = { l2Gas: 1e7 + 1e6 + 2e6, daGas: 1e7 + 2e6 };
const expectedTotalGasUsed = teardownGas.add(setupGasUsed).add(appGasUsed);

// Inclusion fee plus block gas fees times total gas used
const expectedTxFee = 1e4 + (1e7 + 1e6 + 2e6) * 1 + (1e7 + 2e6) * 1;
const expectedTxFee =
tx.data.constants.txContext.gasSettings.inclusionFee.toNumber() +
expectedTotalGasUsed.l2Gas * 1 +
expectedTotalGasUsed.daGas * 1;
const transactionFee = new Fr(expectedTxFee);

const simulatorResults: PublicExecutionResult[] = [
Expand Down

0 comments on commit 8722f80

Please sign in to comment.