Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
feat(fee): add events gas cost
Browse files Browse the repository at this point in the history
  • Loading branch information
barak-b-starkware committed Feb 11, 2024
1 parent 98ebaf4 commit 753a4cb
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 18 deletions.
52 changes: 43 additions & 9 deletions crates/blockifier/src/fee/gas_usage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashMap;

use crate::abi::constants;
use crate::context::{BlockContext, TransactionContext};
use crate::execution::call_info::{CallInfo, MessageL1CostInfo};
use crate::execution::call_info::{CallInfo, MessageL1CostInfo, OrderedEvent};
use crate::fee::eth_gas_constants;
use crate::fee::fee_utils::calculate_tx_gas_vector;
use crate::state::cached_state::StateChangesCount;
Expand All @@ -19,34 +19,68 @@ use crate::versioned_constants::VersionedConstants;
#[path = "gas_usage_test.rs"]
pub mod test;

/// Returns an estimation of the L1 gas amount that will be used (by Starknet's state update and
/// the Verifier) following the addition of a transaction with the given parameters to a batch;
/// e.g., a message from L2 to L1 is followed by a storage write operation in Starknet L1 contract
/// which requires gas.
/// Calculates an estimated gas usage for a transaction on L1, based on the provided parameters.
/// This function estimates the amount of L1 gas required for processing state updates and
/// verification after adding a transaction to a batch. This includes scenarios such as L2 to L1
/// messages, which result in storage write operations on the StarkNet L1 contract, consuming
/// gas.
// TODO(barak, 18/03/2024): Move to ActualCostBuilder impl block.
#[allow(clippy::too_many_arguments)]
pub fn calculate_tx_gas_usage_vector<'a>(
versioned_constants: &VersionedConstants,
call_infos: impl Iterator<Item = &'a CallInfo>,
call_infos: impl Iterator<Item = &'a CallInfo> + Clone,
state_changes_count: StateChangesCount,
calldata_length: usize,
signature_length: usize,
l1_handler_payload_size: Option<usize>,
class_info: Option<ClassInfo>,
use_kzg_da: bool,
) -> TransactionExecutionResult<GasVector> {
Ok(calculate_messages_gas_vector(call_infos, l1_handler_payload_size)?
Ok(get_messages_gas_cost(call_infos.clone(), l1_handler_payload_size)?
+ get_da_gas_cost(state_changes_count, use_kzg_da)
+ get_calldata_and_signature_gas_cost(
calldata_length,
signature_length,
versioned_constants,
)
+ get_code_gas_cost(class_info, versioned_constants))
+ get_code_gas_cost(class_info, versioned_constants)
+ get_tx_events_gas_cost(call_infos, versioned_constants))
}

pub fn get_tx_events_gas_cost<'a>(
call_infos: impl Iterator<Item = &'a CallInfo>,
versioned_constants: &VersionedConstants,
) -> GasVector {
let l1_milligas: u128 = call_infos
.map(|call_info| get_events_milligas_cost(&call_info.execution.events, versioned_constants))
.sum();
GasVector { l1_gas: l1_milligas / 1000_u128, l1_data_gas: 0_u128 }
}

pub fn get_events_milligas_cost(
events: &[OrderedEvent],
versioned_constants: &VersionedConstants,
) -> u128 {
let l2_resource_gas_costs = &versioned_constants.l2_resource_gas_costs;
let (event_key_factor, data_word_cost) =
(l2_resource_gas_costs.event_key_factor, l2_resource_gas_costs.milligas_per_data_felt);
let safe_u128_from_usize =
|x| u128_from_usize(x).expect("Could not convert starknet gas usage from usize to u128.");
events
.iter()
.map(|OrderedEvent { event, .. }| {
// TODO(barak: 18/03/2024): Once we start charging per byte change to num_bytes_keys and
// num_bytes_data.
let keys_size = safe_u128_from_usize(event.keys.len());
let data_size = safe_u128_from_usize(event.data.0.len());
event_key_factor * data_word_cost * keys_size + data_word_cost * data_size
})
.sum()
}

/// Returns an estimation of the gas usage for processing L1<>L2 messages on L1. Accounts for both
/// Starknet and SHARP contracts.
pub fn calculate_messages_gas_vector<'a>(
pub fn get_messages_gas_cost<'a>(
call_infos: impl Iterator<Item = &'a CallInfo>,
l1_handler_payload_size: Option<usize>,
) -> TransactionExecutionResult<GasVector> {
Expand Down
81 changes: 77 additions & 4 deletions crates/blockifier/src/fee/gas_usage_test.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,93 @@
use pretty_assertions::assert_eq;
use rstest::rstest;
use rstest::{fixture, rstest};
use starknet_api::hash::StarkFelt;
use starknet_api::stark_felt;
use starknet_api::transaction::L2ToL1Payload;
use starknet_api::transaction::{EventContent, EventData, EventKey, L2ToL1Payload};

use crate::execution::call_info::{CallExecution, CallInfo, MessageToL1, OrderedL2ToL1Message};
use crate::execution::call_info::{
CallExecution, CallInfo, MessageToL1, OrderedEvent, OrderedL2ToL1Message,
};
use crate::fee::eth_gas_constants;
use crate::fee::gas_usage::{
calculate_tx_gas_usage_vector, get_consumed_message_to_l2_emissions_cost, get_da_gas_cost,
get_log_message_to_l1_emissions_cost, get_message_segment_length,
get_log_message_to_l1_emissions_cost, get_message_segment_length, get_tx_events_gas_cost,
};
use crate::state::cached_state::StateChangesCount;
use crate::transaction::objects::GasVector;
use crate::utils::{u128_from_usize, usize_from_u128};
use crate::versioned_constants::VersionedConstants;

#[fixture]
fn versioned_constants() -> &'static VersionedConstants {
VersionedConstants::latest_constants()
}

