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