Skip to content

Commit

Permalink
feat(blockifier): convert L2 gas to L1 gas units when computing fee w…
Browse files Browse the repository at this point in the history
…ith no L2 bounds

Signed-off-by: Dori Medini <dori@starkware.co>
  • Loading branch information
dorimedini-starkware committed Jan 1, 2025
1 parent 8aaddf0 commit 191993e
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 23 deletions.
16 changes: 11 additions & 5 deletions crates/blockifier/src/fee/fee_checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ use starknet_types_core::felt::Felt;
use thiserror::Error;

use crate::context::TransactionContext;
use crate::fee::fee_utils::{get_balance_and_if_covers_fee, get_fee_by_gas_vector};
use crate::fee::fee_utils::{
get_balance_and_if_covers_fee,
get_fee_by_gas_vector,
GasVectorToL1GasForFee,
};
use crate::fee::receipt::TransactionReceipt;
use crate::state::state_api::StateReader;
use crate::transaction::errors::TransactionExecutionError;
Expand Down Expand Up @@ -213,14 +217,16 @@ impl FeeCheckReport {
gas_vector: &GasVector,
tx_context: &TransactionContext,
) -> FeeCheckResult<()> {
let total_discounted_gas_used =
gas_vector.to_discounted_l1_gas(tx_context.get_gas_prices());
let total_l1_gas_used = gas_vector.to_l1_gas_for_fee(
tx_context.get_gas_prices(),
&tx_context.block_context.versioned_constants,
);

if total_discounted_gas_used > l1_bounds.max_amount {
if total_l1_gas_used > l1_bounds.max_amount {
return Err(FeeCheckError::MaxGasAmountExceeded {
resource: L1Gas,
max_amount: l1_bounds.max_amount,
actual_amount: total_discounted_gas_used,
actual_amount: total_l1_gas_used,
});
}
Ok(())
Expand Down
35 changes: 33 additions & 2 deletions crates/blockifier/src/fee/fee_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use cairo_vm::types::builtin_name::BuiltinName;
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
use num_bigint::BigUint;
use starknet_api::abi::abi_utils::get_fee_token_var_address;
use starknet_api::block::{BlockInfo, FeeType};
use starknet_api::block::{BlockInfo, FeeType, GasPriceVector};
use starknet_api::core::ContractAddress;
use starknet_api::execution_resources::GasVector;
use starknet_api::execution_resources::{GasAmount, GasVector};
use starknet_api::state::StorageKey;
use starknet_api::transaction::fields::ValidResourceBounds::{AllResources, L1Gas};
use starknet_api::transaction::fields::{Fee, GasVectorComputationMode, Resource};
Expand All @@ -24,6 +24,37 @@ use crate::versioned_constants::VersionedConstants;
#[path = "fee_test.rs"]
pub mod test;

/// A trait for converting a gas vector to L1 gas for fee. Converts both L1 data gas and L2 gas to
/// L1 gas units.
/// The trait is defined to allow implementing a method on GasVector, which is a starknet-api type.
pub trait GasVectorToL1GasForFee {
fn to_l1_gas_for_fee(
&self,
gas_prices: &GasPriceVector,
versioned_constants: &VersionedConstants,
) -> GasAmount;
}

impl GasVectorToL1GasForFee for GasVector {
fn to_l1_gas_for_fee(
&self,
gas_prices: &GasPriceVector,
versioned_constants: &VersionedConstants,
) -> GasAmount {
// Discounted gas converts data gas to L1 gas. Add L2 gas using conversion ratio.
let discounted_l1_gas = self.to_discounted_l1_gas(gas_prices);
discounted_l1_gas
.checked_add(versioned_constants.sierra_gas_to_l1_gas_amount_round_up(self.l2_gas))
.unwrap_or_else(|| {
panic!(
"L1 gas amount overflowed: addition of converted L2 gas ({}) to discounted \
gas ({}) resulted in overflow.",
self.l2_gas, discounted_l1_gas
);
})
}
}

/// Calculates the gas consumed when submitting the underlying Cairo program to SHARP.
/// I.e., returns the heaviest Cairo resource weight (in terms of gas), as the size of
/// a proof is determined similarly - by the (normalized) largest segment.
Expand Down
30 changes: 24 additions & 6 deletions crates/blockifier/src/fee/gas_usage_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::abi::constants;
use crate::context::BlockContext;
use crate::execution::call_info::{CallExecution, CallInfo, OrderedEvent};
use crate::fee::eth_gas_constants;
use crate::fee::fee_utils::get_fee_by_gas_vector;
use crate::fee::fee_utils::{get_fee_by_gas_vector, GasVectorToL1GasForFee};
use crate::fee::gas_usage::{get_da_gas_cost, get_message_segment_length};
use crate::fee::resources::{
ComputationResources,
Expand Down Expand Up @@ -281,25 +281,43 @@ fn test_get_message_segment_length(
fn test_discounted_gas_from_gas_vector_computation() {
let tx_context = BlockContext::create_for_testing()
.to_tx_context(&invoke_tx_with_default_flags(invoke_tx_args! {}));
let gas_usage =
GasVector { l1_gas: 100_u8.into(), l1_data_gas: 2_u8.into(), ..Default::default() };
let actual_result = gas_usage.to_discounted_l1_gas(tx_context.get_gas_prices());
let mut gas_usage =
GasVector { l1_gas: 100_u8.into(), l1_data_gas: 2_u8.into(), l2_gas: 3_u8.into() };
let actual_result = gas_usage.to_l1_gas_for_fee(
tx_context.get_gas_prices(),
&tx_context.block_context.versioned_constants,
);
let converted_l2_gas = tx_context
.block_context
.versioned_constants
.sierra_gas_to_l1_gas_amount_round_up(gas_usage.l2_gas);

let result_div_ceil = gas_usage.l1_gas
+ (gas_usage.l1_data_gas.checked_mul(DEFAULT_ETH_L1_DATA_GAS_PRICE.into()).unwrap())
.checked_div_ceil(DEFAULT_ETH_L1_GAS_PRICE)
.unwrap();
.unwrap()
+ converted_l2_gas;
let result_div_floor = gas_usage.l1_gas
+ (gas_usage.l1_data_gas.checked_mul(DEFAULT_ETH_L1_DATA_GAS_PRICE.into()).unwrap())
.checked_div(DEFAULT_ETH_L1_GAS_PRICE)
.unwrap();
.unwrap()
+ converted_l2_gas;

assert_eq!(actual_result, result_div_ceil);
assert_eq!(actual_result, result_div_floor + 1_u8.into());
assert!(
get_fee_by_gas_vector(&tx_context.block_context.block_info, gas_usage, &FeeType::Eth)
<= actual_result.checked_mul(DEFAULT_ETH_L1_GAS_PRICE.into()).unwrap()
);

// Make sure L2 gas has an effect.
gas_usage.l2_gas = 0_u8.into();
assert!(
gas_usage.to_l1_gas_for_fee(
tx_context.get_gas_prices(),
&tx_context.block_context.versioned_constants,
) < actual_result
);
}

#[rstest]
Expand Down
6 changes: 5 additions & 1 deletion crates/blockifier/src/transaction/account_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use crate::fee::fee_utils::{
get_fee_by_gas_vector,
get_sequencer_balance_keys,
verify_can_pay_committed_bounds,
GasVectorToL1GasForFee,
};
use crate::fee::gas_usage::estimate_minimal_gas_vector;
use crate::fee::receipt::TransactionReceipt;
Expand Down Expand Up @@ -274,7 +275,10 @@ impl AccountTransaction {
ValidResourceBounds::L1Gas(l1_gas_resource_bounds) => vec![(
L1Gas,
l1_gas_resource_bounds,
minimal_gas_amount_vector.to_discounted_l1_gas(tx_context.get_gas_prices()),
minimal_gas_amount_vector.to_l1_gas_for_fee(
tx_context.get_gas_prices(),
&tx_context.block_context.versioned_constants,
),
block_info.gas_prices.l1_gas_price(fee_type),
)],
ValidResourceBounds::AllResources(AllResourceBounds {
Expand Down
10 changes: 8 additions & 2 deletions crates/blockifier/src/transaction/account_transactions_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ use crate::execution::call_info::CallInfo;
use crate::execution::contract_class::TrackedResource;
use crate::execution::entry_point::EntryPointExecutionContext;
use crate::execution::syscalls::SyscallSelector;
use crate::fee::fee_utils::{get_fee_by_gas_vector, get_sequencer_balance_keys};
use crate::fee::fee_utils::{
get_fee_by_gas_vector,
get_sequencer_balance_keys,
GasVectorToL1GasForFee,
};
use crate::fee::gas_usage::estimate_minimal_gas_vector;
use crate::state::cached_state::{StateChangesCount, StateChangesCountForFee, TransactionalState};
use crate::state::state_api::{State, StateReader};
Expand Down Expand Up @@ -555,7 +559,9 @@ fn test_max_fee_limit_validate(
};
let gas_prices = tx_context.get_gas_prices();
l1_resource_bounds(
estimated_min_gas_usage_vector.to_discounted_l1_gas(gas_prices),
estimated_min_gas_usage_vector.to_l1_gas_for_fee(
gas_prices, &tx_context.block_context.versioned_constants
),
gas_prices.l1_gas_price.into(),
)
}
Expand Down
3 changes: 2 additions & 1 deletion crates/blockifier/src/transaction/post_execution_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use starknet_types_core::felt::Felt;

use crate::context::{BlockContext, ChainInfo};
use crate::fee::fee_checks::FeeCheckError;
use crate::fee::fee_utils::GasVectorToL1GasForFee;
use crate::state::state_api::StateReader;
use crate::test_utils::contracts::FeatureContract;
use crate::test_utils::initial_test_state::test_state;
Expand Down Expand Up @@ -310,7 +311,7 @@ fn test_revert_on_resource_overuse(
// units for bounds check in post-execution.
let tight_resource_bounds = match gas_mode {
GasVectorComputationMode::NoL2Gas => l1_resource_bounds(
actual_gas_usage.to_discounted_l1_gas(gas_prices),
actual_gas_usage.to_l1_gas_for_fee(gas_prices, &block_context.versioned_constants),
DEFAULT_STRK_L1_GAS_PRICE.into(),
),
GasVectorComputationMode::All => {
Expand Down
6 changes: 4 additions & 2 deletions crates/blockifier/src/transaction/transactions_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ use crate::execution::entry_point::{CallEntryPoint, CallType};
use crate::execution::errors::{ConstructorEntryPointExecutionError, EntryPointExecutionError};
use crate::execution::syscalls::hint_processor::EmitEventError;
use crate::execution::syscalls::SyscallSelector;
use crate::fee::fee_utils::{balance_to_big_uint, get_fee_by_gas_vector};
use crate::fee::fee_utils::{balance_to_big_uint, get_fee_by_gas_vector, GasVectorToL1GasForFee};
use crate::fee::gas_usage::{
estimate_minimal_gas_vector,
get_da_gas_cost,
Expand Down Expand Up @@ -1389,7 +1389,9 @@ fn test_actual_fee_gt_resource_bounds(
// Create new gas bounds that are lower than the actual gas.
let (expected_fee, overdraft_resource_bounds) = match gas_mode {
GasVectorComputationMode::NoL2Gas => {
let l1_gas_bound = GasAmount(actual_gas.to_discounted_l1_gas(gas_prices).0 - 1);
let l1_gas_bound = GasAmount(
actual_gas.to_l1_gas_for_fee(gas_prices, &block_context.versioned_constants).0 - 1,
);
(
GasVector::from_l1_gas(l1_gas_bound).cost(gas_prices),
l1_resource_bounds(l1_gas_bound, gas_prices.l1_gas_price.into()),
Expand Down
6 changes: 2 additions & 4 deletions crates/starknet_api/src/execution_resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,9 @@ impl GasVector {
/// If this function is called with kzg_flag==false, then l1_data_gas==0, and this discount
/// function does nothing.
/// Panics on overflow.
/// Does not take L2 gas into account - more context is required to convert L2 gas units to L1
/// gas units (context defined outside of the current crate).
pub fn to_discounted_l1_gas(&self, gas_prices: &GasPriceVector) -> GasAmount {
if self.l2_gas.0 > 0 {
// TODO(Yoni, 10/12/2024): convert L2 gas as well.
todo!();
}
let l1_data_gas_fee = self
.l1_data_gas
.checked_mul(gas_prices.l1_data_gas_price.into())
Expand Down

0 comments on commit 191993e

Please sign in to comment.