Skip to content

Commit

Permalink
feat: da gas metering
Browse files Browse the repository at this point in the history
  • Loading branch information
just-mitch committed Apr 30, 2024
1 parent 1904fa8 commit 42f56cf
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 46 deletions.
3 changes: 3 additions & 0 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ library Constants {
uint256 internal constant DEFAULT_TEARDOWN_GAS_LIMIT = 100_000_000;
uint256 internal constant DEFAULT_MAX_FEE_PER_GAS = 10;
uint256 internal constant DEFAULT_INCLUSION_FEE = 0;
uint256 internal constant DA_BYTES_PER_FIELD = 32;
uint256 internal constant DA_GAS_PER_BYTE = 16;
uint256 internal constant FIXED_DA_GAS = 512;
uint256 internal constant CANONICAL_KEY_REGISTRY_ADDRESS =
0x1585e564a60e6ec974bc151b62705292ebfc75c33341986a47fd9749cedb567e;
uint256 internal constant AZTEC_ADDRESS_LENGTH = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ use dep::types::{
abis::{
kernel_data::PrivateKernelData,
kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputsBuilder, PublicKernelCircuitPublicInputs},
note_hash::NoteHashContext, nullifier::Nullifier, side_effect::{SideEffect, Ordered}
note_hash::NoteHashContext, nullifier::Nullifier, side_effect::{SideEffect, Ordered}, gas::Gas
},
constants::{
MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX,
MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX,
MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX
MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, DA_BYTES_PER_FIELD, FIXED_DA_GAS,
DA_GAS_PER_BYTE
},
grumpkin_private_key::GrumpkinPrivateKey,
hash::{compute_note_hash_nonce, compute_unique_siloed_note_hash},
Expand Down Expand Up @@ -99,8 +100,6 @@ impl KernelCircuitPublicInputsComposer {

self.silo_values();

self.set_gas_used();

*self
}

Expand All @@ -113,18 +112,14 @@ impl KernelCircuitPublicInputsComposer {
}

pub fn finish(self) -> KernelCircuitPublicInputs {
self.public_inputs.finish_tail()
let teardown_gas = self.previous_kernel.public_inputs.constants.tx_context.gas_settings.teardown_gas_limits;
self.public_inputs.finish_tail(teardown_gas)
}

pub fn finish_to_public(self) -> PublicKernelCircuitPublicInputs {
let min_revertible_side_effect_counter = self.previous_kernel.public_inputs.min_revertible_side_effect_counter;
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;
self.public_inputs.finish_to_public(teardown_gas, min_revertible_side_effect_counter)
}

fn silo_values(&mut self) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ mod tests {
};
use dep::types::constants::{
MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX,
MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX
MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX,
DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE
};
use dep::types::{
abis::{
Expand Down Expand Up @@ -508,6 +509,8 @@ mod tests {
let public_inputs = builder.execute();
assert_eq(array_length(public_inputs.end.new_note_hashes), 2);
assert_eq(array_length(public_inputs.end.new_nullifiers), 3);
let expected_gas = Gas::tx_overhead() + Gas::new(DA_GAS_PER_BYTE * DA_BYTES_PER_FIELD * 5, 0);
assert_eq(public_inputs.end.gas_used, expected_gas);
}

#[test(should_fail_with="Hinted note hash does not match")]
Expand Down Expand Up @@ -558,12 +561,15 @@ mod tests {
}

#[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.
unconstrained fn empty_tx_consumes_teardown_limits_plus_fixed_gas() {
let mut builder = PrivateKernelTailInputsBuilder::new();
builder.previous_kernel.tx_context.gas_settings.teardown_gas_limits = Gas::new(300, 300);
let public_inputs = builder.execute();

assert_eq(public_inputs.end.gas_used, Gas::new(300, 300));

let expected_gas_consumed = Gas::new(300, 300) // teardown gas
+ Gas::tx_overhead() // tx overhead
+ Gas::new(DA_GAS_PER_BYTE * DA_BYTES_PER_FIELD * 1, 0); // tx nullifier
assert_eq(public_inputs.end.gas_used, expected_gas_consumed);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ mod tests {
};
use dep::types::constants::{
MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX,
MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX
MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX,
DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE
};
use dep::types::{
abis::{
Expand Down Expand Up @@ -532,6 +533,11 @@ mod tests {
[new_nullifiers[3], new_nullifiers[4]]
)
);

assert_eq(public_inputs.end.gas_used, Gas::new(2 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE, 0));
assert_eq(
public_inputs.end_non_revertible.gas_used, Gas::new(3 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE, 0) + Gas::tx_overhead()
);
}

#[test]
Expand Down Expand Up @@ -586,12 +592,12 @@ mod tests {
}

#[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.
unconstrained fn empty_tx_consumes_teardown_limits_plus_fixed_gas() {
let mut builder = PrivateKernelTailToPublicInputsBuilder::new();
builder.previous_kernel.tx_context.gas_settings.teardown_gas_limits = Gas::new(300, 300);
let public_inputs = builder.execute();

assert_eq(public_inputs.end.gas_used, Gas::new(300, 300));
let expected_gas_consumed = Gas::new(300, 300) + Gas::tx_overhead();
assert_eq(public_inputs.end.gas_used, expected_gas_consumed);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ use crate::{
constants::{
MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX,
MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX,
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX,
DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE
},
traits::Empty
traits::{Empty, is_empty}
};

// Builds via PrivateKernelCircuitPublicInputsBuilder:
Expand Down Expand Up @@ -60,10 +61,11 @@ impl PrivateAccumulatedDataBuilder {
}
}

pub fn to_combined(self) -> CombinedAccumulatedData {
pub fn to_combined(self, teardown_gas: Gas) -> CombinedAccumulatedData {
// TODO(Miranda): Hash here or elsewhere?
let encrypted_logs_hash = compute_tx_logs_hash(self.encrypted_logs_hashes.storage);
let unencrypted_logs_hash = compute_tx_logs_hash(self.unencrypted_logs_hashes.storage);
let gas_used = self.to_metered_gas_used() + Gas::tx_overhead() + teardown_gas;

CombinedAccumulatedData {
new_note_hashes: self.new_note_hashes.storage.map(|n: NoteHashContext| n.value),
Expand All @@ -74,36 +76,88 @@ impl PrivateAccumulatedDataBuilder {
encrypted_log_preimages_length: self.encrypted_log_preimages_length,
unencrypted_log_preimages_length: self.unencrypted_log_preimages_length,
public_data_update_requests: [PublicDataUpdateRequest::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX],
gas_used: self.gas_used.add(self.non_revertible_gas_used)
gas_used
}
}

pub fn to_metered_gas_used(self) -> Gas {
let mut metered_bytes = 0;

// note_hash_gas
for i in 0..self.new_note_hashes.storage.len() {
if !is_empty(self.new_note_hashes.get_unchecked(i)) {
metered_bytes += DA_BYTES_PER_FIELD;
}
}

// nullifier_gas
for i in 0..self.new_nullifiers.storage.len() {
if !is_empty(self.new_nullifiers.get_unchecked(i)) {
metered_bytes += DA_BYTES_PER_FIELD;
}
}

// l2_to_l1_msg_gas
for i in 0..self.new_l2_to_l1_msgs.storage.len() {
if !is_empty(self.new_l2_to_l1_msgs.get_unchecked(i)) {
metered_bytes += DA_BYTES_PER_FIELD;
}
}

// encrypted_logs_hash_gas
metered_bytes += self.encrypted_log_preimages_length as u32;

// unencrypted_logs_hash_gas
metered_bytes += self.unencrypted_log_preimages_length as u32;

Gas::new(DA_GAS_PER_BYTE * metered_bytes, 0)
}

pub fn split_to_public(
self,
min_revertible_side_effect_counter: u32
min_revertible_side_effect_counter: u32,
teardown_gas: Gas
) -> (PublicAccumulatedData, PublicAccumulatedData) {
let mut non_revertible_builder = PublicAccumulatedDataBuilder::empty();
let mut revertible_builder = PublicAccumulatedDataBuilder::empty();
let mut non_revertible_da_gas_used = 0;
let mut non_revertible_l2_gas_used = 0;
let mut revertible_da_gas_used = teardown_gas.da_gas; // pre-pay for teardown gas
let mut revertible_l2_gas_used = teardown_gas.l2_gas;
let DA_GAS_PER_FIELD = DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE;

for i in 0..MAX_NEW_NOTE_HASHES_PER_TX {
let note_hash = self.new_note_hashes.storage[i];
let public_note_hash = note_hash.expose_to_public();
if note_hash.counter < min_revertible_side_effect_counter {
non_revertible_builder.new_note_hashes.push(public_note_hash);
if !is_empty(public_note_hash) {
non_revertible_da_gas_used += DA_GAS_PER_FIELD ;
}
} else {
revertible_builder.new_note_hashes.push(public_note_hash);
if !is_empty(public_note_hash) {
revertible_da_gas_used += DA_GAS_PER_FIELD;
}
}
}

for i in 0..MAX_NEW_NULLIFIERS_PER_TX {
let nullifier = self.new_nullifiers.storage[i];
if nullifier.counter < min_revertible_side_effect_counter {
non_revertible_builder.new_nullifiers.push(nullifier);
if !is_empty(nullifier) {
non_revertible_da_gas_used += DA_GAS_PER_FIELD;
}
} else {
revertible_builder.new_nullifiers.push(nullifier);
if !is_empty(nullifier) {
revertible_da_gas_used += DA_GAS_PER_FIELD;
}
}
}

// TODO(gas): add AVM_STARTUP_L2_GAS here
for i in 0..MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX {
let call_stack_item = self.public_call_stack.storage[i];
if call_stack_item.start_side_effect_counter < min_revertible_side_effect_counter {
Expand Down Expand Up @@ -136,8 +190,10 @@ impl PrivateAccumulatedDataBuilder {
revertible_builder.encrypted_log_preimages_length = self.encrypted_log_preimages_length;
revertible_builder.unencrypted_log_preimages_length = self.unencrypted_log_preimages_length;

revertible_builder.gas_used = self.gas_used;
non_revertible_builder.gas_used = self.non_revertible_gas_used;
revertible_da_gas_used += DA_GAS_PER_BYTE * (self.encrypted_log_preimages_length as u32 + self.unencrypted_log_preimages_length as u32);

revertible_builder.gas_used = Gas::new(revertible_da_gas_used, revertible_l2_gas_used);
non_revertible_builder.gas_used = Gas::tx_overhead() + Gas::new(non_revertible_da_gas_used, non_revertible_l2_gas_used);
(non_revertible_builder.finish(), revertible_builder.finish())
}
}
Expand All @@ -150,7 +206,7 @@ mod tests {
note_hash::{NoteHash, NoteHashContext}, nullifier::Nullifier,
public_data_update_request::PublicDataUpdateRequest, side_effect::SideEffect
},
address::AztecAddress, utils::arrays::array_eq
address::AztecAddress, utils::arrays::array_eq, constants::{DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE}
};

#[test]
Expand Down Expand Up @@ -213,10 +269,7 @@ mod tests {
builder.public_call_stack.extend_from_array(non_revertible_public_stack);
builder.public_call_stack.extend_from_array(revertible_public_call_stack);

builder.gas_used = Gas::new(20,20);
builder.non_revertible_gas_used = Gas::new(10,10);

let (non_revertible, revertible) = builder.split_to_public(7);
let (non_revertible, revertible) = builder.split_to_public(7, Gas::new(42, 17));

assert(
array_eq(
Expand All @@ -242,8 +295,14 @@ mod tests {
assert(array_eq(revertible.new_nullifiers, revertible_nullifiers));
assert(array_eq(revertible.public_call_stack, revertible_public_call_stack));

assert_eq(revertible.gas_used, Gas::new(20, 20));
assert_eq(non_revertible.gas_used, Gas::new(10, 10));
assert_eq(
revertible.gas_used, Gas::new(4 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE, 0) + Gas::new(42, 17)
);

print(non_revertible.gas_used);
assert_eq(
non_revertible.gas_used, Gas::new(4 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE, 0) + Gas::tx_overhead()
);
}
}

Expand Down
26 changes: 18 additions & 8 deletions noir-projects/noir-protocol-circuits/crates/types/src/abis/gas.nr
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::{
abis::function_selector::FunctionSelector, address::{EthAddress, AztecAddress},
constants::GAS_LENGTH, hash::pedersen_hash, traits::{Deserialize, Hash, Serialize, Empty},
abis::side_effect::Ordered, utils::reader::Reader, abis::gas_fees::GasFees
constants::{GAS_LENGTH, FIXED_DA_GAS}, hash::pedersen_hash,
traits::{Deserialize, Hash, Serialize, Empty}, abis::side_effect::Ordered, utils::reader::Reader,
abis::gas_fees::GasFees
};
use dep::std::ops::{Add, Sub};

struct Gas {
da_gas: u32,
Expand All @@ -14,12 +16,8 @@ impl Gas {
Self { da_gas, l2_gas }
}

pub fn add(self, other: Gas) -> Self {
Gas::new(self.da_gas + other.da_gas, self.l2_gas + other.l2_gas)
}

pub fn sub(self, other: Gas) -> Self {
Gas::new(self.da_gas - other.da_gas, self.l2_gas - other.l2_gas)
pub fn tx_overhead() -> Self {
Self { da_gas: FIXED_DA_GAS, l2_gas: 0 }
}

pub fn compute_fee(self, fees: GasFees) -> Field {
Expand All @@ -31,6 +29,18 @@ impl Gas {
}
}

impl Add for Gas {
fn add(self, other: Gas) -> Self {
Gas::new(self.da_gas + other.da_gas, self.l2_gas + other.l2_gas)
}
}

impl Sub for Gas {
fn sub(self, other: Gas) -> Self {
Gas::new(self.da_gas - other.da_gas, self.l2_gas - other.l2_gas)
}
}

impl Serialize<GAS_LENGTH> for Gas {
fn serialize(self) -> [Field; GAS_LENGTH] {
[self.da_gas as Field, self.l2_gas as Field]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
private_kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs,
public_kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs
},
validation_requests::validation_requests_builder::ValidationRequestsBuilder
gas::Gas, validation_requests::validation_requests_builder::ValidationRequestsBuilder
},
mocked::AggregationObject, partial_state_reference::PartialStateReference, traits::Empty
};
Expand Down Expand Up @@ -34,19 +34,23 @@ impl PrivateKernelCircuitPublicInputsBuilder {
}
}

pub fn finish_tail(self) -> KernelCircuitPublicInputs {
pub fn finish_tail(self, teardown_gas: Gas) -> KernelCircuitPublicInputs {
KernelCircuitPublicInputs {
aggregation_object: self.aggregation_object,
rollup_validation_requests: self.validation_requests.to_rollup(),
end: self.end.to_combined(),
end: self.end.to_combined(teardown_gas),
constants: self.constants,
start_state: PartialStateReference::empty(),
revert_code: 0
}
}

pub fn finish_to_public(self, min_revertible_side_effect_counter: u32) -> PublicKernelCircuitPublicInputs {
let (end_non_revertible, end) = self.end.split_to_public(min_revertible_side_effect_counter);
pub fn finish_to_public(
self,
teardown_gas: Gas,
min_revertible_side_effect_counter: u32
) -> PublicKernelCircuitPublicInputs {
let (end_non_revertible, end) = self.end.split_to_public(min_revertible_side_effect_counter, teardown_gas);

PublicKernelCircuitPublicInputs {
aggregation_object: self.aggregation_object,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ global DEFAULT_GAS_LIMIT: u32 = 1_000_000_000;
global DEFAULT_TEARDOWN_GAS_LIMIT: u32 = 100_000_000;
global DEFAULT_MAX_FEE_PER_GAS: Field = 10;
global DEFAULT_INCLUSION_FEE: Field = 0;
global DA_BYTES_PER_FIELD: u32 = 32;
global DA_GAS_PER_BYTE: u32 = 16;
global FIXED_DA_GAS: u32 = 512;

global CANONICAL_KEY_REGISTRY_ADDRESS = 0x1585e564a60e6ec974bc151b62705292ebfc75c33341986a47fd9749cedb567e;

Expand Down
Loading

0 comments on commit 42f56cf

Please sign in to comment.