#[rstest]
fn test_get_event_gas_cost(versioned_constants: &VersionedConstants) {
let l2_resource_gas_costs = &versioned_constants.l2_resource_gas_costs;
let (event_key_factor, data_word_cost) =
(l2_resource_gas_costs.event_key_factor, l2_resource_gas_costs.milligas_per_data_felt);

let call_infos = vec![CallInfo::default(), CallInfo::default(), CallInfo::default()];
assert_eq!(
GasVector::default(),
get_tx_events_gas_cost(call_infos.iter(), versioned_constants)
);

let create_trivial_ordered_event_from_keys_and_data_sizes =
|keys_size: usize, data_size: usize| OrderedEvent {
order: 0,
event: EventContent {
keys: vec![EventKey(StarkFelt::ZERO); keys_size],
data: EventData(vec![StarkFelt::ZERO; data_size]),
},
};
let call_infos = vec![
CallInfo {
execution: CallExecution {
events: vec![
create_trivial_ordered_event_from_keys_and_data_sizes(1, 2),
create_trivial_ordered_event_from_keys_and_data_sizes(1, 2),
],
..Default::default()
},
..Default::default()
},
CallInfo {
execution: CallExecution {
events: vec![
create_trivial_ordered_event_from_keys_and_data_sizes(1, 0),
create_trivial_ordered_event_from_keys_and_data_sizes(0, 1),
],
..Default::default()
},
..Default::default()
},
CallInfo {
execution: CallExecution {
events: vec![create_trivial_ordered_event_from_keys_and_data_sizes(0, 1)],
..Default::default()
},
inner_calls: vec![CallInfo {
execution: CallExecution {
events: vec![create_trivial_ordered_event_from_keys_and_data_sizes(1, 0)],
..Default::default()
},
..Default::default()
}],
..Default::default()
},
];
let expected = GasVector {
// 4 keys and 6 data words overall.
l1_gas: (event_key_factor * data_word_cost * 4_u128 + data_word_cost * 6_u128) / 1000,
l1_data_gas: 0_u128,
};
let gas_vector = get_tx_events_gas_cost(call_infos.iter(), versioned_constants);
assert_eq!(expected, gas_vector);
assert_ne!(GasVector::default(), gas_vector)
}

#[rstest]
#[case::storage_write(StateChangesCount {
n_storage_updates: 1,
Expand Down
4 changes: 3 additions & 1 deletion crates/blockifier/src/transaction/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ pub struct DeprecatedTransactionInfo {
pub max_fee: Fee,
}

#[derive(derive_more::Add, derive_more::Sum, Clone, Debug, Default, Eq, PartialEq, Serialize)]
#[derive(
derive_more::Add, derive_more::Sum, Clone, Copy, Debug, Default, Eq, PartialEq, Serialize,
)]
pub struct GasVector {
pub l1_gas: u128,
pub l1_data_gas: u128,
Expand Down
9 changes: 5 additions & 4 deletions crates/blockifier/src/transaction/transactions_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ fn validate_final_balances(
}
}

// TODO(Gilad, 30/03/2024): Make this an associated function of InvokeTxArgs.
fn default_invoke_tx_args(
account_contract_address: ContractAddress,
test_contract_address: ContractAddress,
Expand Down Expand Up @@ -434,7 +435,7 @@ fn test_invoke_tx(
execute_call_info: expected_execute_call_info,
fee_transfer_call_info: expected_fee_transfer_call_info,
actual_fee: expected_actual_fee,
da_gas: da_gas.clone(),
da_gas,
actual_resources: ResourcesMapping(HashMap::from([
(
abi_constants::BLOB_GAS_USAGE.to_string(),
Expand Down Expand Up @@ -1135,14 +1136,14 @@ fn test_declare_tx(

let da_gas = declare_expected_gas_vector(tx_version, use_kzg_da);
let code_gas: GasVector = get_code_gas_cost(Some(class_info.clone()), versioned_constants);
let gas_usage = code_gas + da_gas.clone();
let gas_usage = code_gas + da_gas;

let expected_execution_info = TransactionExecutionInfo {
validate_call_info: expected_validate_call_info,
execute_call_info: None,
fee_transfer_call_info: expected_fee_transfer_call_info,
actual_fee: expected_actual_fee,
da_gas: da_gas.clone(),
da_gas,
revert_error: None,
actual_resources: ResourcesMapping(HashMap::from([
(abi_constants::L1_GAS_USAGE.to_string(), gas_usage.l1_gas.try_into().unwrap()),
Expand Down Expand Up @@ -1279,7 +1280,7 @@ fn test_deploy_account_tx(
execute_call_info: expected_execute_call_info,
fee_transfer_call_info: expected_fee_transfer_call_info,
actual_fee: expected_actual_fee,
da_gas: da_gas.clone(),
da_gas,
revert_error: None,
actual_resources: ResourcesMapping(HashMap::from([
(abi_constants::L1_GAS_USAGE.to_string(), usize_from_u128(da_gas.l1_gas).unwrap()),
Expand Down

0 comments on commit 753a4cb

Please sign in to comment.