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 + '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>
623    where
624        Network: Peers,
625    {
626        AdminApi::new(self.network.clone(), self.provider.chain_spec())
627    }
628
629    /// Instantiates `Web3Api`
630    pub fn web3_api(&self) -> Web3Api<Network> {
631        Web3Api::new(self.network.clone())
632    }
633
634    /// Register Admin Namespace
635    pub fn register_admin(&mut self) -> &mut Self
636    where
637        Network: Peers,
638    {
639        let adminapi = self.admin_api();
640        self.modules.insert(RethRpcModule::Admin, adminapi.into_rpc().into());
641        self
642    }
643
644    /// Register Web3 Namespace
645    pub fn register_web3(&mut self) -> &mut Self {
646        let web3api = self.web3_api();
647        self.modules.insert(RethRpcModule::Web3, web3api.into_rpc().into());
648        self
649    }
650}
651
652impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
653    RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
654where
655    N: NodePrimitives,
656    Provider: FullRpcProvider<
657            Header = N::BlockHeader,
658            Block = N::Block,
659            Receipt = N::Receipt,
660            Transaction = N::SignedTx,
661        > + AccountReader
662        + ChangeSetReader
663        + CanonStateSubscriptions,
664    Network: NetworkInfo + Peers + Clone + 'static,
665    EthApi: EthApiServer<
666            RpcTxReq<EthApi::NetworkTypes>,
667            RpcTransaction<EthApi::NetworkTypes>,
668            RpcBlock<EthApi::NetworkTypes>,
669            RpcReceipt<EthApi::NetworkTypes>,
670            RpcHeader<EthApi::NetworkTypes>,
671        > + EthApiTypes,
672    EvmConfig: ConfigureEvm<Primitives = N> + 'static,
673{
674    /// Register Eth Namespace
675    ///
676    /// # Panics
677    ///
678    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
679    pub fn register_eth(&mut self) -> &mut Self {
680        let eth_api = self.eth_api().clone();
681        self.modules.insert(RethRpcModule::Eth, eth_api.into_rpc().into());
682        self
683    }
684
685    /// Register Otterscan Namespace
686    ///
687    /// # Panics
688    ///
689    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
690    pub fn register_ots(&mut self) -> &mut Self
691    where
692        EthApi: TraceExt + EthTransactions,
693    {
694        let otterscan_api = self.otterscan_api();
695        self.modules.insert(RethRpcModule::Ots, otterscan_api.into_rpc().into());
696        self
697    }
698
699    /// Register Debug Namespace
700    ///
701    /// # Panics
702    ///
703    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
704    pub fn register_debug(&mut self) -> &mut Self
705    where
706        EthApi: EthApiSpec + EthTransactions + TraceExt,
707        EvmConfig::Primitives: NodePrimitives<Block = ProviderBlock<EthApi::Provider>>,
708    {
709        let debug_api = self.debug_api();
710        self.modules.insert(RethRpcModule::Debug, debug_api.into_rpc().into());
711        self
712    }
713
714    /// Register Trace Namespace
715    ///
716    /// # Panics
717    ///
718    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
719    pub fn register_trace(&mut self) -> &mut Self
720    where
721        EthApi: TraceExt,
722    {
723        let trace_api = self.trace_api();
724        self.modules.insert(RethRpcModule::Trace, trace_api.into_rpc().into());
725        self
726    }
727
728    /// Register Net Namespace
729    ///
730    /// See also [`Self::eth_api`]
731    ///
732    /// # Panics
733    ///
734    /// If called outside of the tokio runtime.
735    pub fn register_net(&mut self) -> &mut Self
736    where
737        EthApi: EthApiSpec + 'static,
738    {
739        let netapi = self.net_api();
740        self.modules.insert(RethRpcModule::Net, netapi.into_rpc().into());
741        self
742    }
743
744    /// Register Reth namespace
745    ///
746    /// See also [`Self::eth_api`]
747    ///
748    /// # Panics
749    ///
750    /// If called outside of the tokio runtime.
751    pub fn register_reth(&mut self) -> &mut Self {
752        let rethapi = self.reth_api();
753        self.modules.insert(RethRpcModule::Reth, rethapi.into_rpc().into());
754        self
755    }
756
757    /// Instantiates `OtterscanApi`
758    ///
759    /// # Panics
760    ///
761    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
762    pub fn otterscan_api(&self) -> OtterscanApi<EthApi> {
763        let eth_api = self.eth_api().clone();
764        OtterscanApi::new(eth_api)
765    }
766}
767
768impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
769    RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
770where
771    N: NodePrimitives,
772    Provider: FullRpcProvider<
773            Block = N::Block,
774            Header = N::BlockHeader,
775            Transaction = N::SignedTx,
776            Receipt = N::Receipt,
777        > + AccountReader
778        + ChangeSetReader,
779    Network: NetworkInfo + Peers + Clone + 'static,
780    EthApi: EthApiTypes,
781    EvmConfig: ConfigureEvm<Primitives = N>,
782{
783    /// Instantiates `TraceApi`
784    ///
785    /// # Panics
786    ///
787    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
788    pub fn trace_api(&self) -> TraceApi<EthApi> {
789        TraceApi::new(
790            self.eth_api().clone(),
791            self.blocking_pool_guard.clone(),
792            self.eth_config.clone(),
793        )
794    }
795
796    /// Instantiates [`EthBundle`] Api
797    ///
798    /// # Panics
799    ///
800    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
801    pub fn bundle_api(&self) -> EthBundle<EthApi>
802    where
803        EthApi: EthTransactions + LoadPendingBlock + Call,
804    {
805        let eth_api = self.eth_api().clone();
806        EthBundle::new(eth_api, self.blocking_pool_guard.clone())
807    }
808
809    /// Instantiates `DebugApi`
810    ///
811    /// # Panics
812    ///
813    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
814    pub fn debug_api(&self) -> DebugApi<EthApi> {
815        DebugApi::new(self.eth_api().clone(), self.blocking_pool_guard.clone())
816    }
817
818    /// Instantiates `NetApi`
819    ///
820    /// # Panics
821    ///
822    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
823    pub fn net_api(&self) -> NetApi<Network, EthApi>
824    where
825        EthApi: EthApiSpec + 'static,
826    {
827        let eth_api = self.eth_api().clone();
828        NetApi::new(self.network.clone(), eth_api)
829    }
830
831    /// Instantiates `RethApi`
832    pub fn reth_api(&self) -> RethApi<Provider> {
833        RethApi::new(self.provider.clone(), self.executor.clone())
834    }
835}
836
837impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
838    RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
839where
840    N: NodePrimitives,
841    Provider: FullRpcProvider<Block = N::Block>
842        + CanonStateSubscriptions<Primitives = N>
843        + AccountReader
844        + ChangeSetReader,
845    Pool: TransactionPool + 'static,
846    Network: NetworkInfo + Peers + Clone + 'static,
847    EthApi: FullEthApiServer,
848    EvmConfig: ConfigureEvm<Primitives = N> + 'static,
849    Consensus: FullConsensus<N, Error = ConsensusError> + Clone + 'static,
850{
851    /// Configures the auth module that includes the
852    ///   * `engine_` namespace
853    ///   * `api_` namespace
854    ///
855    /// Note: This does _not_ register the `engine_` in this registry.
856    pub fn create_auth_module(&self, engine_api: impl IntoEngineApiRpcModule) -> AuthRpcModule {
857        let mut module = engine_api.into_rpc_module();
858
859        // also merge a subset of `eth_` handlers
860        let eth_handlers = self.eth_handlers();
861        let engine_eth = EngineEthApi::new(eth_handlers.api.clone(), eth_handlers.filter.clone());
862
863        module.merge(engine_eth.into_rpc()).expect("No conflicting methods");
864
865        AuthRpcModule { inner: module }
866    }
867
868    /// Helper function to create a [`RpcModule`] if it's not `None`
869    fn maybe_module(&mut self, config: Option<&RpcModuleSelection>) -> Option<RpcModule<()>> {
870        config.map(|config| self.module_for(config))
871    }
872
873    /// Configure a [`TransportRpcModules`] using the current registry. This
874    /// creates [`RpcModule`] instances for the modules selected by the
875    /// `config`.
876    pub fn create_transport_rpc_modules(
877        &mut self,
878        config: TransportRpcModuleConfig,
879    ) -> TransportRpcModules<()> {
880        let mut modules = TransportRpcModules::default();
881        let http = self.maybe_module(config.http.as_ref());
882        let ws = self.maybe_module(config.ws.as_ref());
883        let ipc = self.maybe_module(config.ipc.as_ref());
884
885        modules.config = config;
886        modules.http = http;
887        modules.ws = ws;
888        modules.ipc = ipc;
889        modules
890    }
891
892    /// Populates a new [`RpcModule`] based on the selected [`RethRpcModule`]s in the given
893    /// [`RpcModuleSelection`]
894    pub fn module_for(&mut self, config: &RpcModuleSelection) -> RpcModule<()> {
895        let mut module = RpcModule::new(());
896        let all_methods = self.reth_methods(config.iter_selection());
897        for methods in all_methods {
898            module.merge(methods).expect("No conflicts");
899        }
900        module
901    }
902
903    /// Returns the [Methods] for the given [`RethRpcModule`]
904    ///
905    /// If this is the first time the namespace is requested, a new instance of API implementation
906    /// will be created.
907    ///
908    /// # Panics
909    ///
910    /// If called outside of the tokio runtime. See also [`Self::eth_api`]
911    pub fn reth_methods(
912        &mut self,
913        namespaces: impl Iterator<Item = RethRpcModule>,
914    ) -> Vec<Methods> {
915        let EthHandlers { api: eth_api, filter: eth_filter, pubsub: eth_pubsub, .. } =
916            self.eth_handlers().clone();
917
918        // Create a copy, so we can list out all the methods for rpc_ api
919        let namespaces: Vec<_> = namespaces.collect();
920        namespaces
921            .iter()
922            .copied()
923            .map(|namespace| {
924                self.modules
925                    .entry(namespace)
926                    .or_insert_with(|| match namespace {
927                        RethRpcModule::Admin => {
928                            AdminApi::new(self.network.clone(), self.provider.chain_spec())
929                                .into_rpc()
930                                .into()
931                        }
932                        RethRpcModule::Debug => {
933                            DebugApi::new(eth_api.clone(), self.blocking_pool_guard.clone())
934                                .into_rpc()
935                                .into()
936                        }
937                        RethRpcModule::Eth => {
938                            // merge all eth handlers
939                            let mut module = eth_api.clone().into_rpc();
940                            module.merge(eth_filter.clone().into_rpc()).expect("No conflicts");
941                            module.merge(eth_pubsub.clone().into_rpc()).expect("No conflicts");
942                            module
943                                .merge(
944                                    EthBundle::new(
945                                        eth_api.clone(),
946                                        self.blocking_pool_guard.clone(),
947                                    )
948                                    .into_rpc(),
949                                )
950                                .expect("No conflicts");
951
952                            module.into()
953                        }
954                        RethRpcModule::Net => {
955                            NetApi::new(self.network.clone(), eth_api.clone()).into_rpc().into()
956                        }
957                        RethRpcModule::Trace => TraceApi::new(
958                            eth_api.clone(),
959                            self.blocking_pool_guard.clone(),
960                            self.eth_config.clone(),
961                        )
962                        .into_rpc()
963                        .into(),
964                        RethRpcModule::Web3 => Web3Api::new(self.network.clone()).into_rpc().into(),
965                        RethRpcModule::Txpool => TxPoolApi::new(
966                            self.eth.api.pool().clone(),
967                            self.eth.api.tx_resp_builder().clone(),
968                        )
969                        .into_rpc()
970                        .into(),
971                        RethRpcModule::Rpc => RPCApi::new(
972                            namespaces
973                                .iter()
974                                .map(|module| (module.to_string(), "1.0".to_string()))
975                                .collect(),
976                        )
977                        .into_rpc()
978                        .into(),
979                        RethRpcModule::Ots => OtterscanApi::new(eth_api.clone()).into_rpc().into(),
980                        RethRpcModule::Reth => {
981                            RethApi::new(self.provider.clone(), self.executor.clone())
982                                .into_rpc()
983                                .into()
984                        }
985                        // only relevant for Ethereum and configured in `EthereumAddOns`
986                        // implementation
987                        // TODO: can we get rid of this here?
988                        RethRpcModule::Flashbots => Default::default(),
989                        RethRpcModule::Miner => MinerApi::default().into_rpc().into(),
990                        RethRpcModule::Mev => {
991                            EthSimBundle::new(eth_api.clone(), self.blocking_pool_guard.clone())
992                                .into_rpc()
993                                .into()
994                        }
995                    })
996                    .clone()
997            })
998            .collect::<Vec<_>>()
999    }
1000}
1001
1002/// A builder type for configuring and launching the servers that will handle RPC requests.
1003///
1004/// Supported server transports are:
1005///    - http
1006///    - ws
1007///    - ipc
1008///
1009/// Http and WS share the same settings: [`ServerBuilder`].
1010///
1011/// Once the [`RpcModule`] is built via [`RpcModuleBuilder`] the servers can be started, See also
1012/// [`ServerBuilder::build`] and [`Server::start`](jsonrpsee::server::Server::start).
1013#[derive(Debug)]
1014pub struct RpcServerConfig<RpcMiddleware = Identity> {
1015    /// Configs for JSON-RPC Http.
1016    http_server_config: Option<ServerConfigBuilder>,
1017    /// Allowed CORS Domains for http
1018    http_cors_domains: Option<String>,
1019    /// Address where to bind the http server to
1020    http_addr: Option<SocketAddr>,
1021    /// Control whether http responses should be compressed
1022    http_disable_compression: bool,
1023    /// Configs for WS server
1024    ws_server_config: Option<ServerConfigBuilder>,
1025    /// Allowed CORS Domains for ws.
1026    ws_cors_domains: Option<String>,
1027    /// Address where to bind the ws server to
1028    ws_addr: Option<SocketAddr>,
1029    /// Configs for JSON-RPC IPC server
1030    ipc_server_config: Option<IpcServerBuilder<Identity, Identity>>,
1031    /// The Endpoint where to launch the ipc server
1032    ipc_endpoint: Option<String>,
1033    /// JWT secret for authentication
1034    jwt_secret: Option<JwtSecret>,
1035    /// Configurable RPC middleware
1036    rpc_middleware: RpcMiddleware,
1037}
1038
1039// === impl RpcServerConfig ===
1040
1041impl Default for RpcServerConfig<Identity> {
1042    /// Create a new config instance
1043    fn default() -> Self {
1044        Self {
1045            http_server_config: None,
1046            http_cors_domains: None,
1047            http_addr: None,
1048            http_disable_compression: false,
1049            ws_server_config: None,
1050            ws_cors_domains: None,
1051            ws_addr: None,
1052            ipc_server_config: None,
1053            ipc_endpoint: None,
1054            jwt_secret: None,
1055            rpc_middleware: Default::default(),
1056        }
1057    }
1058}
1059
1060impl RpcServerConfig {
1061    /// Creates a new config with only http set
1062    pub fn http(config: ServerConfigBuilder) -> Self {
1063        Self::default().with_http(config)
1064    }
1065
1066    /// Creates a new config with only ws set
1067    pub fn ws(config: ServerConfigBuilder) -> Self {
1068        Self::default().with_ws(config)
1069    }
1070
1071    /// Creates a new config with only ipc set
1072    pub fn ipc(config: IpcServerBuilder<Identity, Identity>) -> Self {
1073        Self::default().with_ipc(config)
1074    }
1075
1076    /// Configures the http server
1077    ///
1078    /// Note: this always configures an [`EthSubscriptionIdProvider`] [`IdProvider`] for
1079    /// convenience. To set a custom [`IdProvider`], please use [`Self::with_id_provider`].
1080    pub fn with_http(mut self, config: ServerConfigBuilder) -> Self {
1081        self.http_server_config =
1082            Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1083        self
1084    }
1085
1086    /// Configures the ws server
1087    ///
1088    /// Note: this always configures an [`EthSubscriptionIdProvider`] [`IdProvider`] for
1089    /// convenience. To set a custom [`IdProvider`], please use [`Self::with_id_provider`].
1090    pub fn with_ws(mut self, config: ServerConfigBuilder) -> Self {
1091        self.ws_server_config = Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1092        self
1093    }
1094
1095    /// Configures the ipc server
1096    ///
1097    /// Note: this always configures an [`EthSubscriptionIdProvider`] [`IdProvider`] for
1098    /// convenience. To set a custom [`IdProvider`], please use [`Self::with_id_provider`].
1099    pub fn with_ipc(mut self, config: IpcServerBuilder<Identity, Identity>) -> Self {
1100        self.ipc_server_config = Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1101        self
1102    }
1103}
1104
1105impl<RpcMiddleware> RpcServerConfig<RpcMiddleware> {
1106    /// Configure rpc middleware
1107    pub fn set_rpc_middleware<T>(self, rpc_middleware: T) -> RpcServerConfig<T> {
1108        RpcServerConfig {
1109            http_server_config: self.http_server_config,
1110            http_cors_domains: self.http_cors_domains,
1111            http_addr: self.http_addr,
1112            http_disable_compression: self.http_disable_compression,
1113            ws_server_config: self.ws_server_config,
1114            ws_cors_domains: self.ws_cors_domains,
1115            ws_addr: self.ws_addr,
1116            ipc_server_config: self.ipc_server_config,
1117            ipc_endpoint: self.ipc_endpoint,
1118            jwt_secret: self.jwt_secret,
1119            rpc_middleware,
1120        }
1121    }
1122
1123    /// Configure the cors domains for http _and_ ws
1124    pub fn with_cors(self, cors_domain: Option<String>) -> Self {
1125        self.with_http_cors(cors_domain.clone()).with_ws_cors(cors_domain)
1126    }
1127
1128    /// Configure the cors domains for WS
1129    pub fn with_ws_cors(mut self, cors_domain: Option<String>) -> Self {
1130        self.ws_cors_domains = cors_domain;
1131        self
1132    }
1133
1134    /// Configure whether HTTP responses should be compressed
1135    pub const fn with_http_disable_compression(mut self, http_disable_compression: bool) -> Self {
1136        self.http_disable_compression = http_disable_compression;
1137        self
1138    }
1139
1140    /// Configure the cors domains for HTTP
1141    pub fn with_http_cors(mut self, cors_domain: Option<String>) -> Self {
1142        self.http_cors_domains = cors_domain;
1143        self
1144    }
1145
1146    /// Configures the [`SocketAddr`] of the http server
1147    ///
1148    /// Default is [`Ipv4Addr::LOCALHOST`] and
1149    /// [`reth_rpc_server_types::constants::DEFAULT_HTTP_RPC_PORT`]
1150    pub const fn with_http_address(mut self, addr: SocketAddr) -> Self {
1151        self.http_addr = Some(addr);
1152        self
1153    }
1154
1155    /// Configures the [`SocketAddr`] of the ws server
1156    ///
1157    /// Default is [`Ipv4Addr::LOCALHOST`] and
1158    /// [`reth_rpc_server_types::constants::DEFAULT_WS_RPC_PORT`]
1159    pub const fn with_ws_address(mut self, addr: SocketAddr) -> Self {
1160        self.ws_addr = Some(addr);
1161        self
1162    }
1163
1164    /// Sets a custom [`IdProvider`] for all configured transports.
1165    ///
1166    /// By default all transports use [`EthSubscriptionIdProvider`]
1167    pub fn with_id_provider<I>(mut self, id_provider: I) -> Self
1168    where
1169        I: IdProvider + Clone + 'static,
1170    {
1171        if let Some(config) = self.http_server_config {
1172            self.http_server_config = Some(config.set_id_provider(id_provider.clone()));
1173        }
1174        if let Some(config) = self.ws_server_config {
1175            self.ws_server_config = Some(config.set_id_provider(id_provider.clone()));
1176        }
1177        if let Some(ipc) = self.ipc_server_config {
1178            self.ipc_server_config = Some(ipc.set_id_provider(id_provider));
1179        }
1180
1181        self
1182    }
1183
1184    /// Configures the endpoint of the ipc server
1185    ///
1186    /// Default is [`reth_rpc_server_types::constants::DEFAULT_IPC_ENDPOINT`]
1187    pub fn with_ipc_endpoint(mut self, path: impl Into<String>) -> Self {
1188        self.ipc_endpoint = Some(path.into());
1189        self
1190    }
1191
1192    /// Configures the JWT secret for authentication.
1193    pub const fn with_jwt_secret(mut self, secret: Option<JwtSecret>) -> Self {
1194        self.jwt_secret = secret;
1195        self
1196    }
1197
1198    /// Configures a custom tokio runtime for the rpc server.
1199    pub fn with_tokio_runtime(mut self, tokio_runtime: Option<tokio::runtime::Handle>) -> Self {
1200        let Some(tokio_runtime) = tokio_runtime else { return self };
1201        if let Some(http_server_config) = self.http_server_config {
1202            self.http_server_config =
1203                Some(http_server_config.custom_tokio_runtime(tokio_runtime.clone()));
1204        }
1205        if let Some(ws_server_config) = self.ws_server_config {
1206            self.ws_server_config =
1207                Some(ws_server_config.custom_tokio_runtime(tokio_runtime.clone()));
1208        }
1209        if let Some(ipc_server_config) = self.ipc_server_config {
1210            self.ipc_server_config = Some(ipc_server_config.custom_tokio_runtime(tokio_runtime));
1211        }
1212        self
1213    }
1214
1215    /// Returns true if any server is configured.
1216    ///
1217    /// If no server is configured, no server will be launched on [`RpcServerConfig::start`].
1218    pub const fn has_server(&self) -> bool {
1219        self.http_server_config.is_some() ||
1220            self.ws_server_config.is_some() ||
1221            self.ipc_server_config.is_some()
1222    }
1223
1224    /// Returns the [`SocketAddr`] of the http server
1225    pub const fn http_address(&self) -> Option<SocketAddr> {
1226        self.http_addr
1227    }
1228
1229    /// Returns the [`SocketAddr`] of the ws server
1230    pub const fn ws_address(&self) -> Option<SocketAddr> {
1231        self.ws_addr
1232    }
1233
1234    /// Returns the endpoint of the ipc server
1235    pub fn ipc_endpoint(&self) -> Option<String> {
1236        self.ipc_endpoint.clone()
1237    }
1238
1239    /// Creates the [`CorsLayer`] if any
1240    fn maybe_cors_layer(cors: Option<String>) -> Result<Option<CorsLayer>, CorsDomainError> {
1241        cors.as_deref().map(cors::create_cors_layer).transpose()
1242    }
1243
1244    /// Creates the [`AuthLayer`] if any
1245    fn maybe_jwt_layer(jwt_secret: Option<JwtSecret>) -> Option<AuthLayer<JwtAuthValidator>> {
1246        jwt_secret.map(|secret| AuthLayer::new(JwtAuthValidator::new(secret)))
1247    }
1248
1249    /// Returns a [`CompressionLayer`] that adds compression support (gzip, deflate, brotli, zstd)
1250    /// based on the client's `Accept-Encoding` header
1251    fn maybe_compression_layer(disable_compression: bool) -> Option<CompressionLayer> {
1252        if disable_compression {
1253            None
1254        } else {
1255            Some(CompressionLayer::new())
1256        }
1257    }
1258
1259    /// Builds and starts the configured server(s): http, ws, ipc.
1260    ///
1261    /// If both http and ws are on the same port, they are combined into one server.
1262    ///
1263    /// Returns the [`RpcServerHandle`] with the handle to the started servers.
1264    pub async fn start(self, modules: &TransportRpcModules) -> Result<RpcServerHandle, RpcError>
1265    where
1266        RpcMiddleware: RethRpcMiddleware,
1267    {
1268        let mut http_handle = None;
1269        let mut ws_handle = None;
1270        let mut ipc_handle = None;
1271
1272        let http_socket_addr = self.http_addr.unwrap_or(SocketAddr::V4(SocketAddrV4::new(
1273            Ipv4Addr::LOCALHOST,
1274            constants::DEFAULT_HTTP_RPC_PORT,
1275        )));
1276
1277        let ws_socket_addr = self.ws_addr.unwrap_or(SocketAddr::V4(SocketAddrV4::new(
1278            Ipv4Addr::LOCALHOST,
1279            constants::DEFAULT_WS_RPC_PORT,
1280        )));
1281
1282        let metrics = modules.ipc.as_ref().map(RpcRequestMetrics::ipc).unwrap_or_default();
1283        let ipc_path =
1284            self.ipc_endpoint.clone().unwrap_or_else(|| constants::DEFAULT_IPC_ENDPOINT.into());
1285
1286        if let Some(builder) = self.ipc_server_config {
1287            let ipc = builder
1288                .set_rpc_middleware(IpcRpcServiceBuilder::new().layer(metrics))
1289                .build(ipc_path);
1290            ipc_handle = Some(ipc.start(modules.ipc.clone().expect("ipc server error")).await?);
1291        }
1292
1293        // If both are configured on the same port, we combine them into one server.
1294        if self.http_addr == self.ws_addr &&
1295            self.http_server_config.is_some() &&
1296            self.ws_server_config.is_some()
1297        {
1298            let cors = match (self.ws_cors_domains.as_ref(), self.http_cors_domains.as_ref()) {
1299                (Some(ws_cors), Some(http_cors)) => {
1300                    if ws_cors.trim() != http_cors.trim() {
1301                        return Err(WsHttpSamePortError::ConflictingCorsDomains {
1302                            http_cors_domains: Some(http_cors.clone()),
1303                            ws_cors_domains: Some(ws_cors.clone()),
1304                        }
1305                        .into());
1306                    }
1307                    Some(ws_cors)
1308                }
1309                (a, b) => a.or(b),
1310            }
1311            .cloned();
1312
1313            // we merge this into one server using the http setup
1314            modules.config.ensure_ws_http_identical()?;
1315
1316            if let Some(config) = self.http_server_config {
1317                let server = ServerBuilder::new()
1318                    .set_http_middleware(
1319                        tower::ServiceBuilder::new()
1320                            .option_layer(Self::maybe_cors_layer(cors)?)
1321                            .option_layer(Self::maybe_jwt_layer(self.jwt_secret))
1322                            .option_layer(Self::maybe_compression_layer(
1323                                self.http_disable_compression,
1324                            )),
1325                    )
1326                    .set_rpc_middleware(
1327                        RpcServiceBuilder::default()
1328                            .layer(
1329                                modules
1330                                    .http
1331                                    .as_ref()
1332                                    .or(modules.ws.as_ref())
1333                                    .map(RpcRequestMetrics::same_port)
1334                                    .unwrap_or_default(),
1335                            )
1336                            .layer(self.rpc_middleware.clone()),
1337                    )
1338                    .set_config(config.build())
1339                    .build(http_socket_addr)
1340                    .await
1341                    .map_err(|err| {
1342                        RpcError::server_error(err, ServerKind::WsHttp(http_socket_addr))
1343                    })?;
1344                let addr = server.local_addr().map_err(|err| {
1345                    RpcError::server_error(err, ServerKind::WsHttp(http_socket_addr))
1346                })?;
1347                if let Some(module) = modules.http.as_ref().or(modules.ws.as_ref()) {
1348                    let handle = server.start(module.clone());
1349                    http_handle = Some(handle.clone());
1350                    ws_handle = Some(handle);
1351                }
1352                return Ok(RpcServerHandle {
1353                    http_local_addr: Some(addr),
1354                    ws_local_addr: Some(addr),
1355                    http: http_handle,
1356                    ws: ws_handle,
1357                    ipc_endpoint: self.ipc_endpoint.clone(),
1358                    ipc: ipc_handle,
1359                    jwt_secret: self.jwt_secret,
1360                });
1361            }
1362        }
1363
1364        let mut ws_local_addr = None;
1365        let mut ws_server = None;
1366        let mut http_local_addr = None;
1367        let mut http_server = None;
1368
1369        if let Some(config) = self.ws_server_config {
1370            let server = ServerBuilder::new()
1371                .set_config(config.ws_only().build())
1372                .set_http_middleware(
1373                    tower::ServiceBuilder::new()
1374                        .option_layer(Self::maybe_cors_layer(self.ws_cors_domains.clone())?)
1375                        .option_layer(Self::maybe_jwt_layer(self.jwt_secret)),
1376                )
1377                .set_rpc_middleware(
1378                    RpcServiceBuilder::default()
1379                        .layer(modules.ws.as_ref().map(RpcRequestMetrics::ws).unwrap_or_default())
1380                        .layer(self.rpc_middleware.clone()),
1381                )
1382                .build(ws_socket_addr)
1383                .await
1384                .map_err(|err| RpcError::server_error(err, ServerKind::WS(ws_socket_addr)))?;
1385
1386            let addr = server
1387                .local_addr()
1388                .map_err(|err| RpcError::server_error(err, ServerKind::WS(ws_socket_addr)))?;
1389
1390            ws_local_addr = Some(addr);
1391            ws_server = Some(server);
1392        }
1393
1394        if let Some(config) = self.http_server_config {
1395            let server = ServerBuilder::new()
1396                .set_config(config.http_only().build())
1397                .set_http_middleware(
1398                    tower::ServiceBuilder::new()
1399                        .option_layer(Self::maybe_cors_layer(self.http_cors_domains.clone())?)
1400                        .option_layer(Self::maybe_jwt_layer(self.jwt_secret))
1401                        .option_layer(Self::maybe_compression_layer(self.http_disable_compression)),
1402                )
1403                .set_rpc_middleware(
1404                    RpcServiceBuilder::default()
1405                        .layer(
1406                            modules.http.as_ref().map(RpcRequestMetrics::http).unwrap_or_default(),
1407                        )
1408                        .layer(self.rpc_middleware.clone()),
1409                )
1410                .build(http_socket_addr)
1411                .await
1412                .map_err(|err| RpcError::server_error(err, ServerKind::Http(http_socket_addr)))?;
1413            let local_addr = server
1414                .local_addr()
1415                .map_err(|err| RpcError::server_error(err, ServerKind::Http(http_socket_addr)))?;
1416            http_local_addr = Some(local_addr);
1417            http_server = Some(server);
1418        }
1419
1420        http_handle = http_server
1421            .map(|http_server| http_server.start(modules.http.clone().expect("http server error")));
1422        ws_handle = ws_server
1423            .map(|ws_server| ws_server.start(modules.ws.clone().expect("ws server error")));
1424        Ok(RpcServerHandle {
1425            http_local_addr,
1426            ws_local_addr,
1427            http: http_handle,
1428            ws: ws_handle,
1429            ipc_endpoint: self.ipc_endpoint.clone(),
1430            ipc: ipc_handle,
1431            jwt_secret: self.jwt_secret,
1432        })
1433    }
1434}
1435
1436/// Holds modules to be installed per transport type
1437///
1438/// # Example
1439///
1440/// Configure a http transport only
1441///
1442/// ```
1443/// use reth_rpc_builder::{RethRpcModule, TransportRpcModuleConfig};
1444/// let config =
1445///     TransportRpcModuleConfig::default().with_http([RethRpcModule::Eth, RethRpcModule::Admin]);
1446/// ```
1447#[derive(Debug, Clone, Default, Eq, PartialEq)]
1448pub struct TransportRpcModuleConfig {
1449    /// http module configuration
1450    http: Option<RpcModuleSelection>,
1451    /// ws module configuration
1452    ws: Option<RpcModuleSelection>,
1453    /// ipc module configuration
1454    ipc: Option<RpcModuleSelection>,
1455    /// Config for the modules
1456    config: Option<RpcModuleConfig>,
1457}
1458
1459// === impl TransportRpcModuleConfig ===
1460
1461impl TransportRpcModuleConfig {
1462    /// Creates a new config with only http set
1463    pub fn set_http(http: impl Into<RpcModuleSelection>) -> Self {
1464        Self::default().with_http(http)
1465    }
1466
1467    /// Creates a new config with only ws set
1468    pub fn set_ws(ws: impl Into<RpcModuleSelection>) -> Self {
1469        Self::default().with_ws(ws)
1470    }
1471
1472    /// Creates a new config with only ipc set
1473    pub fn set_ipc(ipc: impl Into<RpcModuleSelection>) -> Self {
1474        Self::default().with_ipc(ipc)
1475    }
1476
1477    /// Sets the [`RpcModuleSelection`] for the http transport.
1478    pub fn with_http(mut self, http: impl Into<RpcModuleSelection>) -> Self {
1479        self.http = Some(http.into());
1480        self
1481    }
1482
1483    /// Sets the [`RpcModuleSelection`] for the ws transport.
1484    pub fn with_ws(mut self, ws: impl Into<RpcModuleSelection>) -> Self {
1485        self.ws = Some(ws.into());
1486        self
1487    }
1488
1489    /// Sets the [`RpcModuleSelection`] for the http transport.
1490    pub fn with_ipc(mut self, ipc: impl Into<RpcModuleSelection>) -> Self {
1491        self.ipc = Some(ipc.into());
1492        self
1493    }
1494
1495    /// Sets a custom [`RpcModuleConfig`] for the configured modules.
1496    pub fn with_config(mut self, config: RpcModuleConfig) -> Self {
1497        self.config = Some(config);
1498        self
1499    }
1500
1501    /// Get a mutable reference to the
1502    pub const fn http_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1503        &mut self.http
1504    }
1505
1506    /// Get a mutable reference to the
1507    pub const fn ws_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1508        &mut self.ws
1509    }
1510
1511    /// Get a mutable reference to the
1512    pub const fn ipc_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1513        &mut self.ipc
1514    }
1515
1516    /// Get a mutable reference to the
1517    pub const fn config_mut(&mut self) -> &mut Option<RpcModuleConfig> {
1518        &mut self.config
1519    }
1520
1521    /// Returns true if no transports are configured
1522    pub const fn is_empty(&self) -> bool {
1523        self.http.is_none() && self.ws.is_none() && self.ipc.is_none()
1524    }
1525
1526    /// Returns the [`RpcModuleSelection`] for the http transport
1527    pub const fn http(&self) -> Option<&RpcModuleSelection> {
1528        self.http.as_ref()
1529    }
1530
1531    /// Returns the [`RpcModuleSelection`] for the ws transport
1532    pub const fn ws(&self) -> Option<&RpcModuleSelection> {
1533        self.ws.as_ref()
1534    }
1535
1536    /// Returns the [`RpcModuleSelection`] for the ipc transport
1537    pub const fn ipc(&self) -> Option<&RpcModuleSelection> {
1538        self.ipc.as_ref()
1539    }
1540
1541    /// Returns the [`RpcModuleConfig`] for the configured modules
1542    pub const fn config(&self) -> Option<&RpcModuleConfig> {
1543        self.config.as_ref()
1544    }
1545
1546    /// Returns true if the given module is configured for any transport.
1547    pub fn contains_any(&self, module: &RethRpcModule) -> bool {
1548        self.contains_http(module) || self.contains_ws(module) || self.contains_ipc(module)
1549    }
1550
1551    /// Returns true if the given module is configured for the http transport.
1552    pub fn contains_http(&self, module: &RethRpcModule) -> bool {
1553        self.http.as_ref().is_some_and(|http| http.contains(module))
1554    }
1555
1556    /// Returns true if the given module is configured for the ws transport.
1557    pub fn contains_ws(&self, module: &RethRpcModule) -> bool {
1558        self.ws.as_ref().is_some_and(|ws| ws.contains(module))
1559    }
1560
1561    /// Returns true if the given module is configured for the ipc transport.
1562    pub fn contains_ipc(&self, module: &RethRpcModule) -> bool {
1563        self.ipc.as_ref().is_some_and(|ipc| ipc.contains(module))
1564    }
1565
1566    /// Ensures that both http and ws are configured and that they are configured to use the same
1567    /// port.
1568    fn ensure_ws_http_identical(&self) -> Result<(), WsHttpSamePortError> {
1569        if RpcModuleSelection::are_identical(self.http.as_ref(), self.ws.as_ref()) {
1570            Ok(())
1571        } else {
1572            let http_modules =
1573                self.http.as_ref().map(RpcModuleSelection::to_selection).unwrap_or_default();
1574            let ws_modules =
1575                self.ws.as_ref().map(RpcModuleSelection::to_selection).unwrap_or_default();
1576
1577            let http_not_ws = http_modules.difference(&ws_modules).copied().collect();
1578            let ws_not_http = ws_modules.difference(&http_modules).copied().collect();
1579            let overlap = http_modules.intersection(&ws_modules).copied().collect();
1580
1581            Err(WsHttpSamePortError::ConflictingModules(Box::new(ConflictingModules {
1582                overlap,
1583                http_not_ws,
1584                ws_not_http,
1585            })))
1586        }
1587    }
1588}
1589
1590/// Holds installed modules per transport type.
1591#[derive(Debug, Clone, Default)]
1592pub struct TransportRpcModules<Context = ()> {
1593    /// The original config
1594    config: TransportRpcModuleConfig,
1595    /// rpcs module for http
1596    http: Option<RpcModule<Context>>,
1597    /// rpcs module for ws
1598    ws: Option<RpcModule<Context>>,
1599    /// rpcs module for ipc
1600    ipc: Option<RpcModule<Context>>,
1601}
1602
1603// === impl TransportRpcModules ===
1604
1605impl TransportRpcModules {
1606    /// Sets a custom [`TransportRpcModuleConfig`] for the configured modules.
1607    /// This will overwrite current configuration, if any.
1608    pub fn with_config(mut self, config: TransportRpcModuleConfig) -> Self {
1609        self.config = config;
1610        self
1611    }
1612
1613    /// Sets the [`RpcModule`] for the http transport.
1614    /// This will overwrite current module, if any.
1615    pub fn with_http(mut self, http: RpcModule<()>) -> Self {
1616        self.http = Some(http);
1617        self
1618    }
1619
1620    /// Sets the [`RpcModule`] for the ws transport.
1621    /// This will overwrite current module, if any.
1622    pub fn with_ws(mut self, ws: RpcModule<()>) -> Self {
1623        self.ws = Some(ws);
1624        self
1625    }
1626
1627    /// Sets the [`RpcModule`] for the http transport.
1628    /// This will overwrite current module, if any.
1629    pub fn with_ipc(mut self, ipc: RpcModule<()>) -> Self {
1630        self.ipc = Some(ipc);
1631        self
1632    }
1633
1634    /// Returns the [`TransportRpcModuleConfig`] used to configure this instance.
1635    pub const fn module_config(&self) -> &TransportRpcModuleConfig {
1636        &self.config
1637    }
1638
1639    /// Merge the given [`Methods`] in all configured transport modules if the given
1640    /// [`RethRpcModule`] is configured for the transport.
1641    ///
1642    /// Fails if any of the methods in other is present already.
1643    pub fn merge_if_module_configured(
1644        &mut self,
1645        module: RethRpcModule,
1646        other: impl Into<Methods>,
1647    ) -> Result<(), RegisterMethodError> {
1648        let other = other.into();
1649        if self.module_config().contains_http(&module) {
1650            self.merge_http(other.clone())?;
1651        }
1652        if self.module_config().contains_ws(&module) {
1653            self.merge_ws(other.clone())?;
1654        }
1655        if self.module_config().contains_ipc(&module) {
1656            self.merge_ipc(other)?;
1657        }
1658
1659        Ok(())
1660    }
1661
1662    /// Merge the given [Methods] in the configured http methods.
1663    ///
1664    /// Fails if any of the methods in other is present already.
1665    ///
1666    /// Returns [Ok(false)] if no http transport is configured.
1667    pub fn merge_http(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1668        if let Some(ref mut http) = self.http {
1669            return http.merge(other.into()).map(|_| true)
1670        }
1671        Ok(false)
1672    }
1673
1674    /// Merge the given [Methods] in the configured ws methods.
1675    ///
1676    /// Fails if any of the methods in other is present already.
1677    ///
1678    /// Returns [Ok(false)] if no ws transport is configured.
1679    pub fn merge_ws(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1680        if let Some(ref mut ws) = self.ws {
1681            return ws.merge(other.into()).map(|_| true)
1682        }
1683        Ok(false)
1684    }
1685
1686    /// Merge the given [Methods] in the configured ipc methods.
1687    ///
1688    /// Fails if any of the methods in other is present already.
1689    ///
1690    /// Returns [Ok(false)] if no ipc transport is configured.
1691    pub fn merge_ipc(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1692        if let Some(ref mut ipc) = self.ipc {
1693            return ipc.merge(other.into()).map(|_| true)
1694        }
1695        Ok(false)
1696    }
1697
1698    /// Merge the given [`Methods`] in all configured methods.
1699    ///
1700    /// Fails if any of the methods in other is present already.
1701    pub fn merge_configured(
1702        &mut self,
1703        other: impl Into<Methods>,
1704    ) -> Result<(), RegisterMethodError> {
1705        let other = other.into();
1706        self.merge_http(other.clone())?;
1707        self.merge_ws(other.clone())?;
1708        self.merge_ipc(other)?;
1709        Ok(())
1710    }
1711
1712    /// Returns all unique endpoints installed for the given module.
1713    ///
1714    /// Note: In case of duplicate method names this only record the first occurrence.
1715    pub fn methods_by_module<F>(&self, module: RethRpcModule) -> Methods {
1716        self.methods_by(|name| name.starts_with(module.as_str()))
1717    }
1718
1719    /// Returns all unique endpoints installed in any of the configured modules.
1720    ///
1721    /// Note: In case of duplicate method names this only record the first occurrence.
1722    pub fn methods_by<F>(&self, mut filter: F) -> Methods
1723    where
1724        F: FnMut(&str) -> bool,
1725    {
1726        let mut methods = Methods::new();
1727
1728        // filter that matches the given filter and also removes duplicates we already have
1729        let mut f =
1730            |name: &str, mm: &Methods| filter(name) && !mm.method_names().any(|m| m == name);
1731
1732        if let Some(m) = self.http_methods(|name| f(name, &methods)) {
1733            let _ = methods.merge(m);
1734        }
1735        if let Some(m) = self.ws_methods(|name| f(name, &methods)) {
1736            let _ = methods.merge(m);
1737        }
1738        if let Some(m) = self.ipc_methods(|name| f(name, &methods)) {
1739            let _ = methods.merge(m);
1740        }
1741        methods
1742    }
1743
1744    /// Returns all [`Methods`] installed for the http server based in the given closure.
1745    ///
1746    /// Returns `None` if no http support is configured.
1747    pub fn http_methods<F>(&self, filter: F) -> Option<Methods>
1748    where
1749        F: FnMut(&str) -> bool,
1750    {
1751        self.http.as_ref().map(|module| methods_by(module, filter))
1752    }
1753
1754    /// Returns all [`Methods`] installed for the ws server based in the given closure.
1755    ///
1756    /// Returns `None` if no ws support is configured.
1757    pub fn ws_methods<F>(&self, filter: F) -> Option<Methods>
1758    where
1759        F: FnMut(&str) -> bool,
1760    {
1761        self.ws.as_ref().map(|module| methods_by(module, filter))
1762    }
1763
1764    /// Returns all [`Methods`] installed for the ipc server based in the given closure.
1765    ///
1766    /// Returns `None` if no ipc support is configured.
1767    pub fn ipc_methods<F>(&self, filter: F) -> Option<Methods>
1768    where
1769        F: FnMut(&str) -> bool,
1770    {
1771        self.ipc.as_ref().map(|module| methods_by(module, filter))
1772    }
1773
1774    /// Removes the method with the given name from the configured http methods.
1775    ///
1776    /// Returns `true` if the method was found and removed, `false` otherwise.
1777    ///
1778    /// Be aware that a subscription consist of two methods, `subscribe` and `unsubscribe` and
1779    /// it's the caller responsibility to remove both `subscribe` and `unsubscribe` methods for
1780    /// subscriptions.
1781    pub fn remove_http_method(&mut self, method_name: &'static str) -> bool {
1782        if let Some(http_module) = &mut self.http {
1783            http_module.remove_method(method_name).is_some()
1784        } else {
1785            false
1786        }
1787    }
1788
1789    /// Removes the given methods from the configured http methods.
1790    pub fn remove_http_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
1791        for name in methods {
1792            self.remove_http_method(name);
1793        }
1794    }
1795
1796    /// Removes the method with the given name from the configured ws methods.
1797    ///
1798    /// Returns `true` if the method was found and removed, `false` otherwise.
1799    ///
1800    /// Be aware that a subscription consist of two methods, `subscribe` and `unsubscribe` and
1801    /// it's the caller responsibility to remove both `subscribe` and `unsubscribe` methods for
1802    /// subscriptions.
1803    pub fn remove_ws_method(&mut self, method_name: &'static str) -> bool {
1804        if let Some(ws_module) = &mut self.ws {
1805            ws_module.remove_method(method_name).is_some()
1806        } else {
1807            false
1808        }
1809    }
1810
1811    /// Removes the given methods from the configured ws methods.
1812    pub fn remove_ws_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
1813        for name in methods {
1814            self.remove_ws_method(name);
1815        }
1816    }
1817
1818    /// Removes the method with the given name from the configured ipc methods.
1819    ///
1820    /// Returns `true` if the method was found and removed, `false` otherwise.
1821    ///
1822    /// Be aware that a subscription consist of two methods, `subscribe` and `unsubscribe` and
1823    /// it's the caller responsibility to remove both `subscribe` and `unsubscribe` methods for
1824    /// subscriptions.
1825    pub fn remove_ipc_method(&mut self, method_name: &'static str) -> bool {
1826        if let Some(ipc_module) = &mut self.ipc {
1827            ipc_module.remove_method(method_name).is_some()
1828        } else {
1829            false
1830        }
1831    }
1832
1833    /// Removes the given methods from the configured ipc methods.
1834    pub fn remove_ipc_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
1835        for name in methods {
1836            self.remove_ipc_method(name);
1837        }
1838    }
1839
1840    /// Removes the method with the given name from all configured transports.
1841    ///
1842    /// Returns `true` if the method was found and removed, `false` otherwise.
1843    pub fn remove_method_from_configured(&mut self, method_name: &'static str) -> bool {
1844        let http_removed = self.remove_http_method(method_name);
1845        let ws_removed = self.remove_ws_method(method_name);
1846        let ipc_removed = self.remove_ipc_method(method_name);
1847
1848        http_removed || ws_removed || ipc_removed
1849    }
1850
1851    /// Renames a method in all configured transports by:
1852    /// 1. Removing the old method name.
1853    /// 2. Adding the new method.
1854    pub fn rename(
1855        &mut self,
1856        old_name: &'static str,
1857        new_method: impl Into<Methods>,
1858    ) -> Result<(), RegisterMethodError> {
1859        // Remove the old method from all configured transports
1860        self.remove_method_from_configured(old_name);
1861
1862        // Merge the new method into the configured transports
1863        self.merge_configured(new_method)
1864    }
1865
1866    /// Replace the given [`Methods`] in the configured http methods.
1867    ///
1868    /// Fails if any of the methods in other is present already or if the method being removed is
1869    /// not present
1870    ///
1871    /// Returns [Ok(false)] if no http transport is configured.
1872    pub fn replace_http(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1873        let other = other.into();
1874        self.remove_http_methods(other.method_names());
1875        self.merge_http(other)
1876    }
1877
1878    /// Replace the given [Methods] in the configured ipc methods.
1879    ///
1880    /// Fails if any of the methods in other is present already or if the method being removed is
1881    /// not present
1882    ///
1883    /// Returns [Ok(false)] if no ipc transport is configured.
1884    pub fn replace_ipc(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1885        let other = other.into();
1886        self.remove_ipc_methods(other.method_names());
1887        self.merge_ipc(other)
1888    }
1889
1890    /// Replace the given [Methods] in the configured ws methods.
1891    ///
1892    /// Fails if any of the methods in other is present already or if the method being removed is
1893    /// not present
1894    ///
1895    /// Returns [Ok(false)] if no ws transport is configured.
1896    pub fn replace_ws(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1897        let other = other.into();
1898        self.remove_ws_methods(other.method_names());
1899        self.merge_ws(other)
1900    }
1901
1902    /// Replaces the method with the given name from all configured transports.
1903    ///
1904    /// Returns `true` if the method was found and replaced, `false` otherwise
1905    pub fn replace_configured(
1906        &mut self,
1907        other: impl Into<Methods>,
1908    ) -> Result<bool, RegisterMethodError> {
1909        let other = other.into();
1910        self.replace_http(other.clone())?;
1911        self.replace_ws(other.clone())?;
1912        self.replace_ipc(other)?;
1913        Ok(true)
1914    }
1915
1916    /// Adds or replaces given [`Methods`] in http module.
1917    ///
1918    /// Returns `true` if the methods were replaced or added, `false` otherwise.
1919    pub fn add_or_replace_http(
1920        &mut self,
1921        other: impl Into<Methods>,
1922    ) -> Result<bool, RegisterMethodError> {
1923        let other = other.into();
1924        self.remove_http_methods(other.method_names());
1925        self.merge_http(other)
1926    }
1927
1928    /// Adds or replaces given [`Methods`] in ws module.
1929    ///
1930    /// Returns `true` if the methods were replaced or added, `false` otherwise.
1931    pub fn add_or_replace_ws(
1932        &mut self,
1933        other: impl Into<Methods>,
1934    ) -> Result<bool, RegisterMethodError> {
1935        let other = other.into();
1936        self.remove_ws_methods(other.method_names());
1937        self.merge_ws(other)
1938    }
1939
1940    /// Adds or replaces given [`Methods`] in ipc module.
1941    ///
1942    /// Returns `true` if the methods were replaced or added, `false` otherwise.
1943    pub fn add_or_replace_ipc(
1944        &mut self,
1945        other: impl Into<Methods>,
1946    ) -> Result<bool, RegisterMethodError> {
1947        let other = other.into();
1948        self.remove_ipc_methods(other.method_names());
1949        self.merge_ipc(other)
1950    }
1951
1952    /// Adds or replaces given [`Methods`] in all configured network modules.
1953    pub fn add_or_replace_configured(
1954        &mut self,
1955        other: impl Into<Methods>,
1956    ) -> Result<(), RegisterMethodError> {
1957        let other = other.into();
1958        self.add_or_replace_http(other.clone())?;
1959        self.add_or_replace_ws(other.clone())?;
1960        self.add_or_replace_ipc(other)?;
1961        Ok(())
1962    }
1963}
1964
1965/// Returns the methods installed in the given module that match the given filter.
1966fn methods_by<T, F>(module: &RpcModule<T>, mut filter: F) -> Methods
1967where
1968    F: FnMut(&str) -> bool,
1969{
1970    let mut methods = Methods::new();
1971    let method_names = module.method_names().filter(|name| filter(name));
1972
1973    for name in method_names {
1974        if let Some(matched_method) = module.method(name).cloned() {
1975            let _ = methods.verify_and_insert(name, matched_method);
1976        }
1977    }
1978
1979    methods
1980}
1981
1982/// A handle to the spawned servers.
1983///
1984/// When this type is dropped or [`RpcServerHandle::stop`] has been called the server will be
1985/// stopped.
1986#[derive(Clone, Debug)]
1987#[must_use = "Server stops if dropped"]
1988pub struct RpcServerHandle {
1989    /// The address of the http/ws server
1990    http_local_addr: Option<SocketAddr>,
1991    ws_local_addr: Option<SocketAddr>,
1992    http: Option<ServerHandle>,
1993    ws: Option<ServerHandle>,
1994    ipc_endpoint: Option<String>,
1995    ipc: Option<jsonrpsee::server::ServerHandle>,
1996    jwt_secret: Option<JwtSecret>,
1997}
1998
1999// === impl RpcServerHandle ===
2000
2001impl RpcServerHandle {
2002    /// Configures the JWT secret for authentication.
2003    fn bearer_token(&self) -> Option<String> {
2004        self.jwt_secret.as_ref().map(|secret| {
2005            format!(
2006                "Bearer {}",
2007                secret
2008                    .encode(&Claims {
2009                        iat: (SystemTime::now().duration_since(UNIX_EPOCH).unwrap() +
2010                            Duration::from_secs(60))
2011                        .as_secs(),
2012                        exp: None,
2013                    })
2014                    .unwrap()
2015            )
2016        })
2017    }
2018    /// Returns the [`SocketAddr`] of the http server if started.
2019    pub const fn http_local_addr(&self) -> Option<SocketAddr> {
2020        self.http_local_addr
2021    }
2022
2023    /// Returns the [`SocketAddr`] of the ws server if started.
2024    pub const fn ws_local_addr(&self) -> Option<SocketAddr> {
2025        self.ws_local_addr
2026    }
2027
2028    /// Tell the server to stop without waiting for the server to stop.
2029    pub fn stop(self) -> Result<(), AlreadyStoppedError> {
2030        if let Some(handle) = self.http {
2031            handle.stop()?
2032        }
2033
2034        if let Some(handle) = self.ws {
2035            handle.stop()?
2036        }
2037
2038        if let Some(handle) = self.ipc {
2039            handle.stop()?
2040        }
2041
2042        Ok(())
2043    }
2044
2045    /// Returns the endpoint of the launched IPC server, if any
2046    pub fn ipc_endpoint(&self) -> Option<String> {
2047        self.ipc_endpoint.clone()
2048    }
2049
2050    /// Returns the url to the http server
2051    pub fn http_url(&self) -> Option<String> {
2052        self.http_local_addr.map(|addr| format!("http://{addr}"))
2053    }
2054
2055    /// Returns the url to the ws server
2056    pub fn ws_url(&self) -> Option<String> {
2057        self.ws_local_addr.map(|addr| format!("ws://{addr}"))
2058    }
2059
2060    /// Returns a http client connected to the server.
2061    pub fn http_client(&self) -> Option<jsonrpsee::http_client::HttpClient> {
2062        let url = self.http_url()?;
2063
2064        let client = if let Some(token) = self.bearer_token() {
2065            jsonrpsee::http_client::HttpClientBuilder::default()
2066                .set_headers(HeaderMap::from_iter([(AUTHORIZATION, token.parse().unwrap())]))
2067                .build(url)
2068        } else {
2069            jsonrpsee::http_client::HttpClientBuilder::default().build(url)
2070        };
2071
2072        client.expect("failed to create http client").into()
2073    }
2074
2075    /// Returns a ws client connected to the server.
2076    pub async fn ws_client(&self) -> Option<jsonrpsee::ws_client::WsClient> {
2077        let url = self.ws_url()?;
2078        let mut builder = jsonrpsee::ws_client::WsClientBuilder::default();
2079
2080        if let Some(token) = self.bearer_token() {
2081            let headers = HeaderMap::from_iter([(AUTHORIZATION, token.parse().unwrap())]);
2082            builder = builder.set_headers(headers);
2083        }
2084
2085        let client = builder.build(url).await.expect("failed to create ws client");
2086        Some(client)
2087    }
2088
2089    /// Returns a new [`alloy_network::Ethereum`] http provider with its recommended fillers.
2090    pub fn eth_http_provider(
2091        &self,
2092    ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2093        self.new_http_provider_for()
2094    }
2095
2096    /// Returns a new [`alloy_network::Ethereum`] http provider with its recommended fillers and
2097    /// installed wallet.
2098    pub fn eth_http_provider_with_wallet<W>(
2099        &self,
2100        wallet: W,
2101    ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static>
2102    where
2103        W: IntoWallet<alloy_network::Ethereum, NetworkWallet: Clone + Unpin + 'static>,
2104    {
2105        let rpc_url = self.http_url()?;
2106        let provider =
2107            ProviderBuilder::new().wallet(wallet).connect_http(rpc_url.parse().expect("valid url"));
2108        Some(provider)
2109    }
2110
2111    /// Returns an http provider from the rpc server handle for the
2112    /// specified [`alloy_network::Network`].
2113    ///
2114    /// This installs the recommended fillers: [`RecommendedFillers`]
2115    pub fn new_http_provider_for<N>(&self) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2116    where
2117        N: RecommendedFillers<RecommendedFillers: Unpin>,
2118    {
2119        let rpc_url = self.http_url()?;
2120        let provider = ProviderBuilder::default()
2121            .with_recommended_fillers()
2122            .connect_http(rpc_url.parse().expect("valid url"));
2123        Some(provider)
2124    }
2125
2126    /// Returns a new [`alloy_network::Ethereum`] websocket provider with its recommended fillers.
2127    pub async fn eth_ws_provider(
2128        &self,
2129    ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2130        self.new_ws_provider_for().await
2131    }
2132
2133    /// Returns a new [`alloy_network::Ethereum`] ws provider with its recommended fillers and
2134    /// installed wallet.
2135    pub async fn eth_ws_provider_with_wallet<W>(
2136        &self,
2137        wallet: W,
2138    ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static>
2139    where
2140        W: IntoWallet<alloy_network::Ethereum, NetworkWallet: Clone + Unpin + 'static>,
2141    {
2142        let rpc_url = self.ws_url()?;
2143        let provider = ProviderBuilder::new()
2144            .wallet(wallet)
2145            .connect(&rpc_url)
2146            .await
2147            .expect("failed to create ws client");
2148        Some(provider)
2149    }
2150
2151    /// Returns an ws provider from the rpc server handle for the
2152    /// specified [`alloy_network::Network`].
2153    ///
2154    /// This installs the recommended fillers: [`RecommendedFillers`]
2155    pub async fn new_ws_provider_for<N>(&self) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2156    where
2157        N: RecommendedFillers<RecommendedFillers: Unpin>,
2158    {
2159        let rpc_url = self.ws_url()?;
2160        let provider = ProviderBuilder::default()
2161            .with_recommended_fillers()
2162            .connect(&rpc_url)
2163            .await
2164            .expect("failed to create ws client");
2165        Some(provider)
2166    }
2167
2168    /// Returns a new [`alloy_network::Ethereum`] ipc provider with its recommended fillers.
2169    pub async fn eth_ipc_provider(
2170        &self,
2171    ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2172        self.new_ipc_provider_for().await
2173    }
2174
2175    /// Returns an ipc provider from the rpc server handle for the
2176    /// specified [`alloy_network::Network`].
2177    ///
2178    /// This installs the recommended fillers: [`RecommendedFillers`]
2179    pub async fn new_ipc_provider_for<N>(
2180        &self,
2181    ) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2182    where
2183        N: RecommendedFillers<RecommendedFillers: Unpin>,
2184    {
2185        let rpc_url = self.ipc_endpoint()?;
2186        let provider = ProviderBuilder::default()
2187            .with_recommended_fillers()
2188            .connect(&rpc_url)
2189            .await
2190            .expect("failed to create ipc client");
2191        Some(provider)
2192    }
2193}
2194
2195#[cfg(test)]
2196mod tests {
2197    use super::*;
2198
2199    #[test]
2200    fn parse_eth_call_bundle_selection() {
2201        let selection = "eth,admin,debug".parse::<RpcModuleSelection>().unwrap();
2202        assert_eq!(
2203            selection,
2204            RpcModuleSelection::Selection(
2205                [RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Debug,].into()
2206            )
2207        );
2208    }
2209
2210    #[test]
2211    fn parse_rpc_module_selection() {
2212        let selection = "all".parse::<RpcModuleSelection>().unwrap();
2213        assert_eq!(selection, RpcModuleSelection::All);
2214    }
2215
2216    #[test]
2217    fn parse_rpc_module_selection_none() {
2218        let selection = "none".parse::<RpcModuleSelection>().unwrap();
2219        assert_eq!(selection, RpcModuleSelection::Selection(Default::default()));
2220    }
2221
2222    #[test]
2223    fn parse_rpc_unique_module_selection() {
2224        let selection = "eth,admin,eth,net".parse::<RpcModuleSelection>().unwrap();
2225        assert_eq!(
2226            selection,
2227            RpcModuleSelection::Selection(
2228                [RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Net,].into()
2229            )
2230        );
2231    }
2232
2233    #[test]
2234    fn identical_selection() {
2235        assert!(RpcModuleSelection::are_identical(
2236            Some(&RpcModuleSelection::All),
2237            Some(&RpcModuleSelection::All),
2238        ));
2239        assert!(!RpcModuleSelection::are_identical(
2240            Some(&RpcModuleSelection::All),
2241            Some(&RpcModuleSelection::Standard),
2242        ));
2243        assert!(RpcModuleSelection::are_identical(
2244            Some(&RpcModuleSelection::Selection(RpcModuleSelection::Standard.to_selection())),
2245            Some(&RpcModuleSelection::Standard),
2246        ));
2247        assert!(RpcModuleSelection::are_identical(
2248            Some(&RpcModuleSelection::Selection([RethRpcModule::Eth].into())),
2249            Some(&RpcModuleSelection::Selection([RethRpcModule::Eth].into())),
2250        ));
2251        assert!(RpcModuleSelection::are_identical(
2252            None,
2253            Some(&RpcModuleSelection::Selection(Default::default())),
2254        ));
2255        assert!(RpcModuleSelection::are_identical(
2256            Some(&RpcModuleSelection::Selection(Default::default())),
2257            None,
2258        ));
2259        assert!(RpcModuleSelection::are_identical(None, None));
2260    }
2261
2262    #[test]
2263    fn test_rpc_module_str() {
2264        macro_rules! assert_rpc_module {
2265            ($($s:expr => $v:expr,)*) => {
2266                $(
2267                    let val: RethRpcModule  = $s.parse().unwrap();
2268                    assert_eq!(val, $v);
2269                    assert_eq!(val.to_string().as_str(), $s);
2270                )*
2271            };
2272        }
2273        assert_rpc_module!
2274        (
2275                "admin" =>  RethRpcModule::Admin,
2276                "debug" =>  RethRpcModule::Debug,
2277                "eth" =>  RethRpcModule::Eth,
2278                "net" =>  RethRpcModule::Net,
2279                "trace" =>  RethRpcModule::Trace,
2280                "web3" =>  RethRpcModule::Web3,
2281                "rpc" => RethRpcModule::Rpc,
2282                "ots" => RethRpcModule::Ots,
2283                "reth" => RethRpcModule::Reth,
2284            );
2285    }
2286
2287    #[test]
2288    fn test_default_selection() {
2289        let selection = RpcModuleSelection::Standard.to_selection();
2290        assert_eq!(selection, [RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3].into())
2291    }
2292
2293    #[test]
2294    fn test_create_rpc_module_config() {
2295        let selection = vec!["eth", "admin"];
2296        let config = RpcModuleSelection::try_from_selection(selection).unwrap();
2297        assert_eq!(
2298            config,
2299            RpcModuleSelection::Selection([RethRpcModule::Eth, RethRpcModule::Admin].into())
2300        );
2301    }
2302
2303    #[test]
2304    fn test_configure_transport_config() {
2305        let config = TransportRpcModuleConfig::default()
2306            .with_http([RethRpcModule::Eth, RethRpcModule::Admin]);
2307        assert_eq!(
2308            config,
2309            TransportRpcModuleConfig {
2310                http: Some(RpcModuleSelection::Selection(
2311                    [RethRpcModule::Eth, RethRpcModule::Admin].into()
2312                )),
2313                ws: None,
2314                ipc: None,
2315                config: None,
2316            }
2317        )
2318    }
2319
2320    #[test]
2321    fn test_configure_transport_config_none() {
2322        let config = TransportRpcModuleConfig::default().with_http(Vec::<RethRpcModule>::new());
2323        assert_eq!(
2324            config,
2325            TransportRpcModuleConfig {
2326                http: Some(RpcModuleSelection::Selection(Default::default())),
2327                ws: None,
2328                ipc: None,
2329                config: None,
2330            }
2331        )
2332    }
2333
2334    fn create_test_module() -> RpcModule<()> {
2335        let mut module = RpcModule::new(());
2336        module.register_method("anything", |_, _, _| "succeed").unwrap();
2337        module
2338    }
2339
2340    #[test]
2341    fn test_remove_http_method() {
2342        let mut modules =
2343            TransportRpcModules { http: Some(create_test_module()), ..Default::default() };
2344        // Remove a method that exists
2345        assert!(modules.remove_http_method("anything"));
2346
2347        // Remove a method that does not exist
2348        assert!(!modules.remove_http_method("non_existent_method"));
2349
2350        // Verify that the method was removed
2351        assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2352    }
2353
2354    #[test]
2355    fn test_remove_ws_method() {
2356        let mut modules =
2357            TransportRpcModules { ws: Some(create_test_module()), ..Default::default() };
2358
2359        // Remove a method that exists
2360        assert!(modules.remove_ws_method("anything"));
2361
2362        // Remove a method that does not exist
2363        assert!(!modules.remove_ws_method("non_existent_method"));
2364
2365        // Verify that the method was removed
2366        assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2367    }
2368
2369    #[test]
2370    fn test_remove_ipc_method() {
2371        let mut modules =
2372            TransportRpcModules { ipc: Some(create_test_module()), ..Default::default() };
2373
2374        // Remove a method that exists
2375        assert!(modules.remove_ipc_method("anything"));
2376
2377        // Remove a method that does not exist
2378        assert!(!modules.remove_ipc_method("non_existent_method"));
2379
2380        // Verify that the method was removed
2381        assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2382    }
2383
2384    #[test]
2385    fn test_remove_method_from_configured() {
2386        let mut modules = TransportRpcModules {
2387            http: Some(create_test_module()),
2388            ws: Some(create_test_module()),
2389            ipc: Some(create_test_module()),
2390            ..Default::default()
2391        };
2392
2393        // Remove a method that exists
2394        assert!(modules.remove_method_from_configured("anything"));
2395
2396        // Remove a method that was just removed (it does not exist anymore)
2397        assert!(!modules.remove_method_from_configured("anything"));
2398
2399        // Remove a method that does not exist
2400        assert!(!modules.remove_method_from_configured("non_existent_method"));
2401
2402        // Verify that the method was removed from all transports
2403        assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2404        assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2405        assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2406    }
2407
2408    #[test]
2409    fn test_transport_rpc_module_rename() {
2410        let mut modules = TransportRpcModules {
2411            http: Some(create_test_module()),
2412            ws: Some(create_test_module()),
2413            ipc: Some(create_test_module()),
2414            ..Default::default()
2415        };
2416
2417        // Verify that the old we want to rename exists at the start
2418        assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2419        assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2420        assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2421
2422        // Verify that the new method does not exist at the start
2423        assert!(modules.http.as_ref().unwrap().method("something").is_none());
2424        assert!(modules.ws.as_ref().unwrap().method("something").is_none());
2425        assert!(modules.ipc.as_ref().unwrap().method("something").is_none());
2426
2427        // Create another module
2428        let mut other_module = RpcModule::new(());
2429        other_module.register_method("something", |_, _, _| "fails").unwrap();
2430
2431        // Rename the method
2432        modules.rename("anything", other_module).expect("rename failed");
2433
2434        // Verify that the old method was removed from all transports
2435        assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2436        assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2437        assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2438
2439        // Verify that the new method was added to all transports
2440        assert!(modules.http.as_ref().unwrap().method("something").is_some());
2441        assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2442        assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2443    }
2444
2445    #[test]
2446    fn test_replace_http_method() {
2447        let mut modules =
2448            TransportRpcModules { http: Some(create_test_module()), ..Default::default() };
2449
2450        let mut other_module = RpcModule::new(());
2451        other_module.register_method("something", |_, _, _| "fails").unwrap();
2452
2453        assert!(modules.replace_http(other_module.clone()).unwrap());
2454
2455        assert!(modules.http.as_ref().unwrap().method("something").is_some());
2456
2457        other_module.register_method("anything", |_, _, _| "fails").unwrap();
2458        assert!(modules.replace_http(other_module.clone()).unwrap());
2459
2460        assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2461    }
2462    #[test]
2463    fn test_replace_ipc_method() {
2464        let mut modules =
2465            TransportRpcModules { ipc: Some(create_test_module()), ..Default::default() };
2466
2467        let mut other_module = RpcModule::new(());
2468        other_module.register_method("something", |_, _, _| "fails").unwrap();
2469
2470        assert!(modules.replace_ipc(other_module.clone()).unwrap());
2471
2472        assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2473
2474        other_module.register_method("anything", |_, _, _| "fails").unwrap();
2475        assert!(modules.replace_ipc(other_module.clone()).unwrap());
2476
2477        assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2478    }
2479    #[test]
2480    fn test_replace_ws_method() {
2481        let mut modules =
2482            TransportRpcModules { ws: Some(create_test_module()), ..Default::default() };
2483
2484        let mut other_module = RpcModule::new(());
2485        other_module.register_method("something", |_, _, _| "fails").unwrap();
2486
2487        assert!(modules.replace_ws(other_module.clone()).unwrap());
2488
2489        assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2490
2491        other_module.register_method("anything", |_, _, _| "fails").unwrap();
2492        assert!(modules.replace_ws(other_module.clone()).unwrap());
2493
2494        assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2495    }
2496
2497    #[test]
2498    fn test_replace_configured() {
2499        let mut modules = TransportRpcModules {
2500            http: Some(create_test_module()),
2501            ws: Some(create_test_module()),
2502            ipc: Some(create_test_module()),
2503            ..Default::default()
2504        };
2505        let mut other_module = RpcModule::new(());
2506        other_module.register_method("something", |_, _, _| "fails").unwrap();
2507
2508        assert!(modules.replace_configured(other_module).unwrap());
2509
2510        // Verify that the other_method was added
2511        assert!(modules.http.as_ref().unwrap().method("something").is_some());
2512        assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2513        assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2514
2515        assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2516        assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2517        assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2518    }
2519}