Repository: paradigmxyz/reth (Rust)

Issue:
Replace generic `Tasks` with Box<dyn TaskSpawner> in rpc stack
### Describe the feature

we still treat tasks as a generic type, when we really only ever need `Box<dyn TaskSpawner>`

using dyn dispatch for this is fine and would get rid of a few generics.

e.g:
https://github.com/paradigmxyz/reth/blob/d456af044e886243577a8a48c42e7d7fdec160d5/crates/rpc/rpc-builder/src/lib.rs#L124-L124

## TODO
* replace `Tasks` generic with `Box<dyn TaskSpawner>` in rpc-node-builder

### Additional context

_No response_


Discussion:
Could I take it?

Edit: Didn’t see that it was already assigned
@gitToki this is already assigned, 

be on the lookout for new issues though :)
hey @mattsse @jenpaff  I can start working on it if its is stll needed and no one is already working on it 
This issue is stale because it has been open for 21 days with no activity.



Patch:
diff --git a/crates/node/builder/src/rpc.rs b/crates/node/builder/src/rpc.rs
index 71638921fbf..6ce9b95e113 100644
--- a/crates/node/builder/src/rpc.rs
+++ b/crates/node/builder/src/rpc.rs
@@ -25,7 +25,6 @@ use reth_rpc_builder::{
 };
 use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
 use reth_rpc_eth_types::{cache::cache_new_blocks_task, EthConfig, EthStateCache};
