diff --git a/crates/blockifier/src/fee/eth_gas_constants.rs b/crates/blockifier/src/fee/eth_gas_constants.rs index 6c337ea245..de33dbb0fc 100644 --- a/crates/blockifier/src/fee/eth_gas_constants.rs +++ b/crates/blockifier/src/fee/eth_gas_constants.rs @@ -16,12 +16,20 @@ pub const GAS_PER_NONZERO_TO_INT_STORAGE_SET: usize = 2900; pub const GAS_PER_COUNTER_DECREASE: usize = GAS_PER_COLD_STORAGE_ACCESS + GAS_PER_NONZERO_TO_INT_STORAGE_SET; -// Events. +// L1 Events. pub const GAS_PER_LOG: usize = 375; pub const GAS_PER_LOG_TOPIC: usize = 375; pub const GAS_PER_LOG_DATA_BYTE: usize = 8; pub const GAS_PER_LOG_DATA_WORD: usize = GAS_PER_LOG_DATA_BYTE * WORD_WIDTH; +// L2 Events. +pub const MILLI_GAS_PER_KEY_BYTE: usize = 40; +pub const MILLI_GAS_PER_DATA_BYTE: usize = 2 * MILLI_GAS_PER_KEY_BYTE; +// TODO(barak, 18/03/2024): Remove calculation per StarkFelt. +// Every key and every data word is a StarkFelt which contains 32 bytes. +pub const MILLI_GAS_PER_KEY: usize = 32 * MILLI_GAS_PER_KEY_BYTE; +pub const MILLI_GAS_PER_DATA_WORD: usize = 32 * MILLI_GAS_PER_DATA_BYTE; + // SHARP empirical costs. pub const SHARP_ADDITIONAL_GAS_PER_MEMORY_WORD: usize = 100; // This value is not accurate. pub const SHARP_GAS_PER_MEMORY_WORD: usize = diff --git a/crates/blockifier/src/fee/gas_usage.rs b/crates/blockifier/src/fee/gas_usage.rs index 8535f688da..de90137e1f 100644 --- a/crates/blockifier/src/fee/gas_usage.rs +++ b/crates/blockifier/src/fee/gas_usage.rs @@ -22,18 +22,42 @@ pub mod test; /// e.g., a message from L2 to L1 is followed by a storage write operation in Starknet L1 contract /// which requires gas. pub fn calculate_tx_gas_usage_vector<'a>( - call_infos: impl Iterator, + call_infos: impl Iterator + Clone, state_changes_count: StateChangesCount, l1_handler_payload_size: Option, use_kzg_da: bool, ) -> TransactionExecutionResult { - Ok(calculate_messages_gas_vector(call_infos, l1_handler_payload_size)? - + get_da_gas_cost(state_changes_count, use_kzg_da)) + // TODO(barak, 18/03/2024): Iterate over call_infos once without cloning. + Ok(get_messages_gas_cost(call_infos.clone(), l1_handler_payload_size)? + + get_da_gas_cost(state_changes_count, use_kzg_da) + + get_events_gas_cost(call_infos)) +} + +fn get_events_gas_cost<'a>(call_infos: impl Iterator) -> GasVector { + let mut milli_gas_vector = GasVector { l1_gas: 0, blob_gas: 0 }; + for call_info in call_infos { + milli_gas_vector = milli_gas_vector + + call_info.execution.events.iter().fold( + GasVector { l1_gas: 0, blob_gas: 0 }, + |sum, ordered_event| { + sum + GasVector { + l1_gas: u128_from_usize( + ordered_event.event.keys.len() * eth_gas_constants::MILLI_GAS_PER_KEY + + ordered_event.event.data.0.len() + * eth_gas_constants::MILLI_GAS_PER_DATA_WORD, + ) + .expect("Could not convert starknet gas usage from usize to u128."), + blob_gas: 0, + } + }, + ) + } + GasVector { l1_gas: milli_gas_vector.l1_gas / 1000, blob_gas: milli_gas_vector.blob_gas / 1000 } } /// 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, l1_handler_payload_size: Option, ) -> TransactionExecutionResult {