Skip to content
3 changes: 1 addition & 2 deletions noir-projects/noir-contracts/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@ NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo}
$NARGO compile --silence-warnings

echo "Transpiling avm contracts... (only '#[aztec(public-vm)]')"
TRANSPILER=${TRANSPILER:-../../avm-transpiler/target/release/avm-transpiler}
ls target/avm_*.json | parallel "$TRANSPILER {} {}"
scripts/transpile.sh
5 changes: 5 additions & 0 deletions noir-projects/noir-contracts/scripts/transpile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -eu

TRANSPILER=${TRANSPILER:-../../avm-transpiler/target/release/avm-transpiler}
ls target/avm_*.json | parallel "$TRANSPILER {} {}"
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ fn asc_sort_by_counters<T>(a: T, b: T) -> bool where T: Ordered {
a.counter() < b.counter()
}

// Builds:
// .finish -> KernelCircuitPublicInputs (from PrivateKernelTailCircuitPrivateInputs)
// .finish_to_public -> PublicKernelCircuitPublicInputs (from PrivateKernelTailToPublicCircuitPrivateInputs)
struct KernelCircuitPublicInputsComposer {
public_inputs: PrivateKernelCircuitPublicInputsBuilder,
previous_kernel: PrivateKernelData,
Expand All @@ -47,7 +50,7 @@ impl KernelCircuitPublicInputsComposer {
sorted_encrypted_log_hashes: [SideEffect; MAX_ENCRYPTED_LOGS_PER_TX],
sorted_encrypted_log_hashes_indexes: [u64; MAX_ENCRYPTED_LOGS_PER_TX],
sorted_unencrypted_log_hashes: [SideEffect; MAX_UNENCRYPTED_LOGS_PER_TX],
sorted_unencrypted_log_hashes_indexes: [u64; MAX_UNENCRYPTED_LOGS_PER_TX],
sorted_unencrypted_log_hashes_indexes: [u64; MAX_UNENCRYPTED_LOGS_PER_TX]
) -> Self {
let public_inputs = PrivateKernelCircuitPublicInputsBuilder::empty();

Expand All @@ -62,7 +65,7 @@ impl KernelCircuitPublicInputsComposer {
sorted_encrypted_log_hashes,
sorted_encrypted_log_hashes_indexes,
sorted_unencrypted_log_hashes,
sorted_unencrypted_log_hashes_indexes,
sorted_unencrypted_log_hashes_indexes
}
}

Expand All @@ -82,6 +85,8 @@ impl KernelCircuitPublicInputsComposer {

self.silo_values();

self.set_gas_used();

*self
}

Expand All @@ -102,6 +107,12 @@ impl KernelCircuitPublicInputsComposer {
self.public_inputs.finish_to_public(min_revertible_side_effect_counter)
}

fn set_gas_used(&mut self) {
// TODO(gas): Compute DA gas used here and add to public_inputs.(end,end_non_revertible).gas_used
let teardown_gas = self.previous_kernel.public_inputs.constants.tx_context.gas_settings.teardown_gas_limits;
self.public_inputs.end.gas_used = teardown_gas;
}

fn silo_values(&mut self) {
self.silo_note_hashes();
// TODO: Move siloing from init/inner circuits to here.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ impl PrivateKernelInitCircuitPrivateInputs {
// Ensure we are passing the correct arguments to the function.
let args_match = tx_request.args_hash == call_stack_item.public_inputs.args_hash;
assert(args_match, "noir function args passed to tx_request must match args in the call_stack_item");
//
// Ensure we are passing the correct tx context
let tx_context_matches = tx_request.tx_context == call_stack_item.public_inputs.tx_context;
assert(tx_context_matches, "tx_context in tx_request must match tx_context in call_stack_item");
}

fn validate_inputs(self) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl PrivateKernelTailCircuitPrivateInputs {
self.sorted_encrypted_log_hashes,
self.sorted_encrypted_log_hashes_indexes,
self.sorted_unencrypted_log_hashes,
self.sorted_unencrypted_log_hashes_indexes,
self.sorted_unencrypted_log_hashes_indexes
);
composer.compose().finish()
}
Expand All @@ -76,7 +76,7 @@ mod tests {
use dep::types::{
abis::{
kernel_circuit_public_inputs::KernelCircuitPublicInputs, max_block_number::MaxBlockNumber,
side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered}
side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered}, gas::Gas
},
grumpkin_private_key::GrumpkinPrivateKey,
hash::{compute_note_hash_nonce, compute_unique_siloed_note_hash, accumulate_sha256},
Expand Down Expand Up @@ -189,7 +189,7 @@ mod tests {
sorted_encrypted_log_hashes_indexes,
sorted_unencrypted_log_hashes,
sorted_unencrypted_log_hashes_indexes,
master_nullifier_secret_keys: [GrumpkinPrivateKey::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX],
master_nullifier_secret_keys: [GrumpkinPrivateKey::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX]
};
kernel.native_private_kernel_circuit_tail()
}
Expand Down Expand Up @@ -488,4 +488,14 @@ mod tests {
builder.previous_kernel.new_nullifiers = BoundedVec::new();
builder.failed();
}

