diff --git a/crates/executor/src/estimate.rs b/crates/executor/src/estimate.rs index cc87e5f826..b92407760f 100644 --- a/crates/executor/src/estimate.rs +++ b/crates/executor/src/estimate.rs @@ -8,7 +8,6 @@ use blockifier::{ transaction::transaction_execution::Transaction, transaction::transactions::ExecutableTransaction, }; -use primitive_types::U256; pub fn estimate( mut execution_state: ExecutionState<'_>, @@ -25,18 +24,16 @@ pub fn estimate( let fee_type = &super::transaction::fee_type(&transaction); - let gas_price: U256 = block_context + let gas_price = block_context .block_info() .gas_prices .get_gas_price_by_fee_type(fee_type) - .get() - .into(); - let data_gas_price: U256 = block_context + .get(); + let data_gas_price = block_context .block_info() .gas_prices .get_data_gas_price_by_fee_type(fee_type) - .get() - .into(); + .get(); let unit = match fee_type { blockifier::transaction::objects::FeeType::Strk => PriceUnit::Fri, blockifier::transaction::objects::FeeType::Eth => PriceUnit::Wei, @@ -69,14 +66,12 @@ pub fn estimate( tracing::trace!(actual_fee=%tx_info.actual_fee.0, actual_resources=?tx_info.actual_resources, "Transaction estimation finished"); - fees.push(FeeEstimate { - gas_consumed: U256::from(tx_info.actual_fee.0) / gas_price.max(1.into()), + fees.push(FeeEstimate::from_tx_info_and_gas_price( + &tx_info, gas_price, - data_gas_consumed: U256::from(tx_info.da_gas.l1_data_gas), data_gas_price, - overall_fee: tx_info.actual_fee.0.into(), unit, - }); + )); } Err(error) => { tracing::debug!(%error, %transaction_idx, "Transaction estimation failed"); diff --git a/crates/executor/src/execution_state.rs b/crates/executor/src/execution_state.rs index 5a9bec3e3e..8d79b3a2cf 100644 --- a/crates/executor/src/execution_state.rs +++ b/crates/executor/src/execution_state.rs @@ -10,7 +10,9 @@ use blockifier::{ state::cached_state::{CachedState, GlobalContractCache}, versioned_constants::VersionedConstants, }; -use pathfinder_common::{contract_address, BlockHeader, ChainId, ContractAddress, StateUpdate}; +use pathfinder_common::{ + contract_address, BlockHeader, ChainId, ContractAddress, L1DataAvailabilityMode, StateUpdate, +}; use starknet_api::core::PatriciaKey; // NOTE: these are the same for _all_ networks @@ -63,6 +65,7 @@ pub struct ExecutionState<'tx> { pub header: BlockHeader, execute_on_parent_state: bool, pending_state: Option>, + allow_use_kzg_data: bool, } impl<'tx> ExecutionState<'tx> { @@ -196,7 +199,8 @@ impl<'tx> ExecutionState<'tx> { self.header.strk_l1_data_gas_price.0.try_into().unwrap() }, }, - use_kzg_da: false, + use_kzg_da: self.allow_use_kzg_data + && self.header.l1_da_mode == L1DataAvailabilityMode::Blob, }) } @@ -212,6 +216,7 @@ impl<'tx> ExecutionState<'tx> { header, pending_state, execute_on_parent_state: true, + allow_use_kzg_data: true, } } @@ -220,6 +225,7 @@ impl<'tx> ExecutionState<'tx> { chain_id: ChainId, header: BlockHeader, pending_state: Option>, + l1_blob_data_availability: L1BlobDataAvailability, ) -> Self { Self { transaction, @@ -227,6 +233,13 @@ impl<'tx> ExecutionState<'tx> { header, pending_state, execute_on_parent_state: false, + allow_use_kzg_data: l1_blob_data_availability == L1BlobDataAvailability::Enabled, } } } + +#[derive(Copy, Clone, PartialEq)] +pub enum L1BlobDataAvailability { + Disabled, + Enabled, +} diff --git a/crates/executor/src/lib.rs b/crates/executor/src/lib.rs index 96ffee9f29..49878d3a7d 100644 --- a/crates/executor/src/lib.rs +++ b/crates/executor/src/lib.rs @@ -15,7 +15,7 @@ pub use call::call; pub use class::{parse_casm_definition, parse_deprecated_class_definition}; pub use error::{CallError, TransactionExecutionError}; pub use estimate::estimate; -pub use execution_state::{ExecutionState, ETH_FEE_TOKEN_ADDRESS}; +pub use execution_state::{ExecutionState, L1BlobDataAvailability, ETH_FEE_TOKEN_ADDRESS}; pub use felt::{IntoFelt, IntoStarkFelt}; pub use simulate::{simulate, trace, TraceCache}; diff --git a/crates/executor/src/simulate.rs b/crates/executor/src/simulate.rs index 575961eb91..7b496e96a0 100644 --- a/crates/executor/src/simulate.rs +++ b/crates/executor/src/simulate.rs @@ -14,7 +14,6 @@ use pathfinder_common::{ BlockHash, CasmHash, ClassHash, ContractAddress, ContractNonce, SierraHash, StorageAddress, StorageValue, TransactionHash, }; -use primitive_types::U256; use crate::{ transaction::transaction_hash, @@ -68,18 +67,16 @@ pub fn simulate( transaction_declared_deprecated_class(&transaction); let fee_type = &super::transaction::fee_type(&transaction); - let gas_price: U256 = block_context + let gas_price = block_context .block_info() .gas_prices .get_gas_price_by_fee_type(fee_type) - .get() - .into(); - let data_gas_price: U256 = block_context + .get(); + let data_gas_price = block_context .block_info() .gas_prices .get_data_gas_price_by_fee_type(fee_type) - .get() - .into(); + .get(); let unit = match fee_type { blockifier::transaction::objects::FeeType::Strk => PriceUnit::Fri, blockifier::transaction::objects::FeeType::Eth => PriceUnit::Wei, @@ -117,14 +114,12 @@ pub fn simulate( tracing::trace!(actual_fee=%tx_info.actual_fee.0, actual_resources=?tx_info.actual_resources, "Transaction simulation finished"); simulations.push(TransactionSimulation { - fee_estimation: FeeEstimate { - gas_consumed: U256::from(tx_info.actual_fee.0) / gas_price.max(1.into()), + fee_estimation: FeeEstimate::from_tx_info_and_gas_price( + &tx_info, gas_price, - data_gas_consumed: U256::from(tx_info.da_gas.l1_data_gas), data_gas_price, - overall_fee: tx_info.actual_fee.0.into(), unit, - }, + ), trace: to_trace(transaction_type, tx_info, state_diff), }); } diff --git a/crates/executor/src/types.rs b/crates/executor/src/types.rs index a209226fe8..b10793615f 100644 --- a/crates/executor/src/types.rs +++ b/crates/executor/src/types.rs @@ -1,6 +1,8 @@ use std::collections::{BTreeMap, HashSet}; -use blockifier::execution::call_info::OrderedL2ToL1Message; +use blockifier::{ + execution::call_info::OrderedL2ToL1Message, transaction::objects::TransactionExecutionInfo, +}; use pathfinder_common::{ CasmHash, ClassHash, ContractAddress, ContractNonce, SierraHash, StorageAddress, StorageValue, }; @@ -18,6 +20,37 @@ pub struct FeeEstimate { pub unit: PriceUnit, } +impl FeeEstimate { + /// Computes fee estimate from the transaction execution information. + /// + /// `TransactionExecutionInfo` contains two related fields: + /// - `TransactionExecutionInfo::actual_fee` is the overall cost of the transaction (in WEI/FRI) + /// - `TransactionExecutionInfo::da_gas` is the gas usage for _data availability_. + /// + /// The problem is that we have to return both `gas_usage` and `data_gas_usage` but we don't + /// directly have the value of `gas_usage` from the execution info, so we have to calculate + /// that from other fields. + pub(crate) fn from_tx_info_and_gas_price( + tx_info: &TransactionExecutionInfo, + gas_price: u128, + data_gas_price: u128, + unit: PriceUnit, + ) -> FeeEstimate { + let data_gas_consumed = tx_info.da_gas.l1_data_gas; + let data_gas_fee = data_gas_consumed.saturating_mul(data_gas_price); + let gas_consumed = tx_info.actual_fee.0.saturating_sub(data_gas_fee) / gas_price.max(1); + + FeeEstimate { + gas_consumed: gas_consumed.into(), + gas_price: gas_price.into(), + data_gas_consumed: data_gas_consumed.into(), + data_gas_price: data_gas_price.into(), + overall_fee: tx_info.actual_fee.0.into(), + unit, + } + } +} + #[derive(Debug, Eq, PartialEq)] pub enum PriceUnit { Wei, diff --git a/crates/pathfinder/examples/re_execute.rs b/crates/pathfinder/examples/re_execute.rs index 0674e059e9..6667e67069 100644 --- a/crates/pathfinder/examples/re_execute.rs +++ b/crates/pathfinder/examples/re_execute.rs @@ -85,9 +85,9 @@ fn main() -> anyhow::Result<()> { .par_bridge() .for_each_with(storage, |storage, block| execute(storage, chain_id, block)); - let elapsed = start_time.elapsed().as_millis(); + let elapsed = start_time.elapsed(); - tracing::debug!(%num_transactions, %elapsed, "Finished"); + tracing::info!(%num_transactions, ?elapsed, "Finished"); Ok(()) } @@ -95,6 +95,7 @@ fn main() -> anyhow::Result<()> { fn get_chain_id(tx: &pathfinder_storage::Transaction<'_>) -> anyhow::Result { use pathfinder_common::consts::{ GOERLI_INTEGRATION_GENESIS_HASH, GOERLI_TESTNET_GENESIS_HASH, MAINNET_GENESIS_HASH, + SEPOLIA_INTEGRATION_GENESIS_HASH, SEPOLIA_TESTNET_GENESIS_HASH, }; let (_, genesis_hash) = tx @@ -106,6 +107,8 @@ fn get_chain_id(tx: &pathfinder_storage::Transaction<'_>) -> anyhow::Result ChainId::MAINNET, GOERLI_TESTNET_GENESIS_HASH => ChainId::GOERLI_TESTNET, GOERLI_INTEGRATION_GENESIS_HASH => ChainId::GOERLI_INTEGRATION, + SEPOLIA_TESTNET_GENESIS_HASH => ChainId::SEPOLIA_TESTNET, + SEPOLIA_INTEGRATION_GENESIS_HASH => ChainId::SEPOLIA_INTEGRATION, _ => anyhow::bail!("Unknown chain"), }; @@ -143,9 +146,9 @@ fn execute(storage: &mut Storage, chain_id: ChainId, work: Work) { } }; - match pathfinder_executor::estimate(execution_state, transactions, false) { - Ok(fee_estimates) => { - for (estimate, receipt) in fee_estimates.iter().zip(work.receipts.iter()) { + match pathfinder_executor::simulate(execution_state, transactions, false, false) { + Ok(simulations) => { + for (simulation, receipt) in simulations.iter().zip(work.receipts.iter()) { if let Some(actual_fee) = receipt.actual_fee { let actual_fee = u128::from_be_bytes(actual_fee.0.to_be_bytes()[16..].try_into().unwrap()); @@ -155,15 +158,38 @@ fn execute(storage: &mut Storage, chain_id: ChainId, work: Work) { continue; } - let gas_price = work.header.eth_l1_gas_price.0; - let actual_gas_consumed = actual_fee / gas_price.max(1); + let estimate = &simulation.fee_estimation; + + let (gas_price, data_gas_price) = match estimate.unit { + pathfinder_executor::types::PriceUnit::Wei => ( + work.header.eth_l1_gas_price.0, + work.header.eth_l1_data_gas_price.0, + ), + pathfinder_executor::types::PriceUnit::Fri => ( + work.header.strk_l1_gas_price.0, + work.header.strk_l1_data_gas_price.0, + ), + }; + + let actual_data_gas_consumed = + receipt.execution_resources.data_availability.l1_data_gas; + let actual_gas_consumed = (actual_fee + - actual_data_gas_consumed.saturating_mul(data_gas_price)) + / gas_price.max(1); let estimated_gas_consumed = estimate.gas_consumed.as_u128(); - - let diff = actual_gas_consumed.abs_diff(estimated_gas_consumed); - - if diff > (actual_gas_consumed * 2 / 10) { - tracing::warn!(block_number=%work.header.number, transaction_hash=%receipt.transaction_hash, %estimated_gas_consumed, %actual_gas_consumed, estimated_fee=%estimate.overall_fee, %actual_fee, "Estimation mismatch"); + let estimated_data_gas_consumed = estimate.data_gas_consumed.as_u128(); + + let gas_diff = actual_gas_consumed.abs_diff(estimated_gas_consumed); + let data_gas_diff = + actual_data_gas_consumed.abs_diff(estimated_data_gas_consumed); + + if gas_diff > (actual_gas_consumed * 2 / 10) + || data_gas_diff > (actual_data_gas_consumed * 2 / 10) + { + tracing::warn!(block_number=%work.header.number, transaction_hash=%receipt.transaction_hash, %estimated_gas_consumed, %actual_gas_consumed, %estimated_data_gas_consumed, %actual_data_gas_consumed, estimated_fee=%estimate.overall_fee, %actual_fee, "Estimation mismatch"); + } else { + tracing::debug!(block_number=%work.header.number, transaction_hash=%receipt.transaction_hash, %estimated_gas_consumed, %actual_gas_consumed, %estimated_data_gas_consumed, %actual_data_gas_consumed, estimated_fee=%estimate.overall_fee, %actual_fee, "Estimation matches"); } } } diff --git a/crates/rpc/src/test_setup.rs b/crates/rpc/src/test_setup.rs index 1a362b73f4..42dea6e7c9 100644 --- a/crates/rpc/src/test_setup.rs +++ b/crates/rpc/src/test_setup.rs @@ -53,8 +53,9 @@ pub async fn test_storage StateUpdate>( .with_timestamp(BlockTimestamp::new_or_panic(1)) .with_eth_l1_gas_price(GasPrice(1)) .with_strk_l1_gas_price(GasPrice(2)) - .with_eth_l1_data_gas_price(GasPrice(1)) + .with_eth_l1_data_gas_price(GasPrice(2)) .with_strk_l1_data_gas_price(GasPrice(2)) + .with_l1_da_mode(pathfinder_common::L1DataAvailabilityMode::Blob) .with_sequencer_address(sequencer_address!( "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8" )) diff --git a/crates/rpc/src/v05/method/call.rs b/crates/rpc/src/v05/method/call.rs index 6e990bc7a2..8f8965c243 100644 --- a/crates/rpc/src/v05/method/call.rs +++ b/crates/rpc/src/v05/method/call.rs @@ -3,7 +3,7 @@ use crate::error::ApplicationError; use crate::felt::RpcFelt; use anyhow::Context; use pathfinder_common::{BlockId, CallParam, CallResultValue, ContractAddress, EntryPoint}; -use pathfinder_executor::ExecutionState; +use pathfinder_executor::{ExecutionState, L1BlobDataAvailability}; #[derive(Debug)] pub enum CallError { @@ -109,7 +109,13 @@ pub async fn call(context: RpcContext, input: CallInput) -> Result