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

fix: validate gas used #7459

Merged
merged 3 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use crate::components::private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer;
mod meter_gas_used;

use crate::components::{
private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer,
tail_output_composer::meter_gas_used::meter_gas_used
};
use dep::types::{
abis::{
accumulated_data::combined_accumulated_data::CombinedAccumulatedData, gas::Gas,
accumulated_data::combined_accumulated_data::CombinedAccumulatedData,
kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputs},
log_hash::{ScopedEncryptedLogHash, NoteLogHash, ScopedLogHash}, note_hash::ScopedNoteHash,
nullifier::ScopedNullifier
},
constants::{DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, L2_GAS_PER_LOG_BYTE},
hash::{compute_tx_logs_hash, compute_tx_note_logs_hash},
messaging::l2_to_l1_message::ScopedL2ToL1Message
};
Expand Down Expand Up @@ -45,37 +49,7 @@ impl TailOutputComposer {
data.note_encrypted_log_preimages_length = source.note_encrypted_logs_hashes.storage.fold(0, |len, l: NoteLogHash| len + l.length);
data.encrypted_log_preimages_length = source.encrypted_logs_hashes.storage.fold(0, |len, l: ScopedEncryptedLogHash| len + l.log_hash.length);
data.unencrypted_log_preimages_length = source.unencrypted_logs_hashes.storage.fold(0, |len, l: ScopedLogHash| len + l.log_hash.length);
data.gas_used = self.meter_gas_used(data);
data.gas_used = meter_gas_used(data, self.output_composer.public_inputs.constants.tx_context.gas_settings);
data
}

