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