reth_rpc_builder/
lib.rs

1//! Configure reth RPC.
2//!
3//! This crate contains several builder and config types that allow to configure the selection of
4//! [`RethRpcModule`] specific to transports (ws, http, ipc).
5//!
6//! The [`RpcModuleBuilder`] is the main entrypoint for configuring all reth modules. It takes
7//! instances of components required to start the servers, such as provider impls, network and
8//! transaction pool. [`RpcModuleBuilder::build`] returns a [`TransportRpcModules`] which contains
9//! the transport specific config (what APIs are available via this transport).
10//!
11//! The [`RpcServerConfig`] is used to assemble and start the http server, ws server, ipc servers,
12//! it requires the [`TransportRpcModules`] so it can start the servers with the configured modules.
13
14#![doc(
15    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
16    html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
17    issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
18)]
19#![cfg_attr(not(test), warn(unused_crate_dependencies))]
20#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
21
22use crate::{auth::AuthRpcModule, error::WsHttpSamePortError, metrics::RpcRequestMetrics};
23use alloy_provider::{fillers::RecommendedFillers, Provider, ProviderBuilder};
24use core::marker::PhantomData;
25use error::{ConflictingModules, RpcError, ServerKind};
26use http::{header::AUTHORIZATION, HeaderMap};
27use jsonrpsee::{
28    core::RegisterMethodError,
29    server::{
30        middleware::rpc::{RpcService, RpcServiceT},
31        AlreadyStoppedError, IdProvider, RpcServiceBuilder, ServerHandle,
32    },
33    Methods, RpcModule,
34};
35use reth_chainspec::EthereumHardforks;
36use reth_consensus::{ConsensusError, FullConsensus};
37use reth_evm::{execute::BlockExecutorProvider, ConfigureEvm};
38use reth_network_api::{noop::NoopNetwork, NetworkInfo, Peers};
39use reth_primitives_traits::NodePrimitives;
40use reth_provider::{
41    AccountReader, BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider,
42    ChangeSetReader, FullRpcProvider, ProviderBlock, StateProviderFactory,
43};
44use reth_rpc::{
45    AdminApi, DebugApi, EngineEthApi, EthApi, EthApiBuilder, EthBundle, MinerApi, NetApi,
46    OtterscanApi, RPCApi, RethApi, TraceApi, TxPoolApi, ValidationApiConfig, Web3Api,
47};
48use reth_rpc_api::servers::*;
49use reth_rpc_eth_api::{
50    helpers::{Call, EthApiSpec, EthTransactions, LoadPendingBlock, TraceExt},
51    EthApiServer, EthApiTypes, FullEthApiServer, RpcBlock, RpcHeader, RpcReceipt, RpcTransaction,
52};
53use reth_rpc_eth_types::{EthConfig, EthSubscriptionIdProvider};
54use reth_rpc_layer::{AuthLayer, Claims, CompressionLayer, JwtAuthValidator, JwtSecret};
55use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor};
56use reth_transaction_pool::{noop::NoopTransactionPool, PoolTransaction, TransactionPool};
57use serde::{Deserialize, Serialize};
58use std::{
59    collections::HashMap,
60    fmt::Debug,
61    net::{Ipv4Addr, SocketAddr, SocketAddrV4},
62    sync::Arc,
63    time::{Duration, SystemTime, UNIX_EPOCH},
64};
65use tower::Layer;
66use tower_http::cors::CorsLayer;
67
68pub use cors::CorsDomainError;
69
70// re-export for convenience
71pub use jsonrpsee::server::ServerBuilder;
72pub use reth_ipc::server::{
73    Builder as IpcServerBuilder, RpcServiceBuilder as IpcRpcServiceBuilder,
74};
75pub use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection};
76pub use tower::layer::util::{Identity, Stack};
77
78/// Auth server utilities.
79pub mod auth;
80
81/// RPC server utilities.
82pub mod config;
83
84/// Cors utilities.
85mod cors;
86
87/// Rpc error utilities.
88pub mod error;
89
90/// Eth utils
91pub mod eth;
92pub use eth::EthHandlers;
93
94// Rpc server metrics
95mod metrics;
96pub use metrics::{MeteredRequestFuture, RpcRequestMetricsService};
97use reth_rpc::eth::sim_bundle::EthSimBundle;
98
99// Rpc rate limiter
100pub mod rate_limiter;
101
102/// Convenience function for starting a server in one step.
103#[expect(clippy::too_many_arguments)]
104pub async fn launch<N, Provider, Pool, Network, Tasks, EvmConfig, EthApi, BlockExecutor>(
105    provider: Provider,
106    pool: Pool,
107    network: Network,
108    module_config: impl Into<TransportRpcModuleConfig>,
109    server_config: impl Into<RpcServerConfig>,
110    executor: Tasks,
111    evm_config: EvmConfig,
112    eth: EthApi,
113    block_executor: BlockExecutor,
114    consensus: Arc<dyn FullConsensus<N, Error = ConsensusError>>,
115) -> Result<RpcServerHandle, RpcError>
116where
117    N: NodePrimitives,
118    Provider: FullRpcProvider<Block = N::Block, Receipt = N::Receipt, Header = N::BlockHeader>
119        + CanonStateSubscriptions<Primitives = N>
120        + AccountReader
121        + ChangeSetReader,
122    Pool: TransactionPool + 'static,
123    Network: NetworkInfo + Peers + Clone + 'static,
124    Tasks: TaskSpawner + Clone + 'static,
125    EvmConfig: ConfigureEvm<Primitives = N>,
126    EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
127    BlockExecutor: BlockExecutorProvider<Primitives = N>,
128{
129    let module_config = module_config.into();
130    server_config
131        .into()
132        .start(
133            &RpcModuleBuilder::new(
134                provider,
135                pool,
136                network,
137                executor,
138                evm_config,
139                block_executor,
140                consensus,
141            )
142            .build(module_config, eth),
143        )
144        .await
145}
146
147/// A builder type to configure the RPC module: See [`RpcModule`]
148///
149/// This is the main entrypoint and the easiest way to configure an RPC server.
150#[derive(Debug, Clone)]
151pub struct RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
152{
153    /// The Provider type to when creating all rpc handlers
154    provider: Provider,
155    /// The Pool type to when creating all rpc handlers
156    pool: Pool,
157    /// The Network type to when creating all rpc handlers
158    network: Network,
159    /// How additional tasks are spawned, for example in the eth pubsub namespace
160    executor: Tasks,
161    /// Defines how the EVM should be configured before execution.
162    evm_config: EvmConfig,
163    /// The provider for getting a block executor that executes blocks
164    block_executor: BlockExecutor,
165    /// The consensus implementation.
166    consensus: Consensus,
167    /// Node data primitives.
168    _primitives: PhantomData<N>,
169}
170
171// === impl RpcBuilder ===
172
173impl<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
174    RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
175where
176    N: NodePrimitives,
177{
178    /// Create a new instance of the builder
179    pub const fn new(
180        provider: Provider,
181        pool: Pool,
182        network: Network,
183        executor: Tasks,
184        evm_config: EvmConfig,
185        block_executor: BlockExecutor,
186        consensus: Consensus,
187    ) -> Self {
188        Self {
189            provider,
190            pool,
191            network,
192            executor,
193            evm_config,
194            block_executor,
195            consensus,
196            _primitives: PhantomData,
197        }
198    }
199
200    /// Configure the provider instance.
201    pub fn with_provider<P>(
202        self,
203        provider: P,
204    ) -> RpcModuleBuilder<N, P, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
205    where
206        P: BlockReader<Block = N::Block, Header = N::BlockHeader, Receipt = N::Receipt>
207            + StateProviderFactory
208            + 'static,
209    {
210        let Self {
211            pool,
212            network,
213            executor,
214            evm_config,
215            block_executor,
216            consensus,
217            _primitives,
218            ..
219        } = self;
220        RpcModuleBuilder {
221            provider,
222            network,
223            pool,
224            executor,
225            evm_config,
226            block_executor,
227            consensus,
228            _primitives,
229        }
230    }
231
232    /// Configure the transaction pool instance.
233    pub fn with_pool<P>(
234        self,
235        pool: P,
236    ) -> RpcModuleBuilder<N, Provider, P, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
237    where
238        P: TransactionPool<Transaction: PoolTransaction<Consensus = N::SignedTx>> + 'static,
239    {
240        let Self {
241            provider,
242            network,
243            executor,
244            evm_config,
245            block_executor,
246            consensus,
247            _primitives,
248            ..
249        } = self;
250        RpcModuleBuilder {
251            provider,
252            network,
253            pool,
254            executor,
255            evm_config,
256            block_executor,
257            consensus,
258            _primitives,
259        }
260    }
261
262    /// Configure a [`NoopTransactionPool`] instance.
263    ///
264    /// Caution: This will configure a pool API that does absolutely nothing.
265    /// This is only intended for allow easier setup of namespaces that depend on the
266    /// [`EthApi`] which requires a [`TransactionPool`] implementation.
267    pub fn with_noop_pool(
268        self,
269    ) -> RpcModuleBuilder<
270        N,
271        Provider,
272        NoopTransactionPool,
273        Network,
274        Tasks,
275        EvmConfig,
276        BlockExecutor,
277        Consensus,
278    > {
279        let Self {
280            provider,
281            executor,
282            network,
283            evm_config,
284            block_executor,
285            consensus,
286            _primitives,
287            ..
288        } = self;
289        RpcModuleBuilder {
290            provider,
291            executor,
292            network,
293            evm_config,
294            block_executor,
295            pool: NoopTransactionPool::default(),
296            consensus,
297            _primitives,
298        }
299    }
300
301    /// Configure the network instance.
302    pub fn with_network<Net>(
303        self,
304        network: Net,
305    ) -> RpcModuleBuilder<N, Provider, Pool, Net, Tasks, EvmConfig, BlockExecutor, Consensus>
306    where
307        Net: NetworkInfo + Peers + 'static,
308    {
309        let Self {
310            provider,
311            pool,
312            executor,
313            evm_config,
314            block_executor,
315            consensus,
316            _primitives,
317            ..
318        } = self;
319        RpcModuleBuilder {
320            provider,
321            network,
322            pool,
323            executor,
324            evm_config,
325            block_executor,
326            consensus,
327            _primitives,
328        }
329    }
330
331    /// Configure a [`NoopNetwork`] instance.
332    ///
333    /// Caution: This will configure a network API that does absolutely nothing.
334    /// This is only intended for allow easier setup of namespaces that depend on the
335    /// [`EthApi`] which requires a [`NetworkInfo`] implementation.
336    pub fn with_noop_network(
337        self,
338    ) -> RpcModuleBuilder<N, Provider, Pool, NoopNetwork, Tasks, EvmConfig, BlockExecutor, Consensus>
339    {
340        let Self {
341            provider,
342            pool,
343            executor,
344            evm_config,
345            block_executor,
346            consensus,
347            _primitives,
348            ..
349        } = self;
350        RpcModuleBuilder {
351            provider,
352            pool,
353            executor,
354            network: NoopNetwork::default(),
355            evm_config,
356            block_executor,
357            consensus,
358            _primitives,
359        }
360    }
361
362    /// Configure the task executor to use for additional tasks.
363    pub fn with_executor<T>(
364        self,
365        executor: T,
366    ) -> RpcModuleBuilder<N, Provider, Pool, Network, T, EvmConfig, BlockExecutor, Consensus>
367    where
368        T: TaskSpawner + 'static,
369    {
370        let Self {
371            pool,
372            network,
373            provider,
374            evm_config,
375            block_executor,
376            consensus,
377            _primitives,
378            ..
379        } = self;
380        RpcModuleBuilder {
381            provider,
382            network,
383            pool,
384            executor,
385            evm_config,
386            block_executor,
387            consensus,
388            _primitives,
389        }
390    }
391
392    /// Configure [`TokioTaskExecutor`] as the task executor to use for additional tasks.
393    ///
394    /// This will spawn additional tasks directly via `tokio::task::spawn`, See
395    /// [`TokioTaskExecutor`].
396    pub fn with_tokio_executor(
397        self,
398    ) -> RpcModuleBuilder<
399        N,
400        Provider,
401        Pool,
402        Network,
403        TokioTaskExecutor,
404        EvmConfig,
405        BlockExecutor,
406        Consensus,
407    > {
408        let Self {
409            pool,
410            network,
411            provider,
412            evm_config,
413            block_executor,
414            consensus,
415            _primitives,
416            ..
417        } = self;
418        RpcModuleBuilder {
419            provider,
420            network,
421            pool,
422            executor: TokioTaskExecutor::default(),
423            evm_config,
424            block_executor,
425            consensus,
426            _primitives,
427        }
428    }
429
430    /// Configure the evm configuration type
431    pub fn with_evm_config<E>(
432        self,
433        evm_config: E,
434    ) -> RpcModuleBuilder<N, Provider, Pool, Network, Tasks, E, BlockExecutor, Consensus>
435    where
436        EvmConfig: 'static,
437    {
438        let Self {
439            provider, pool, executor, network, block_executor, consensus, _primitives, ..
440        } = self;
441        RpcModuleBuilder {
442            provider,
443            network,
444            pool,
445            executor,
446            evm_config,
447            block_executor,
448            consensus,
449            _primitives,
450        }
451    }
452
453    /// Configure the block executor provider
454    pub fn with_block_executor<BE>(
455        self,
456        block_executor: BE,
457    ) -> RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, BE, Consensus>
458    where
459        BE: BlockExecutorProvider<Primitives = N> + 'static,
460    {
461        let Self { provider, network, pool, executor, evm_config, consensus, _primitives, .. } =
462            self;
463        RpcModuleBuilder {
464            provider,
465            network,
466            pool,
467            executor,
468            evm_config,
469            block_executor,
470            consensus,
471            _primitives,
472        }
473    }
474
475    /// Configure the consensus implementation.
476    pub fn with_consensus<C>(
477        self,
478        consensus: C,
479    ) -> RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, C> {
480        let Self {
481            provider, network, pool, executor, evm_config, block_executor, _primitives, ..
482        } = self;
483        RpcModuleBuilder {
484            provider,
485            network,
486            pool,
487            executor,
488            evm_config,
489            block_executor,
490            consensus,
491            _primitives,
492        }
493    }
494
495    /// Instantiates a new [`EthApiBuilder`] from the configured components.
496    pub fn eth_api_builder(&self) -> EthApiBuilder<Provider, Pool, Network, EvmConfig>
497    where
498        Provider: BlockReaderIdExt + Clone,
499        Pool: Clone,
500        Network: Clone,
501        EvmConfig: Clone,
502    {
503        EthApiBuilder::new(
504            self.provider.clone(),
505            self.pool.clone(),
506            self.network.clone(),
507            self.evm_config.clone(),
508        )
509    }
510
511    /// Initializes a new [`EthApiServer`] with the configured components and default settings.
512    ///
513    /// Note: This spawns all necessary tasks.
514    ///
515    /// See also [`EthApiBuilder`].
516    pub fn bootstrap_eth_api(&self) -> EthApi<Provider, Pool, Network, EvmConfig>
517    where
518        Provider: BlockReaderIdExt<Block = N::Block, Header = N::BlockHeader, Receipt = N::Receipt>
519            + StateProviderFactory
520            + CanonStateSubscriptions<Primitives = N>
521            + ChainSpecProvider
522            + Clone
523            + Unpin
524            + 'static,
525        Pool: Clone,
526        EvmConfig: Clone,
527        Network: Clone,
528    {
529        self.eth_api_builder().build()
530    }
531}
532
533impl<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
534    RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
535where
536    N: NodePrimitives,
537    Provider: FullRpcProvider<Block = N::Block, Receipt = N::Receipt, Header = N::BlockHeader>
538        + CanonStateSubscriptions<Primitives = N>
539        + AccountReader
540        + ChangeSetReader,
541    Pool: TransactionPool + 'static,
542    Network: NetworkInfo + Peers + Clone + 'static,
543    Tasks: TaskSpawner + Clone + 'static,
544    EvmConfig: ConfigureEvm<Primitives = N>,
545    BlockExecutor: BlockExecutorProvider<Primitives = N>,
546    Consensus: FullConsensus<N, Error = ConsensusError> + Clone + 'static,
547{
548    /// Configures all [`RpcModule`]s specific to the given [`TransportRpcModuleConfig`] which can
549    /// be used to start the transport server(s).
550    ///
551    /// This behaves exactly as [`RpcModuleBuilder::build`] for the [`TransportRpcModules`], but
552    /// also configures the auth (engine api) server, which exposes a subset of the `eth_`
553    /// namespace.
554    #[expect(clippy::type_complexity)]
555    pub fn build_with_auth_server<EthApi>(
556        self,
557        module_config: TransportRpcModuleConfig,
558        engine: impl IntoEngineApiRpcModule,
559        eth: EthApi,
560    ) -> (
561        TransportRpcModules,
562        AuthRpcModule,
563        RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>,
564    )
565    where
566        EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
567    {
568        let Self {
569            provider, pool, network, executor, evm_config, block_executor, consensus, ..
570        } = self;
571
572        let config = module_config.config.clone().unwrap_or_default();
573
574        let mut registry = RpcRegistryInner::new(
575            provider,
576            pool,
577            network,
578            executor,
579            consensus,
580            config,
581            evm_config,
582            eth,
583            block_executor,
584        );
585
586        let modules = registry.create_transport_rpc_modules(module_config);
587
588        let auth_module = registry.create_auth_module(engine);
589
590        (modules, auth_module, registry)
591    }
592
593    /// Converts the builder into a [`RpcRegistryInner`] which can be used to create all
594    /// components.
595    ///
596    /// This is useful for getting access to API handlers directly
597    pub fn into_registry<EthApi>(
598        self,
599        config: RpcModuleConfig,
600        eth: EthApi,
601    ) -> RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
602    where
603        EthApi: EthApiTypes + 'static,
604    {
605        let Self {
606            provider, pool, network, executor, evm_config, block_executor, consensus, ..
607        } = self;
608        RpcRegistryInner::new(
609            provider,
610            pool,
611            network,
612            executor,
613            consensus,
614            config,
615            evm_config,
616            eth,
617            block_executor,
618        )
619    }
620
621    /// Configures all [`RpcModule`]s specific to the given [`TransportRpcModuleConfig`] which can
622    /// be used to start the transport server(s).
623    pub fn build<EthApi>(
624        self,
625        module_config: TransportRpcModuleConfig,
626        eth: EthApi,
627    ) -> TransportRpcModules<()>
628    where
629        EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
630    {
631        let mut modules = TransportRpcModules::default();
632
633        let Self {
634            provider, pool, network, executor, evm_config, block_executor, consensus, ..
635        } = self;
636
637        if !module_config.is_empty() {
638            let TransportRpcModuleConfig { http, ws, ipc, config } = module_config.clone();
639
640            let mut registry = RpcRegistryInner::new(
641                provider,
642                pool,
643                network,
644                executor,
645                consensus,
646                config.unwrap_or_default(),
647                evm_config,
648                eth,
649                block_executor,
650            );
651
652            modules.config = module_config;
653            modules.http = registry.maybe_module(http.as_ref());
654            modules.ws = registry.maybe_module(ws.as_ref());
655            modules.ipc = registry.maybe_module(ipc.as_ref());
656        }
657
658        modules
659    }
660}
661
662impl<N: NodePrimitives> Default for RpcModuleBuilder<N, (), (), (), (), (), (), ()> {
663    fn default() -> Self {
664        Self::new((), (), (), (), (), (), ())
665    }
666}
667
668/// Bundles settings for modules
669#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
670pub struct RpcModuleConfig {
671    /// `eth` namespace settings
672    eth: EthConfig,
673    /// `flashbots` namespace settings
674    flashbots: ValidationApiConfig,
675}
676
677// === impl RpcModuleConfig ===
678
679impl RpcModuleConfig {
680    /// Convenience method to create a new [`RpcModuleConfigBuilder`]
681    pub fn builder() -> RpcModuleConfigBuilder {
682        RpcModuleConfigBuilder::default()
683    }
684
685    /// Returns a new RPC module config given the eth namespace config
686    pub const fn new(eth: EthConfig, flashbots: ValidationApiConfig) -> Self {
687        Self { eth, flashbots }
688    }
689
690    /// Get a reference to the eth namespace config
691    pub const fn eth(&self) -> &EthConfig {
692        &self.eth
693    }
694
695    /// Get a mutable reference to the eth namespace config
696    pub const fn eth_mut(&mut self) -> &mut EthConfig {
697        &mut self.eth
698    }
699}
700
701/// Configures [`RpcModuleConfig`]
702#[derive(Clone, Debug, Default)]
703pub struct RpcModuleConfigBuilder {
704    eth: Option<EthConfig>,
705    flashbots: Option<ValidationApiConfig>,
706}
707
708// === impl RpcModuleConfigBuilder ===
709
710impl RpcModuleConfigBuilder {
711    /// Configures a custom eth namespace config
712    pub const fn eth(mut self, eth: EthConfig) -> Self {
713        self.eth = Some(eth);
714        self
715    }
716
717    /// Configures a custom flashbots namespace config
718    pub fn flashbots(mut self, flashbots: ValidationApiConfig) -> Self {
719        self.flashbots = Some(flashbots);
720        self
721    }
722
723    /// Consumes the type and creates the [`RpcModuleConfig`]
724    pub fn build(self) -> RpcModuleConfig {
725        let Self { eth, flashbots } = self;
726        RpcModuleConfig { eth: eth.unwrap_or_default(), flashbots: flashbots.unwrap_or_default() }
727    }
728
729    /// Get a reference to the eth namespace config, if any
730    pub const fn get_eth(&self) -> Option<&EthConfig> {
731        self.eth.as_ref()
732    }
733
734    /// Get a mutable reference to the eth namespace config, if any
735    pub const fn eth_mut(&mut self) -> &mut Option<EthConfig> {
736        &mut self.eth
737    }
738
739    /// Get the eth namespace config, creating a default if none is set
740    pub fn eth_mut_or_default(&mut self) -> &mut EthConfig {
741        self.eth.get_or_insert_with(EthConfig::default)
742    }
743}
744
745/// A Helper type the holds instances of the configured modules.
746#[derive(Debug, Clone)]
747#[expect(dead_code)] // Consensus generic, might be useful in the future
748pub struct RpcRegistryInner<
749    Provider: BlockReader,
750    Pool,
751    Network,
752    Tasks,
753    EthApi: EthApiTypes,
754    BlockExecutor,
755    Consensus,
756> {
757    provider: Provider,
758    pool: Pool,
759    network: Network,
760    executor: Tasks,
761    block_executor: BlockExecutor,
762    consensus: Consensus,
763    /// Holds a all `eth_` namespace handlers
764    eth: EthHandlers<EthApi>,
765    /// to put trace calls behind semaphore
766    blocking_pool_guard: BlockingTaskGuard,
767    /// Contains the [Methods] of a module
768    modules: HashMap<RethRpcModule, Methods>,
769    /// eth config settings
770    eth_config: EthConfig,
771}
772
773// === impl RpcRegistryInner ===
774
775impl<N, Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
776    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
777where
778    N: NodePrimitives,
779    Provider: StateProviderFactory
780        + CanonStateSubscriptions<Primitives = N>
781        + BlockReader<Block = N::Block, Receipt = N::Receipt>
782        + Clone
783        + Unpin
784        + 'static,
785    Pool: Send + Sync + Clone + 'static,
786    Network: Clone + 'static,
787    Tasks: TaskSpawner + Clone + 'static,
788    EthApi: EthApiTypes + 'static,
789    BlockExecutor: BlockExecutorProvider<Primitives = N>,
790{
791    /// Creates a new, empty instance.
792    #[expect(clippy::too_many_arguments)]
793    pub fn new<EvmConfig>(
794        provider: Provider,
795        pool: Pool,
796        network: Network,
797        executor: Tasks,
798        consensus: Consensus,
799        config: RpcModuleConfig,
800        _evm_config: EvmConfig,
801        eth_api: EthApi,
802        block_executor: BlockExecutor,
803    ) -> Self
804    where
805        EvmConfig: ConfigureEvm<Primitives = N>,
806    {
807        let blocking_pool_guard = BlockingTaskGuard::new(config.eth.max_tracing_requests);
808
809        let eth = EthHandlers::bootstrap(config.eth, executor.clone(), eth_api);
810
811        Self {
812            provider,
813            pool,
814            network,
815            eth,
816            executor,
817            consensus,
818            modules: Default::default(),
819            blocking_pool_guard,
820            block_executor,
821            eth_config: config.eth,
822        }
823    }
824}
825
826impl<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
827    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
828where
829    Provider: BlockReader,
830    EthApi: EthApiTypes,
831{
832    /// Returns a reference to the installed [`EthApi`].
833    pub const fn eth_api(&self) -> &EthApi {
834        &self.eth.api
835    }
836
837    /// Returns a reference to the installed [`EthHandlers`].
838    pub const fn eth_handlers(&self) -> &EthHandlers<EthApi> {
839        &self.eth
840    }
841
842    /// Returns a reference to the pool
843    pub const fn pool(&self) -> &Pool {
844        &self.pool
845    }
846
847    /// Returns a reference to the tasks type
848    pub const fn tasks(&self) -> &Tasks {
849        &self.executor
850    }
851
852    /// Returns a reference to the provider
853    pub const fn provider(&self) -> &Provider {
854        &self.provider
855    }
856
857    /// Returns all installed methods
858    pub fn methods(&self) -> Vec<Methods> {
859        self.modules.values().cloned().collect()
860    }
861
862    /// Returns a merged `RpcModule`
863    pub fn module(&self) -> RpcModule<()> {
864        let mut module = RpcModule::new(());
865        for methods in self.modules.values().cloned() {
866            module.merge(methods).expect("No conflicts");
867        }
868        module
869    }
870}
871
872impl<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
873    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
874where
875    Network: NetworkInfo + Clone + 'static,
876    EthApi: EthApiTypes,
877    Provider: BlockReader + ChainSpecProvider<ChainSpec: EthereumHardforks>,
878    BlockExecutor: BlockExecutorProvider,
879{
880    /// Instantiates `AdminApi`
881    pub fn admin_api(&self) -> AdminApi<Network, Provider::ChainSpec>
882    where
883        Network: Peers,
884    {
885        AdminApi::new(self.network.clone(), self.provider.chain_spec())
886    }
887
888    /// Instantiates `Web3Api`
889    pub fn web3_api(&self) -> Web3Api<Network> {
890        Web3Api::new(self.network.clone())
891    }
892
893    /// Register Admin Namespace
894    pub fn register_admin(&mut self) -> &mut Self
895    where
896        Network: Peers,
897    {
898        let adminapi = self.admin_api();
899        self.modules.insert(RethRpcModule::Admin, adminapi.into_rpc().into());
900        self
901    }
902
903    /// Register Web3 Namespace
904    pub fn register_web3(&mut self) -> &mut Self {
905        let web3api = self.web3_api();
906        self.modules.insert(RethRpcModule::Web3, web3api.into_rpc().into());
907        self
908    }
909}
910
911impl<N, Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
912    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
913where
914    N: NodePrimitives,
915    Provider: FullRpcProvider<
916            Header = N::BlockHeader,
917            Block = N::Block,
918            Receipt = N::Receipt,
919            Transaction = N::SignedTx,
920        > + AccountReader
921        + ChangeSetReader,
922    Network: NetworkInfo + Peers + Clone + 'static,
923    Tasks: TaskSpawner + Clone + 'static,
924    EthApi: EthApiServer<
925            RpcTransaction<EthApi::NetworkTypes>,
926            RpcBlock<EthApi::NetworkTypes>,
927            RpcReceipt<EthApi::NetworkTypes>,
928            RpcHeader<EthApi::NetworkTypes>,
929        > + EthApiTypes,
930    BlockExecutor: BlockExecutorProvider<Primitives = N>,
931{
932    /// Register Eth Namespace
933    ///
934    /// # Panics
935    ///
936    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
937    pub fn register_eth(&mut self) -> &mut Self {
938        let eth_api = self.eth_api().clone();
939        self.modules.insert(RethRpcModule::Eth, eth_api.into_rpc().into());
940        self
941    }
942
943    /// Register Otterscan Namespace
944    ///
945    /// # Panics
946    ///
947    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
948    pub fn register_ots(&mut self) -> &mut Self
949    where
950        EthApi: TraceExt + EthTransactions,
951    {
952        let otterscan_api = self.otterscan_api();
953        self.modules.insert(RethRpcModule::Ots, otterscan_api.into_rpc().into());
954        self
955    }
956
957    /// Register Debug Namespace
958    ///
959    /// # Panics
960    ///
961    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
962    pub fn register_debug(&mut self) -> &mut Self
963    where
964        EthApi: EthApiSpec + EthTransactions + TraceExt,
965        BlockExecutor::Primitives: NodePrimitives<Block = ProviderBlock<EthApi::Provider>>,
966    {
967        let debug_api = self.debug_api();
968        self.modules.insert(RethRpcModule::Debug, debug_api.into_rpc().into());
969        self
970    }
971
972    /// Register Trace Namespace
973    ///
974    /// # Panics
975    ///
976    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
977    pub fn register_trace(&mut self) -> &mut Self
978    where
979        EthApi: TraceExt,
980    {
981        let trace_api = self.trace_api();
982        self.modules.insert(RethRpcModule::Trace, trace_api.into_rpc().into());
983        self
984    }
985
986    /// Register Net Namespace
987    ///
988    /// See also [`Self::eth_api`]
989    ///
990    /// # Panics
991    ///
992    /// If called outside of the tokio runtime.
993    pub fn register_net(&mut self) -> &mut Self
994    where
995        EthApi: EthApiSpec + 'static,
996    {
997        let netapi = self.net_api();
998        self.modules.insert(RethRpcModule::Net, netapi.into_rpc().into());
999        self
1000    }
1001
1002    /// Register Reth namespace
1003    ///
1004    /// See also [`Self::eth_api`]
1005    ///
1006    /// # Panics
1007    ///
1008    /// If called outside of the tokio runtime.
1009    pub fn register_reth(&mut self) -> &mut Self {
1010        let rethapi = self.reth_api();
1011        self.modules.insert(RethRpcModule::Reth, rethapi.into_rpc().into());
1012        self
1013    }
1014
1015    /// Instantiates `OtterscanApi`
1016    ///
1017    /// # Panics
1018    ///
1019    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
1020    pub fn otterscan_api(&self) -> OtterscanApi<EthApi> {
1021        let eth_api = self.eth_api().clone();
1022        OtterscanApi::new(eth_api)
1023    }
1024}
1025
1026impl<N, Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
1027    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
1028where
1029    N: NodePrimitives,
1030    Provider: FullRpcProvider<
1031            Block = N::Block,
1032            Header = N::BlockHeader,
1033            Transaction = N::SignedTx,
1034            Receipt = N::Receipt,
1035        > + AccountReader
1036        + ChangeSetReader,
1037    Network: NetworkInfo + Peers + Clone + 'static,
1038    Tasks: TaskSpawner + Clone + 'static,
1039    EthApi: EthApiTypes,
1040    BlockExecutor: BlockExecutorProvider<Primitives = N>,
1041{
1042    /// Instantiates `TraceApi`
1043    ///
1044    /// # Panics
1045    ///
1046    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
1047    pub fn trace_api(&self) -> TraceApi<EthApi>
1048    where
1049        EthApi: TraceExt,
1050    {
1051        TraceApi::new(self.eth_api().clone(), self.blocking_pool_guard.clone(), self.eth_config)
1052    }
1053
1054    /// Instantiates [`EthBundle`] Api
1055    ///
1056    /// # Panics
1057    ///
1058    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
1059    pub fn bundle_api(&self) -> EthBundle<EthApi>
1060    where
1061        EthApi: EthTransactions + LoadPendingBlock + Call,
1062    {
1063        let eth_api = self.eth_api().clone();
1064        EthBundle::new(eth_api, self.blocking_pool_guard.clone())
1065    }
1066
1067    /// Instantiates `DebugApi`
1068    ///
1069    /// # Panics
1070    ///
1071    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
1072    pub fn debug_api(&self) -> DebugApi<EthApi, BlockExecutor>
1073    where
1074        EthApi: EthApiSpec + EthTransactions + TraceExt,
1075        BlockExecutor::Primitives: NodePrimitives<Block = ProviderBlock<EthApi::Provider>>,
1076    {
1077        DebugApi::new(
1078            self.eth_api().clone(),
1079            self.blocking_pool_guard.clone(),
1080            self.block_executor.clone(),
1081        )
1082    }
1083
1084    /// Instantiates `NetApi`
1085    ///
1086    /// # Panics
1087    ///
1088    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
1089    pub fn net_api(&self) -> NetApi<Network, EthApi>
1090    where
1091        EthApi: EthApiSpec + 'static,
1092    {
1093        let eth_api = self.eth_api().clone();
1094        NetApi::new(self.network.clone(), eth_api)
1095    }
1096
1097    /// Instantiates `RethApi`
1098    pub fn reth_api(&self) -> RethApi<Provider> {
1099        RethApi::new(self.provider.clone(), Box::new(self.executor.clone()))
1100    }
1101}
1102
1103impl<N, Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
1104    RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
1105where
1106    N: NodePrimitives,
1107    Provider: FullRpcProvider<Block = N::Block>
1108        + CanonStateSubscriptions<Primitives = N>
1109        + AccountReader
1110        + ChangeSetReader,
1111    Pool: TransactionPool + 'static,
1112    Network: NetworkInfo + Peers + Clone + 'static,
1113    Tasks: TaskSpawner + Clone + 'static,
1114    EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
1115    BlockExecutor: BlockExecutorProvider<Primitives = N>,
1116    Consensus: FullConsensus<N, Error = ConsensusError> + Clone + 'static,
1117{
1118    /// Configures the auth module that includes the
1119    ///   * `engine_` namespace
1120    ///   * `api_` namespace
1121    ///
1122    /// Note: This does _not_ register the `engine_` in this registry.
1123    pub fn create_auth_module(&self, engine_api: impl IntoEngineApiRpcModule) -> AuthRpcModule {
1124        let mut module = engine_api.into_rpc_module();
1125
1126        // also merge a subset of `eth_` handlers
1127        let eth_handlers = self.eth_handlers();
1128        let engine_eth = EngineEthApi::new(eth_handlers.api.clone(), eth_handlers.filter.clone());
1129
1130        module.merge(engine_eth.into_rpc()).expect("No conflicting methods");
1131
1132        AuthRpcModule { inner: module }
1133    }
1134
1135    /// Helper function to create a [`RpcModule`] if it's not `None`
1136    fn maybe_module(&mut self, config: Option<&RpcModuleSelection>) -> Option<RpcModule<()>> {
1137        config.map(|config| self.module_for(config))
1138    }
1139
1140    /// Configure a [`TransportRpcModules`] using the current registry. This
1141    /// creates [`RpcModule`] instances for the modules selected by the
1142    /// `config`.
1143    pub fn create_transport_rpc_modules(
1144        &mut self,
1145        config: TransportRpcModuleConfig,
1146    ) -> TransportRpcModules<()> {
1147        let mut modules = TransportRpcModules::default();
1148        let http = self.maybe_module(config.http.as_ref());
1149        let ws = self.maybe_module(config.ws.as_ref());
1150        let ipc = self.maybe_module(config.ipc.as_ref());
1151
1152        modules.config = config;
1153        modules.http = http;
1154        modules.ws = ws;
1155        modules.ipc = ipc;
1156        modules
1157    }
1158
1159    /// Populates a new [`RpcModule`] based on the selected [`RethRpcModule`]s in the given
1160    /// [`RpcModuleSelection`]
1161    pub fn module_for(&mut self, config: &RpcModuleSelection) -> RpcModule<()> {
1162        let mut module = RpcModule::new(());
1163        let all_methods = self.reth_methods(config.iter_selection());
1164        for methods in all_methods {
1165            module.merge(methods).expect("No conflicts");
1166        }
1167        module
1168    }
1169
1170    /// Returns the [Methods] for the given [`RethRpcModule`]
1171    ///
1172    /// If this is the first time the namespace is requested, a new instance of API implementation
1173    /// will be created.
1174    ///
1175    /// # Panics
1176    ///
1177    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
1178    pub fn reth_methods(
1179        &mut self,
1180        namespaces: impl Iterator<Item = RethRpcModule>,
1181    ) -> Vec<Methods> {
1182        let EthHandlers { api: eth_api, filter: eth_filter, pubsub: eth_pubsub, .. } =
1183            self.eth_handlers().clone();
1184
1185        // Create a copy, so we can list out all the methods for rpc_ api
1186        let namespaces: Vec<_> = namespaces.collect();
1187        namespaces
1188            .iter()
1189            .copied()
1190            .map(|namespace| {
1191                self.modules
1192                    .entry(namespace)
1193                    .or_insert_with(|| match namespace {
1194                        RethRpcModule::Admin => {
1195                            AdminApi::new(self.network.clone(), self.provider.chain_spec())
1196                                .into_rpc()
1197                                .into()
1198                        }
1199                        RethRpcModule::Debug => DebugApi::new(
1200                            eth_api.clone(),
1201                            self.blocking_pool_guard.clone(),
1202                            self.block_executor.clone(),
1203                        )
1204                        .into_rpc()
1205                        .into(),
1206                        RethRpcModule::Eth => {
1207                            // merge all eth handlers
1208                            let mut module = eth_api.clone().into_rpc();
1209                            module.merge(eth_filter.clone().into_rpc()).expect("No conflicts");
1210                            module.merge(eth_pubsub.clone().into_rpc()).expect("No conflicts");
1211                            module
1212                                .merge(
1213                                    EthBundle::new(
1214                                        eth_api.clone(),
1215                                        self.blocking_pool_guard.clone(),
1216                                    )
1217                                    .into_rpc(),
1218                                )
1219                                .expect("No conflicts");
1220
1221                            module.into()
1222                        }
1223                        RethRpcModule::Net => {
1224                            NetApi::new(self.network.clone(), eth_api.clone()).into_rpc().into()
1225                        }
1226                        RethRpcModule::Trace => TraceApi::new(
1227                            eth_api.clone(),
1228                            self.blocking_pool_guard.clone(),
1229                            self.eth_config,
1230                        )
1231                        .into_rpc()
1232                        .into(),
1233                        RethRpcModule::Web3 => Web3Api::new(self.network.clone()).into_rpc().into(),
1234                        RethRpcModule::Txpool => TxPoolApi::new(
1235                            self.eth.api.pool().clone(),
1236                            self.eth.api.tx_resp_builder().clone(),
1237                        )
1238                        .into_rpc()
1239                        .into(),
1240                        RethRpcModule::Rpc => RPCApi::new(
1241                            namespaces
1242                                .iter()
1243                                .map(|module| (module.to_string(), "1.0".to_string()))
1244                                .collect(),
1245                        )
1246                        .into_rpc()
1247                        .into(),
1248                        RethRpcModule::Ots => OtterscanApi::new(eth_api.clone()).into_rpc().into(),
1249                        RethRpcModule::Reth => {
1250                            RethApi::new(self.provider.clone(), Box::new(self.executor.clone()))
1251                                .into_rpc()
1252                                .into()
1253                        }
1254                        // only relevant for Ethereum and configured in `EthereumAddOns`
1255                        // implementation
1256                        // TODO: can we get rid of this here?
1257                        RethRpcModule::Flashbots => Default::default(),
1258                        RethRpcModule::Miner => MinerApi::default().into_rpc().into(),
1259                        RethRpcModule::Mev => {
1260                            EthSimBundle::new(eth_api.clone(), self.blocking_pool_guard.clone())
1261                                .into_rpc()
1262                                .into()
1263                        }
1264                    })
1265                    .clone()
1266            })
1267            .collect::<Vec<_>>()
1268    }
1269}
1270
1271/// A builder type for configuring and launching the servers that will handle RPC requests.
1272///
1273/// Supported server transports are:
1274///    - http
1275///    - ws
1276///    - ipc
1277///
1278/// Http and WS share the same settings: [`ServerBuilder`].
1279///
1280/// Once the [`RpcModule`] is built via [`RpcModuleBuilder`] the servers can be started, See also
1281/// [`ServerBuilder::build`] and [`Server::start`](jsonrpsee::server::Server::start).
1282#[derive(Debug)]
1283pub struct RpcServerConfig<RpcMiddleware = Identity> {
1284    /// Configs for JSON-RPC Http.
1285    http_server_config: Option<ServerBuilder<Identity, Identity>>,
1286    /// Allowed CORS Domains for http
1287    http_cors_domains: Option<String>,
1288    /// Address where to bind the http server to
1289    http_addr: Option<SocketAddr>,
1290    /// Configs for WS server
1291    ws_server_config: Option<ServerBuilder<Identity, Identity>>,
1292    /// Allowed CORS Domains for ws.
1293    ws_cors_domains: Option<String>,
1294    /// Address where to bind the ws server to
1295    ws_addr: Option<SocketAddr>,
1296    /// Configs for JSON-RPC IPC server
1297    ipc_server_config: Option<IpcServerBuilder<Identity, Identity>>,
1298    /// The Endpoint where to launch the ipc server
1299    ipc_endpoint: Option<String>,
1300    /// JWT secret for authentication
1301    jwt_secret: Option<JwtSecret>,
1302    /// Configurable RPC middleware
1303    rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
1304}
1305
1306// === impl RpcServerConfig ===
1307
1308impl Default for RpcServerConfig<Identity> {
1309    /// Create a new config instance
1310    fn default() -> Self {
1311        Self {
1312            http_server_config: None,
1313            http_cors_domains: None,
1314            http_addr: None,
1315            ws_server_config: None,
1316            ws_cors_domains: None,
1317            ws_addr: None,
1318            ipc_server_config: None,
1319            ipc_endpoint: None,
1320            jwt_secret: None,
1321            rpc_middleware: RpcServiceBuilder::new(),
1322        }
1323    }
1324}
1325
1326impl RpcServerConfig {
1327    /// Creates a new config with only http set
1328    pub fn http(config: ServerBuilder<Identity, Identity>) -> Self {
1329        Self::default().with_http(config)
1330    }
1331
1332    /// Creates a new config with only ws set
1333    pub fn ws(config: ServerBuilder<Identity, Identity>) -> Self {
1334        Self::default().with_ws(config)
1335    }
1336
1337    /// Creates a new config with only ipc set
1338    pub fn ipc(config: IpcServerBuilder<Identity, Identity>) -> Self {
1339        Self::default().with_ipc(config)
1340    }
1341
1342    /// Configures the http server
1343    ///
1344    /// Note: this always configures an [`EthSubscriptionIdProvider`] [`IdProvider`] for
1345    /// convenience. To set a custom [`IdProvider`], please use [`Self::with_id_provider`].
1346    pub fn with_http(mut self, config: ServerBuilder<Identity, Identity>) -> Self {
1347        self.http_server_config =
1348            Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1349        self
1350    }
1351
1352    /// Configures the ws server
1353    ///
1354    /// Note: this always configures an [`EthSubscriptionIdProvider`] [`IdProvider`] for
1355    /// convenience. To set a custom [`IdProvider`], please use [`Self::with_id_provider`].
1356    pub fn with_ws(mut self, config: ServerBuilder<Identity, Identity>) -> Self {
1357        self.ws_server_config = Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1358        self
1359    }
1360
1361    /// Configures the ipc server
1362    ///
1363    /// Note: this always configures an [`EthSubscriptionIdProvider`] [`IdProvider`] for
1364    /// convenience. To set a custom [`IdProvider`], please use [`Self::with_id_provider`].
1365    pub fn with_ipc(mut self, config: IpcServerBuilder<Identity, Identity>) -> Self {
1366        self.ipc_server_config = Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1367        self
1368    }
1369}
1370
1371impl<RpcMiddleware> RpcServerConfig<RpcMiddleware> {
1372    /// Configure rpc middleware
1373    pub fn set_rpc_middleware<T>(self, rpc_middleware: RpcServiceBuilder<T>) -> RpcServerConfig<T> {
1374        RpcServerConfig {
1375            http_server_config: self.http_server_config,
1376            http_cors_domains: self.http_cors_domains,
1377            http_addr: self.http_addr,
1378            ws_server_config: self.ws_server_config,
1379            ws_cors_domains: self.ws_cors_domains,
1380            ws_addr: self.ws_addr,
1381            ipc_server_config: self.ipc_server_config,
1382            ipc_endpoint: self.ipc_endpoint,
1383            jwt_secret: self.jwt_secret,
1384            rpc_middleware,
1385        }
1386    }
1387
1388    /// Configure the cors domains for http _and_ ws
1389    pub fn with_cors(self, cors_domain: Option<String>) -> Self {
1390        self.with_http_cors(cors_domain.clone()).with_ws_cors(cors_domain)
1391    }
1392
1393    /// Configure the cors domains for WS
1394    pub fn with_ws_cors(mut self, cors_domain: Option<String>) -> Self {
1395        self.ws_cors_domains = cors_domain;
1396        self
1397    }
1398
1399    /// Configure the cors domains for HTTP
1400    pub fn with_http_cors(mut self, cors_domain: Option<String>) -> Self {
1401        self.http_cors_domains = cors_domain;
1402        self
1403    }
1404
1405    /// Configures the [`SocketAddr`] of the http server
1406    ///
1407    /// Default is [`Ipv4Addr::LOCALHOST`] and
1408    /// [`reth_rpc_server_types::constants::DEFAULT_HTTP_RPC_PORT`]
1409    pub const fn with_http_address(mut self, addr: SocketAddr) -> Self {
1410        self.http_addr = Some(addr);
1411        self
1412    }
1413
1414    /// Configures the [`SocketAddr`] of the ws server
1415    ///
1416    /// Default is [`Ipv4Addr::LOCALHOST`] and
1417    /// [`reth_rpc_server_types::constants::DEFAULT_WS_RPC_PORT`]
1418    pub const fn with_ws_address(mut self, addr: SocketAddr) -> Self {
1419        self.ws_addr = Some(addr);
1420        self
1421    }
1422
1423    /// Sets a custom [`IdProvider`] for all configured transports.
1424    ///
1425    /// By default all transports use [`EthSubscriptionIdProvider`]
1426    pub fn with_id_provider<I>(mut self, id_provider: I) -> Self
1427    where
1428        I: IdProvider + Clone + 'static,
1429    {
1430        if let Some(http) = self.http_server_config {
1431            self.http_server_config = Some(http.set_id_provider(id_provider.clone()));
1432        }
1433        if let Some(ws) = self.ws_server_config {
1434            self.ws_server_config = Some(ws.set_id_provider(id_provider.clone()));
1435        }
1436        if let Some(ipc) = self.ipc_server_config {
1437            self.ipc_server_config = Some(ipc.set_id_provider(id_provider));
1438        }
1439
1440        self
1441    }
1442
1443    /// Configures the endpoint of the ipc server
1444    ///
1445    /// Default is [`reth_rpc_server_types::constants::DEFAULT_IPC_ENDPOINT`]
1446    pub fn with_ipc_endpoint(mut self, path: impl Into<String>) -> Self {
1447        self.ipc_endpoint = Some(path.into());
1448        self
1449    }
1450
1451    /// Configures the JWT secret for authentication.
1452    pub const fn with_jwt_secret(mut self, secret: Option<JwtSecret>) -> Self {
1453        self.jwt_secret = secret;
1454        self
1455    }
1456
1457    /// Returns true if any server is configured.
1458    ///
1459    /// If no server is configured, no server will be launched on [`RpcServerConfig::start`].
1460    pub const fn has_server(&self) -> bool {
1461        self.http_server_config.is_some() ||
1462            self.ws_server_config.is_some() ||
1463            self.ipc_server_config.is_some()
1464    }
1465
1466    /// Returns the [`SocketAddr`] of the http server
1467    pub const fn http_address(&self) -> Option<SocketAddr> {
1468        self.http_addr
1469    }
1470
1471    /// Returns the [`SocketAddr`] of the ws server
1472    pub const fn ws_address(&self) -> Option<SocketAddr> {
1473        self.ws_addr
1474    }
1475
1476    /// Returns the endpoint of the ipc server
1477    pub fn ipc_endpoint(&self) -> Option<String> {
1478        self.ipc_endpoint.clone()
1479    }
1480
1481    /// Creates the [`CorsLayer`] if any
1482    fn maybe_cors_layer(cors: Option<String>) -> Result<Option<CorsLayer>, CorsDomainError> {
1483        cors.as_deref().map(cors::create_cors_layer).transpose()
1484    }
1485
1486    /// Creates the [`AuthLayer`] if any
1487    fn maybe_jwt_layer(jwt_secret: Option<JwtSecret>) -> Option<AuthLayer<JwtAuthValidator>> {
1488        jwt_secret.map(|secret| AuthLayer::new(JwtAuthValidator::new(secret)))
1489    }
1490
1491    /// Returns a [`CompressionLayer`] that adds compression support (gzip, deflate, brotli, zstd)
1492    /// based on the client's `Accept-Encoding` header
1493    fn maybe_compression_layer() -> Option<CompressionLayer> {
1494        Some(CompressionLayer::new())
1495    }
1496
1497    /// Builds and starts the configured server(s): http, ws, ipc.
1498    ///
1499    /// If both http and ws are on the same port, they are combined into one server.
1500    ///
1501    /// Returns the [`RpcServerHandle`] with the handle to the started servers.
1502    pub async fn start(self, modules: &TransportRpcModules) -> Result<RpcServerHandle, RpcError>
1503    where
1504        RpcMiddleware: Layer<RpcRequestMetricsService<RpcService>> + Clone + Send + 'static,
1505        for<'a> <RpcMiddleware as Layer<RpcRequestMetricsService<RpcService>>>::Service:
1506            Send + Sync + 'static + RpcServiceT<'a>,
1507    {
1508        let mut http_handle = None;
1509        let mut ws_handle = None;
1510        let mut ipc_handle = None;
1511
1512        let http_socket_addr = self.http_addr.unwrap_or(SocketAddr::V4(SocketAddrV4::new(
1513            Ipv4Addr::LOCALHOST,
1514            constants::DEFAULT_HTTP_RPC_PORT,
1515        )));
1516
1517        let ws_socket_addr = self.ws_addr.unwrap_or(SocketAddr::V4(SocketAddrV4::new(
1518            Ipv4Addr::LOCALHOST,
1519            constants::DEFAULT_WS_RPC_PORT,
1520        )));
1521
1522        let metrics = modules.ipc.as_ref().map(RpcRequestMetrics::ipc).unwrap_or_default();
1523        let ipc_path =
1524            self.ipc_endpoint.clone().unwrap_or_else(|| constants::DEFAULT_IPC_ENDPOINT.into());
1525
1526        if let Some(builder) = self.ipc_server_config {
1527            let ipc = builder
1528                .set_rpc_middleware(IpcRpcServiceBuilder::new().layer(metrics))
1529                .build(ipc_path);
1530            ipc_handle = Some(ipc.start(modules.ipc.clone().expect("ipc server error")).await?);
1531        }
1532
1533        // If both are configured on the same port, we combine them into one server.
1534        if self.http_addr == self.ws_addr &&
1535            self.http_server_config.is_some() &&
1536            self.ws_server_config.is_some()
1537        {
1538            let cors = match (self.ws_cors_domains.as_ref(), self.http_cors_domains.as_ref()) {
1539                (Some(ws_cors), Some(http_cors)) => {
1540                    if ws_cors.trim() != http_cors.trim() {
1541                        return Err(WsHttpSamePortError::ConflictingCorsDomains {
1542                            http_cors_domains: Some(http_cors.clone()),
1543                            ws_cors_domains: Some(ws_cors.clone()),
1544                        }
1545                        .into());
1546                    }
1547                    Some(ws_cors)
1548                }
1549                (a, b) => a.or(b),
1550            }
1551            .cloned();
1552
1553            // we merge this into one server using the http setup
1554            modules.config.ensure_ws_http_identical()?;
1555
1556            if let Some(builder) = self.http_server_config {
1557                let server = builder
1558                    .set_http_middleware(
1559                        tower::ServiceBuilder::new()
1560                            .option_layer(Self::maybe_cors_layer(cors)?)
1561                            .option_layer(Self::maybe_jwt_layer(self.jwt_secret))
1562                            .option_layer(Self::maybe_compression_layer()),
1563                    )
1564                    .set_rpc_middleware(
1565                        self.rpc_middleware.clone().layer(
1566                            modules
1567                                .http
1568                                .as_ref()
1569                                .or(modules.ws.as_ref())
1570                                .map(RpcRequestMetrics::same_port)
1571                                .unwrap_or_default(),
1572                        ),
1573                    )
1574                    .build(http_socket_addr)
1575                    .await
1576                    .map_err(|err| {
1577                        RpcError::server_error(err, ServerKind::WsHttp(http_socket_addr))
1578                    })?;
1579                let addr = server.local_addr().map_err(|err| {
1580                    RpcError::server_error(err, ServerKind::WsHttp(http_socket_addr))
1581                })?;
1582                if let Some(module) = modules.http.as_ref().or(modules.ws.as_ref()) {
1583                    let handle = server.start(module.clone());
1584                    http_handle = Some(handle.clone());
1585                    ws_handle = Some(handle);
1586                }
1587                return Ok(RpcServerHandle {
1588                    http_local_addr: Some(addr),
1589                    ws_local_addr: Some(addr),
1590                    http: http_handle,
1591                    ws: ws_handle,
1592                    ipc_endpoint: self.ipc_endpoint.clone(),
1593                    ipc: ipc_handle,
1594                    jwt_secret: self.jwt_secret,
1595                });
1596            }
1597        }
1598
1599        let mut ws_local_addr = None;
1600        let mut ws_server = None;
1601        let mut http_local_addr = None;
1602        let mut http_server = None;
1603
1604        if let Some(builder) = self.ws_server_config {
1605            let server = builder
1606                .ws_only()
1607                .set_http_middleware(
1608                    tower::ServiceBuilder::new()
1609                        .option_layer(Self::maybe_cors_layer(self.ws_cors_domains.clone())?)
1610                        .option_layer(Self::maybe_jwt_layer(self.jwt_secret)),
1611                )
1612                .set_rpc_middleware(
1613                    self.rpc_middleware
1614                        .clone()
1615                        .layer(modules.ws.as_ref().map(RpcRequestMetrics::ws).unwrap_or_default()),
1616                )
1617                .build(ws_socket_addr)
1618                .await
1619                .map_err(|err| RpcError::server_error(err, ServerKind::WS(ws_socket_addr)))?;
1620
1621            let addr = server
1622                .local_addr()
1623                .map_err(|err| RpcError::server_error(err, ServerKind::WS(ws_socket_addr)))?;
1624
1625            ws_local_addr = Some(addr);
1626            ws_server = Some(server);
1627        }
1628
1629        if let Some(builder) = self.http_server_config {
1630            let server = builder
1631                .http_only()
1632                .set_http_middleware(
1633                    tower::ServiceBuilder::new()
1634                        .option_layer(Self::maybe_cors_layer(self.http_cors_domains.clone())?)
1635                        .option_layer(Self::maybe_jwt_layer(self.jwt_secret))
1636                        .option_layer(Self::maybe_compression_layer()),
1637                )
1638                .set_rpc_middleware(
1639                    self.rpc_middleware.clone().layer(
1640                        modules.http.as_ref().map(RpcRequestMetrics::http).unwrap_or_default(),
1641                    ),
1642                )
1643                .build(http_socket_addr)
1644                .await
1645                .map_err(|err| RpcError::server_error(err, ServerKind::Http(http_socket_addr)))?;
1646            let local_addr = server
1647                .local_addr()
1648                .map_err(|err| RpcError::server_error(err, ServerKind::Http(http_socket_addr)))?;
1649            http_local_addr = Some(local_addr);
1650            http_server = Some(server);
1651        }
1652
1653        http_handle = http_server
1654            .map(|http_server| http_server.start(modules.http.clone().expect("http server error")));
1655        ws_handle = ws_server
1656            .map(|ws_server| ws_server.start(modules.ws.clone().expect("ws server error")));
1657        Ok(RpcServerHandle {
1658            http_local_addr,
1659            ws_local_addr,
1660            http: http_handle,
1661            ws: ws_handle,
1662            ipc_endpoint: self.ipc_endpoint.clone(),
1663            ipc: ipc_handle,
1664            jwt_secret: self.jwt_secret,
1665        })
1666    }
1667}
1668
1669/// Holds modules to be installed per transport type
1670///
1671/// # Example
1672///
1673/// Configure a http transport only
1674///
1675/// ```
1676/// use reth_rpc_builder::{RethRpcModule, TransportRpcModuleConfig};
1677/// let config =
1678///     TransportRpcModuleConfig::default().with_http([RethRpcModule::Eth, RethRpcModule::Admin]);
1679/// ```
1680#[derive(Debug, Clone, Default, Eq, PartialEq)]
1681pub struct TransportRpcModuleConfig {
1682    /// http module configuration
1683    http: Option<RpcModuleSelection>,
1684    /// ws module configuration
1685    ws: Option<RpcModuleSelection>,
1686    /// ipc module configuration
1687    ipc: Option<RpcModuleSelection>,
1688    /// Config for the modules
1689    config: Option<RpcModuleConfig>,
1690}
1691
1692// === impl TransportRpcModuleConfig ===
1693
1694impl TransportRpcModuleConfig {
1695    /// Creates a new config with only http set
1696    pub fn set_http(http: impl Into<RpcModuleSelection>) -> Self {
1697        Self::default().with_http(http)
1698    }
1699
1700    /// Creates a new config with only ws set
1701    pub fn set_ws(ws: impl Into<RpcModuleSelection>) -> Self {
1702        Self::default().with_ws(ws)
1703    }
1704
1705    /// Creates a new config with only ipc set
1706    pub fn set_ipc(ipc: impl Into<RpcModuleSelection>) -> Self {
1707        Self::default().with_ipc(ipc)
1708    }
1709
1710    /// Sets the [`RpcModuleSelection`] for the http transport.
1711    pub fn with_http(mut self, http: impl Into<RpcModuleSelection>) -> Self {
1712        self.http = Some(http.into());
1713        self
1714    }
1715
1716    /// Sets the [`RpcModuleSelection`] for the ws transport.
1717    pub fn with_ws(mut self, ws: impl Into<RpcModuleSelection>) -> Self {
1718        self.ws = Some(ws.into());
1719        self
1720    }
1721
1722    /// Sets the [`RpcModuleSelection`] for the http transport.
1723    pub fn with_ipc(mut self, ipc: impl Into<RpcModuleSelection>) -> Self {
1724        self.ipc = Some(ipc.into());
1725        self
1726    }
1727
1728    /// Sets a custom [`RpcModuleConfig`] for the configured modules.
1729    pub fn with_config(mut self, config: RpcModuleConfig) -> Self {
1730        self.config = Some(config);
1731        self
1732    }
1733
1734    /// Get a mutable reference to the
1735    pub const fn http_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1736        &mut self.http
1737    }
1738
1739    /// Get a mutable reference to the
1740    pub const fn ws_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1741        &mut self.ws
1742    }
1743
1744    /// Get a mutable reference to the
1745    pub const fn ipc_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1746        &mut self.ipc
1747    }
1748
1749    /// Get a mutable reference to the
1750    pub const fn config_mut(&mut self) -> &mut Option<RpcModuleConfig> {
1751        &mut self.config
1752    }
1753
1754    /// Returns true if no transports are configured
1755    pub const fn is_empty(&self) -> bool {
1756        self.http.is_none() && self.ws.is_none() && self.ipc.is_none()
1757    }
1758
1759    /// Returns the [`RpcModuleSelection`] for the http transport
1760    pub const fn http(&self) -> Option<&RpcModuleSelection> {
1761        self.http.as_ref()
1762    }
1763
1764    /// Returns the [`RpcModuleSelection`] for the ws transport
1765    pub const fn ws(&self) -> Option<&RpcModuleSelection> {
1766        self.ws.as_ref()
1767    }
1768
1769    /// Returns the [`RpcModuleSelection`] for the ipc transport
1770    pub const fn ipc(&self) -> Option<&RpcModuleSelection> {
1771        self.ipc.as_ref()
1772    }
1773
1774    /// Returns the [`RpcModuleConfig`] for the configured modules
1775    pub const fn config(&self) -> Option<&RpcModuleConfig> {
1776        self.config.as_ref()
1777    }
1778
1779    /// Returns true if the given module is configured for any transport.
1780    pub fn contains_any(&self, module: &RethRpcModule) -> bool {
1781        self.contains_http(module) || self.contains_ws(module) || self.contains_ipc(module)
1782    }
1783
1784    /// Returns true if the given module is configured for the http transport.
1785    pub fn contains_http(&self, module: &RethRpcModule) -> bool {
1786        self.http.as_ref().is_some_and(|http| http.contains(module))
1787    }
1788
1789    /// Returns true if the given module is configured for the ws transport.
1790    pub fn contains_ws(&self, module: &RethRpcModule) -> bool {
1791        self.ws.as_ref().is_some_and(|ws| ws.contains(module))
1792    }
1793
1794    /// Returns true if the given module is configured for the ipc transport.
1795    pub fn contains_ipc(&self, module: &RethRpcModule) -> bool {
1796        self.ipc.as_ref().is_some_and(|ipc| ipc.contains(module))
1797    }
1798
1799    /// Ensures that both http and ws are configured and that they are configured to use the same
1800    /// port.
1801    fn ensure_ws_http_identical(&self) -> Result<(), WsHttpSamePortError> {
1802        if RpcModuleSelection::are_identical(self.http.as_ref(), self.ws.as_ref()) {
1803            Ok(())
1804        } else {
1805            let http_modules =
1806                self.http.as_ref().map(RpcModuleSelection::to_selection).unwrap_or_default();
1807            let ws_modules =
1808                self.ws.as_ref().map(RpcModuleSelection::to_selection).unwrap_or_default();
1809
1810            let http_not_ws = http_modules.difference(&ws_modules).copied().collect();
1811            let ws_not_http = ws_modules.difference(&http_modules).copied().collect();
1812            let overlap = http_modules.intersection(&ws_modules).copied().collect();
1813
1814            Err(WsHttpSamePortError::ConflictingModules(Box::new(ConflictingModules {
1815                overlap,
1816                http_not_ws,
1817                ws_not_http,
1818            })))
1819        }
1820    }
1821}
1822
1823/// Holds installed modules per transport type.
1824#[derive(Debug, Clone, Default)]
1825pub struct TransportRpcModules<Context = ()> {
1826    /// The original config
1827    config: TransportRpcModuleConfig,
1828    /// rpcs module for http
1829    http: Option<RpcModule<Context>>,
1830    /// rpcs module for ws
1831    ws: Option<RpcModule<Context>>,
1832    /// rpcs module for ipc
1833    ipc: Option<RpcModule<Context>>,
1834}
1835
1836// === impl TransportRpcModules ===
1837
1838impl TransportRpcModules {
1839    /// Sets a custom [`TransportRpcModuleConfig`] for the configured modules.
1840    /// This will overwrite current configuration, if any.
1841    pub fn with_config(mut self, config: TransportRpcModuleConfig) -> Self {
1842        self.config = config;
1843        self
1844    }
1845
1846    /// Sets the [`RpcModule`] for the http transport.
1847    /// This will overwrite current module, if any.
1848    pub fn with_http(mut self, http: RpcModule<()>) -> Self {
1849        self.http = Some(http);
1850        self
1851    }
1852
1853    /// Sets the [`RpcModule`] for the ws transport.
1854    /// This will overwrite current module, if any.
1855    pub fn with_ws(mut self, ws: RpcModule<()>) -> Self {
1856        self.ws = Some(ws);
1857        self
1858    }
1859
1860    /// Sets the [`RpcModule`] for the http transport.
1861    /// This will overwrite current module, if any.
1862    pub fn with_ipc(mut self, ipc: RpcModule<()>) -> Self {
1863        self.ipc = Some(ipc);
1864        self
1865    }
1866
1867    /// Returns the [`TransportRpcModuleConfig`] used to configure this instance.
1868    pub const fn module_config(&self) -> &TransportRpcModuleConfig {
1869        &self.config
1870    }
1871
1872    /// Merge the given [`Methods`] in all configured transport modules if the given
1873    /// [`RethRpcModule`] is configured for the transport.
1874    ///
1875    /// Fails if any of the methods in other is present already.
1876    pub fn merge_if_module_configured(
1877        &mut self,
1878        module: RethRpcModule,
1879        other: impl Into<Methods>,
1880    ) -> Result<(), RegisterMethodError> {
1881        let other = other.into();
1882        if self.module_config().contains_http(&module) {
1883            self.merge_http(other.clone())?;
1884        }
1885        if self.module_config().contains_ws(&module) {
1886            self.merge_ws(other.clone())?;
1887        }
1888        if self.module_config().contains_ipc(&module) {
1889            self.merge_ipc(other)?;
1890        }
1891
1892        Ok(())
1893    }
1894
1895    /// Merge the given [Methods] in the configured http methods.
1896    ///
1897    /// Fails if any of the methods in other is present already.
1898    ///
1899    /// Returns [Ok(false)] if no http transport is configured.
1900    pub fn merge_http(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1901        if let Some(ref mut http) = self.http {
1902            return http.merge(other.into()).map(|_| true)
1903        }
1904        Ok(false)
1905    }
1906
1907    /// Merge the given [Methods] in the configured ws methods.
1908    ///
1909    /// Fails if any of the methods in other is present already.
1910    ///
1911    /// Returns [Ok(false)] if no ws transport is configured.
1912    pub fn merge_ws(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1913        if let Some(ref mut ws) = self.ws {
1914            return ws.merge(other.into()).map(|_| true)
1915        }
1916        Ok(false)
1917    }
1918
1919    /// Merge the given [Methods] in the configured ipc methods.
1920    ///
1921    /// Fails if any of the methods in other is present already.
1922    ///
1923    /// Returns [Ok(false)] if no ipc transport is configured.
1924    pub fn merge_ipc(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1925        if let Some(ref mut ipc) = self.ipc {
1926            return ipc.merge(other.into()).map(|_| true)
1927        }
1928        Ok(false)
1929    }
1930
1931    /// Merge the given [`Methods`] in all configured methods.
1932    ///
1933    /// Fails if any of the methods in other is present already.
1934    pub fn merge_configured(
1935        &mut self,
1936        other: impl Into<Methods>,
1937    ) -> Result<(), RegisterMethodError> {
1938        let other = other.into();
1939        self.merge_http(other.clone())?;
1940        self.merge_ws(other.clone())?;
1941        self.merge_ipc(other)?;
1942        Ok(())
1943    }
1944
1945    /// Returns all unique endpoints installed for the given module.
1946    ///
1947    /// Note: In case of duplicate method names this only record the first occurrence.
1948    pub fn methods_by_module<F>(&self, module: RethRpcModule) -> Methods {
1949        self.methods_by(|name| name.starts_with(module.as_str()))
1950    }
1951
1952    /// Returns all unique endpoints installed in any of the configured modules.
1953    ///
1954    /// Note: In case of duplicate method names this only record the first occurrence.
1955    pub fn methods_by<F>(&self, mut filter: F) -> Methods
1956    where
1957        F: FnMut(&str) -> bool,
1958    {
1959        let mut methods = Methods::new();
1960
1961        // filter that matches the given filter and also removes duplicates we already have
1962        let mut f =
1963            |name: &str, mm: &Methods| filter(name) && !mm.method_names().any(|m| m == name);
1964
1965        if let Some(m) = self.http_methods(|name| f(name, &methods)) {
1966            let _ = methods.merge(m);
1967        }
1968        if let Some(m) = self.ws_methods(|name| f(name, &methods)) {
1969            let _ = methods.merge(m);
1970        }
1971        if let Some(m) = self.ipc_methods(|name| f(name, &methods)) {
1972            let _ = methods.merge(m);
1973        }
1974        methods
1975    }
1976
1977    /// Returns all [`Methods`] installed for the http server based in the given closure.
1978    ///
1979    /// Returns `None` if no http support is configured.
1980    pub fn http_methods<F>(&self, filter: F) -> Option<Methods>
1981    where
1982        F: FnMut(&str) -> bool,
1983    {
1984        self.http.as_ref().map(|module| methods_by(module, filter))
1985    }
1986
1987    /// Returns all [`Methods`] installed for the ws server based in the given closure.
1988    ///
1989    /// Returns `None` if no ws support is configured.
1990    pub fn ws_methods<F>(&self, filter: F) -> Option<Methods>
1991    where
1992        F: FnMut(&str) -> bool,
1993    {
1994        self.ws.as_ref().map(|module| methods_by(module, filter))
1995    }
1996
1997    /// Returns all [`Methods`] installed for the ipc server based in the given closure.
1998    ///
1999    /// Returns `None` if no ipc support is configured.
2000    pub fn ipc_methods<F>(&self, filter: F) -> Option<Methods>
2001    where
2002        F: FnMut(&str) -> bool,
2003    {
2004        self.ipc.as_ref().map(|module| methods_by(module, filter))
2005    }
2006
2007    /// Removes the method with the given name from the configured http methods.
2008    ///
2009    /// Returns `true` if the method was found and removed, `false` otherwise.
2010    ///
2011    /// Be aware that a subscription consist of two methods, `subscribe` and `unsubscribe` and
2012    /// it's the caller responsibility to remove both `subscribe` and `unsubscribe` methods for
2013    /// subscriptions.
2014    pub fn remove_http_method(&mut self, method_name: &'static str) -> bool {
2015        if let Some(http_module) = &mut self.http {
2016            http_module.remove_method(method_name).is_some()
2017        } else {
2018            false
2019        }
2020    }
2021
2022    /// Removes the given methods from the configured http methods.
2023    pub fn remove_http_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
2024        for name in methods {
2025            self.remove_http_method(name);
2026        }
2027    }
2028
2029    /// Removes the method with the given name from the configured ws methods.
2030    ///
2031    /// Returns `true` if the method was found and removed, `false` otherwise.
2032    ///
2033    /// Be aware that a subscription consist of two methods, `subscribe` and `unsubscribe` and
2034    /// it's the caller responsibility to remove both `subscribe` and `unsubscribe` methods for
2035    /// subscriptions.
2036    pub fn remove_ws_method(&mut self, method_name: &'static str) -> bool {
2037        if let Some(ws_module) = &mut self.ws {
2038            ws_module.remove_method(method_name).is_some()
2039        } else {
2040            false
2041        }
2042    }
2043
2044    /// Removes the given methods from the configured ws methods.
2045    pub fn remove_ws_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
2046        for name in methods {
2047            self.remove_ws_method(name);
2048        }
2049    }
2050
2051    /// Removes the method with the given name from the configured ipc methods.
2052    ///
2053    /// Returns `true` if the method was found and removed, `false` otherwise.
2054    ///
2055    /// Be aware that a subscription consist of two methods, `subscribe` and `unsubscribe` and
2056    /// it's the caller responsibility to remove both `subscribe` and `unsubscribe` methods for
2057    /// subscriptions.
2058    pub fn remove_ipc_method(&mut self, method_name: &'static str) -> bool {
2059        if let Some(ipc_module) = &mut self.ipc {
2060            ipc_module.remove_method(method_name).is_some()
2061        } else {
2062            false
2063        }
2064    }
2065
2066    /// Removes the given methods from the configured ipc methods.
2067    pub fn remove_ipc_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
2068        for name in methods {
2069            self.remove_ipc_method(name);
2070        }
2071    }
2072
2073    /// Removes the method with the given name from all configured transports.
2074    ///
2075    /// Returns `true` if the method was found and removed, `false` otherwise.
2076    pub fn remove_method_from_configured(&mut self, method_name: &'static str) -> bool {
2077        let http_removed = self.remove_http_method(method_name);
2078        let ws_removed = self.remove_ws_method(method_name);
2079        let ipc_removed = self.remove_ipc_method(method_name);
2080
2081        http_removed || ws_removed || ipc_removed
2082    }
2083
2084    /// Renames a method in all configured transports by:
2085    /// 1. Removing the old method name.
2086    /// 2. Adding the new method.
2087    pub fn rename(
2088        &mut self,
2089        old_name: &'static str,
2090        new_method: impl Into<Methods>,
2091    ) -> Result<(), RegisterMethodError> {
2092        // Remove the old method from all configured transports
2093        self.remove_method_from_configured(old_name);
2094
2095        // Merge the new method into the configured transports
2096        self.merge_configured(new_method)
2097    }
2098
2099    /// Replace the given [`Methods`] in the configured http methods.
2100    ///
2101    /// Fails if any of the methods in other is present already or if the method being removed is
2102    /// not present
2103    ///
2104    /// Returns [Ok(false)] if no http transport is configured.
2105    pub fn replace_http(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
2106        let other = other.into();
2107        self.remove_http_methods(other.method_names());
2108        self.merge_http(other)
2109    }
2110
2111    /// Replace the given [Methods] in the configured ipc methods.
2112    ///
2113    /// Fails if any of the methods in other is present already or if the method being removed is
2114    /// not present
2115    ///
2116    /// Returns [Ok(false)] if no ipc transport is configured.
2117    pub fn replace_ipc(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
2118        let other = other.into();
2119        self.remove_ipc_methods(other.method_names());
2120        self.merge_ipc(other)
2121    }
2122
2123    /// Replace the given [Methods] in the configured ws methods.
2124    ///
2125    /// Fails if any of the methods in other is present already or if the method being removed is
2126    /// not present
2127    ///
2128    /// Returns [Ok(false)] if no ws transport is configured.
2129    pub fn replace_ws(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
2130        let other = other.into();
2131        self.remove_ws_methods(other.method_names());
2132        self.merge_ws(other)
2133    }
2134
2135    /// Replaces the method with the given name from all configured transports.
2136    ///
2137    /// Returns `true` if the method was found and replaced, `false` otherwise
2138    pub fn replace_configured(
2139        &mut self,
2140        other: impl Into<Methods>,
2141    ) -> Result<bool, RegisterMethodError> {
2142        let other = other.into();
2143        self.replace_http(other.clone())?;
2144        self.replace_ws(other.clone())?;
2145        self.replace_ipc(other)?;
2146        Ok(true)
2147    }
2148}
2149
2150/// Returns the methods installed in the given module that match the given filter.
2151fn methods_by<T, F>(module: &RpcModule<T>, mut filter: F) -> Methods
2152where
2153    F: FnMut(&str) -> bool,
2154{
2155    let mut methods = Methods::new();
2156    let method_names = module.method_names().filter(|name| filter(name));
2157
2158    for name in method_names {
2159        if let Some(matched_method) = module.method(name).cloned() {
2160            let _ = methods.verify_and_insert(name, matched_method);
2161        }
2162    }
2163
2164    methods
2165}
2166
2167/// A handle to the spawned servers.
2168///
2169/// When this type is dropped or [`RpcServerHandle::stop`] has been called the server will be
2170/// stopped.
2171#[derive(Clone, Debug)]
2172#[must_use = "Server stops if dropped"]
2173pub struct RpcServerHandle {
2174    /// The address of the http/ws server
2175    http_local_addr: Option<SocketAddr>,
2176    ws_local_addr: Option<SocketAddr>,
2177    http: Option<ServerHandle>,
2178    ws: Option<ServerHandle>,
2179    ipc_endpoint: Option<String>,
2180    ipc: Option<jsonrpsee::server::ServerHandle>,
2181    jwt_secret: Option<JwtSecret>,
2182}
2183
2184// === impl RpcServerHandle ===
2185
2186impl RpcServerHandle {
2187    /// Configures the JWT secret for authentication.
2188    fn bearer_token(&self) -> Option<String> {
2189        self.jwt_secret.as_ref().map(|secret| {
2190            format!(
2191                "Bearer {}",
2192                secret
2193                    .encode(&Claims {
2194                        iat: (SystemTime::now().duration_since(UNIX_EPOCH).unwrap() +
2195                            Duration::from_secs(60))
2196                        .as_secs(),
2197                        exp: None,
2198                    })
2199                    .unwrap()
2200            )
2201        })
2202    }
2203    /// Returns the [`SocketAddr`] of the http server if started.
2204    pub const fn http_local_addr(&self) -> Option<SocketAddr> {
2205        self.http_local_addr
2206    }
2207
2208    /// Returns the [`SocketAddr`] of the ws server if started.
2209    pub const fn ws_local_addr(&self) -> Option<SocketAddr> {
2210        self.ws_local_addr
2211    }
2212
2213    /// Tell the server to stop without waiting for the server to stop.
2214    pub fn stop(self) -> Result<(), AlreadyStoppedError> {
2215        if let Some(handle) = self.http {
2216            handle.stop()?
2217        }
2218
2219        if let Some(handle) = self.ws {
2220            handle.stop()?
2221        }
2222
2223        if let Some(handle) = self.ipc {
2224            handle.stop()?
2225        }
2226
2227        Ok(())
2228    }
2229
2230    /// Returns the endpoint of the launched IPC server, if any
2231    pub fn ipc_endpoint(&self) -> Option<String> {
2232        self.ipc_endpoint.clone()
2233    }
2234
2235    /// Returns the url to the http server
2236    pub fn http_url(&self) -> Option<String> {
2237        self.http_local_addr.map(|addr| format!("http://{addr}"))
2238    }
2239
2240    /// Returns the url to the ws server
2241    pub fn ws_url(&self) -> Option<String> {
2242        self.ws_local_addr.map(|addr| format!("ws://{addr}"))
2243    }
2244
2245    /// Returns a http client connected to the server.
2246    pub fn http_client(&self) -> Option<jsonrpsee::http_client::HttpClient> {
2247        let url = self.http_url()?;
2248
2249        let client = if let Some(token) = self.bearer_token() {
2250            jsonrpsee::http_client::HttpClientBuilder::default()
2251                .set_headers(HeaderMap::from_iter([(AUTHORIZATION, token.parse().unwrap())]))
2252                .build(url)
2253        } else {
2254            jsonrpsee::http_client::HttpClientBuilder::default().build(url)
2255        };
2256
2257        client.expect("failed to create http client").into()
2258    }
2259
2260    /// Returns a ws client connected to the server.
2261    pub async fn ws_client(&self) -> Option<jsonrpsee::ws_client::WsClient> {
2262        let url = self.ws_url()?;
2263        let mut builder = jsonrpsee::ws_client::WsClientBuilder::default();
2264
2265        if let Some(token) = self.bearer_token() {
2266            let headers = HeaderMap::from_iter([(AUTHORIZATION, token.parse().unwrap())]);
2267            builder = builder.set_headers(headers);
2268        }
2269
2270        let client = builder.build(url).await.expect("failed to create ws client");
2271        Some(client)
2272    }
2273
2274    /// Returns a new [`alloy_network::Ethereum`] http provider with its recommended fillers.
2275    pub fn eth_http_provider(
2276        &self,
2277    ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2278        self.new_http_provider_for()
2279    }
2280
2281    /// Returns an http provider from the rpc server handle for the
2282    /// specified [`alloy_network::Network`].
2283    ///
2284    /// This installs the recommended fillers: [`RecommendedFillers`]
2285    pub fn new_http_provider_for<N>(&self) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2286    where
2287        N: RecommendedFillers<RecommendedFillers: Unpin>,
2288    {
2289        let rpc_url = self.http_url()?;
2290        let provider = ProviderBuilder::default()
2291            .with_recommended_fillers()
2292            .on_http(rpc_url.parse().expect("valid url"));
2293        Some(provider)
2294    }
2295
2296    /// Returns a new [`alloy_network::Ethereum`] websocket provider with its recommended fillers.
2297    pub async fn eth_ws_provider(
2298        &self,
2299    ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2300        self.new_ws_provider_for().await
2301    }
2302
2303    /// Returns an ws provider from the rpc server handle for the
2304    /// specified [`alloy_network::Network`].
2305    ///
2306    /// This installs the recommended fillers: [`RecommendedFillers`]
2307    pub async fn new_ws_provider_for<N>(&self) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2308    where
2309        N: RecommendedFillers<RecommendedFillers: Unpin>,
2310    {
2311        let rpc_url = self.ws_url()?;
2312        let provider = ProviderBuilder::default()
2313            .with_recommended_fillers()
2314            .connect(&rpc_url)
2315            .await
2316            .expect("failed to create ws client");
2317        Some(provider)
2318    }
2319
2320    /// Returns a new [`alloy_network::Ethereum`] ipc provider with its recommended fillers.
2321    pub async fn eth_ipc_provider(
2322        &self,
2323    ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2324        self.new_ws_provider_for().await
2325    }
2326
2327    /// Returns an ipc provider from the rpc server handle for the
2328    /// specified [`alloy_network::Network`].
2329    ///
2330    /// This installs the recommended fillers: [`RecommendedFillers`]
2331    pub async fn new_ipc_provider_for<N>(
2332        &self,
2333    ) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2334    where
2335        N: RecommendedFillers<RecommendedFillers: Unpin>,
2336    {
2337        let rpc_url = self.ipc_endpoint()?;
2338        let provider = ProviderBuilder::default()
2339            .with_recommended_fillers()
2340            .connect(&rpc_url)
2341            .await
2342            .expect("failed to create ipc client");
2343        Some(provider)
2344    }
2345}
2346
2347#[cfg(test)]
2348mod tests {
2349    use super::*;
2350
2351    #[test]
2352    fn parse_eth_call_bundle_selection() {
2353        let selection = "eth,admin,debug".parse::<RpcModuleSelection>().unwrap();
2354        assert_eq!(
2355            selection,
2356            RpcModuleSelection::Selection(
2357                [RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Debug,].into()
2358            )
2359        );
2360    }
2361
2362    #[test]
2363    fn parse_rpc_module_selection() {
2364        let selection = "all".parse::<RpcModuleSelection>().unwrap();
2365        assert_eq!(selection, RpcModuleSelection::All);
2366    }
2367
2368    #[test]
2369    fn parse_rpc_module_selection_none() {
2370        let selection = "none".parse::<RpcModuleSelection>().unwrap();
2371        assert_eq!(selection, RpcModuleSelection::Selection(Default::default()));
2372    }
2373
2374    #[test]
2375    fn parse_rpc_unique_module_selection() {
2376        let selection = "eth,admin,eth,net".parse::<RpcModuleSelection>().unwrap();
2377        assert_eq!(
2378            selection,
2379            RpcModuleSelection::Selection(
2380                [RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Net,].into()
2381            )
2382        );
2383    }
2384
2385    #[test]
2386    fn identical_selection() {
2387        assert!(RpcModuleSelection::are_identical(
2388            Some(&RpcModuleSelection::All),
2389            Some(&RpcModuleSelection::All),
2390        ));
2391        assert!(!RpcModuleSelection::are_identical(
2392            Some(&RpcModuleSelection::All),
2393            Some(&RpcModuleSelection::Standard),
2394        ));
2395        assert!(RpcModuleSelection::are_identical(
2396            Some(&RpcModuleSelection::Selection(RpcModuleSelection::Standard.to_selection())),
2397            Some(&RpcModuleSelection::Standard),
2398        ));
2399        assert!(RpcModuleSelection::are_identical(
2400            Some(&RpcModuleSelection::Selection([RethRpcModule::Eth].into())),
2401            Some(&RpcModuleSelection::Selection([RethRpcModule::Eth].into())),
2402        ));
2403        assert!(RpcModuleSelection::are_identical(
2404            None,
2405            Some(&RpcModuleSelection::Selection(Default::default())),
2406        ));
2407        assert!(RpcModuleSelection::are_identical(
2408            Some(&RpcModuleSelection::Selection(Default::default())),
2409            None,
2410        ));
2411        assert!(RpcModuleSelection::are_identical(None, None));
2412    }
2413
2414    #[test]
2415    fn test_rpc_module_str() {
2416        macro_rules! assert_rpc_module {
2417            ($($s:expr => $v:expr,)*) => {
2418                $(
2419                    let val: RethRpcModule  = $s.parse().unwrap();
2420                    assert_eq!(val, $v);
2421                    assert_eq!(val.to_string().as_str(), $s);
2422                )*
2423            };
2424        }
2425        assert_rpc_module!
2426        (
2427                "admin" =>  RethRpcModule::Admin,
2428                "debug" =>  RethRpcModule::Debug,
2429                "eth" =>  RethRpcModule::Eth,
2430                "net" =>  RethRpcModule::Net,
2431                "trace" =>  RethRpcModule::Trace,
2432                "web3" =>  RethRpcModule::Web3,
2433                "rpc" => RethRpcModule::Rpc,
2434                "ots" => RethRpcModule::Ots,
2435                "reth" => RethRpcModule::Reth,
2436            );
2437    }
2438
2439    #[test]
2440    fn test_default_selection() {
2441        let selection = RpcModuleSelection::Standard.to_selection();
2442        assert_eq!(selection, [RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3].into())
2443    }
2444
2445    #[test]
2446    fn test_create_rpc_module_config() {
2447        let selection = vec!["eth", "admin"];
2448        let config = RpcModuleSelection::try_from_selection(selection).unwrap();
2449        assert_eq!(
2450            config,
2451            RpcModuleSelection::Selection([RethRpcModule::Eth, RethRpcModule::Admin].into())
2452        );
2453    }
2454
2455    #[test]
2456    fn test_configure_transport_config() {
2457        let config = TransportRpcModuleConfig::default()
2458            .with_http([RethRpcModule::Eth, RethRpcModule::Admin]);
2459        assert_eq!(
2460            config,
2461            TransportRpcModuleConfig {
2462                http: Some(RpcModuleSelection::Selection(
2463                    [RethRpcModule::Eth, RethRpcModule::Admin].into()
2464                )),
2465                ws: None,
2466                ipc: None,
2467                config: None,
2468            }
2469        )
2470    }
2471
2472    #[test]
2473    fn test_configure_transport_config_none() {
2474        let config = TransportRpcModuleConfig::default().with_http(Vec::<RethRpcModule>::new());
2475        assert_eq!(
2476            config,
2477            TransportRpcModuleConfig {
2478                http: Some(RpcModuleSelection::Selection(Default::default())),
2479                ws: None,
2480                ipc: None,
2481                config: None,
2482            }
2483        )
2484    }
2485
2486    fn create_test_module() -> RpcModule<()> {
2487        let mut module = RpcModule::new(());
2488        module.register_method("anything", |_, _, _| "succeed").unwrap();
2489        module
2490    }
2491
2492    #[test]
2493    fn test_remove_http_method() {
2494        let mut modules =
2495            TransportRpcModules { http: Some(create_test_module()), ..Default::default() };
2496        // Remove a method that exists
2497        assert!(modules.remove_http_method("anything"));
2498
2499        // Remove a method that does not exist
2500        assert!(!modules.remove_http_method("non_existent_method"));
2501
2502        // Verify that the method was removed
2503        assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2504    }
2505
2506    #[test]
2507    fn test_remove_ws_method() {
2508        let mut modules =
2509            TransportRpcModules { ws: Some(create_test_module()), ..Default::default() };
2510
2511        // Remove a method that exists
2512        assert!(modules.remove_ws_method("anything"));
2513
2514        // Remove a method that does not exist
2515        assert!(!modules.remove_ws_method("non_existent_method"));
2516
2517        // Verify that the method was removed
2518        assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2519    }
2520
2521    #[test]
2522    fn test_remove_ipc_method() {
2523        let mut modules =
2524            TransportRpcModules { ipc: Some(create_test_module()), ..Default::default() };
2525
2526        // Remove a method that exists
2527        assert!(modules.remove_ipc_method("anything"));
2528
2529        // Remove a method that does not exist
2530        assert!(!modules.remove_ipc_method("non_existent_method"));
2531
2532        // Verify that the method was removed
2533        assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2534    }
2535
2536    #[test]
2537    fn test_remove_method_from_configured() {
2538        let mut modules = TransportRpcModules {
2539            http: Some(create_test_module()),
2540            ws: Some(create_test_module()),
2541            ipc: Some(create_test_module()),
2542            ..Default::default()
2543        };
2544
2545        // Remove a method that exists
2546        assert!(modules.remove_method_from_configured("anything"));
2547
2548        // Remove a method that was just removed (it does not exist anymore)
2549        assert!(!modules.remove_method_from_configured("anything"));
2550
2551        // Remove a method that does not exist
2552        assert!(!modules.remove_method_from_configured("non_existent_method"));
2553
2554        // Verify that the method was removed from all transports
2555        assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2556        assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2557        assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2558    }
2559
2560    #[test]
2561    fn test_transport_rpc_module_rename() {
2562        let mut modules = TransportRpcModules {
2563            http: Some(create_test_module()),
2564            ws: Some(create_test_module()),
2565            ipc: Some(create_test_module()),
2566            ..Default::default()
2567        };
2568
2569        // Verify that the old we want to rename exists at the start
2570        assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2571        assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2572        assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2573
2574        // Verify that the new method does not exist at the start
2575        assert!(modules.http.as_ref().unwrap().method("something").is_none());
2576        assert!(modules.ws.as_ref().unwrap().method("something").is_none());
2577        assert!(modules.ipc.as_ref().unwrap().method("something").is_none());
2578
2579        // Create another module
2580        let mut other_module = RpcModule::new(());
2581        other_module.register_method("something", |_, _, _| "fails").unwrap();
2582
2583        // Rename the method
2584        modules.rename("anything", other_module).expect("rename failed");
2585
2586        // Verify that the old method was removed from all transports
2587        assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2588        assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2589        assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2590
2591        // Verify that the new method was added to all transports
2592        assert!(modules.http.as_ref().unwrap().method("something").is_some());
2593        assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2594        assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2595    }
2596
2597    #[test]
2598    fn test_replace_http_method() {
2599        let mut modules =
2600            TransportRpcModules { http: Some(create_test_module()), ..Default::default() };
2601
2602        let mut other_module = RpcModule::new(());
2603        other_module.register_method("something", |_, _, _| "fails").unwrap();
2604
2605        assert!(modules.replace_http(other_module.clone()).unwrap());
2606
2607        assert!(modules.http.as_ref().unwrap().method("something").is_some());
2608
2609        other_module.register_method("anything", |_, _, _| "fails").unwrap();
2610        assert!(modules.replace_http(other_module.clone()).unwrap());
2611
2612        assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2613    }
2614    #[test]
2615    fn test_replace_ipc_method() {
2616        let mut modules =
2617            TransportRpcModules { ipc: Some(create_test_module()), ..Default::default() };
2618
2619        let mut other_module = RpcModule::new(());
2620        other_module.register_method("something", |_, _, _| "fails").unwrap();
2621
2622        assert!(modules.replace_ipc(other_module.clone()).unwrap());
2623
2624        assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2625
2626        other_module.register_method("anything", |_, _, _| "fails").unwrap();
2627        assert!(modules.replace_ipc(other_module.clone()).unwrap());
2628
2629        assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2630    }
2631    #[test]
2632    fn test_replace_ws_method() {
2633        let mut modules =
2634            TransportRpcModules { ws: Some(create_test_module()), ..Default::default() };
2635
2636        let mut other_module = RpcModule::new(());
2637        other_module.register_method("something", |_, _, _| "fails").unwrap();
2638
2639        assert!(modules.replace_ws(other_module.clone()).unwrap());
2640
2641        assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2642
2643        other_module.register_method("anything", |_, _, _| "fails").unwrap();
2644        assert!(modules.replace_ws(other_module.clone()).unwrap());
2645
2646        assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2647    }
2648
2649    #[test]
2650    fn test_replace_configured() {
2651        let mut modules = TransportRpcModules {
2652            http: Some(create_test_module()),
2653            ws: Some(create_test_module()),
2654            ipc: Some(create_test_module()),
2655            ..Default::default()
2656        };
2657        let mut other_module = RpcModule::new(());
2658        other_module.register_method("something", |_, _, _| "fails").unwrap();
2659
2660        assert!(modules.replace_configured(other_module).unwrap());
2661
2662        // Verify that the other_method was added
2663        assert!(modules.http.as_ref().unwrap().method("something").is_some());
2664        assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2665        assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2666
2667        assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2668        assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2669        assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2670    }
2671}