-use reth_tasks::TaskExecutor;
 use reth_tokio_util::EventSender;
 use reth_tracing::tracing::{debug, info};
 use std::{
@@ -194,7 +193,6 @@ pub struct RpcRegistry<Node: FullNodeComponents, EthApi: EthApiTypes> {
         Node::Provider,
         Node::Pool,
         Node::Network,
-        TaskExecutor,
         EthApi,
         Node::Evm,
         Node::Consensus,
@@ -210,7 +208,6 @@ where
         Node::Provider,
         Node::Pool,
         Node::Network,
-        TaskExecutor,
         EthApi,
         Node::Evm,
         Node::Consensus,
@@ -511,7 +508,7 @@ where
             .with_provider(node.provider().clone())
             .with_pool(node.pool().clone())
             .with_network(node.network().clone())
-            .with_executor(node.task_executor().clone())
+            .with_executor(Box::new(node.task_executor().clone()))
             .with_evm_config(node.evm_config().clone())
             .with_consensus(node.consensus().clone())
             .build_with_auth_server(module_config, engine_api, eth_api);
diff --git a/crates/rpc/rpc-builder/src/eth.rs b/crates/rpc/rpc-builder/src/eth.rs
index a4909c5029a..1ef0fd33be3 100644
--- a/crates/rpc/rpc-builder/src/eth.rs
+++ b/crates/rpc/rpc-builder/src/eth.rs
@@ -21,14 +21,14 @@ where
     /// Returns a new instance with the additional handlers for the `eth` namespace.
     ///
     /// This will spawn all necessary tasks for the additional handlers.
-    pub fn bootstrap<Tasks>(config: EthConfig, executor: Tasks, eth_api: EthApi) -> Self
-    where
-        Tasks: TaskSpawner + Clone + 'static,
-    {
-        let filter =
-            EthFilter::new(eth_api.clone(), config.filter_config(), Box::new(executor.clone()));
+    pub fn bootstrap(
+        config: EthConfig,
+        executor: Box<dyn TaskSpawner + 'static>,
+        eth_api: EthApi,
+    ) -> Self {
+        let filter = EthFilter::new(eth_api.clone(), config.filter_config(), executor.clone());
 
-        let pubsub = EthPubSub::with_spawner(eth_api.clone(), Box::new(executor));
+        let pubsub = EthPubSub::with_spawner(eth_api.clone(), executor);
 
         Self { api: eth_api, filter, pubsub }
     }
diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs
index ae7fdce7832..3050f78ae05 100644
--- a/crates/rpc/rpc-builder/src/lib.rs
+++ b/crates/rpc/rpc-builder/src/lib.rs
@@ -103,13 +103,13 @@ pub mod rate_limiter;
 
 /// Convenience function for starting a server in one step.
 #[expect(clippy::too_many_arguments)]
-pub async fn launch<N, Provider, Pool, Network, Tasks, EvmConfig, EthApi>(
+pub async fn launch<N, Provider, Pool, Network, EvmConfig, EthApi>(
     provider: Provider,
     pool: Pool,
     network: Network,
     module_config: impl Into<TransportRpcModuleConfig>,
     server_config: impl Into<RpcServerConfig>,
-    executor: Tasks,
+    executor: Box<dyn TaskSpawner + 'static>,
     evm_config: EvmConfig,
     eth: EthApi,
     consensus: Arc<dyn FullConsensus<N, Error = ConsensusError>>,
@@ -122,7 +122,6 @@ where
         + ChangeSetReader,
     Pool: TransactionPool + 'static,
     Network: NetworkInfo + Peers + Clone + 'static,
-    Tasks: TaskSpawner + Clone + 'static,
     EvmConfig: ConfigureEvm<Primitives = N> + 'static,
     EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
 {
@@ -140,7 +139,7 @@ where
 ///
 /// This is the main entrypoint and the easiest way to configure an RPC server.
 #[derive(Debug, Clone)]
-pub struct RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, Consensus> {
+pub struct RpcModuleBuilder<N, Provider, Pool, Network, EvmConfig, Consensus> {
     /// The Provider type to when creating all rpc handlers
     provider: Provider,
     /// The Pool type to when creating all rpc handlers
@@ -148,7 +147,7 @@ pub struct RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, Consen
     /// The Network type to when creating all rpc handlers
     network: Network,
     /// How additional tasks are spawned, for example in the eth pubsub namespace
-    executor: Tasks,
+    executor: Box<dyn TaskSpawner + 'static>,
     /// Defines how the EVM should be configured before execution.
     evm_config: EvmConfig,
     /// The consensus implementation.
@@ -159,8 +158,8 @@ pub struct RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, Consen
 
 // === impl RpcBuilder ===
 
-impl<N, Provider, Pool, Network, Tasks, EvmConfig, Consensus>
-    RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, Consensus>
+impl<N, Provider, Pool, Network, EvmConfig, Consensus>
+    RpcModuleBuilder<N, Provider, Pool, Network, EvmConfig, Consensus>
 where
     N: NodePrimitives,
     EvmConfig: Clone,
@@ -170,7 +169,7 @@ where
         provider: Provider,
         pool: Pool,
         network: Network,
-        executor: Tasks,
+        executor: Box<dyn TaskSpawner + 'static>,
         evm_config: EvmConfig,
         consensus: Consensus,
     ) -> Self {
@@ -181,7 +180,7 @@ where
     pub fn with_provider<P>(
         self,
         provider: P,
-    ) -> RpcModuleBuilder<N, P, Pool, Network, Tasks, EvmConfig, Consensus>
+    ) -> RpcModuleBuilder<N, P, Pool, Network, EvmConfig, Consensus>
     where
         P: BlockReader<Block = N::Block, Header = N::BlockHeader, Receipt = N::Receipt>
             + StateProviderFactory
@@ -195,7 +194,7 @@ where
     pub fn with_pool<P>(
         self,
         pool: P,
-    ) -> RpcModuleBuilder<N, Provider, P, Network, Tasks, EvmConfig, Consensus>
+    ) -> RpcModuleBuilder<N, Provider, P, Network, EvmConfig, Consensus>
     where
         P: TransactionPool<Transaction: PoolTransaction<Consensus = N::SignedTx>> + 'static,
     {
@@ -210,8 +209,7 @@ where
     /// [`EthApi`] which requires a [`TransactionPool`] implementation.
     pub fn with_noop_pool(
         self,
-    ) -> RpcModuleBuilder<N, Provider, NoopTransactionPool, Network, Tasks, EvmConfig, Consensus>
-    {
+    ) -> RpcModuleBuilder<N, Provider, NoopTransactionPool, Network, EvmConfig, Consensus> {
         let Self { provider, executor, network, evm_config, consensus, _primitives, .. } = self;
         RpcModuleBuilder {
             provider,
@@ -228,7 +226,7 @@ where
     pub fn with_network<Net>(
         self,
         network: Net,
-    ) -> RpcModuleBuilder<N, Provider, Pool, Net, Tasks, EvmConfig, Consensus>
+    ) -> RpcModuleBuilder<N, Provider, Pool, Net, EvmConfig, Consensus>
     where
         Net: NetworkInfo + Peers + 'static,
     {
@@ -243,7 +241,7 @@ where
     /// [`EthApi`] which requires a [`NetworkInfo`] implementation.
     pub fn with_noop_network(
         self,
-    ) -> RpcModuleBuilder<N, Provider, Pool, NoopNetwork, Tasks, EvmConfig, Consensus> {
+    ) -> RpcModuleBuilder<N, Provider, Pool, NoopNetwork, EvmConfig, Consensus> {
         let Self { provider, pool, executor, evm_config, consensus, _primitives, .. } = self;
         RpcModuleBuilder {
             provider,
@@ -257,30 +255,22 @@ where
     }
 
     /// Configure the task executor to use for additional tasks.
-    pub fn with_executor<T>(
-        self,
-        executor: T,
-    ) -> RpcModuleBuilder<N, Provider, Pool, Network, T, EvmConfig, Consensus>
-    where
-        T: TaskSpawner + 'static,
-    {
+    pub fn with_executor(self, executor: Box<dyn TaskSpawner + 'static>) -> Self {
         let Self { pool, network, provider, evm_config, consensus, _primitives, .. } = self;
-        RpcModuleBuilder { provider, network, pool, executor, evm_config, consensus, _primitives }
+        Self { provider, network, pool, executor, evm_config, consensus, _primitives }
     }
 
     /// Configure [`TokioTaskExecutor`] as the task executor to use for additional tasks.
     ///
     /// This will spawn additional tasks directly via `tokio::task::spawn`, See
     /// [`TokioTaskExecutor`].
-    pub fn with_tokio_executor(
-        self,
-    ) -> RpcModuleBuilder<N, Provider, Pool, Network, TokioTaskExecutor, EvmConfig, Consensus> {
+    pub fn with_tokio_executor(self) -> Self {
         let Self { pool, network, provider, evm_config, consensus, _primitives, .. } = self;
-        RpcModuleBuilder {
+        Self {
             provider,
             network,
             pool,
-            executor: TokioTaskExecutor::default(),
+            executor: Box::new(TokioTaskExecutor::default()),
             evm_config,
             consensus,
             _primitives,
@@ -291,7 +281,7 @@ where
     pub fn with_evm_config<E>(
         self,
         evm_config: E,
-    ) -> RpcModuleBuilder<N, Provider, Pool, Network, Tasks, E, Consensus>
+    ) -> RpcModuleBuilder<N, Provider, Pool, Network, E, Consensus>
     where
         EvmConfig: 'static,
         E: ConfigureEvm + Clone,
@@ -304,7 +294,7 @@ where
     pub fn with_consensus<C>(
         self,
         consensus: C,
-    ) -> RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, C> {
+    ) -> RpcModuleBuilder<N, Provider, Pool, Network, EvmConfig, C> {
         let Self { provider, network, pool, executor, evm_config, _primitives, .. } = self;
         RpcModuleBuilder { provider, network, pool, executor, evm_config, consensus, _primitives }
     }
@@ -347,8 +337,8 @@ where
     }
 }
 
-impl<N, Provider, Pool, Network, Tasks, EvmConfig, Consensus>
-    RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, Consensus>
+impl<N, Provider, Pool, Network, EvmConfig, Consensus>
+    RpcModuleBuilder<N, Provider, Pool, Network, EvmConfig, Consensus>
 where
     N: NodePrimitives,
     Provider: FullRpcProvider<Block = N::Block, Receipt = N::Receipt, Header = N::BlockHeader>
@@ -357,7 +347,6 @@ where
         + ChangeSetReader,
     Pool: TransactionPool + 'static,
     Network: NetworkInfo + Peers + Clone + 'static,
-    Tasks: TaskSpawner + Clone + 'static,
     EvmConfig: ConfigureEvm<Primitives = N> + 'static,
     Consensus: FullConsensus<N, Error = ConsensusError> + Clone + 'static,
 {
@@ -367,7 +356,6 @@ where
     /// This behaves exactly as [`RpcModuleBuilder::build`] for the [`TransportRpcModules`], but
     /// also configures the auth (engine api) server, which exposes a subset of the `eth_`
     /// namespace.
-    #[expect(clippy::type_complexity)]
     pub fn build_with_auth_server<EthApi>(
         self,
         module_config: TransportRpcModuleConfig,
@@ -376,7 +364,7 @@ where
     ) -> (
         TransportRpcModules,
         AuthRpcModule,
-        RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>,
+        RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>,
     )
     where
         EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
@@ -404,7 +392,7 @@ where
         self,
         config: RpcModuleConfig,
         eth: EthApi,
-    ) -> RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
+    ) -> RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
     where
         EthApi: EthApiTypes + 'static,
     {
@@ -450,9 +438,9 @@ where
     }
 }
 
-impl<N: NodePrimitives> Default for RpcModuleBuilder<N, (), (), (), (), (), ()> {
+impl<N: NodePrimitives> Default for RpcModuleBuilder<N, (), (), (), (), ()> {
     fn default() -> Self {
-        Self::new((), (), (), (), (), ())
+        Self::new((), (), (), Box::new(TokioTaskExecutor::default()), (), ())
     }
 }
 
@@ -540,7 +528,6 @@ pub struct RpcRegistryInner<
     Provider: BlockReader,
     Pool,
     Network,
-    Tasks,
     EthApi: EthApiTypes,
     EvmConfig,
     Consensus,
@@ -548,7 +535,7 @@ pub struct RpcRegistryInner<
     provider: Provider,
     pool: Pool,
     network: Network,
-    executor: Tasks,
+    executor: Box<dyn TaskSpawner + 'static>,
     evm_config: EvmConfig,
     consensus: Consensus,
     /// Holds a all `eth_` namespace handlers
@@ -563,8 +550,8 @@ pub struct RpcRegistryInner<
 
 // === impl RpcRegistryInner ===
 
-impl<N, Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
-    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
+impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
+    RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
 where
     N: NodePrimitives,
     Provider: StateProviderFactory
@@ -575,7 +562,6 @@ where
         + 'static,
     Pool: Send + Sync + Clone + 'static,
     Network: Clone + 'static,
-    Tasks: TaskSpawner + Clone + 'static,
     EthApi: EthApiTypes + 'static,
     EvmConfig: ConfigureEvm<Primitives = N>,
 {
@@ -585,7 +571,7 @@ where
         provider: Provider,
         pool: Pool,
         network: Network,
-        executor: Tasks,
+        executor: Box<dyn TaskSpawner + 'static>,
         consensus: Consensus,
         config: RpcModuleConfig,
         evm_config: EvmConfig,
@@ -613,8 +599,8 @@ where
     }
 }
 
-impl<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
-    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
+impl<Provider, Pool, Network, EthApi, BlockExecutor, Consensus>
+    RpcRegistryInner<Provider, Pool, Network, EthApi, BlockExecutor, Consensus>
 where
     Provider: BlockReader,
     EthApi: EthApiTypes,
@@ -635,8 +621,8 @@ where
     }
 
     /// Returns a reference to the tasks type
-    pub const fn tasks(&self) -> &Tasks {
-        &self.executor
+    pub const fn tasks(&self) -> &(dyn TaskSpawner + 'static) {
+        &*self.executor
     }
 
     /// Returns a reference to the provider
@@ -659,8 +645,8 @@ where
     }
 }
 
-impl<Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
-    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
+impl<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
+    RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
 where
     Network: NetworkInfo + Clone + 'static,
     EthApi: EthApiTypes,
@@ -698,8 +684,8 @@ where
     }
 }
 
-impl<N, Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
-    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
+impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
+    RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
 where
     N: NodePrimitives,
     Provider: FullRpcProvider<
@@ -710,7 +696,6 @@ where
         > + AccountReader
         + ChangeSetReader,
     Network: NetworkInfo + Peers + Clone + 'static,
-    Tasks: TaskSpawner + Clone + 'static,
     EthApi: EthApiServer<
             RpcTransaction<EthApi::NetworkTypes>,
             RpcBlock<EthApi::NetworkTypes>,
@@ -813,8 +798,8 @@ where
     }
 }
 
-impl<N, Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
-    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
+impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
+    RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
 where
     N: NodePrimitives,
     Provider: FullRpcProvider<
@@ -825,7 +810,6 @@ where
         > + AccountReader
         + ChangeSetReader,
     Network: NetworkInfo + Peers + Clone + 'static,
-    Tasks: TaskSpawner + Clone + 'static,
     EthApi: EthApiTypes,
     EvmConfig: ConfigureEvm<Primitives = N>,
 {
@@ -886,12 +870,12 @@ where
 
     /// Instantiates `RethApi`
     pub fn reth_api(&self) -> RethApi<Provider> {
-        RethApi::new(self.provider.clone(), Box::new(self.executor.clone()))
+        RethApi::new(self.provider.clone(), self.executor.clone())
     }
 }
 
-impl<N, Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
-    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, EvmConfig, Consensus>
+impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
+    RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
 where
     N: NodePrimitives,
     Provider: FullRpcProvider<Block = N::Block>
@@ -900,7 +884,6 @@ where
         + ChangeSetReader,
     Pool: TransactionPool + 'static,
     Network: NetworkInfo + Peers + Clone + 'static,
-    Tasks: TaskSpawner + Clone + 'static,
     EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
     EvmConfig: ConfigureEvm<Primitives = N> + 'static,
     Consensus: FullConsensus<N, Error = ConsensusError> + Clone + 'static,
@@ -1037,7 +1020,7 @@ where
                         .into(),
                         RethRpcModule::Ots => OtterscanApi::new(eth_api.clone()).into_rpc().into(),
                         RethRpcModule::Reth => {
-                            RethApi::new(self.provider.clone(), Box::new(self.executor.clone()))
+                            RethApi::new(self.provider.clone(), self.executor.clone())
                                 .into_rpc()
                                 .into()
                         }
diff --git a/examples/rpc-db/src/main.rs b/examples/rpc-db/src/main.rs
index 16ba5b6e406..b241dc8670c 100644
--- a/examples/rpc-db/src/main.rs
+++ b/examples/rpc-db/src/main.rs
@@ -65,7 +65,7 @@ async fn main() -> eyre::Result<()> {
         // Rest is just noops that do nothing
         .with_noop_pool()
         .with_noop_network()
-        .with_executor(TokioTaskExecutor::default())
+        .with_executor(Box::new(TokioTaskExecutor::default()))
         .with_evm_config(EthEvmConfig::new(spec.clone()))
         .with_consensus(EthBeaconConsensus::new(spec.clone()));
 


Test patch:
diff --git a/crates/rpc/rpc-builder/tests/it/utils.rs b/crates/rpc/rpc-builder/tests/it/utils.rs
index 3b21e848ce8..5c95dbc7ad5 100644
--- a/crates/rpc/rpc-builder/tests/it/utils.rs
+++ b/crates/rpc/rpc-builder/tests/it/utils.rs
@@ -118,20 +118,14 @@ pub async fn launch_http_ws_same_port(modules: impl Into<RpcModuleSelection>) ->
 }
 
 /// Returns an [`RpcModuleBuilder`] with testing components.
-pub fn test_rpc_builder() -> RpcModuleBuilder<
-    EthPrimitives,
-    NoopProvider,
-    TestPool,
-    NoopNetwork,
-    TokioTaskExecutor,
-    EthEvmConfig,
-    NoopConsensus,
-> {
+pub fn test_rpc_builder(
+) -> RpcModuleBuilder<EthPrimitives, NoopProvider, TestPool, NoopNetwork, EthEvmConfig, NoopConsensus>
+{
     RpcModuleBuilder::default()
         .with_provider(NoopProvider::default())
         .with_pool(TestPoolBuilder::default().into())
         .with_network(NoopNetwork::default())
-        .with_executor(TokioTaskExecutor::default())
+        .with_executor(Box::new(TokioTaskExecutor::default()))
         .with_evm_config(EthEvmConfig::mainnet())
         .with_consensus(NoopConsensus::default())
 }