diff --git a/bin/rundler/src/cli/builder.rs b/bin/rundler/src/cli/builder.rs index de832dfdc..7066d4118 100644 --- a/bin/rundler/src/cli/builder.rs +++ b/bin/rundler/src/cli/builder.rs @@ -463,6 +463,7 @@ pub async fn spawn_tasks( provider, ep_v0_6, ep_v0_7, + da_gas_oracle_sync, } = super::construct_providers(&common_args, &chain_spec)?; BuilderTask::new( @@ -473,6 +474,7 @@ pub async fn spawn_tasks( provider, ep_v0_6, ep_v0_7, + da_gas_oracle_sync, ) .spawn(task_spawner) .await?; diff --git a/bin/rundler/src/cli/mod.rs b/bin/rundler/src/cli/mod.rs index ab064b60c..c6cd8854a 100644 --- a/bin/rundler/src/cli/mod.rs +++ b/bin/rundler/src/cli/mod.rs @@ -32,7 +32,8 @@ use pool::PoolCliArgs; use reth_tasks::TaskManager; use rpc::RpcCliArgs; use rundler_provider::{ - AlloyEntryPointV0_6, AlloyEntryPointV0_7, AlloyEvmProvider, EntryPointProvider, EvmProvider, + AlloyEntryPointV0_6, AlloyEntryPointV0_7, AlloyEvmProvider, DAGasOracleSync, + EntryPointProvider, EvmProvider, }; use rundler_rpc::{EthApiSettings, RundlerApiSettings}; use rundler_sim::{ @@ -544,6 +545,7 @@ pub struct RundlerProviders { provider: P, ep_v0_6: Option, ep_v0_7: Option, + da_gas_oracle_sync: Option>, } pub fn construct_providers( @@ -559,6 +561,8 @@ pub fn construct_providers( let provider = Arc::new(rundler_provider::new_alloy_provider( args.node_http.as_ref().context("must provide node_http")?, )?); + let (da_gas_oracle, da_gas_oracle_sync) = + rundler_provider::new_alloy_da_gas_oracle(chain_spec, provider.clone()); let ep_v0_6 = if args.disable_entry_point_v0_6 { None @@ -569,6 +573,7 @@ pub fn construct_providers( args.max_simulate_handle_ops_gas, args.max_simulate_handle_ops_gas, provider.clone(), + da_gas_oracle.clone(), )) }; @@ -581,6 +586,7 @@ pub fn construct_providers( args.max_simulate_handle_ops_gas, args.max_simulate_handle_ops_gas, provider.clone(), + da_gas_oracle.clone(), )) }; @@ -588,6 +594,7 @@ pub fn construct_providers( provider: AlloyEvmProvider::new(provider), ep_v0_6, ep_v0_7, + da_gas_oracle_sync, }) } diff --git a/bin/rundler/src/cli/node/mod.rs b/bin/rundler/src/cli/node/mod.rs index 47abf2a2d..8e914b813 100644 --- a/bin/rundler/src/cli/node/mod.rs +++ b/bin/rundler/src/cli/node/mod.rs @@ -114,6 +114,7 @@ pub async fn spawn_tasks( provider, ep_v0_6, ep_v0_7, + da_gas_oracle_sync, } = super::construct_providers(&common_args, &chain_spec)?; PoolTask::new( @@ -123,6 +124,7 @@ pub async fn spawn_tasks( provider.clone(), ep_v0_6.clone(), ep_v0_7.clone(), + da_gas_oracle_sync.clone(), ) .spawn(task_spawner.clone()) .await?; @@ -135,6 +137,7 @@ pub async fn spawn_tasks( provider.clone(), ep_v0_6.clone(), ep_v0_7.clone(), + da_gas_oracle_sync, ) .spawn(task_spawner.clone()) .await?; diff --git a/bin/rundler/src/cli/pool.rs b/bin/rundler/src/cli/pool.rs index 3d3192de5..a4f271cfa 100644 --- a/bin/rundler/src/cli/pool.rs +++ b/bin/rundler/src/cli/pool.rs @@ -305,6 +305,7 @@ pub async fn spawn_tasks( provider, ep_v0_6, ep_v0_7, + da_gas_oracle_sync, } = super::construct_providers(&common_args, &chain_spec)?; PoolTask::new( @@ -314,6 +315,7 @@ pub async fn spawn_tasks( provider, ep_v0_6, ep_v0_7, + da_gas_oracle_sync, ) .spawn(task_spawner) .await?; diff --git a/bin/rundler/src/cli/rpc.rs b/bin/rundler/src/cli/rpc.rs index 11e9a7d22..85b08f6f9 100644 --- a/bin/rundler/src/cli/rpc.rs +++ b/bin/rundler/src/cli/rpc.rs @@ -180,6 +180,7 @@ pub async fn spawn_tasks( provider, ep_v0_6, ep_v0_7, + .. } = super::construct_providers(&common_args, &chain_spec)?; RpcTask::new(task_args, pool, builder, provider, ep_v0_6, ep_v0_7) diff --git a/crates/builder/src/bundle_proposer.rs b/crates/builder/src/bundle_proposer.rs index b6dee4f97..9105d4232 100644 --- a/crates/builder/src/bundle_proposer.rs +++ b/crates/builder/src/bundle_proposer.rs @@ -29,7 +29,8 @@ use linked_hash_map::LinkedHashMap; #[cfg(test)] use mockall::automock; use rundler_provider::{ - BundleHandler, DAGasProvider, EntryPoint, EvmProvider, HandleOpsOut, SignatureAggregator, + BundleHandler, DAGasOracleSync, DAGasProvider, EntryPoint, EvmProvider, HandleOpsOut, + SignatureAggregator, }; use rundler_sim::{ ExpectedStorage, FeeEstimator, PriorityFeeMode, SimulationError, SimulationResult, Simulator, @@ -134,7 +135,6 @@ pub(crate) enum BundleProposerError { Other(#[from] anyhow::Error), } -#[derive(Debug)] pub(crate) struct BundleProposerImpl { builder_index: u64, pool: M, @@ -145,6 +145,7 @@ pub(crate) struct BundleProposerImpl { fee_estimator: F, event_sender: broadcast::Sender>, condition_not_met_notified: bool, + da_gas_oracle: Option>, _uo_type: PhantomData, } @@ -216,8 +217,11 @@ where .filter_map(|op| op.uo.paymaster()) .collect::>(); - let da_block_data = if self.settings.da_gas_tracking_enabled { - match self.entry_point.block_data(block_hash.into()).await { + let da_block_data = if self.settings.da_gas_tracking_enabled && self.da_gas_oracle.is_some() + { + let da_gas_oracle = self.da_gas_oracle.as_ref().unwrap(); + + match da_gas_oracle.block_data(block_hash.into()).await { Ok(block_data) => Some(block_data), Err(e) => { error!("Failed to get block data for block hash {block_hash:?}, falling back to async da gas calculations: {e:?}"); @@ -342,6 +346,7 @@ where entry_point: E, provider: P, fee_estimator: F, + da_gas_oracle: Option>, settings: Settings, event_sender: broadcast::Sender>, ) -> Self { @@ -352,6 +357,7 @@ where entry_point, provider, fee_estimator, + da_gas_oracle, settings, event_sender, condition_not_met_notified: false, @@ -398,9 +404,13 @@ where return Some(op); } - let required_da_gas = if self.settings.da_gas_tracking_enabled && da_block_data.is_some() { + let required_da_gas = if self.settings.da_gas_tracking_enabled + && da_block_data.is_some() + && self.da_gas_oracle.is_some() + { + let da_gas_oracle = self.da_gas_oracle.as_ref().unwrap(); let da_block_data = da_block_data.unwrap(); - self.entry_point.calc_da_gas_sync( + da_gas_oracle.calc_da_gas_sync( &op.da_gas_data, da_block_data, required_op_fees.max_fee_per_gas, @@ -2415,6 +2425,7 @@ mod tests { entry_point, provider, fee_estimator, + None, Settings { chain_spec: ChainSpec::default(), max_bundle_size, diff --git a/crates/builder/src/task.rs b/crates/builder/src/task.rs index 3ac494e23..666c35b85 100644 --- a/crates/builder/src/task.rs +++ b/crates/builder/src/task.rs @@ -11,11 +11,11 @@ // You should have received a copy of the GNU General Public License along with Rundler. // If not, see https://www.gnu.org/licenses/. -use std::{collections::HashMap, net::SocketAddr, time::Duration}; +use std::{collections::HashMap, net::SocketAddr, sync::Arc, time::Duration}; use alloy_primitives::{Address, B256}; use anyhow::Context; -use rundler_provider::{EntryPointProvider, EvmProvider}; +use rundler_provider::{DAGasOracleSync, EntryPointProvider, EvmProvider}; use rundler_sim::{ gas::{self, FeeEstimatorImpl}, simulation::{self, UnsafeSimulator}, @@ -107,7 +107,6 @@ pub struct EntryPointBuilderSettings { } /// Builder task -#[derive(Debug)] pub struct BuilderTask { args: Args, event_sender: broadcast::Sender>, @@ -116,10 +115,12 @@ pub struct BuilderTask { provider: PR, ep_06: Option, ep_07: Option, + da_gas_oracle: Option>, } impl BuilderTask { /// Create a new builder task + #[allow(clippy::too_many_arguments)] pub fn new( args: Args, event_sender: broadcast::Sender>, @@ -128,6 +129,7 @@ impl BuilderTask { provider: PR, ep_06: Option, ep_07: Option, + da_gas_oracle: Option>, ) -> Self { Self { args, @@ -137,6 +139,7 @@ impl BuilderTask { provider, ep_06, ep_07, + da_gas_oracle, } } } @@ -404,6 +407,7 @@ where entry_point.clone(), provider.clone(), fee_estimator, + self.da_gas_oracle.clone(), proposer_settings, self.event_sender.clone(), ); diff --git a/crates/pool/src/mempool/pool.rs b/crates/pool/src/mempool/pool.rs index d699a6050..d6d39c6b7 100644 --- a/crates/pool/src/mempool/pool.rs +++ b/crates/pool/src/mempool/pool.rs @@ -23,7 +23,7 @@ use anyhow::Context; use metrics::{Gauge, Histogram}; use metrics_derive::Metrics; use parking_lot::RwLock; -use rundler_provider::DAGasProvider; +use rundler_provider::DAGasOracleSync; use rundler_types::{ chain::ChainSpec, da::DAGasBlockData, @@ -67,8 +67,8 @@ impl From for PoolInnerConfig { pub(crate) struct PoolInner { /// Pool settings config: PoolInnerConfig, - /// DA Gas Provider - da_gas_provider: D, + /// DA Gas Oracle + da_gas_oracle: Option, /// Operations by hash by_hash: HashMap>, /// Operations by operation ID @@ -104,17 +104,17 @@ pub(crate) struct PoolInner { impl PoolInner where - D: DAGasProvider, + D: DAGasOracleSync, { pub(crate) fn new( config: PoolInnerConfig, - da_gas_provider: D, + da_gas_oracle: Option, event_sender: broadcast::Sender>, ) -> Self { let entry_point = config.entry_point.to_string(); Self { config, - da_gas_provider, + da_gas_oracle, by_hash: HashMap::new(), by_id: HashMap::new(), best: BTreeSet::new(), @@ -259,9 +259,11 @@ where continue; } - if self.config.da_gas_tracking_enabled && block_da_data.is_some() { + if self.da_gas_oracle.is_some() && block_da_data.is_some() { + let da_gas_oracle = self.da_gas_oracle.as_ref().unwrap(); let block_da_data = block_da_data.unwrap(); - let required_da_gas = self.da_gas_provider.calc_da_gas_sync( + + let required_da_gas = da_gas_oracle.calc_da_gas_sync( &op.po.da_gas_data, block_da_data, candidate_gas_price, @@ -764,7 +766,6 @@ struct PoolMetrics { #[cfg(test)] mod tests { use alloy_primitives::U256; - use rundler_provider::MockEntryPointV0_6; use rundler_types::{ v0_6::UserOperation, EntityInfo, EntityInfos, UserOperation as UserOperationTrait, ValidTimeRange, @@ -1238,20 +1239,12 @@ mod tests { } } - fn pool() -> PoolInner { - PoolInner::new( - conf(), - MockEntryPointV0_6::new(), - broadcast::channel(100000).0, - ) + fn pool() -> PoolInner> { + PoolInner::new(conf(), None, broadcast::channel(100000).0) } - fn pool_with_conf(conf: PoolInnerConfig) -> PoolInner { - PoolInner::new( - conf, - MockEntryPointV0_6::new(), - broadcast::channel(100000).0, - ) + fn pool_with_conf(conf: PoolInnerConfig) -> PoolInner> { + PoolInner::new(conf, None, broadcast::channel(100000).0) } fn mem_size_of_ordered_pool_op() -> usize { diff --git a/crates/pool/src/mempool/uo_pool.rs b/crates/pool/src/mempool/uo_pool.rs index 672b4dce3..5640f6dab 100644 --- a/crates/pool/src/mempool/uo_pool.rs +++ b/crates/pool/src/mempool/uo_pool.rs @@ -20,7 +20,9 @@ use itertools::Itertools; use metrics::{Counter, Gauge, Histogram}; use metrics_derive::Metrics; use parking_lot::RwLock; -use rundler_provider::{DAGasProvider, EntryPoint, EvmProvider, SimulationProvider, StateOverride}; +use rundler_provider::{ + DAGasOracleSync, EntryPoint, EvmProvider, SimulationProvider, StateOverride, +}; use rundler_sim::{Prechecker, Simulator}; use rundler_types::{ pool::{ @@ -50,7 +52,7 @@ use crate::{ /// block on write locks. pub(crate) struct UoPool { config: PoolConfig, - state: RwLock>, + state: RwLock, paymaster: PaymasterTracker, reputation: Arc, event_sender: broadcast::Sender>, @@ -60,11 +62,12 @@ pub(crate) struct UoPool { simulator: S, ep_specific_metrics: UoPoolMetricsEPSpecific, metrics: UoPoolMetrics, + da_gas_oracle: Option>, _uo_type: PhantomData, } -struct UoPoolState { - pool: PoolInner, +struct UoPoolState { + pool: PoolInner>, throttled_ops: HashSet, block_number: u64, block_hash: B256, @@ -75,7 +78,7 @@ struct UoPoolState { impl UoPool where UO: From, - E: DAGasProvider + SimulationProvider + Clone, + E: SimulationProvider + Clone, { // TODO refactor provider args #[allow(clippy::too_many_arguments)] @@ -88,13 +91,14 @@ where simulator: S, paymaster: PaymasterTracker, reputation: Arc, + da_gas_oracle: Option>, ) -> Self { let ep = config.entry_point.to_string(); Self { state: RwLock::new(UoPoolState { pool: PoolInner::new( config.clone().into(), - entry_point.clone(), + da_gas_oracle.clone(), event_sender.clone(), ), throttled_ops: HashSet::new(), @@ -113,6 +117,7 @@ where config, ep_specific_metrics: UoPoolMetricsEPSpecific::new_with_labels(&[("entry_point", ep)]), metrics: UoPoolMetrics::default(), + da_gas_oracle, _uo_type: PhantomData, } } @@ -216,7 +221,7 @@ where EP: EvmProvider, P: Prechecker, S: Simulator, - E: EntryPoint + DAGasProvider + SimulationProvider + Clone, + E: EntryPoint + SimulationProvider + Clone, { async fn on_chain_update(&self, update: &ChainUpdate) { let deduped_ops = update.deduped_ops(); @@ -339,9 +344,9 @@ where .unmined_operations .increment(unmined_op_count); - let da_block_data = if self.config.da_gas_tracking_enabled { - match self - .entry_point + let da_block_data = if self.config.da_gas_tracking_enabled && self.da_gas_oracle.is_some() { + let da_gas_oracle = self.da_gas_oracle.as_ref().unwrap(); + match da_gas_oracle .block_data(update.latest_block_hash.into()) .await { @@ -1644,10 +1649,7 @@ mod tests { impl EvmProvider, impl Prechecker, impl Simulator, - impl EntryPoint - + DAGasProvider - + SimulationProvider - + Clone, + impl EntryPoint + SimulationProvider + Clone, > { let entrypoint = MockEntryPointV0_6::new(); create_pool_with_entry_point(ops, entrypoint) @@ -1661,10 +1663,7 @@ mod tests { impl EvmProvider, impl Prechecker, impl Simulator, - impl EntryPoint - + DAGasProvider - + SimulationProvider - + Clone, + impl EntryPoint + SimulationProvider + Clone, > { let entrypoint = Arc::new(entrypoint); let args = PoolConfig { @@ -1771,6 +1770,7 @@ mod tests { simulator, paymaster, reputation, + None, ) } @@ -1783,10 +1783,7 @@ mod tests { impl EvmProvider, impl Prechecker, impl Simulator, - impl EntryPoint - + DAGasProvider - + SimulationProvider - + Clone, + impl EntryPoint + SimulationProvider + Clone, >, Vec, ) { @@ -1806,10 +1803,7 @@ mod tests { impl EvmProvider, impl Prechecker, impl Simulator, - impl EntryPoint - + DAGasProvider - + SimulationProvider - + Clone, + impl EntryPoint + SimulationProvider + Clone, >, Vec, ) { diff --git a/crates/pool/src/task.rs b/crates/pool/src/task.rs index 8ba7d45e7..66d05bedf 100644 --- a/crates/pool/src/task.rs +++ b/crates/pool/src/task.rs @@ -15,7 +15,7 @@ use std::{collections::HashMap, net::SocketAddr, sync::Arc, time::Duration}; use anyhow::{bail, Context}; use futures::FutureExt; -use rundler_provider::{EntryPointProvider, EvmProvider}; +use rundler_provider::{DAGasOracleSync, EntryPointProvider, EvmProvider}; use rundler_sim::{ gas::{self, FeeEstimatorImpl}, simulation::{self, UnsafeSimulator}, @@ -63,7 +63,6 @@ pub struct Args { } /// Mempool task. -#[derive(Debug)] pub struct PoolTask { args: Args, event_sender: broadcast::Sender>, @@ -71,6 +70,7 @@ pub struct PoolTask { provider: P, ep_06: Option, ep_07: Option, + da_gas_oracle: Option>, } impl PoolTask { @@ -82,6 +82,7 @@ impl PoolTask { provider: P, ep_06: Option, ep_07: Option, + da_gas_oracle: Option>, ) -> Self { Self { args, @@ -90,6 +91,7 @@ impl PoolTask { provider, ep_06, ep_07, + da_gas_oracle, } } } @@ -209,12 +211,11 @@ where if unsafe_mode { let simulator = UnsafeSimulator::new(ep.clone()); - Self::create_mempool( + self.create_mempool( task_spawner, chain_spec, pool_config, event_sender, - self.provider.clone(), ep.clone(), simulator, ) @@ -225,12 +226,11 @@ where pool_config.sim_settings.clone(), pool_config.mempool_channel_configs.clone(), ); - Self::create_mempool( + self.create_mempool( task_spawner, chain_spec, pool_config, event_sender, - self.provider.clone(), ep.clone(), simulator, ) @@ -252,12 +252,11 @@ where if unsafe_mode { let simulator = UnsafeSimulator::new(ep.clone()); - Self::create_mempool( + self.create_mempool( task_spawner, chain_spec, pool_config, event_sender, - self.provider.clone(), ep.clone(), simulator, ) @@ -268,12 +267,11 @@ where pool_config.sim_settings.clone(), pool_config.mempool_channel_configs.clone(), ); - Self::create_mempool( + self.create_mempool( task_spawner, chain_spec, pool_config, event_sender, - self.provider.clone(), ep.clone(), simulator, ) @@ -281,11 +279,11 @@ where } fn create_mempool( + &self, task_spawner: &T, chain_spec: ChainSpec, pool_config: &PoolConfig, event_sender: broadcast::Sender>, - evm: P, ep: E, simulator: S, ) -> anyhow::Result> @@ -296,9 +294,9 @@ where E: EntryPointProvider + Clone + 'static, S: Simulator + 'static, { - let fee_oracle = gas::get_fee_oracle(&chain_spec, evm.clone()); + let fee_oracle = gas::get_fee_oracle(&chain_spec, self.provider.clone()); let fee_estimator = FeeEstimatorImpl::new( - evm.clone(), + self.provider.clone(), fee_oracle, pool_config.precheck_settings.priority_fee_mode, pool_config @@ -308,7 +306,7 @@ where let prechecker = PrecheckerImpl::new( chain_spec, - evm.clone(), + self.provider.clone(), ep.clone(), fee_estimator, pool_config.precheck_settings, @@ -340,12 +338,13 @@ where let uo_pool = UoPool::new( pool_config.clone(), event_sender, - evm, + self.provider.clone(), ep, prechecker, simulator, paymaster, reputation, + self.da_gas_oracle.clone(), ); Ok(Arc::new(uo_pool)) diff --git a/crates/provider/src/alloy/da/arbitrum.rs b/crates/provider/src/alloy/da/arbitrum.rs index 8a43ef1e8..9814260de 100644 --- a/crates/provider/src/alloy/da/arbitrum.rs +++ b/crates/provider/src/alloy/da/arbitrum.rs @@ -81,26 +81,4 @@ where DAGasBlockData::Empty, )) } - - async fn block_data(&self, _block: BlockHashOrNumber) -> ProviderResult { - Ok(DAGasBlockData::Empty) - } - - async fn uo_data( - &self, - _uo_data: Bytes, - _to: Address, - _block: BlockHashOrNumber, - ) -> ProviderResult { - Ok(DAGasUOData::Empty) - } - - fn calc_da_gas_sync( - &self, - _uo_data: &DAGasUOData, - _block_data: &DAGasBlockData, - _gas_price: u128, - ) -> u128 { - panic!("ArbitrumNitroDAGasOracle does not support calc_da_gas_sync") - } } diff --git a/crates/provider/src/alloy/da/local/bedrock.rs b/crates/provider/src/alloy/da/local/bedrock.rs index 9e9f92b44..08956c0b8 100644 --- a/crates/provider/src/alloy/da/local/bedrock.rs +++ b/crates/provider/src/alloy/da/local/bedrock.rs @@ -23,14 +23,11 @@ use tokio::sync::Mutex as TokioMutex; use super::multicall::{self, Multicall::MulticallInstance, MULTICALL_BYTECODE}; use crate::{ - alloy::da::{ - optimism::GasPriceOracle::{ - baseFeeScalarCall, blobBaseFeeCall, blobBaseFeeScalarCall, l1BaseFeeCall, - GasPriceOracleCalls, GasPriceOracleInstance, - }, - DAGasOracle, + alloy::da::optimism::GasPriceOracle::{ + baseFeeScalarCall, blobBaseFeeCall, blobBaseFeeScalarCall, l1BaseFeeCall, + GasPriceOracleCalls, GasPriceOracleInstance, }, - BlockHashOrNumber, ProviderResult, + BlockHashOrNumber, DAGasOracle, DAGasOracleSync, ProviderResult, }; // From https://github.com/ethereum-optimism/optimism/blob/f93f9f40adcd448168c6ea27820aeee5da65fcbd/packages/contracts-bedrock/src/L2/GasPriceOracle.sol#L26 @@ -86,7 +83,14 @@ where let da_gas = self.calc_da_gas_sync(&uo_data, &block_data, gas_price); Ok((da_gas, uo_data, block_data)) } +} +#[async_trait::async_trait] +impl DAGasOracleSync for LocalBedrockDAGasOracle +where + AP: AlloyProvider, + T: Transport + Clone, +{ async fn block_data(&self, block: BlockHashOrNumber) -> ProviderResult { let mut cache = self.block_data_cache.lock().await; match cache.get(&block) { diff --git a/crates/provider/src/alloy/da/local/nitro.rs b/crates/provider/src/alloy/da/local/nitro.rs index 678f58f76..5711b8351 100644 --- a/crates/provider/src/alloy/da/local/nitro.rs +++ b/crates/provider/src/alloy/da/local/nitro.rs @@ -20,8 +20,8 @@ use rundler_utils::cache::LruMap; use tokio::sync::Mutex as TokioMutex; use crate::{ - alloy::da::{arbitrum::NodeInterface::NodeInterfaceInstance, DAGasOracle}, - BlockHashOrNumber, ProviderResult, + alloy::da::arbitrum::NodeInterface::NodeInterfaceInstance, BlockHashOrNumber, DAGasOracle, + DAGasOracleSync, ProviderResult, }; /// Cached Arbitrum Nitro DA gas oracle @@ -93,7 +93,14 @@ where } } } +} +#[async_trait::async_trait] +impl DAGasOracleSync for CachedNitroDAGasOracle +where + AP: AlloyProvider, + T: Transport + Clone, +{ async fn block_data(&self, block: BlockHashOrNumber) -> ProviderResult { let mut cache = self.block_data_cache.lock().await; match cache.get(&block) { diff --git a/crates/provider/src/alloy/da/mod.rs b/crates/provider/src/alloy/da/mod.rs index b9d86762a..90349844a 100644 --- a/crates/provider/src/alloy/da/mod.rs +++ b/crates/provider/src/alloy/da/mod.rs @@ -11,6 +11,8 @@ // You should have received a copy of the GNU General Public License along with Rundler. // If not, see https://www.gnu.org/licenses/. +use std::sync::Arc; + use alloy_primitives::{Address, Bytes}; use alloy_provider::Provider as AlloyProvider; use alloy_transport::Transport; @@ -19,7 +21,7 @@ use rundler_types::{ da::{DAGasBlockData, DAGasOracleContractType, DAGasUOData}, }; -use crate::{BlockHashOrNumber, DAGasOracle, ProviderResult}; +use crate::{BlockHashOrNumber, DAGasOracle, DAGasOracleSync, ProviderResult}; mod arbitrum; use arbitrum::ArbitrumNitroDAGasOracle; @@ -41,56 +43,50 @@ impl DAGasOracle for ZeroDAGasOracle { ) -> ProviderResult<(u128, DAGasUOData, DAGasBlockData)> { Ok((0, DAGasUOData::Empty, DAGasBlockData::Empty)) } - - async fn block_data(&self, _block: BlockHashOrNumber) -> ProviderResult { - Ok(DAGasBlockData::Empty) - } - - async fn uo_data( - &self, - _uo_data: Bytes, - _to: Address, - _block: BlockHashOrNumber, - ) -> ProviderResult { - Ok(DAGasUOData::Empty) - } - - fn calc_da_gas_sync( - &self, - _uo_data: &DAGasUOData, - _block_data: &DAGasBlockData, - _gas_price: u128, - ) -> u128 { - panic!("ZeroDAGasOracle does not support calc_da_gas_sync") - } } -pub(crate) fn da_gas_oracle_for_chain<'a, AP, T>( +/// Create a DA gas oracle for the given chain spec +pub fn new_alloy_da_gas_oracle<'a, AP, T>( chain_spec: &ChainSpec, provider: AP, -) -> Box +) -> ( + Arc, + Option>, +) where AP: AlloyProvider + Clone + 'a, T: Transport + Clone, { match chain_spec.da_gas_oracle_contract_type { - DAGasOracleContractType::ArbitrumNitro => Box::new(ArbitrumNitroDAGasOracle::new( - chain_spec.da_gas_oracle_contract_address, - provider, - )), - DAGasOracleContractType::OptimismBedrock => Box::new(OptimismBedrockDAGasOracle::new( - chain_spec.da_gas_oracle_contract_address, - provider, - )), - DAGasOracleContractType::LocalBedrock => Box::new(LocalBedrockDAGasOracle::new( - chain_spec.da_gas_oracle_contract_address, - provider, - )), - DAGasOracleContractType::CachedNitro => Box::new(CachedNitroDAGasOracle::new( - chain_spec.da_gas_oracle_contract_address, - provider, - )), - DAGasOracleContractType::None => Box::new(ZeroDAGasOracle), + DAGasOracleContractType::ArbitrumNitro => { + let oracle = Arc::new(ArbitrumNitroDAGasOracle::new( + chain_spec.da_gas_oracle_contract_address, + provider, + )); + (oracle, None) + } + DAGasOracleContractType::OptimismBedrock => { + let oracle = Arc::new(OptimismBedrockDAGasOracle::new( + chain_spec.da_gas_oracle_contract_address, + provider, + )); + (oracle, None) + } + DAGasOracleContractType::LocalBedrock => { + let oracle = Arc::new(LocalBedrockDAGasOracle::new( + chain_spec.da_gas_oracle_contract_address, + provider, + )); + (oracle.clone(), Some(oracle)) + } + DAGasOracleContractType::CachedNitro => { + let oracle = Arc::new(CachedNitroDAGasOracle::new( + chain_spec.da_gas_oracle_contract_address, + provider, + )); + (oracle.clone(), Some(oracle)) + } + DAGasOracleContractType::None => (Arc::new(ZeroDAGasOracle), None), } } diff --git a/crates/provider/src/alloy/da/optimism.rs b/crates/provider/src/alloy/da/optimism.rs index adce5de1d..2c409e760 100644 --- a/crates/provider/src/alloy/da/optimism.rs +++ b/crates/provider/src/alloy/da/optimism.rs @@ -81,26 +81,4 @@ where DAGasBlockData::Empty, )) } - - async fn block_data(&self, _block: BlockHashOrNumber) -> ProviderResult { - Ok(DAGasBlockData::Empty) - } - - async fn uo_data( - &self, - _uo_data: Bytes, - _to: Address, - _block: BlockHashOrNumber, - ) -> ProviderResult { - Ok(DAGasUOData::Empty) - } - - fn calc_da_gas_sync( - &self, - _uo_data: &DAGasUOData, - _block_data: &DAGasBlockData, - _gas_price: u128, - ) -> u128 { - panic!("OptimismBedrockDAGasOracle does not support calc_da_gas_sync") - } } diff --git a/crates/provider/src/alloy/entry_point/v0_6.rs b/crates/provider/src/alloy/entry_point/v0_6.rs index ccf95b6b6..101fa566f 100644 --- a/crates/provider/src/alloy/entry_point/v0_6.rs +++ b/crates/provider/src/alloy/entry_point/v0_6.rs @@ -11,8 +11,6 @@ // You should have received a copy of the GNU General Public License along with Rundler. // If not, see https://www.gnu.org/licenses/. -use std::sync::Arc; - use alloy_contract::Error as ContractError; use alloy_primitives::{Address, Bytes, U256}; use alloy_provider::Provider as AlloyProvider; @@ -38,26 +36,27 @@ use rundler_types::{ }; use crate::{ - alloy::da, AggregatorOut, AggregatorSimOut, BlockHashOrNumber, BundleHandler, DAGasOracle, - DAGasProvider, DepositInfo, EntryPoint, EntryPointProvider as EntryPointProviderTrait, EvmCall, + AggregatorOut, AggregatorSimOut, BlockHashOrNumber, BundleHandler, DAGasOracle, DAGasProvider, + DepositInfo, EntryPoint, EntryPointProvider as EntryPointProviderTrait, EvmCall, ExecutionResult, HandleOpsOut, ProviderResult, SignatureAggregator, SimulationProvider, }; /// Entry point provider for v0.6 #[derive(Clone)] -pub struct EntryPointProvider<'a, AP, T> { +pub struct EntryPointProvider { i_entry_point: IEntryPointInstance, - da_gas_oracle: Arc, + da_gas_oracle: D, max_verification_gas: u64, max_simulate_handle_op_gas: u64, max_aggregation_gas: u64, chain_spec: ChainSpec, } -impl<'a, AP, T> EntryPointProvider<'a, AP, T> +impl EntryPointProvider where T: Transport + Clone, - AP: AlloyProvider + Clone + 'a, + AP: AlloyProvider + Clone, + D: DAGasOracle, { /// Create a new `EntryPoint` instance for v0.6 pub fn new( @@ -66,13 +65,14 @@ where max_simulate_handle_op_gas: u64, max_aggregation_gas: u64, provider: AP, + da_gas_oracle: D, ) -> Self { Self { i_entry_point: IEntryPointInstance::new( chain_spec.entry_point_address_v0_6, provider.clone(), ), - da_gas_oracle: Arc::from(da::da_gas_oracle_for_chain(&chain_spec, provider)), + da_gas_oracle, max_verification_gas, max_simulate_handle_op_gas, max_aggregation_gas, @@ -82,10 +82,11 @@ where } #[async_trait::async_trait] -impl<'a, AP, T> EntryPoint for EntryPointProvider<'a, AP, T> +impl EntryPoint for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: Send + Sync, { fn address(&self) -> &Address { self.i_entry_point.address() @@ -138,10 +139,11 @@ where } #[async_trait::async_trait] -impl<'a, AP, T> SignatureAggregator for EntryPointProvider<'a, AP, T> +impl SignatureAggregator for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: Send + Sync, { type UO = UserOperation; @@ -216,10 +218,11 @@ where } #[async_trait::async_trait] -impl<'a, AP, T> BundleHandler for EntryPointProvider<'a, AP, T> +impl BundleHandler for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: Send + Sync, { type UO = UserOperation; @@ -306,10 +309,11 @@ where } #[async_trait::async_trait] -impl<'a, AP, T> DAGasProvider for EntryPointProvider<'a, AP, T> +impl DAGasProvider for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: DAGasOracle, { type UO = UserOperation; @@ -334,49 +338,14 @@ where .estimate_da_gas(bundle_data, *self.i_entry_point.address(), block, gas_price) .await } - - async fn block_data(&self, block: BlockHashOrNumber) -> ProviderResult { - self.da_gas_oracle.block_data(block).await - } - - async fn uo_data( - &self, - uo: UserOperation, - block: BlockHashOrNumber, - ) -> ProviderResult { - let gas_price = uo.max_fee_per_gas; - let data = self - .i_entry_point - .handleOps(vec![uo.into()], Address::random()) - .into_transaction_request() - .input - .into_input() - .unwrap(); - - let bundle_data = - super::max_bundle_transaction_data(*self.i_entry_point.address(), data, gas_price); - - self.da_gas_oracle - .uo_data(bundle_data, *self.i_entry_point.address(), block) - .await - } - - fn calc_da_gas_sync( - &self, - uo_data: &DAGasUOData, - block_data: &DAGasBlockData, - gas_price: u128, - ) -> u128 { - self.da_gas_oracle - .calc_da_gas_sync(uo_data, block_data, gas_price) - } } #[async_trait::async_trait] -impl<'a, AP, T> SimulationProvider for EntryPointProvider<'a, AP, T> +impl SimulationProvider for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: Send + Sync, { type UO = UserOperation; @@ -536,10 +505,11 @@ where } } -impl<'a, AP, T> EntryPointProviderTrait for EntryPointProvider<'a, AP, T> +impl EntryPointProviderTrait for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: DAGasOracle, { } diff --git a/crates/provider/src/alloy/entry_point/v0_7.rs b/crates/provider/src/alloy/entry_point/v0_7.rs index 6bd450d15..a72efd47c 100644 --- a/crates/provider/src/alloy/entry_point/v0_7.rs +++ b/crates/provider/src/alloy/entry_point/v0_7.rs @@ -11,8 +11,6 @@ // You should have received a copy of the GNU General Public License along with Rundler. // If not, see https://www.gnu.org/licenses/. -use std::sync::Arc; - use alloy_contract::Error as ContractError; use alloy_json_rpc::ErrorPayload; use alloy_primitives::{Address, Bytes, U256}; @@ -45,7 +43,6 @@ use rundler_types::{ }; use crate::{ - alloy::da::{self}, AggregatorOut, AggregatorSimOut, BlockHashOrNumber, BundleHandler, DAGasOracle, DAGasProvider, DepositInfo, EntryPoint, EntryPointProvider as EntryPointProviderTrait, EvmCall, ExecutionResult, HandleOpsOut, ProviderResult, SignatureAggregator, SimulationProvider, @@ -53,19 +50,19 @@ use crate::{ /// Entry point provider for v0.7 #[derive(Clone)] -pub struct EntryPointProvider<'a, AP, T> { +pub struct EntryPointProvider { i_entry_point: IEntryPointInstance, - da_gas_oracle: Arc, + da_gas_oracle: D, max_verification_gas: u64, max_simulate_handle_ops_gas: u64, max_aggregation_gas: u64, chain_spec: ChainSpec, } -impl<'a, AP, T> EntryPointProvider<'a, AP, T> +impl EntryPointProvider where T: Transport + Clone, - AP: AlloyProvider + Clone + 'a, + AP: AlloyProvider + Clone, { /// Create a new `EntryPoint` instance for v0.7 pub fn new( @@ -74,13 +71,14 @@ where max_simulate_handle_ops_gas: u64, max_aggregation_gas: u64, provider: AP, + da_gas_oracle: D, ) -> Self { Self { i_entry_point: IEntryPointInstance::new( chain_spec.entry_point_address_v0_7, provider.clone(), ), - da_gas_oracle: Arc::from(da::da_gas_oracle_for_chain(&chain_spec, provider)), + da_gas_oracle, max_verification_gas, max_simulate_handle_ops_gas, max_aggregation_gas, @@ -90,10 +88,11 @@ where } #[async_trait::async_trait] -impl<'a, AP, T> EntryPoint for EntryPointProvider<'a, AP, T> +impl EntryPoint for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: Send + Sync, { fn address(&self) -> &Address { self.i_entry_point.address() @@ -147,10 +146,11 @@ where } #[async_trait::async_trait] -impl<'a, AP, T> SignatureAggregator for EntryPointProvider<'a, AP, T> +impl SignatureAggregator for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: Send + Sync, { type UO = UserOperation; @@ -227,10 +227,11 @@ where } #[async_trait::async_trait] -impl<'a, AP, T> BundleHandler for EntryPointProvider<'a, AP, T> +impl BundleHandler for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: Send + Sync, { type UO = UserOperation; @@ -296,10 +297,11 @@ where } #[async_trait::async_trait] -impl<'a, AP, T> DAGasProvider for EntryPointProvider<'a, AP, T> +impl DAGasProvider for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: DAGasOracle, { type UO = UserOperation; @@ -324,49 +326,14 @@ where .estimate_da_gas(bundle_data, *self.i_entry_point.address(), block, gas_price) .await } - - async fn block_data(&self, block: BlockHashOrNumber) -> ProviderResult { - self.da_gas_oracle.block_data(block).await - } - - async fn uo_data( - &self, - uo: UserOperation, - block: BlockHashOrNumber, - ) -> ProviderResult { - let gas_price = uo.max_fee_per_gas; - let data = self - .i_entry_point - .handleOps(vec![uo.pack()], Address::random()) - .into_transaction_request() - .input - .into_input() - .unwrap(); - - let bundle_data = - super::max_bundle_transaction_data(*self.i_entry_point.address(), data, gas_price); - - self.da_gas_oracle - .uo_data(bundle_data, *self.i_entry_point.address(), block) - .await - } - - fn calc_da_gas_sync( - &self, - uo_data: &DAGasUOData, - block_data: &DAGasBlockData, - gas_price: u128, - ) -> u128 { - self.da_gas_oracle - .calc_da_gas_sync(uo_data, block_data, gas_price) - } } #[async_trait::async_trait] -impl<'a, AP, T> SimulationProvider for EntryPointProvider<'a, AP, T> +impl SimulationProvider for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: Send + Sync, { type UO = UserOperation; @@ -489,10 +456,11 @@ where } } -impl<'a, AP, T> EntryPointProviderTrait for EntryPointProvider<'a, AP, T> +impl EntryPointProviderTrait for EntryPointProvider where T: Transport + Clone, AP: AlloyProvider, + D: DAGasOracle, { } diff --git a/crates/provider/src/alloy/mod.rs b/crates/provider/src/alloy/mod.rs index 6709e0905..a487f13ca 100644 --- a/crates/provider/src/alloy/mod.rs +++ b/crates/provider/src/alloy/mod.rs @@ -23,7 +23,8 @@ use url::Url; use crate::EvmProvider; -pub(crate) mod da; +mod da; +pub use da::new_alloy_da_gas_oracle; pub(crate) mod entry_point; pub(crate) mod evm; pub(crate) mod metrics; diff --git a/crates/provider/src/lib.rs b/crates/provider/src/lib.rs index dc8f52484..b59cd05ba 100644 --- a/crates/provider/src/lib.rs +++ b/crates/provider/src/lib.rs @@ -31,7 +31,7 @@ pub use alloy::{ }, }, evm::AlloyEvmProvider, - new_alloy_evm_provider, new_alloy_provider, + new_alloy_da_gas_oracle, new_alloy_evm_provider, new_alloy_provider, }; mod traits; diff --git a/crates/provider/src/traits/da.rs b/crates/provider/src/traits/da.rs index 75de2a7fc..75edef6a2 100644 --- a/crates/provider/src/traits/da.rs +++ b/crates/provider/src/traits/da.rs @@ -16,10 +16,10 @@ use rundler_types::da::{DAGasBlockData, DAGasUOData}; use crate::{BlockHashOrNumber, ProviderResult}; -// Trait for a DA gas oracle +/// Trait for a DA gas oracle #[async_trait::async_trait] #[auto_impl::auto_impl(&, &mut, Rc, Arc, Box)] -pub(crate) trait DAGasOracle: Send + Sync { +pub trait DAGasOracle: Send + Sync { /// Estimate the DA gas for a given user operation's bytes /// /// Returns the estimated gas, as well as both the UO DA data and the block DA data. @@ -32,7 +32,12 @@ pub(crate) trait DAGasOracle: Send + Sync { block: BlockHashOrNumber, gas_price: u128, ) -> ProviderResult<(u128, DAGasUOData, DAGasBlockData)>; +} +/// Trait for a DA gas oracle with a synchronous calculation method +#[async_trait::async_trait] +#[auto_impl::auto_impl(&, &mut, Rc, Arc, Box)] +pub trait DAGasOracleSync: DAGasOracle { /// Retrieve the DA gas data for a given block. This value can change block to block and /// thus must be retrieved fresh from the DA for every block. async fn block_data(&self, block: BlockHashOrNumber) -> ProviderResult; diff --git a/crates/provider/src/traits/entry_point.rs b/crates/provider/src/traits/entry_point.rs index 5c683739e..d8dc769e1 100644 --- a/crates/provider/src/traits/entry_point.rs +++ b/crates/provider/src/traits/entry_point.rs @@ -176,32 +176,6 @@ pub trait DAGasProvider: Send + Sync { block: BlockHashOrNumber, gas_price: u128, ) -> ProviderResult<(u128, DAGasUOData, DAGasBlockData)>; - - /// Retrieve the DA gas data for a given block. This value can change block to block and - /// thus must be retrieved fresh from the DA for every block. - async fn block_data(&self, block: BlockHashOrNumber) -> ProviderResult; - - /// Retrieve the DA gas data for a given user operation's bytes - /// - /// This should not change block to block, but may change after underlying hard forks, - /// thus a block number is required. - /// - /// It is safe to calculate this once and re-use if the same UO is used for multiple calls within - /// a small time period (no hard forks impacting DA calculations) - async fn uo_data(&self, uo: Self::UO, block: BlockHashOrNumber) -> ProviderResult; - - /// Synchronously calculate the DA gas for a given user operation data and block data. - /// These values must have been previously retrieved from a DA provider of the same implementation - /// else this function will PANIC. - /// - /// This function is intended to allow synchronous DA gas calculation from a cached UO data and a - /// recently retrieved block data. - fn calc_da_gas_sync( - &self, - uo_data: &DAGasUOData, - block_data: &DAGasBlockData, - gas_price: u128, - ) -> u128; } /// Trait for simulating user operations on an entry point contract diff --git a/crates/provider/src/traits/mod.rs b/crates/provider/src/traits/mod.rs index 2f38d1876..49f58a897 100644 --- a/crates/provider/src/traits/mod.rs +++ b/crates/provider/src/traits/mod.rs @@ -14,7 +14,7 @@ //! Traits for the provider module. mod da; -pub(crate) use da::DAGasOracle; +pub use da::{DAGasOracle, DAGasOracleSync}; mod error; pub use error::*; diff --git a/crates/provider/src/traits/test_utils.rs b/crates/provider/src/traits/test_utils.rs index 442953cf5..5ebf59871 100644 --- a/crates/provider/src/traits/test_utils.rs +++ b/crates/provider/src/traits/test_utils.rs @@ -178,12 +178,6 @@ mockall::mock! { block: BlockHashOrNumber, gas_price: u128, ) -> ProviderResult<(u128, DAGasUOData, DAGasBlockData)>; - - async fn block_data(&self, block: BlockHashOrNumber) -> ProviderResult; - - async fn uo_data(&self, uo: v0_6::UserOperation, block: BlockHashOrNumber) -> ProviderResult; - - fn calc_da_gas_sync(&self, uo_data: &DAGasUOData, block_data: &DAGasBlockData, gas_price: u128) -> u128; } #[async_trait::async_trait] @@ -272,12 +266,6 @@ mockall::mock! { block: BlockHashOrNumber, gas_price: u128, ) -> ProviderResult<(u128, DAGasUOData, DAGasBlockData)>; - - async fn block_data(&self, block: BlockHashOrNumber) -> ProviderResult; - - async fn uo_data(&self, uo: v0_7::UserOperation, block: BlockHashOrNumber) -> ProviderResult; - - fn calc_da_gas_sync(&self, uo_data: &DAGasUOData, block_data: &DAGasBlockData, gas_price: u128) -> u128; } #[async_trait::async_trait]