#[test]
unconstrained fn set_teardown_gas_as_gas_used() {
// TODO(gas): When we compute DA gas used, we'll have to include it here as well.
let mut builder = PrivateKernelTailInputsBuilder::new();
builder.previous_kernel.tx_context.gas_settings.teardown_gas_limits = Gas::new(300, 300, 300);
let public_inputs = builder.execute();

assert_eq(public_inputs.end.gas_used, Gas::new(300, 300, 300));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl PrivateKernelTailToPublicCircuitPrivateInputs {
self.sorted_encrypted_log_hashes,
self.sorted_encrypted_log_hashes_indexes,
self.sorted_unencrypted_log_hashes,
self.sorted_unencrypted_log_hashes_indexes,
self.sorted_unencrypted_log_hashes_indexes
);
composer.compose_public().finish_to_public()
}
Expand All @@ -75,7 +75,7 @@ mod tests {
};
use dep::types::{
abis::{
kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs,
kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, gas::Gas,
side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered}
},
grumpkin_private_key::GrumpkinPrivateKey,
Expand Down Expand Up @@ -196,7 +196,7 @@ mod tests {
sorted_encrypted_log_hashes_indexes,
sorted_unencrypted_log_hashes,
sorted_unencrypted_log_hashes_indexes,
master_nullifier_secret_keys: [GrumpkinPrivateKey::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX],
master_nullifier_secret_keys: [GrumpkinPrivateKey::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX]
};
kernel.execute()
}
Expand Down Expand Up @@ -538,4 +538,14 @@ mod tests {
assert(is_empty_array(public_inputs.end.new_note_hashes));
assert(is_empty_array(public_inputs.end.new_nullifiers));
}

