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: private da gas metering #6103

Merged
merged 1 commit into from
Apr 30, 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 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;
}
}
Comment on lines +87 to +91
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this builder have empty items? I'd expect it to contain only non-empty, since it uses BoundedVecs (otherwise, we could well use fixed-length arrays). We should be able to remove the loop and emptiness check, and just check the BoundedVec's length.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah I think both this and the way we split/meter the non/revertible sets are candidates for significant optimization passes


// 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};
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hah, I hadn't managed to get this to work. Nice!


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
Loading