//! Loads and formats OP transaction RPC response. use std::sync::Arc; use reth_evm_optimism::RethL1BlockInfo; use reth_node_api::FullNodeComponents; use reth_primitives::TransactionSigned; use reth_provider::{BlockReaderIdExt, TransactionsProvider}; use reth_rpc_eth_api::{ helpers::{EthApiSpec, EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}, EthApiTypes, RawTransactionForwarder, }; use reth_rpc_eth_types::EthStateCache; use revm::L1BlockInfo; use crate::{OpEthApi, OpEthApiError}; impl EthTransactions for OpEthApi where Self: LoadTransaction, N: FullNodeComponents, { fn provider(&self) -> impl BlockReaderIdExt { self.inner.provider() } fn raw_tx_forwarder(&self) -> Option> { self.inner.raw_tx_forwarder() } fn signers(&self) -> &parking_lot::RwLock>> { self.inner.signers() } } impl LoadTransaction for OpEthApi where Self: SpawnBlocking, N: FullNodeComponents, { type Pool = N::Pool; fn provider(&self) -> impl TransactionsProvider { self.inner.provider() } fn cache(&self) -> &EthStateCache { self.inner.cache() } fn pool(&self) -> &Self::Pool { self.inner.pool() } } /// L1 fee and data gas for a transaction, along with the L1 block info. #[derive(Debug, Default, Clone)] pub struct OptimismTxMeta { /// The L1 block info. pub l1_block_info: Option, /// The L1 fee for the block. pub l1_fee: Option, /// The L1 data gas for the block. pub l1_data_gas: Option, } impl OptimismTxMeta { /// Creates a new [`OptimismTxMeta`]. pub const fn new( l1_block_info: Option, l1_fee: Option, l1_data_gas: Option, ) -> Self { Self { l1_block_info, l1_fee, l1_data_gas } } } impl OpEthApi where Self: EthApiSpec + LoadTransaction, ::Error: From, N: FullNodeComponents, { /// Builds [`OptimismTxMeta`] object using the provided [`TransactionSigned`], L1 block /// info and block timestamp. The [`L1BlockInfo`] is used to calculate the l1 fee and l1 data /// gas for the transaction. If the [`L1BlockInfo`] is not provided, the meta info will be /// empty. pub fn build_op_tx_meta( &self, tx: &TransactionSigned, l1_block_info: Option, block_timestamp: u64, ) -> Result::Error> { let Some(l1_block_info) = l1_block_info else { return Ok(OptimismTxMeta::default()) }; let (l1_fee, l1_data_gas) = if !tx.is_deposit() { let envelope_buf = tx.envelope_encoded(); let inner_l1_fee = l1_block_info .l1_tx_data_fee(&self.chain_spec(), block_timestamp, &envelope_buf, tx.is_deposit()) .map_err(|_| OpEthApiError::L1BlockFeeError)?; let inner_l1_data_gas = l1_block_info .l1_data_gas(&self.chain_spec(), block_timestamp, &envelope_buf) .map_err(|_| OpEthApiError::L1BlockGasError)?; ( Some(inner_l1_fee.saturating_to::()), Some(inner_l1_data_gas.saturating_to::()), ) } else { (None, None) }; Ok(OptimismTxMeta::new(Some(l1_block_info), l1_fee, l1_data_gas)) } }