#[test]
unconstrained fn set_teardown_gas_as_gas_used() {
// TODO(gas): When we compute DA gas used, we'll have to include it here as well.
let mut builder = PrivateKernelTailToPublicInputsBuilder::new();
builder.previous_kernel.tx_context.gas_settings.teardown_gas_limits = Gas::new(300, 300, 300);
let public_inputs = builder.execute();

assert_eq(public_inputs.end.gas_used, Gas::new(300, 300, 300));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,22 @@ pub fn update_non_revertible_gas_used(public_call: PublicCallData, circuit_outpu
.sub(accum_end_gas_used);
}

// Validates that the start gas injected into the app circuit matches the remaining gas
pub fn validate_start_gas(public_call: PublicCallData, previous_kernel: PublicKernelData) {
let public_call_start_gas = public_call.call_stack_item.public_inputs.start_gas_left;
let tx_gas_limits = previous_kernel.public_inputs.constants.tx_context.gas_settings.gas_limits;
let computed_start_gas = tx_gas_limits.sub(previous_kernel.public_inputs.end.gas_used).sub(previous_kernel.public_inputs.end_non_revertible.gas_used);
assert(
public_call_start_gas == computed_start_gas, "Start gas for public phase does not match transaction gas left"
);
}

// Validates the transaction fee injected into the app circuit is zero for non-teardown phases
pub fn validate_transaction_fee_is_zero(public_call: PublicCallData) {
let transaction_fee = public_call.call_stack_item.public_inputs.transaction_fee;
assert(transaction_fee == 0, "Transaction fee must be zero on setup and app phases");
}

pub fn update_public_end_non_revertible_values(
public_call: PublicCallData,
circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ impl PublicKernelAppLogicCircuitPrivateInputs {
// validate the inputs unique to having a previous public kernel
self.validate_inputs();

common::validate_start_gas(self.public_call, self.previous_kernel);
common::validate_transaction_fee_is_zero(self.public_call);

common::update_validation_requests(self.public_call, &mut public_inputs);

common::update_revertible_gas_used(self.public_call, &mut public_inputs);
Expand Down Expand Up @@ -464,4 +467,22 @@ mod tests {
assert_eq(output.end.gas_used, Gas::new(500, 500, 500));
assert_eq(output.end_non_revertible.gas_used, Gas::new(0, 0, 0));
}

#[test(should_fail_with="Start gas for public phase does not match transaction gas left")]
fn validates_start_gas() {
let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new();

builder.public_call.public_inputs.start_gas_left = Gas::new(200, 100, 100);

builder.failed();
}

#[test(should_fail_with="Transaction fee must be zero on setup and app phases")]
fn validates_transaction_fee() {
let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new();

builder.public_call.public_inputs.transaction_fee = 10;

builder.failed();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ impl PublicKernelSetupCircuitPrivateInputs {
// validate the inputs unique to having a previous private kernel
self.validate_inputs();

common::validate_start_gas(self.public_call, self.previous_kernel);
common::validate_transaction_fee_is_zero(self.public_call);

common::update_non_revertible_gas_used(self.public_call, &mut public_inputs);

// Pops the item from the call stack and validates it against the current execution.
Expand Down Expand Up @@ -519,4 +522,22 @@ mod tests {
assert_eq(output.end_non_revertible.gas_used, Gas::new(500, 500, 500));
assert_eq(output.end.gas_used, Gas::new(100, 100, 100));
}

#[test(should_fail_with="Start gas for public phase does not match transaction gas left")]
fn validates_start_gas() {
let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new();

builder.public_call.public_inputs.start_gas_left = Gas::new(200, 100, 100);

builder.failed();
}

#[test(should_fail_with="Transaction fee must be zero on setup and app phases")]
fn validates_transaction_fee() {
let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new();

builder.public_call.public_inputs.transaction_fee = 10;

builder.failed();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::common;
use dep::types::abis::{
kernel_circuit_public_inputs::{PublicKernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder},
kernel_data::PublicKernelData, public_call_data::PublicCallData
kernel_data::PublicKernelData, public_call_data::PublicCallData, gas_fees::GasFees
};

struct PublicKernelTeardownCircuitPrivateInputs {
Expand All @@ -22,6 +22,45 @@ impl PublicKernelTeardownCircuitPrivateInputs {
assert(needs_teardown == true, "Cannot run unnecessary teardown circuit");
}

// Validates that the start gas injected into the app circuit matches the teardown gas limits set by the user
fn validate_start_gas(self) {
let public_call_start_gas = self.public_call.call_stack_item.public_inputs.start_gas_left;
let teardown_gas_limit = self.previous_kernel.public_inputs.constants.tx_context.gas_settings.teardown_gas_limits;
assert(
public_call_start_gas == teardown_gas_limit, "Start gas for teardown phase does not match teardown gas allocation"
);
}

// Validates the transaction fee injected into the app circuit is properly computed from gas_used and block gas_fees
fn validate_transaction_fee(self) {
let transaction_fee = self.public_call.call_stack_item.public_inputs.transaction_fee;
// Note that teardown_gas is already included in end.gas_used as it was injected by the private kernel
let total_gas_used = self.previous_kernel.public_inputs.end.gas_used.add(self.previous_kernel.public_inputs.end_non_revertible.gas_used);
// TODO(palla/gas): Load gas fees from a PublicConstantData struct that's currently missing
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide to put the current prices in the previous block, we can do this now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not sure about that, but we can do it as a stopgap. I'll do on a subsequent PR!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it goes #6010!

let block_gas_fees = GasFees::default();
let inclusion_fee = self.previous_kernel.public_inputs.constants.tx_context.gas_settings.inclusion_fee;
let computed_transaction_fee = total_gas_used.compute_fee(block_gas_fees) + inclusion_fee;

// dep::types::debug_log::debug_log_format(
// "Validating tx fee: total_gas_used.da={0} total_gas_used.l1={1} total_gas_used.l2={2} block_fee_per_gas.da={3} block_fee_per_gas.l1={4} block_fee_per_gas.l2={5} inclusion_fee={6} computed={7} actual={8}",
// [
// total_gas_used.da_gas as Field,
// total_gas_used.l1_gas as Field,
// total_gas_used.l2_gas as Field,
// block_gas_fees.fee_per_da_gas as Field,
// block_gas_fees.fee_per_l1_gas as Field,
// block_gas_fees.fee_per_l2_gas as Field,
// inclusion_fee,
// computed_transaction_fee,
// transaction_fee
// ]
// );

assert(
transaction_fee == computed_transaction_fee, "Transaction fee on teardown phase does not match expected value"
);
}

fn public_kernel_teardown(self) -> PublicKernelCircuitPublicInputs {
// construct the circuit outputs
let mut public_inputs = PublicKernelCircuitPublicInputsBuilder::empty();
Expand All @@ -42,6 +81,9 @@ impl PublicKernelTeardownCircuitPrivateInputs {
let call_request = public_inputs.end_non_revertible.public_call_stack.pop();
common::validate_call_against_request(self.public_call, call_request);

self.validate_start_gas();
self.validate_transaction_fee();

common::update_validation_requests(self.public_call, &mut public_inputs);

common::update_public_end_non_revertible_values(self.public_call, &mut public_inputs);
Expand All @@ -60,7 +102,7 @@ mod tests {
};
use dep::types::{
abis::{
call_request::CallRequest, function_selector::FunctionSelector,
call_request::CallRequest, function_selector::FunctionSelector, gas::Gas,
kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, public_data_read::PublicDataRead,
public_data_update_request::PublicDataUpdateRequest
},
Expand Down Expand Up @@ -347,12 +389,16 @@ mod tests {

let public_inputs = builder.execute();

assert_eq(public_inputs.end_non_revertible.encrypted_log_preimages_length, prev_encrypted_log_preimages_length);
assert_eq(
public_inputs.end_non_revertible.encrypted_log_preimages_length, prev_encrypted_log_preimages_length
);
assert_eq(
public_inputs.end_non_revertible.unencrypted_log_preimages_length, unencrypted_log_preimages_length + prev_unencrypted_log_preimages_length
);
assert_eq(public_inputs.end_non_revertible.encrypted_logs_hashes[0].value, prev_encrypted_logs_hash);
assert_eq(public_inputs.end_non_revertible.unencrypted_logs_hashes[0].value, prev_unencrypted_logs_hash);
assert_eq(
public_inputs.end_non_revertible.unencrypted_logs_hashes[0].value, prev_unencrypted_logs_hash
);
assert_eq(public_inputs.end_non_revertible.unencrypted_logs_hashes[1].value, unencrypted_logs_hash);
}

Expand All @@ -363,4 +409,20 @@ mod tests {

builder.failed();
}

#[test(should_fail_with="Start gas for teardown phase does not match teardown gas allocation")]
fn validates_start_gas() {
let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new();
builder.public_call.public_inputs.start_gas_left = Gas::new(10, 20, 30);

builder.failed();
}

#[test(should_fail_with="Transaction fee on teardown phase does not match expected value")]
fn validates_transaction_fee() {
let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new();
builder.public_call.public_inputs.transaction_fee = 1234;

builder.failed();
}
}
Loading