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

feat(executor): enable L1 blob data availability mode for execution #1800

Merged
merged 7 commits into from
Feb 23, 2024
19 changes: 7 additions & 12 deletions crates/executor/src/estimate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use blockifier::{
transaction::transaction_execution::Transaction,
transaction::transactions::ExecutableTransaction,
};
use primitive_types::U256;

pub fn estimate(
mut execution_state: ExecutionState<'_>,
Expand All @@ -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,
Expand Down Expand Up @@ -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");
Expand Down
17 changes: 15 additions & 2 deletions crates/executor/src/execution_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -63,6 +65,7 @@ pub struct ExecutionState<'tx> {
pub header: BlockHeader,
execute_on_parent_state: bool,
pending_state: Option<Arc<StateUpdate>>,
allow_use_kzg_data: bool,
}

impl<'tx> ExecutionState<'tx> {
Expand Down Expand Up @@ -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,
})
}

Expand All @@ -212,6 +216,7 @@ impl<'tx> ExecutionState<'tx> {
header,
pending_state,
execute_on_parent_state: true,
allow_use_kzg_data: true,
}
}

Expand All @@ -220,13 +225,21 @@ impl<'tx> ExecutionState<'tx> {
chain_id: ChainId,
header: BlockHeader,
pending_state: Option<Arc<StateUpdate>>,
l1_blob_data_availability: L1BlobDataAvailability,
) -> Self {
Self {
transaction,
chain_id,
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,
}
2 changes: 1 addition & 1 deletion crates/executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down
19 changes: 7 additions & 12 deletions crates/executor/src/simulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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),
});
}
Expand Down
35 changes: 34 additions & 1 deletion crates/executor/src/types.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand All @@ -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,
Expand Down
50 changes: 38 additions & 12 deletions crates/pathfinder/examples/re_execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,17 @@ 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(())
}

fn get_chain_id(tx: &pathfinder_storage::Transaction<'_>) -> anyhow::Result<ChainId> {
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
Expand All @@ -106,6 +107,8 @@ fn get_chain_id(tx: &pathfinder_storage::Transaction<'_>) -> anyhow::Result<Chai
MAINNET_GENESIS_HASH => 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"),
};

Expand Down Expand Up @@ -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());
Expand All @@ -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");
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion crates/rpc/src/test_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ pub async fn test_storage<F: FnOnce(StateUpdate) -> 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"
))
Expand Down
10 changes: 8 additions & 2 deletions crates/rpc/src/v05/method/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -109,7 +109,13 @@ pub async fn call(context: RpcContext, input: CallInput) -> Result<CallOutput, C
}
};

let state = ExecutionState::simulation(&db, context.chain_id, header, pending);
let state = ExecutionState::simulation(
&db,
context.chain_id,
header,
pending,
L1BlobDataAvailability::Disabled,
);

let result = pathfinder_executor::call(
state,
Expand Down
10 changes: 8 additions & 2 deletions crates/rpc/src/v05/method/estimate_fee.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::Context;
use pathfinder_executor::ExecutionState;
use pathfinder_executor::{ExecutionState, L1BlobDataAvailability};
use serde_with::serde_as;

use crate::{
Expand Down Expand Up @@ -127,7 +127,13 @@ pub async fn estimate_fee(
}
};

let state = ExecutionState::simulation(&db, context.chain_id, header, pending);
let state = ExecutionState::simulation(
&db,
context.chain_id,
header,
pending,
L1BlobDataAvailability::Disabled,
);

let transactions = input
.request
Expand Down
13 changes: 10 additions & 3 deletions crates/rpc/src/v05/method/simulate_transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use crate::{
use anyhow::Context;
use pathfinder_common::{BlockId, CallParam, EntryPoint};
use pathfinder_crypto::Felt;
use pathfinder_executor::{types::TransactionSimulation, TransactionExecutionError};
use pathfinder_executor::{
types::TransactionSimulation, L1BlobDataAvailability, TransactionExecutionError,
};
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Debug)]
Expand Down Expand Up @@ -123,8 +125,13 @@ pub async fn simulate_transactions(
}
};

let state =
pathfinder_executor::ExecutionState::simulation(&db, context.chain_id, header, pending);
let state = pathfinder_executor::ExecutionState::simulation(
&db,
context.chain_id,
header,
pending,
L1BlobDataAvailability::Disabled,
);

let transactions = input
.transactions
Expand Down
Loading
Loading