fn meter_gas_used(self, data: CombinedAccumulatedData) -> Gas {
let mut metered_da_bytes = 0;
let mut metered_l2_gas = 0;

let data_builder = self.output_composer.public_inputs.end;
// IMPORTANT: Must use data_builder.__.len(), which is the the number of items pushed to the BoundedVec.
// Do not use data.__.len(), which is the array's max length.
metered_da_bytes += data_builder.note_hashes.len() * DA_BYTES_PER_FIELD;
metered_l2_gas += data_builder.note_hashes.len() * L2_GAS_PER_NOTE_HASH;

metered_da_bytes += data_builder.nullifiers.len() * DA_BYTES_PER_FIELD;
metered_l2_gas += data_builder.nullifiers.len() * L2_GAS_PER_NULLIFIER;

metered_da_bytes += data_builder.l2_to_l1_msgs.len() * DA_BYTES_PER_FIELD;

metered_da_bytes += data.note_encrypted_log_preimages_length as u32;
metered_l2_gas += data.note_encrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE;

metered_da_bytes += data.encrypted_log_preimages_length as u32;
metered_l2_gas += data.encrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE;

metered_da_bytes += data.unencrypted_log_preimages_length as u32;
metered_l2_gas += data.unencrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE;

let teardown_gas = self.output_composer.public_inputs.constants.tx_context.gas_settings.teardown_gas_limits;
Gas::new(metered_da_bytes * DA_GAS_PER_BYTE, metered_l2_gas)
+ Gas::tx_overhead()
+ teardown_gas
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use dep::types::{
abis::{
accumulated_data::combined_accumulated_data::CombinedAccumulatedData, gas::Gas,
gas_settings::GasSettings
},
constants::{DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, L2_GAS_PER_LOG_BYTE},
utils::arrays::array_length
};

fn meter_gas_used(data: CombinedAccumulatedData, gas_settings: GasSettings) -> Gas {
let mut metered_da_bytes = 0;
let mut metered_l2_gas = 0;

let num_note_hashes = array_length(data.note_hashes);
metered_da_bytes += num_note_hashes * DA_BYTES_PER_FIELD;
metered_l2_gas += num_note_hashes * L2_GAS_PER_NOTE_HASH;

let num_nullifiers = array_length(data.nullifiers);
metered_da_bytes += num_nullifiers * DA_BYTES_PER_FIELD;
metered_l2_gas += num_nullifiers * L2_GAS_PER_NULLIFIER;

let num_l2_to_l1_msgs = array_length(data.l2_to_l1_msgs);
metered_da_bytes += num_l2_to_l1_msgs * DA_BYTES_PER_FIELD;

metered_da_bytes += data.note_encrypted_log_preimages_length as u32;
metered_l2_gas += data.note_encrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE;

metered_da_bytes += data.encrypted_log_preimages_length as u32;
metered_l2_gas += data.encrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE;

metered_da_bytes += data.unencrypted_log_preimages_length as u32;
metered_l2_gas += data.unencrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE;

let teardown_gas = gas_settings.teardown_gas_limits;
Gas::new(metered_da_bytes * DA_GAS_PER_BYTE, metered_l2_gas) + Gas::tx_overhead() + teardown_gas
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
mod kernel_circuit_output_hints;
mod validate_value_transformation;

use crate::components::tail_output_validator::{
use crate::components::{
tail_output_composer::meter_gas_used::meter_gas_used,
tail_output_validator::{
kernel_circuit_output_hints::{generate_kernel_circuit_output_hints, Hints},
validate_value_transformation::{validate_transformed_values, validate_value_transformation}
}
};
use dep::types::{
abis::{
Expand Down Expand Up @@ -36,7 +39,7 @@ impl TailOutputValidator {
self.validate_propagated_values();
self.validate_propagated_sorted_siloed_values(hints);
self.validate_accumulated_values(hints);
self.validate_gas_limits();
self.validate_gas_used();
}

fn validate_empty_values(self) {
Expand Down Expand Up @@ -153,7 +156,13 @@ impl TailOutputValidator {
assert_eq(hash, self.output.end.unencrypted_logs_hash, "mismatch unencrypted_logs_hash");
}

fn validate_gas_limits(self) {
fn validate_gas_used(self) {
let gas_used = meter_gas_used(
self.output.end,
self.output.constants.tx_context.gas_settings
);
assert(self.output.end.gas_used == gas_used, "incorrect metered gas used");

let limits = self.previous_kernel.constants.tx_context.gas_settings.gas_limits;
assert(self.output.end.gas_used.within(limits), "The gas used exceeds the gas limits");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ impl TailToPublicOutputComposer {
end_non_revertible.gas_used = meter_gas_used_non_revertible(end_non_revertible);
let teardown_gas = source.constants.tx_context.gas_settings.teardown_gas_limits;
end.gas_used = meter_gas_used_revertible(end, teardown_gas);
output.end_non_revertible = end_non_revertible.finish();
output.end = end.finish();
output.end_non_revertible = end_non_revertible;
output.end = end;

output
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
use dep::types::{
abis::{
accumulated_data::{public_accumulated_data_builder::PublicAccumulatedDataBuilder}, gas::Gas,
log_hash::LogHash
},
abis::{accumulated_data::{public_accumulated_data::PublicAccumulatedData}, gas::Gas, log_hash::LogHash},
constants::{
DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, FIXED_AVM_STARTUP_L2_GAS, L2_GAS_PER_NOTE_HASH,
L2_GAS_PER_NULLIFIER, L2_GAS_PER_LOG_BYTE
}
},
utils::arrays::array_length
};

fn meter_gas_used(data: PublicAccumulatedDataBuilder) -> Gas {
fn meter_gas_used(data: PublicAccumulatedData) -> Gas {
let mut metered_da_bytes = 0;
let mut metered_l2_gas = 0;

metered_da_bytes += data.note_hashes.len() * DA_BYTES_PER_FIELD;
metered_l2_gas += data.note_hashes.len() * L2_GAS_PER_NOTE_HASH;
let num_note_hashes = array_length(data.note_hashes);
metered_da_bytes += num_note_hashes * DA_BYTES_PER_FIELD;
metered_l2_gas += num_note_hashes * L2_GAS_PER_NOTE_HASH;

metered_da_bytes += data.nullifiers.len() * DA_BYTES_PER_FIELD;
metered_l2_gas += data.nullifiers.len() * L2_GAS_PER_NULLIFIER;
let num_nullifiers = array_length(data.nullifiers);
metered_da_bytes += num_nullifiers * DA_BYTES_PER_FIELD;
metered_l2_gas += num_nullifiers * L2_GAS_PER_NULLIFIER;

metered_da_bytes += data.l2_to_l1_msgs.len() * DA_BYTES_PER_FIELD;
metered_da_bytes += array_length(data.l2_to_l1_msgs) * DA_BYTES_PER_FIELD;

let note_encrypted_log_preimages_length = data.note_encrypted_logs_hashes.storage.fold(0, |len, l: LogHash| len + l.length);
let note_encrypted_log_preimages_length = data.note_encrypted_logs_hashes.fold(0, |len, l: LogHash| len + l.length);
metered_da_bytes += note_encrypted_log_preimages_length as u32;
metered_l2_gas += note_encrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE;

let encrypted_log_preimages_length = data.encrypted_logs_hashes.storage.fold(0, |len, l: LogHash| len + l.length);
let encrypted_log_preimages_length = data.encrypted_logs_hashes.fold(0, |len, l: LogHash| len + l.length);
metered_da_bytes += encrypted_log_preimages_length as u32;
metered_l2_gas += encrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE;

let unencrypted_log_preimages_length = data.unencrypted_logs_hashes.storage.fold(0, |len, l: LogHash| len + l.length);
let unencrypted_log_preimages_length = data.unencrypted_logs_hashes.fold(0, |len, l: LogHash| len + l.length);
metered_da_bytes += unencrypted_log_preimages_length as u32;
metered_l2_gas += unencrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE;

metered_l2_gas += data.public_call_stack.len() * FIXED_AVM_STARTUP_L2_GAS;
metered_l2_gas += array_length(data.public_call_stack) * FIXED_AVM_STARTUP_L2_GAS;

Gas::new(metered_da_bytes * DA_GAS_PER_BYTE, metered_l2_gas)
}

pub fn meter_gas_used_non_revertible(data: PublicAccumulatedDataBuilder) -> Gas {
pub fn meter_gas_used_non_revertible(data: PublicAccumulatedData) -> Gas {
meter_gas_used(data) + Gas::tx_overhead()
}

pub fn meter_gas_used_revertible(data: PublicAccumulatedDataBuilder, teardown_gas: Gas) -> Gas {
pub fn meter_gas_used_revertible(data: PublicAccumulatedData, teardown_gas: Gas) -> Gas {
meter_gas_used(data) + Gas::new(teardown_gas.da_gas, teardown_gas.l2_gas)
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use dep::types::abis::{
accumulated_data::{
private_accumulated_data_builder::PrivateAccumulatedDataBuilder,
public_accumulated_data::PublicAccumulatedData,
public_accumulated_data_builder::PublicAccumulatedDataBuilder
}
};

pub fn split_to_public(
data: PrivateAccumulatedDataBuilder,
min_revertible_side_effect_counter: u32
) -> (PublicAccumulatedDataBuilder, PublicAccumulatedDataBuilder) {
) -> (PublicAccumulatedData, PublicAccumulatedData) {
assert(min_revertible_side_effect_counter != 0, "min_revertible_side_effect_counter must not be 0");

let mut non_revertible_builder = PublicAccumulatedDataBuilder::empty();
Expand Down Expand Up @@ -106,5 +107,5 @@ pub fn split_to_public(
}
}

(non_revertible_builder, revertible_builder)
(non_revertible_builder.finish(), revertible_builder.finish())
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod tail_to_public_output_hints;

use crate::components::{
tail_output_validator::validate_value_transformation::{validate_transformed_values, validate_value_transformation},
tail_to_public_output_composer::meter_gas_used::{meter_gas_used_non_revertible, meter_gas_used_revertible},
tail_to_public_output_validator::tail_to_public_output_hints::{generate_tail_to_public_output_hints, TailToPublicOutputHints}
};
use dep::types::{
Expand Down Expand Up @@ -36,7 +37,7 @@ impl TailToPublicOutputValidator {
self.validate_empty_values();
self.validate_propagated_values();
self.validate_propagated_sorted_siloed_values(hints);
self.validate_gas_limits();
self.validate_gas_used();
}

fn validate_empty_values(self) {
Expand Down Expand Up @@ -188,7 +189,18 @@ impl TailToPublicOutputValidator {
)
}

fn validate_gas_limits(self) {
fn validate_gas_used(self) {
let gas_used = meter_gas_used_non_revertible(self.output.end_non_revertible);
assert(
self.output.end_non_revertible.gas_used == gas_used, "incorrect metered non-revertible gas used"
);

let gas_used = meter_gas_used_revertible(
self.output.end,
self.output.constants.tx_context.gas_settings.teardown_gas_limits
);
assert(self.output.end.gas_used == gas_used, "incorrect metered revertible gas used");

let limits = self.previous_kernel.constants.tx_context.gas_settings.gas_limits;
let total_gas_used = self.output.end_non_revertible.gas_used + self.output.end.gas_used;
assert(total_gas_used.within(limits), "The gas used exceeds the gas limits");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::components::tail_output_composer::meter_gas_used::meter_gas_used;
use dep::types::{
abis::gas::Gas,
constants::{DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, L2_GAS_PER_LOG_BYTE},
tests::fixture_builder::FixtureBuilder
};

fn new_builder() -> FixtureBuilder {
let mut builder = FixtureBuilder::new();
builder.tx_context.gas_settings.teardown_gas_limits = Gas::new(12, 345);
builder
}

#[test]
fn meter_gas_used_empty_succeeds() {
let builder = new_builder();
let data = builder.to_combined_accumulated_data();
let gas_settings = builder.tx_context.gas_settings;
let gas = meter_gas_used(data, gas_settings);
assert_eq(gas, Gas::tx_overhead() + gas_settings.teardown_gas_limits);
}

#[test]
fn meter_gas_used_everything_succeeds() {
let mut builder = new_builder();
let mut metered_da_bytes = 0;
let mut computed_l2_gas = 0;

builder.append_note_hashes(4);
metered_da_bytes += 4 * DA_BYTES_PER_FIELD;
computed_l2_gas += 4 * L2_GAS_PER_NOTE_HASH;

builder.append_nullifiers(3);
metered_da_bytes += 3 * DA_BYTES_PER_FIELD;
computed_l2_gas += 3 * L2_GAS_PER_NULLIFIER;

builder.append_l2_to_l1_msgs(1);
metered_da_bytes += 1 * DA_BYTES_PER_FIELD;

builder.add_note_encrypted_log_hash(1001, 12, 0);
metered_da_bytes += 12;
computed_l2_gas += 12 * L2_GAS_PER_LOG_BYTE;

builder.add_note_encrypted_log_hash(1002, 8, 0);
metered_da_bytes += 8;
computed_l2_gas += 8 * L2_GAS_PER_LOG_BYTE;

builder.add_note_encrypted_log_hash(1003, 20, 0);
metered_da_bytes += 20;
computed_l2_gas += 20 * L2_GAS_PER_LOG_BYTE;

builder.add_encrypted_log_hash(2001, 2);
metered_da_bytes += 2;
computed_l2_gas += 2 * L2_GAS_PER_LOG_BYTE;

builder.add_encrypted_log_hash(2002, 6);
metered_da_bytes += 6;
computed_l2_gas += 6 * L2_GAS_PER_LOG_BYTE;

builder.add_unencrypted_log_hash(3001, 51);
metered_da_bytes += 51;
computed_l2_gas += 51 * L2_GAS_PER_LOG_BYTE;

let data = builder.to_combined_accumulated_data();
let gas_settings = builder.tx_context.gas_settings;
let gas = meter_gas_used(data, gas_settings);

assert_eq(
gas, Gas::new(metered_da_bytes * DA_GAS_PER_BYTE, computed_l2_gas)
+ Gas::tx_overhead()
+ gas_settings.teardown_gas_limits
);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod meter_gas_used;

use crate::components::tail_output_composer::TailOutputComposer;
use dep::types::{abis::kernel_circuit_public_inputs::KernelCircuitPublicInputs, tests::fixture_builder::FixtureBuilder};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
mod validate_accumulated_values;
mod validate_empty_values;
mod validate_gas_used;
mod validate_propagated_sorted_siloed_values;
mod validate_propagated_values;

use crate::components::tail_output_validator::TailOutputValidator;
use dep::types::tests::fixture_builder::FixtureBuilder;
use crate::components::{tail_output_composer::meter_gas_used::meter_gas_used, tail_output_validator::TailOutputValidator};
use dep::types::{
abis::{gas_settings::GasSettings, kernel_circuit_public_inputs::KernelCircuitPublicInputs},
tests::fixture_builder::FixtureBuilder
};

struct TailOutputValidatorBuilder {
output: FixtureBuilder,
Expand All @@ -15,13 +19,26 @@ impl TailOutputValidatorBuilder {
pub fn new() -> Self {
let mut output = FixtureBuilder::new();
let mut previous_kernel = FixtureBuilder::new();
output.tx_context.gas_settings = GasSettings::default();
previous_kernel.tx_context.gas_settings = GasSettings::default();
output.set_first_nullifier();
previous_kernel.set_first_nullifier();
TailOutputValidatorBuilder { output, previous_kernel }
}

pub fn export_output(self) -> KernelCircuitPublicInputs {
let mut output = self.output.to_kernel_circuit_public_inputs();
output.end.gas_used = meter_gas_used(output.end, output.constants.tx_context.gas_settings);
output
}

pub fn validate(self) {
let output = self.output.to_kernel_circuit_public_inputs();
let output = self.export_output();
let previous_kernel = self.previous_kernel.to_private_kernel_circuit_public_inputs();
TailOutputValidator::new(output, previous_kernel).validate();
}

pub fn validate_with_output(self, output: KernelCircuitPublicInputs) {
let previous_kernel = self.previous_kernel.to_private_kernel_circuit_public_inputs();
TailOutputValidator::new(output, previous_kernel).validate();
}
Expand Down
Loading
Loading