1#![doc(
15 html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
16 html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
17 issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
18)]
19#![cfg_attr(not(test), warn(unused_crate_dependencies))]
20#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
21
22use crate::{auth::AuthRpcModule, error::WsHttpSamePortError, metrics::RpcRequestMetrics};
23use alloy_network::{Ethereum, IntoWallet};
24use alloy_provider::{fillers::RecommendedFillers, Provider, ProviderBuilder};
25use core::marker::PhantomData;
26use error::{ConflictingModules, RpcError, ServerKind};
27use http::{header::AUTHORIZATION, HeaderMap};
28use jsonrpsee::{
29 core::RegisterMethodError,
30 server::{middleware::rpc::RpcServiceBuilder, AlreadyStoppedError, IdProvider, ServerHandle},
31 Methods, RpcModule,
32};
33use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
34use reth_consensus::{ConsensusError, FullConsensus};
35use reth_evm::ConfigureEvm;
36use reth_network_api::{noop::NoopNetwork, NetworkInfo, Peers};
37use reth_primitives_traits::NodePrimitives;
38use reth_rpc::{
39 AdminApi, DebugApi, EngineEthApi, EthApi, EthApiBuilder, EthBundle, MinerApi, NetApi,
40 OtterscanApi, RPCApi, RethApi, TraceApi, TxPoolApi, ValidationApiConfig, Web3Api,
41};
42use reth_rpc_api::servers::*;
43use reth_rpc_eth_api::{
44 helpers::{
45 pending_block::PendingEnvBuilder, Call, EthApiSpec, EthTransactions, LoadPendingBlock,
46 TraceExt,
47 },
48 node::RpcNodeCoreAdapter,
49 EthApiServer, EthApiTypes, FullEthApiServer, RpcBlock, RpcConvert, RpcConverter, RpcHeader,
50 RpcNodeCore, RpcReceipt, RpcTransaction, RpcTxReq,
51};
52use reth_rpc_eth_types::{receipt::EthReceiptConverter, EthConfig, EthSubscriptionIdProvider};
53use reth_rpc_layer::{AuthLayer, Claims, CompressionLayer, JwtAuthValidator, JwtSecret};
54use reth_storage_api::{
55 AccountReader, BlockReader, ChangeSetReader, FullRpcProvider, ProviderBlock,
56 StateProviderFactory,
57};
58use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor};
59use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool};
60use serde::{Deserialize, Serialize};
61use std::{
62 collections::HashMap,
63 fmt::Debug,
64 net::{Ipv4Addr, SocketAddr, SocketAddrV4},
65 time::{Duration, SystemTime, UNIX_EPOCH},
66};
67use tower_http::cors::CorsLayer;
68
69pub use cors::CorsDomainError;
70
71pub use jsonrpsee::server::ServerBuilder;
73use jsonrpsee::server::ServerConfigBuilder;
74pub use reth_ipc::server::{
75 Builder as IpcServerBuilder, RpcServiceBuilder as IpcRpcServiceBuilder,
76};
77pub use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection};
78pub use tower::layer::util::{Identity, Stack};
79
80pub mod auth;
82
83pub mod config;
85
86pub mod middleware;
88
89mod cors;
91
92pub mod error;
94
95pub mod eth;
97pub use eth::EthHandlers;
98
99mod metrics;
101use crate::middleware::RethRpcMiddleware;
102pub use metrics::{MeteredRequestFuture, RpcRequestMetricsService};
103use reth_chain_state::CanonStateSubscriptions;
104use reth_rpc::eth::sim_bundle::EthSimBundle;
105
106pub mod rate_limiter;
108
109#[derive(Debug, Clone)]
113pub struct RpcModuleBuilder<N, Provider, Pool, Network, EvmConfig, Consensus> {
114 provider: Provider,
116 pool: Pool,
118 network: Network,
120 executor: Box<dyn TaskSpawner + 'static>,
122 evm_config: EvmConfig,
124 consensus: Consensus,
126 _primitives: PhantomData<N>,
128}
129
130impl<N, Provider, Pool, Network, EvmConfig, Consensus>
133 RpcModuleBuilder<N, Provider, Pool, Network, EvmConfig, Consensus>
134{
135 pub const fn new(
137 provider: Provider,
138 pool: Pool,
139 network: Network,
140 executor: Box<dyn TaskSpawner + 'static>,
141 evm_config: EvmConfig,
142 consensus: Consensus,
143 ) -> Self {
144 Self { provider, pool, network, executor, evm_config, consensus, _primitives: PhantomData }
145 }
146
147 pub fn with_provider<P>(
149 self,
150 provider: P,
151 ) -> RpcModuleBuilder<N, P, Pool, Network, EvmConfig, Consensus> {
152 let Self { pool, network, executor, evm_config, consensus, _primitives, .. } = self;
153 RpcModuleBuilder { provider, network, pool, executor, evm_config, consensus, _primitives }
154 }
155
156 pub fn with_pool<P>(
158 self,
159 pool: P,
160 ) -> RpcModuleBuilder<N, Provider, P, Network, EvmConfig, Consensus> {
161 let Self { provider, network, executor, evm_config, consensus, _primitives, .. } = self;
162 RpcModuleBuilder { provider, network, pool, executor, evm_config, consensus, _primitives }
163 }
164
165 pub fn with_noop_pool(
171 self,
172 ) -> RpcModuleBuilder<N, Provider, NoopTransactionPool, Network, EvmConfig, Consensus> {
173 let Self { provider, executor, network, evm_config, consensus, _primitives, .. } = self;
174 RpcModuleBuilder {
175 provider,
176 executor,
177 network,
178 evm_config,
179 pool: NoopTransactionPool::default(),
180 consensus,
181 _primitives,
182 }
183 }
184
185 pub fn with_network<Net>(
187 self,
188 network: Net,
189 ) -> RpcModuleBuilder<N, Provider, Pool, Net, EvmConfig, Consensus> {
190 let Self { provider, pool, executor, evm_config, consensus, _primitives, .. } = self;
191 RpcModuleBuilder { provider, network, pool, executor, evm_config, consensus, _primitives }
192 }
193
194 pub fn with_noop_network(
200 self,
201 ) -> RpcModuleBuilder<N, Provider, Pool, NoopNetwork, EvmConfig, Consensus> {
202 let Self { provider, pool, executor, evm_config, consensus, _primitives, .. } = self;
203 RpcModuleBuilder {
204 provider,
205 pool,
206 executor,
207 network: NoopNetwork::default(),
208 evm_config,
209 consensus,
210 _primitives,
211 }
212 }
213
214 pub fn with_executor(self, executor: Box<dyn TaskSpawner + 'static>) -> Self {
216 let Self { pool, network, provider, evm_config, consensus, _primitives, .. } = self;
217 Self { provider, network, pool, executor, evm_config, consensus, _primitives }
218 }
219
220 pub fn with_tokio_executor(self) -> Self {
225 let Self { pool, network, provider, evm_config, consensus, _primitives, .. } = self;
226 Self {
227 provider,
228 network,
229 pool,
230 executor: Box::new(TokioTaskExecutor::default()),
231 evm_config,
232 consensus,
233 _primitives,
234 }
235 }
236
237 pub fn with_evm_config<E>(
239 self,
240 evm_config: E,
241 ) -> RpcModuleBuilder<N, Provider, Pool, Network, E, Consensus> {
242 let Self { provider, pool, executor, network, consensus, _primitives, .. } = self;
243 RpcModuleBuilder { provider, network, pool, executor, evm_config, consensus, _primitives }
244 }
245
246 pub fn with_consensus<C>(
248 self,
249 consensus: C,
250 ) -> RpcModuleBuilder<N, Provider, Pool, Network, EvmConfig, C> {
251 let Self { provider, network, pool, executor, evm_config, _primitives, .. } = self;
252 RpcModuleBuilder { provider, network, pool, executor, evm_config, consensus, _primitives }
253 }
254
255 #[expect(clippy::type_complexity)]
257 pub fn eth_api_builder<ChainSpec>(
258 &self,
259 ) -> EthApiBuilder<
260 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>,
261 RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>,
262 >
263 where
264 Provider: Clone,
265 Pool: Clone,
266 Network: Clone,
267 EvmConfig: Clone,
268 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>:
269 RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>, Evm = EvmConfig>,
270 {
271 EthApiBuilder::new(
272 self.provider.clone(),
273 self.pool.clone(),
274 self.network.clone(),
275 self.evm_config.clone(),
276 )
277 }
278
279 #[expect(clippy::type_complexity)]
285 pub fn bootstrap_eth_api<ChainSpec>(
286 &self,
287 ) -> EthApi<
288 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>,
289 RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>,
290 >
291 where
292 Provider: Clone,
293 Pool: Clone,
294 Network: Clone,
295 EvmConfig: ConfigureEvm + Clone,
296 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>:
297 RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>, Evm = EvmConfig>,
298 RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>: RpcConvert,
299 (): PendingEnvBuilder<EvmConfig>,
300 {
301 self.eth_api_builder().build()
302 }
303}
304
305impl<N, Provider, Pool, Network, EvmConfig, Consensus>
306 RpcModuleBuilder<N, Provider, Pool, Network, EvmConfig, Consensus>
307where
308 N: NodePrimitives,
309 Provider: FullRpcProvider<Block = N::Block, Receipt = N::Receipt, Header = N::BlockHeader>
310 + CanonStateSubscriptions<Primitives = N>
311 + AccountReader
312 + ChangeSetReader,
313 Pool: TransactionPool + Clone + 'static,
314 Network: NetworkInfo + Peers + Clone + 'static,
315 EvmConfig: ConfigureEvm<Primitives = N> + 'static,
316 Consensus: FullConsensus<N, Error = ConsensusError> + Clone + 'static,
317{
318 pub fn build_with_auth_server<EthApi>(
325 self,
326 module_config: TransportRpcModuleConfig,
327 engine: impl IntoEngineApiRpcModule,
328 eth: EthApi,
329 ) -> (
330 TransportRpcModules,
331 AuthRpcModule,
332 RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>,
333 )
334 where
335 EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
336 {
337 let Self { provider, pool, network, executor, consensus, evm_config, .. } = self;
338
339 let config = module_config.config.clone().unwrap_or_default();
340
341 let mut registry = RpcRegistryInner::new(
342 provider, pool, network, executor, consensus, config, evm_config, eth,
343 );
344
345 let modules = registry.create_transport_rpc_modules(module_config);
346
347 let auth_module = registry.create_auth_module(engine);
348
349 (modules, auth_module, registry)
350 }
351
352 pub fn into_registry<EthApi>(
357 self,
358 config: RpcModuleConfig,
359 eth: EthApi,
360 ) -> RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
361 where
362 EthApi: EthApiTypes + 'static,
363 {
364 let Self { provider, pool, network, executor, consensus, evm_config, .. } = self;
365 RpcRegistryInner::new(provider, pool, network, executor, consensus, config, evm_config, eth)
366 }
367
368 pub fn build<EthApi>(
371 self,
372 module_config: TransportRpcModuleConfig,
373 eth: EthApi,
374 ) -> TransportRpcModules<()>
375 where
376 EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
377 {
378 let mut modules = TransportRpcModules::default();
379
380 let Self { provider, pool, network, executor, consensus, evm_config, .. } = self;
381
382 if !module_config.is_empty() {
383 let TransportRpcModuleConfig { http, ws, ipc, config } = module_config.clone();
384
385 let mut registry = RpcRegistryInner::new(
386 provider,
387 pool,
388 network,
389 executor,
390 consensus,
391 config.unwrap_or_default(),
392 evm_config,
393 eth,
394 );
395
396 modules.config = module_config;
397 modules.http = registry.maybe_module(http.as_ref());
398 modules.ws = registry.maybe_module(ws.as_ref());
399 modules.ipc = registry.maybe_module(ipc.as_ref());
400 }
401
402 modules
403 }
404}
405
406impl<N: NodePrimitives> Default for RpcModuleBuilder<N, (), (), (), (), ()> {
407 fn default() -> Self {
408 Self::new((), (), (), Box::new(TokioTaskExecutor::default()), (), ())
409 }
410}
411
412#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
414pub struct RpcModuleConfig {
415 eth: EthConfig,
417 flashbots: ValidationApiConfig,
419}
420
421impl RpcModuleConfig {
424 pub fn builder() -> RpcModuleConfigBuilder {
426 RpcModuleConfigBuilder::default()
427 }
428
429 pub const fn new(eth: EthConfig, flashbots: ValidationApiConfig) -> Self {
431 Self { eth, flashbots }
432 }
433
434 pub const fn eth(&self) -> &EthConfig {
436 &self.eth
437 }
438
439 pub const fn eth_mut(&mut self) -> &mut EthConfig {
441 &mut self.eth
442 }
443}
444
445#[derive(Clone, Debug, Default)]
447pub struct RpcModuleConfigBuilder {
448 eth: Option<EthConfig>,
449 flashbots: Option<ValidationApiConfig>,
450}
451
452impl RpcModuleConfigBuilder {
455 pub fn eth(mut self, eth: EthConfig) -> Self {
457 self.eth = Some(eth);
458 self
459 }
460
461 pub fn flashbots(mut self, flashbots: ValidationApiConfig) -> Self {
463 self.flashbots = Some(flashbots);
464 self
465 }
466
467 pub fn build(self) -> RpcModuleConfig {
469 let Self { eth, flashbots } = self;
470 RpcModuleConfig { eth: eth.unwrap_or_default(), flashbots: flashbots.unwrap_or_default() }
471 }
472
473 pub const fn get_eth(&self) -> Option<&EthConfig> {
475 self.eth.as_ref()
476 }
477
478 pub const fn eth_mut(&mut self) -> &mut Option<EthConfig> {
480 &mut self.eth
481 }
482
483 pub fn eth_mut_or_default(&mut self) -> &mut EthConfig {
485 self.eth.get_or_insert_with(EthConfig::default)
486 }
487}
488
489#[derive(Debug, Clone)]
491#[expect(dead_code)] pub struct RpcRegistryInner<
493 Provider: BlockReader,
494 Pool,
495 Network,
496 EthApi: EthApiTypes,
497 EvmConfig,
498 Consensus,
499> {
500 provider: Provider,
501 pool: Pool,
502 network: Network,
503 executor: Box<dyn TaskSpawner + 'static>,
504 evm_config: EvmConfig,
505 consensus: Consensus,
506 eth: EthHandlers<EthApi>,
508 blocking_pool_guard: BlockingTaskGuard,
510 modules: HashMap<RethRpcModule, Methods>,
512 eth_config: EthConfig,
514}
515
516impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
519 RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
520where
521 N: NodePrimitives,
522 Provider: StateProviderFactory
523 + CanonStateSubscriptions<Primitives = N>
524 + BlockReader<Block = N::Block, Receipt = N::Receipt>
525 + Clone
526 + Unpin
527 + 'static,
528 Pool: Send + Sync + Clone + 'static,
529 Network: Clone + 'static,
530 EthApi: EthApiTypes + 'static,
531 EvmConfig: ConfigureEvm<Primitives = N>,
532{
533 #[expect(clippy::too_many_arguments)]
535 pub fn new(
536 provider: Provider,
537 pool: Pool,
538 network: Network,
539 executor: Box<dyn TaskSpawner + 'static>,
540 consensus: Consensus,
541 config: RpcModuleConfig,
542 evm_config: EvmConfig,
543 eth_api: EthApi,
544 ) -> Self
545 where
546 EvmConfig: ConfigureEvm<Primitives = N>,
547 {
548 let blocking_pool_guard = BlockingTaskGuard::new(config.eth.max_tracing_requests);
549
550 let eth = EthHandlers::bootstrap(config.eth.clone(), executor.clone(), eth_api);
551
552 Self {
553 provider,
554 pool,
555 network,
556 eth,
557 executor,
558 consensus,
559 modules: Default::default(),
560 blocking_pool_guard,
561 eth_config: config.eth,
562 evm_config,
563 }
564 }
565}
566
567impl<Provider, Pool, Network, EthApi, BlockExecutor, Consensus>
568 RpcRegistryInner<Provider, Pool, Network, EthApi, BlockExecutor, Consensus>
569where
570 Provider: BlockReader,
571 EthApi: EthApiTypes,
572{
573 pub const fn eth_api(&self) -> &EthApi {
575 &self.eth.api
576 }
577
578 pub const fn eth_handlers(&self) -> &EthHandlers<EthApi> {
580 &self.eth
581 }
582
583 pub const fn pool(&self) -> &Pool {
585 &self.pool
586 }
587
588 pub const fn tasks(&self) -> &(dyn TaskSpawner + 'static) {
590 &*self.executor
591 }
592
593 pub const fn provider(&self) -> &Provider {
595 &self.provider
596 }
597
598 pub fn methods(&self) -> Vec<Methods> {
600 self.modules.values().cloned().collect()
601 }
602
603 pub fn module(&self) -> RpcModule<()> {
605 let mut module = RpcModule::new(());
606 for methods in self.modules.values().cloned() {
607 module.merge(methods).expect("No conflicts");
608 }
609 module
610 }
611}
612
613impl<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
614 RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
615where
616 Network: NetworkInfo + Clone + 'static,
617 EthApi: EthApiTypes,
618 Provider: BlockReader + ChainSpecProvider<ChainSpec: EthereumHardforks>,
619 EvmConfig: ConfigureEvm,
620{
621 pub fn admin_api(&self) -> AdminApi<Network, Provider::ChainSpec, Pool>
623 where
624 Network: Peers,
625 Pool: TransactionPool + Clone + 'static,
626 {
627 AdminApi::new(self.network.clone(), self.provider.chain_spec(), self.pool.clone())
628 }
629
630 pub fn web3_api(&self) -> Web3Api<Network> {
632 Web3Api::new(self.network.clone())
633 }
634
635 pub fn register_admin(&mut self) -> &mut Self
637 where
638 Network: Peers,
639 Pool: TransactionPool + Clone + 'static,
640 {
641 let adminapi = self.admin_api();
642 self.modules.insert(RethRpcModule::Admin, adminapi.into_rpc().into());
643 self
644 }
645
646 pub fn register_web3(&mut self) -> &mut Self {
648 let web3api = self.web3_api();
649 self.modules.insert(RethRpcModule::Web3, web3api.into_rpc().into());
650 self
651 }
652}
653
654impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
655 RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
656where
657 N: NodePrimitives,
658 Provider: FullRpcProvider<
659 Header = N::BlockHeader,
660 Block = N::Block,
661 Receipt = N::Receipt,
662 Transaction = N::SignedTx,
663 > + AccountReader
664 + ChangeSetReader
665 + CanonStateSubscriptions,
666 Network: NetworkInfo + Peers + Clone + 'static,
667 EthApi: EthApiServer<
668 RpcTxReq<EthApi::NetworkTypes>,
669 RpcTransaction<EthApi::NetworkTypes>,
670 RpcBlock<EthApi::NetworkTypes>,
671 RpcReceipt<EthApi::NetworkTypes>,
672 RpcHeader<EthApi::NetworkTypes>,
673 > + EthApiTypes,
674 EvmConfig: ConfigureEvm<Primitives = N> + 'static,
675{
676 pub fn register_eth(&mut self) -> &mut Self {
682 let eth_api = self.eth_api().clone();
683 self.modules.insert(RethRpcModule::Eth, eth_api.into_rpc().into());
684 self
685 }
686
687 pub fn register_ots(&mut self) -> &mut Self
693 where
694 EthApi: TraceExt + EthTransactions,
695 {
696 let otterscan_api = self.otterscan_api();
697 self.modules.insert(RethRpcModule::Ots, otterscan_api.into_rpc().into());
698 self
699 }
700
701 pub fn register_debug(&mut self) -> &mut Self
707 where
708 EthApi: EthApiSpec + EthTransactions + TraceExt,
709 EvmConfig::Primitives: NodePrimitives<Block = ProviderBlock<EthApi::Provider>>,
710 {
711 let debug_api = self.debug_api();
712 self.modules.insert(RethRpcModule::Debug, debug_api.into_rpc().into());
713 self
714 }
715
716 pub fn register_trace(&mut self) -> &mut Self
722 where
723 EthApi: TraceExt,
724 {
725 let trace_api = self.trace_api();
726 self.modules.insert(RethRpcModule::Trace, trace_api.into_rpc().into());
727 self
728 }
729
730 pub fn register_net(&mut self) -> &mut Self
738 where
739 EthApi: EthApiSpec + 'static,
740 {
741 let netapi = self.net_api();
742 self.modules.insert(RethRpcModule::Net, netapi.into_rpc().into());
743 self
744 }
745
746 pub fn register_reth(&mut self) -> &mut Self {
754 let rethapi = self.reth_api();
755 self.modules.insert(RethRpcModule::Reth, rethapi.into_rpc().into());
756 self
757 }
758
759 pub fn otterscan_api(&self) -> OtterscanApi<EthApi> {
765 let eth_api = self.eth_api().clone();
766 OtterscanApi::new(eth_api)
767 }
768}
769
770impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
771 RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
772where
773 N: NodePrimitives,
774 Provider: FullRpcProvider<
775 Block = N::Block,
776 Header = N::BlockHeader,
777 Transaction = N::SignedTx,
778 Receipt = N::Receipt,
779 > + AccountReader
780 + ChangeSetReader,
781 Network: NetworkInfo + Peers + Clone + 'static,
782 EthApi: EthApiTypes,
783 EvmConfig: ConfigureEvm<Primitives = N>,
784{
785 pub fn trace_api(&self) -> TraceApi<EthApi> {
791 TraceApi::new(
792 self.eth_api().clone(),
793 self.blocking_pool_guard.clone(),
794 self.eth_config.clone(),
795 )
796 }
797
798 pub fn bundle_api(&self) -> EthBundle<EthApi>
804 where
805 EthApi: EthTransactions + LoadPendingBlock + Call,
806 {
807 let eth_api = self.eth_api().clone();
808 EthBundle::new(eth_api, self.blocking_pool_guard.clone())
809 }
810
811 pub fn debug_api(&self) -> DebugApi<EthApi> {
817 DebugApi::new(self.eth_api().clone(), self.blocking_pool_guard.clone())
818 }
819
820 pub fn net_api(&self) -> NetApi<Network, EthApi>
826 where
827 EthApi: EthApiSpec + 'static,
828 {
829 let eth_api = self.eth_api().clone();
830 NetApi::new(self.network.clone(), eth_api)
831 }
832
833 pub fn reth_api(&self) -> RethApi<Provider> {
835 RethApi::new(self.provider.clone(), self.executor.clone())
836 }
837}
838
839impl<N, Provider, Pool, Network, EthApi, EvmConfig, Consensus>
840 RpcRegistryInner<Provider, Pool, Network, EthApi, EvmConfig, Consensus>
841where
842 N: NodePrimitives,
843 Provider: FullRpcProvider<Block = N::Block>
844 + CanonStateSubscriptions<Primitives = N>
845 + AccountReader
846 + ChangeSetReader,
847 Pool: TransactionPool + Clone + 'static,
848 Network: NetworkInfo + Peers + Clone + 'static,
849 EthApi: FullEthApiServer,
850 EvmConfig: ConfigureEvm<Primitives = N> + 'static,
851 Consensus: FullConsensus<N, Error = ConsensusError> + Clone + 'static,
852{
853 pub fn create_auth_module(&self, engine_api: impl IntoEngineApiRpcModule) -> AuthRpcModule {
859 let mut module = engine_api.into_rpc_module();
860
861 let eth_handlers = self.eth_handlers();
863 let engine_eth = EngineEthApi::new(eth_handlers.api.clone(), eth_handlers.filter.clone());
864
865 module.merge(engine_eth.into_rpc()).expect("No conflicting methods");
866
867 AuthRpcModule { inner: module }
868 }
869
870 fn maybe_module(&mut self, config: Option<&RpcModuleSelection>) -> Option<RpcModule<()>> {
872 config.map(|config| self.module_for(config))
873 }
874
875 pub fn create_transport_rpc_modules(
879 &mut self,
880 config: TransportRpcModuleConfig,
881 ) -> TransportRpcModules<()> {
882 let mut modules = TransportRpcModules::default();
883 let http = self.maybe_module(config.http.as_ref());
884 let ws = self.maybe_module(config.ws.as_ref());
885 let ipc = self.maybe_module(config.ipc.as_ref());
886
887 modules.config = config;
888 modules.http = http;
889 modules.ws = ws;
890 modules.ipc = ipc;
891 modules
892 }
893
894 pub fn module_for(&mut self, config: &RpcModuleSelection) -> RpcModule<()> {
897 let mut module = RpcModule::new(());
898 let all_methods = self.reth_methods(config.iter_selection());
899 for methods in all_methods {
900 module.merge(methods).expect("No conflicts");
901 }
902 module
903 }
904
905 pub fn reth_methods(
914 &mut self,
915 namespaces: impl Iterator<Item = RethRpcModule>,
916 ) -> Vec<Methods> {
917 let EthHandlers { api: eth_api, filter: eth_filter, pubsub: eth_pubsub, .. } =
918 self.eth_handlers().clone();
919
920 let namespaces: Vec<_> = namespaces.collect();
922 namespaces
923 .iter()
924 .map(|namespace| {
925 self.modules
926 .entry(namespace.clone())
927 .or_insert_with(|| match namespace.clone() {
928 RethRpcModule::Admin => AdminApi::new(
929 self.network.clone(),
930 self.provider.chain_spec(),
931 self.pool.clone(),
932 )
933 .into_rpc()
934 .into(),
935 RethRpcModule::Debug => {
936 DebugApi::new(eth_api.clone(), self.blocking_pool_guard.clone())
937 .into_rpc()
938 .into()
939 }
940 RethRpcModule::Eth => {
941 let mut module = eth_api.clone().into_rpc();
943 module.merge(eth_filter.clone().into_rpc()).expect("No conflicts");
944 module.merge(eth_pubsub.clone().into_rpc()).expect("No conflicts");
945 module
946 .merge(
947 EthBundle::new(
948 eth_api.clone(),
949 self.blocking_pool_guard.clone(),
950 )
951 .into_rpc(),
952 )
953 .expect("No conflicts");
954
955 module.into()
956 }
957 RethRpcModule::Net => {
958 NetApi::new(self.network.clone(), eth_api.clone()).into_rpc().into()
959 }
960 RethRpcModule::Trace => TraceApi::new(
961 eth_api.clone(),
962 self.blocking_pool_guard.clone(),
963 self.eth_config.clone(),
964 )
965 .into_rpc()
966 .into(),
967 RethRpcModule::Web3 => Web3Api::new(self.network.clone()).into_rpc().into(),
968 RethRpcModule::Txpool => TxPoolApi::new(
969 self.eth.api.pool().clone(),
970 dyn_clone::clone(self.eth.api.tx_resp_builder()),
971 )
972 .into_rpc()
973 .into(),
974 RethRpcModule::Rpc => RPCApi::new(
975 namespaces
976 .iter()
977 .map(|module| (module.to_string(), "1.0".to_string()))
978 .collect(),
979 )
980 .into_rpc()
981 .into(),
982 RethRpcModule::Ots => OtterscanApi::new(eth_api.clone()).into_rpc().into(),
983 RethRpcModule::Reth => {
984 RethApi::new(self.provider.clone(), self.executor.clone())
985 .into_rpc()
986 .into()
987 }
988 RethRpcModule::Flashbots | RethRpcModule::Other(_) => Default::default(),
994 RethRpcModule::Miner => MinerApi::default().into_rpc().into(),
995 RethRpcModule::Mev => {
996 EthSimBundle::new(eth_api.clone(), self.blocking_pool_guard.clone())
997 .into_rpc()
998 .into()
999 }
1000 })
1001 .clone()
1002 })
1003 .collect::<Vec<_>>()
1004 }
1005}
1006
1007#[derive(Debug)]
1019pub struct RpcServerConfig<RpcMiddleware = Identity> {
1020 http_server_config: Option<ServerConfigBuilder>,
1022 http_cors_domains: Option<String>,
1024 http_addr: Option<SocketAddr>,
1026 http_disable_compression: bool,
1028 ws_server_config: Option<ServerConfigBuilder>,
1030 ws_cors_domains: Option<String>,
1032 ws_addr: Option<SocketAddr>,
1034 ipc_server_config: Option<IpcServerBuilder<Identity, Identity>>,
1036 ipc_endpoint: Option<String>,
1038 jwt_secret: Option<JwtSecret>,
1040 rpc_middleware: RpcMiddleware,
1042}
1043
1044impl Default for RpcServerConfig<Identity> {
1047 fn default() -> Self {
1049 Self {
1050 http_server_config: None,
1051 http_cors_domains: None,
1052 http_addr: None,
1053 http_disable_compression: false,
1054 ws_server_config: None,
1055 ws_cors_domains: None,
1056 ws_addr: None,
1057 ipc_server_config: None,
1058 ipc_endpoint: None,
1059 jwt_secret: None,
1060 rpc_middleware: Default::default(),
1061 }
1062 }
1063}
1064
1065impl RpcServerConfig {
1066 pub fn http(config: ServerConfigBuilder) -> Self {
1068 Self::default().with_http(config)
1069 }
1070
1071 pub fn ws(config: ServerConfigBuilder) -> Self {
1073 Self::default().with_ws(config)
1074 }
1075
1076 pub fn ipc(config: IpcServerBuilder<Identity, Identity>) -> Self {
1078 Self::default().with_ipc(config)
1079 }
1080
1081 pub fn with_http(mut self, config: ServerConfigBuilder) -> Self {
1086 self.http_server_config =
1087 Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1088 self
1089 }
1090
1091 pub fn with_ws(mut self, config: ServerConfigBuilder) -> Self {
1096 self.ws_server_config = Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1097 self
1098 }
1099
1100 pub fn with_ipc(mut self, config: IpcServerBuilder<Identity, Identity>) -> Self {
1105 self.ipc_server_config = Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1106 self
1107 }
1108}
1109
1110impl<RpcMiddleware> RpcServerConfig<RpcMiddleware> {
1111 pub fn set_rpc_middleware<T>(self, rpc_middleware: T) -> RpcServerConfig<T> {
1113 RpcServerConfig {
1114 http_server_config: self.http_server_config,
1115 http_cors_domains: self.http_cors_domains,
1116 http_addr: self.http_addr,
1117 http_disable_compression: self.http_disable_compression,
1118 ws_server_config: self.ws_server_config,
1119 ws_cors_domains: self.ws_cors_domains,
1120 ws_addr: self.ws_addr,
1121 ipc_server_config: self.ipc_server_config,
1122 ipc_endpoint: self.ipc_endpoint,
1123 jwt_secret: self.jwt_secret,
1124 rpc_middleware,
1125 }
1126 }
1127
1128 pub fn with_cors(self, cors_domain: Option<String>) -> Self {
1130 self.with_http_cors(cors_domain.clone()).with_ws_cors(cors_domain)
1131 }
1132
1133 pub fn with_ws_cors(mut self, cors_domain: Option<String>) -> Self {
1135 self.ws_cors_domains = cors_domain;
1136 self
1137 }
1138
1139 pub const fn with_http_disable_compression(mut self, http_disable_compression: bool) -> Self {
1141 self.http_disable_compression = http_disable_compression;
1142 self
1143 }
1144
1145 pub fn with_http_cors(mut self, cors_domain: Option<String>) -> Self {
1147 self.http_cors_domains = cors_domain;
1148 self
1149 }
1150
1151 pub const fn with_http_address(mut self, addr: SocketAddr) -> Self {
1156 self.http_addr = Some(addr);
1157 self
1158 }
1159
1160 pub const fn with_ws_address(mut self, addr: SocketAddr) -> Self {
1165 self.ws_addr = Some(addr);
1166 self
1167 }
1168
1169 pub fn with_id_provider<I>(mut self, id_provider: I) -> Self
1173 where
1174 I: IdProvider + Clone + 'static,
1175 {
1176 if let Some(config) = self.http_server_config {
1177 self.http_server_config = Some(config.set_id_provider(id_provider.clone()));
1178 }
1179 if let Some(config) = self.ws_server_config {
1180 self.ws_server_config = Some(config.set_id_provider(id_provider.clone()));
1181 }
1182 if let Some(ipc) = self.ipc_server_config {
1183 self.ipc_server_config = Some(ipc.set_id_provider(id_provider));
1184 }
1185
1186 self
1187 }
1188
1189 pub fn with_ipc_endpoint(mut self, path: impl Into<String>) -> Self {
1193 self.ipc_endpoint = Some(path.into());
1194 self
1195 }
1196
1197 pub const fn with_jwt_secret(mut self, secret: Option<JwtSecret>) -> Self {
1199 self.jwt_secret = secret;
1200 self
1201 }
1202
1203 pub fn with_tokio_runtime(mut self, tokio_runtime: Option<tokio::runtime::Handle>) -> Self {
1205 let Some(tokio_runtime) = tokio_runtime else { return self };
1206 if let Some(http_server_config) = self.http_server_config {
1207 self.http_server_config =
1208 Some(http_server_config.custom_tokio_runtime(tokio_runtime.clone()));
1209 }
1210 if let Some(ws_server_config) = self.ws_server_config {
1211 self.ws_server_config =
1212 Some(ws_server_config.custom_tokio_runtime(tokio_runtime.clone()));
1213 }
1214 if let Some(ipc_server_config) = self.ipc_server_config {
1215 self.ipc_server_config = Some(ipc_server_config.custom_tokio_runtime(tokio_runtime));
1216 }
1217 self
1218 }
1219
1220 pub const fn has_server(&self) -> bool {
1224 self.http_server_config.is_some() ||
1225 self.ws_server_config.is_some() ||
1226 self.ipc_server_config.is_some()
1227 }
1228
1229 pub const fn http_address(&self) -> Option<SocketAddr> {
1231 self.http_addr
1232 }
1233
1234 pub const fn ws_address(&self) -> Option<SocketAddr> {
1236 self.ws_addr
1237 }
1238
1239 pub fn ipc_endpoint(&self) -> Option<String> {
1241 self.ipc_endpoint.clone()
1242 }
1243
1244 fn maybe_cors_layer(cors: Option<String>) -> Result<Option<CorsLayer>, CorsDomainError> {
1246 cors.as_deref().map(cors::create_cors_layer).transpose()
1247 }
1248
1249 fn maybe_jwt_layer(jwt_secret: Option<JwtSecret>) -> Option<AuthLayer<JwtAuthValidator>> {
1251 jwt_secret.map(|secret| AuthLayer::new(JwtAuthValidator::new(secret)))
1252 }
1253
1254 fn maybe_compression_layer(disable_compression: bool) -> Option<CompressionLayer> {
1257 if disable_compression {
1258 None
1259 } else {
1260 Some(CompressionLayer::new())
1261 }
1262 }
1263
1264 pub async fn start(self, modules: &TransportRpcModules) -> Result<RpcServerHandle, RpcError>
1270 where
1271 RpcMiddleware: RethRpcMiddleware,
1272 {
1273 let mut http_handle = None;
1274 let mut ws_handle = None;
1275 let mut ipc_handle = None;
1276
1277 let http_socket_addr = self.http_addr.unwrap_or(SocketAddr::V4(SocketAddrV4::new(
1278 Ipv4Addr::LOCALHOST,
1279 constants::DEFAULT_HTTP_RPC_PORT,
1280 )));
1281
1282 let ws_socket_addr = self.ws_addr.unwrap_or(SocketAddr::V4(SocketAddrV4::new(
1283 Ipv4Addr::LOCALHOST,
1284 constants::DEFAULT_WS_RPC_PORT,
1285 )));
1286
1287 let metrics = modules.ipc.as_ref().map(RpcRequestMetrics::ipc).unwrap_or_default();
1288 let ipc_path =
1289 self.ipc_endpoint.clone().unwrap_or_else(|| constants::DEFAULT_IPC_ENDPOINT.into());
1290
1291 if let Some(builder) = self.ipc_server_config {
1292 let ipc = builder
1293 .set_rpc_middleware(IpcRpcServiceBuilder::new().layer(metrics))
1294 .build(ipc_path);
1295 ipc_handle = Some(ipc.start(modules.ipc.clone().expect("ipc server error")).await?);
1296 }
1297
1298 if self.http_addr == self.ws_addr &&
1300 self.http_server_config.is_some() &&
1301 self.ws_server_config.is_some()
1302 {
1303 let cors = match (self.ws_cors_domains.as_ref(), self.http_cors_domains.as_ref()) {
1304 (Some(ws_cors), Some(http_cors)) => {
1305 if ws_cors.trim() != http_cors.trim() {
1306 return Err(WsHttpSamePortError::ConflictingCorsDomains {
1307 http_cors_domains: Some(http_cors.clone()),
1308 ws_cors_domains: Some(ws_cors.clone()),
1309 }
1310 .into());
1311 }
1312 Some(ws_cors)
1313 }
1314 (a, b) => a.or(b),
1315 }
1316 .cloned();
1317
1318 modules.config.ensure_ws_http_identical()?;
1320
1321 if let Some(config) = self.http_server_config {
1322 let server = ServerBuilder::new()
1323 .set_http_middleware(
1324 tower::ServiceBuilder::new()
1325 .option_layer(Self::maybe_cors_layer(cors)?)
1326 .option_layer(Self::maybe_jwt_layer(self.jwt_secret))
1327 .option_layer(Self::maybe_compression_layer(
1328 self.http_disable_compression,
1329 )),
1330 )
1331 .set_rpc_middleware(
1332 RpcServiceBuilder::default()
1333 .layer(
1334 modules
1335 .http
1336 .as_ref()
1337 .or(modules.ws.as_ref())
1338 .map(RpcRequestMetrics::same_port)
1339 .unwrap_or_default(),
1340 )
1341 .layer(self.rpc_middleware.clone()),
1342 )
1343 .set_config(config.build())
1344 .build(http_socket_addr)
1345 .await
1346 .map_err(|err| {
1347 RpcError::server_error(err, ServerKind::WsHttp(http_socket_addr))
1348 })?;
1349 let addr = server.local_addr().map_err(|err| {
1350 RpcError::server_error(err, ServerKind::WsHttp(http_socket_addr))
1351 })?;
1352 if let Some(module) = modules.http.as_ref().or(modules.ws.as_ref()) {
1353 let handle = server.start(module.clone());
1354 http_handle = Some(handle.clone());
1355 ws_handle = Some(handle);
1356 }
1357 return Ok(RpcServerHandle {
1358 http_local_addr: Some(addr),
1359 ws_local_addr: Some(addr),
1360 http: http_handle,
1361 ws: ws_handle,
1362 ipc_endpoint: self.ipc_endpoint.clone(),
1363 ipc: ipc_handle,
1364 jwt_secret: self.jwt_secret,
1365 });
1366 }
1367 }
1368
1369 let mut ws_local_addr = None;
1370 let mut ws_server = None;
1371 let mut http_local_addr = None;
1372 let mut http_server = None;
1373
1374 if let Some(config) = self.ws_server_config {
1375 let server = ServerBuilder::new()
1376 .set_config(config.ws_only().build())
1377 .set_http_middleware(
1378 tower::ServiceBuilder::new()
1379 .option_layer(Self::maybe_cors_layer(self.ws_cors_domains.clone())?)
1380 .option_layer(Self::maybe_jwt_layer(self.jwt_secret)),
1381 )
1382 .set_rpc_middleware(
1383 RpcServiceBuilder::default()
1384 .layer(modules.ws.as_ref().map(RpcRequestMetrics::ws).unwrap_or_default())
1385 .layer(self.rpc_middleware.clone()),
1386 )
1387 .build(ws_socket_addr)
1388 .await
1389 .map_err(|err| RpcError::server_error(err, ServerKind::WS(ws_socket_addr)))?;
1390
1391 let addr = server
1392 .local_addr()
1393 .map_err(|err| RpcError::server_error(err, ServerKind::WS(ws_socket_addr)))?;
1394
1395 ws_local_addr = Some(addr);
1396 ws_server = Some(server);
1397 }
1398
1399 if let Some(config) = self.http_server_config {
1400 let server = ServerBuilder::new()
1401 .set_config(config.http_only().build())
1402 .set_http_middleware(
1403 tower::ServiceBuilder::new()
1404 .option_layer(Self::maybe_cors_layer(self.http_cors_domains.clone())?)
1405 .option_layer(Self::maybe_jwt_layer(self.jwt_secret))
1406 .option_layer(Self::maybe_compression_layer(self.http_disable_compression)),
1407 )
1408 .set_rpc_middleware(
1409 RpcServiceBuilder::default()
1410 .layer(
1411 modules.http.as_ref().map(RpcRequestMetrics::http).unwrap_or_default(),
1412 )
1413 .layer(self.rpc_middleware.clone()),
1414 )
1415 .build(http_socket_addr)
1416 .await
1417 .map_err(|err| RpcError::server_error(err, ServerKind::Http(http_socket_addr)))?;
1418 let local_addr = server
1419 .local_addr()
1420 .map_err(|err| RpcError::server_error(err, ServerKind::Http(http_socket_addr)))?;
1421 http_local_addr = Some(local_addr);
1422 http_server = Some(server);
1423 }
1424
1425 http_handle = http_server
1426 .map(|http_server| http_server.start(modules.http.clone().expect("http server error")));
1427 ws_handle = ws_server
1428 .map(|ws_server| ws_server.start(modules.ws.clone().expect("ws server error")));
1429 Ok(RpcServerHandle {
1430 http_local_addr,
1431 ws_local_addr,
1432 http: http_handle,
1433 ws: ws_handle,
1434 ipc_endpoint: self.ipc_endpoint.clone(),
1435 ipc: ipc_handle,
1436 jwt_secret: self.jwt_secret,
1437 })
1438 }
1439}
1440
1441#[derive(Debug, Clone, Default, Eq, PartialEq)]
1453pub struct TransportRpcModuleConfig {
1454 http: Option<RpcModuleSelection>,
1456 ws: Option<RpcModuleSelection>,
1458 ipc: Option<RpcModuleSelection>,
1460 config: Option<RpcModuleConfig>,
1462}
1463
1464impl TransportRpcModuleConfig {
1467 pub fn set_http(http: impl Into<RpcModuleSelection>) -> Self {
1469 Self::default().with_http(http)
1470 }
1471
1472 pub fn set_ws(ws: impl Into<RpcModuleSelection>) -> Self {
1474 Self::default().with_ws(ws)
1475 }
1476
1477 pub fn set_ipc(ipc: impl Into<RpcModuleSelection>) -> Self {
1479 Self::default().with_ipc(ipc)
1480 }
1481
1482 pub fn with_http(mut self, http: impl Into<RpcModuleSelection>) -> Self {
1484 self.http = Some(http.into());
1485 self
1486 }
1487
1488 pub fn with_ws(mut self, ws: impl Into<RpcModuleSelection>) -> Self {
1490 self.ws = Some(ws.into());
1491 self
1492 }
1493
1494 pub fn with_ipc(mut self, ipc: impl Into<RpcModuleSelection>) -> Self {
1496 self.ipc = Some(ipc.into());
1497 self
1498 }
1499
1500 pub fn with_config(mut self, config: RpcModuleConfig) -> Self {
1502 self.config = Some(config);
1503 self
1504 }
1505
1506 pub const fn http_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1508 &mut self.http
1509 }
1510
1511 pub const fn ws_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1513 &mut self.ws
1514 }
1515
1516 pub const fn ipc_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1518 &mut self.ipc
1519 }
1520
1521 pub const fn config_mut(&mut self) -> &mut Option<RpcModuleConfig> {
1523 &mut self.config
1524 }
1525
1526 pub const fn is_empty(&self) -> bool {
1528 self.http.is_none() && self.ws.is_none() && self.ipc.is_none()
1529 }
1530
1531 pub const fn http(&self) -> Option<&RpcModuleSelection> {
1533 self.http.as_ref()
1534 }
1535
1536 pub const fn ws(&self) -> Option<&RpcModuleSelection> {
1538 self.ws.as_ref()
1539 }
1540
1541 pub const fn ipc(&self) -> Option<&RpcModuleSelection> {
1543 self.ipc.as_ref()
1544 }
1545
1546 pub const fn config(&self) -> Option<&RpcModuleConfig> {
1548 self.config.as_ref()
1549 }
1550
1551 pub fn contains_any(&self, module: &RethRpcModule) -> bool {
1553 self.contains_http(module) || self.contains_ws(module) || self.contains_ipc(module)
1554 }
1555
1556 pub fn contains_http(&self, module: &RethRpcModule) -> bool {
1558 self.http.as_ref().is_some_and(|http| http.contains(module))
1559 }
1560
1561 pub fn contains_ws(&self, module: &RethRpcModule) -> bool {
1563 self.ws.as_ref().is_some_and(|ws| ws.contains(module))
1564 }
1565
1566 pub fn contains_ipc(&self, module: &RethRpcModule) -> bool {
1568 self.ipc.as_ref().is_some_and(|ipc| ipc.contains(module))
1569 }
1570
1571 fn ensure_ws_http_identical(&self) -> Result<(), WsHttpSamePortError> {
1574 if RpcModuleSelection::are_identical(self.http.as_ref(), self.ws.as_ref()) {
1575 Ok(())
1576 } else {
1577 let http_modules =
1578 self.http.as_ref().map(RpcModuleSelection::to_selection).unwrap_or_default();
1579 let ws_modules =
1580 self.ws.as_ref().map(RpcModuleSelection::to_selection).unwrap_or_default();
1581
1582 let http_not_ws = http_modules.difference(&ws_modules).cloned().collect();
1583 let ws_not_http = ws_modules.difference(&http_modules).cloned().collect();
1584 let overlap = http_modules.intersection(&ws_modules).cloned().collect();
1585
1586 Err(WsHttpSamePortError::ConflictingModules(Box::new(ConflictingModules {
1587 overlap,
1588 http_not_ws,
1589 ws_not_http,
1590 })))
1591 }
1592 }
1593}
1594
1595#[derive(Debug, Clone, Default)]
1597pub struct TransportRpcModules<Context = ()> {
1598 config: TransportRpcModuleConfig,
1600 http: Option<RpcModule<Context>>,
1602 ws: Option<RpcModule<Context>>,
1604 ipc: Option<RpcModule<Context>>,
1606}
1607
1608impl TransportRpcModules {
1611 pub fn with_config(mut self, config: TransportRpcModuleConfig) -> Self {
1614 self.config = config;
1615 self
1616 }
1617
1618 pub fn with_http(mut self, http: RpcModule<()>) -> Self {
1621 self.http = Some(http);
1622 self
1623 }
1624
1625 pub fn with_ws(mut self, ws: RpcModule<()>) -> Self {
1628 self.ws = Some(ws);
1629 self
1630 }
1631
1632 pub fn with_ipc(mut self, ipc: RpcModule<()>) -> Self {
1635 self.ipc = Some(ipc);
1636 self
1637 }
1638
1639 pub const fn module_config(&self) -> &TransportRpcModuleConfig {
1641 &self.config
1642 }
1643
1644 pub fn merge_if_module_configured(
1649 &mut self,
1650 module: RethRpcModule,
1651 other: impl Into<Methods>,
1652 ) -> Result<(), RegisterMethodError> {
1653 let other = other.into();
1654 if self.module_config().contains_http(&module) {
1655 self.merge_http(other.clone())?;
1656 }
1657 if self.module_config().contains_ws(&module) {
1658 self.merge_ws(other.clone())?;
1659 }
1660 if self.module_config().contains_ipc(&module) {
1661 self.merge_ipc(other)?;
1662 }
1663
1664 Ok(())
1665 }
1666
1667 pub fn merge_http(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1673 if let Some(ref mut http) = self.http {
1674 return http.merge(other.into()).map(|_| true)
1675 }
1676 Ok(false)
1677 }
1678
1679 pub fn merge_ws(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1685 if let Some(ref mut ws) = self.ws {
1686 return ws.merge(other.into()).map(|_| true)
1687 }
1688 Ok(false)
1689 }
1690
1691 pub fn merge_ipc(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1697 if let Some(ref mut ipc) = self.ipc {
1698 return ipc.merge(other.into()).map(|_| true)
1699 }
1700 Ok(false)
1701 }
1702
1703 pub fn merge_configured(
1707 &mut self,
1708 other: impl Into<Methods>,
1709 ) -> Result<(), RegisterMethodError> {
1710 let other = other.into();
1711 self.merge_http(other.clone())?;
1712 self.merge_ws(other.clone())?;
1713 self.merge_ipc(other)?;
1714 Ok(())
1715 }
1716
1717 pub fn methods_by_module(&self, module: RethRpcModule) -> Methods {
1721 self.methods_by(|name| name.starts_with(module.as_str()))
1722 }
1723
1724 pub fn methods_by<F>(&self, mut filter: F) -> Methods
1728 where
1729 F: FnMut(&str) -> bool,
1730 {
1731 let mut methods = Methods::new();
1732
1733 let mut f =
1735 |name: &str, mm: &Methods| filter(name) && !mm.method_names().any(|m| m == name);
1736
1737 if let Some(m) = self.http_methods(|name| f(name, &methods)) {
1738 let _ = methods.merge(m);
1739 }
1740 if let Some(m) = self.ws_methods(|name| f(name, &methods)) {
1741 let _ = methods.merge(m);
1742 }
1743 if let Some(m) = self.ipc_methods(|name| f(name, &methods)) {
1744 let _ = methods.merge(m);
1745 }
1746 methods
1747 }
1748
1749 pub fn http_methods<F>(&self, filter: F) -> Option<Methods>
1753 where
1754 F: FnMut(&str) -> bool,
1755 {
1756 self.http.as_ref().map(|module| methods_by(module, filter))
1757 }
1758
1759 pub fn ws_methods<F>(&self, filter: F) -> Option<Methods>
1763 where
1764 F: FnMut(&str) -> bool,
1765 {
1766 self.ws.as_ref().map(|module| methods_by(module, filter))
1767 }
1768
1769 pub fn ipc_methods<F>(&self, filter: F) -> Option<Methods>
1773 where
1774 F: FnMut(&str) -> bool,
1775 {
1776 self.ipc.as_ref().map(|module| methods_by(module, filter))
1777 }
1778
1779 pub fn remove_http_method(&mut self, method_name: &'static str) -> bool {
1787 if let Some(http_module) = &mut self.http {
1788 http_module.remove_method(method_name).is_some()
1789 } else {
1790 false
1791 }
1792 }
1793
1794 pub fn remove_http_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
1796 for name in methods {
1797 self.remove_http_method(name);
1798 }
1799 }
1800
1801 pub fn remove_ws_method(&mut self, method_name: &'static str) -> bool {
1809 if let Some(ws_module) = &mut self.ws {
1810 ws_module.remove_method(method_name).is_some()
1811 } else {
1812 false
1813 }
1814 }
1815
1816 pub fn remove_ws_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
1818 for name in methods {
1819 self.remove_ws_method(name);
1820 }
1821 }
1822
1823 pub fn remove_ipc_method(&mut self, method_name: &'static str) -> bool {
1831 if let Some(ipc_module) = &mut self.ipc {
1832 ipc_module.remove_method(method_name).is_some()
1833 } else {
1834 false
1835 }
1836 }
1837
1838 pub fn remove_ipc_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
1840 for name in methods {
1841 self.remove_ipc_method(name);
1842 }
1843 }
1844
1845 pub fn remove_method_from_configured(&mut self, method_name: &'static str) -> bool {
1849 let http_removed = self.remove_http_method(method_name);
1850 let ws_removed = self.remove_ws_method(method_name);
1851 let ipc_removed = self.remove_ipc_method(method_name);
1852
1853 http_removed || ws_removed || ipc_removed
1854 }
1855
1856 pub fn rename(
1860 &mut self,
1861 old_name: &'static str,
1862 new_method: impl Into<Methods>,
1863 ) -> Result<(), RegisterMethodError> {
1864 self.remove_method_from_configured(old_name);
1866
1867 self.merge_configured(new_method)
1869 }
1870
1871 pub fn replace_http(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1878 let other = other.into();
1879 self.remove_http_methods(other.method_names());
1880 self.merge_http(other)
1881 }
1882
1883 pub fn replace_ipc(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1890 let other = other.into();
1891 self.remove_ipc_methods(other.method_names());
1892 self.merge_ipc(other)
1893 }
1894
1895 pub fn replace_ws(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1902 let other = other.into();
1903 self.remove_ws_methods(other.method_names());
1904 self.merge_ws(other)
1905 }
1906
1907 pub fn replace_configured(
1911 &mut self,
1912 other: impl Into<Methods>,
1913 ) -> Result<bool, RegisterMethodError> {
1914 let other = other.into();
1915 self.replace_http(other.clone())?;
1916 self.replace_ws(other.clone())?;
1917 self.replace_ipc(other)?;
1918 Ok(true)
1919 }
1920
1921 pub fn add_or_replace_http(
1925 &mut self,
1926 other: impl Into<Methods>,
1927 ) -> Result<bool, RegisterMethodError> {
1928 let other = other.into();
1929 self.remove_http_methods(other.method_names());
1930 self.merge_http(other)
1931 }
1932
1933 pub fn add_or_replace_ws(
1937 &mut self,
1938 other: impl Into<Methods>,
1939 ) -> Result<bool, RegisterMethodError> {
1940 let other = other.into();
1941 self.remove_ws_methods(other.method_names());
1942 self.merge_ws(other)
1943 }
1944
1945 pub fn add_or_replace_ipc(
1949 &mut self,
1950 other: impl Into<Methods>,
1951 ) -> Result<bool, RegisterMethodError> {
1952 let other = other.into();
1953 self.remove_ipc_methods(other.method_names());
1954 self.merge_ipc(other)
1955 }
1956
1957 pub fn add_or_replace_configured(
1959 &mut self,
1960 other: impl Into<Methods>,
1961 ) -> Result<(), RegisterMethodError> {
1962 let other = other.into();
1963 self.add_or_replace_http(other.clone())?;
1964 self.add_or_replace_ws(other.clone())?;
1965 self.add_or_replace_ipc(other)?;
1966 Ok(())
1967 }
1968}
1969
1970fn methods_by<T, F>(module: &RpcModule<T>, mut filter: F) -> Methods
1972where
1973 F: FnMut(&str) -> bool,
1974{
1975 let mut methods = Methods::new();
1976 let method_names = module.method_names().filter(|name| filter(name));
1977
1978 for name in method_names {
1979 if let Some(matched_method) = module.method(name).cloned() {
1980 let _ = methods.verify_and_insert(name, matched_method);
1981 }
1982 }
1983
1984 methods
1985}
1986
1987#[derive(Clone, Debug)]
1992#[must_use = "Server stops if dropped"]
1993pub struct RpcServerHandle {
1994 http_local_addr: Option<SocketAddr>,
1996 ws_local_addr: Option<SocketAddr>,
1997 http: Option<ServerHandle>,
1998 ws: Option<ServerHandle>,
1999 ipc_endpoint: Option<String>,
2000 ipc: Option<jsonrpsee::server::ServerHandle>,
2001 jwt_secret: Option<JwtSecret>,
2002}
2003
2004impl RpcServerHandle {
2007 fn bearer_token(&self) -> Option<String> {
2009 self.jwt_secret.as_ref().map(|secret| {
2010 format!(
2011 "Bearer {}",
2012 secret
2013 .encode(&Claims {
2014 iat: (SystemTime::now().duration_since(UNIX_EPOCH).unwrap() +
2015 Duration::from_secs(60))
2016 .as_secs(),
2017 exp: None,
2018 })
2019 .unwrap()
2020 )
2021 })
2022 }
2023 pub const fn http_local_addr(&self) -> Option<SocketAddr> {
2025 self.http_local_addr
2026 }
2027
2028 pub const fn ws_local_addr(&self) -> Option<SocketAddr> {
2030 self.ws_local_addr
2031 }
2032
2033 pub fn stop(self) -> Result<(), AlreadyStoppedError> {
2035 if let Some(handle) = self.http {
2036 handle.stop()?
2037 }
2038
2039 if let Some(handle) = self.ws {
2040 handle.stop()?
2041 }
2042
2043 if let Some(handle) = self.ipc {
2044 handle.stop()?
2045 }
2046
2047 Ok(())
2048 }
2049
2050 pub fn ipc_endpoint(&self) -> Option<String> {
2052 self.ipc_endpoint.clone()
2053 }
2054
2055 pub fn http_url(&self) -> Option<String> {
2057 self.http_local_addr.map(|addr| format!("http://{addr}"))
2058 }
2059
2060 pub fn ws_url(&self) -> Option<String> {
2062 self.ws_local_addr.map(|addr| format!("ws://{addr}"))
2063 }
2064
2065 pub fn http_client(&self) -> Option<jsonrpsee::http_client::HttpClient> {
2067 let url = self.http_url()?;
2068
2069 let client = if let Some(token) = self.bearer_token() {
2070 jsonrpsee::http_client::HttpClientBuilder::default()
2071 .set_headers(HeaderMap::from_iter([(AUTHORIZATION, token.parse().unwrap())]))
2072 .build(url)
2073 } else {
2074 jsonrpsee::http_client::HttpClientBuilder::default().build(url)
2075 };
2076
2077 client.expect("failed to create http client").into()
2078 }
2079
2080 pub async fn ws_client(&self) -> Option<jsonrpsee::ws_client::WsClient> {
2082 let url = self.ws_url()?;
2083 let mut builder = jsonrpsee::ws_client::WsClientBuilder::default();
2084
2085 if let Some(token) = self.bearer_token() {
2086 let headers = HeaderMap::from_iter([(AUTHORIZATION, token.parse().unwrap())]);
2087 builder = builder.set_headers(headers);
2088 }
2089
2090 let client = builder.build(url).await.expect("failed to create ws client");
2091 Some(client)
2092 }
2093
2094 pub fn eth_http_provider(
2096 &self,
2097 ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2098 self.new_http_provider_for()
2099 }
2100
2101 pub fn eth_http_provider_with_wallet<W>(
2104 &self,
2105 wallet: W,
2106 ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static>
2107 where
2108 W: IntoWallet<alloy_network::Ethereum, NetworkWallet: Clone + Unpin + 'static>,
2109 {
2110 let rpc_url = self.http_url()?;
2111 let provider =
2112 ProviderBuilder::new().wallet(wallet).connect_http(rpc_url.parse().expect("valid url"));
2113 Some(provider)
2114 }
2115
2116 pub fn new_http_provider_for<N>(&self) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2121 where
2122 N: RecommendedFillers<RecommendedFillers: Unpin>,
2123 {
2124 let rpc_url = self.http_url()?;
2125 let provider = ProviderBuilder::default()
2126 .with_recommended_fillers()
2127 .connect_http(rpc_url.parse().expect("valid url"));
2128 Some(provider)
2129 }
2130
2131 pub async fn eth_ws_provider(
2133 &self,
2134 ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2135 self.new_ws_provider_for().await
2136 }
2137
2138 pub async fn eth_ws_provider_with_wallet<W>(
2141 &self,
2142 wallet: W,
2143 ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static>
2144 where
2145 W: IntoWallet<alloy_network::Ethereum, NetworkWallet: Clone + Unpin + 'static>,
2146 {
2147 let rpc_url = self.ws_url()?;
2148 let provider = ProviderBuilder::new()
2149 .wallet(wallet)
2150 .connect(&rpc_url)
2151 .await
2152 .expect("failed to create ws client");
2153 Some(provider)
2154 }
2155
2156 pub async fn new_ws_provider_for<N>(&self) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2161 where
2162 N: RecommendedFillers<RecommendedFillers: Unpin>,
2163 {
2164 let rpc_url = self.ws_url()?;
2165 let provider = ProviderBuilder::default()
2166 .with_recommended_fillers()
2167 .connect(&rpc_url)
2168 .await
2169 .expect("failed to create ws client");
2170 Some(provider)
2171 }
2172
2173 pub async fn eth_ipc_provider(
2175 &self,
2176 ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2177 self.new_ipc_provider_for().await
2178 }
2179
2180 pub async fn new_ipc_provider_for<N>(
2185 &self,
2186 ) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2187 where
2188 N: RecommendedFillers<RecommendedFillers: Unpin>,
2189 {
2190 let rpc_url = self.ipc_endpoint()?;
2191 let provider = ProviderBuilder::default()
2192 .with_recommended_fillers()
2193 .connect(&rpc_url)
2194 .await
2195 .expect("failed to create ipc client");
2196 Some(provider)
2197 }
2198}
2199
2200#[cfg(test)]
2201mod tests {
2202 use super::*;
2203
2204 #[test]
2205 fn parse_eth_call_bundle_selection() {
2206 let selection = "eth,admin,debug".parse::<RpcModuleSelection>().unwrap();
2207 assert_eq!(
2208 selection,
2209 RpcModuleSelection::Selection(
2210 [RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Debug,].into()
2211 )
2212 );
2213 }
2214
2215 #[test]
2216 fn parse_rpc_module_selection() {
2217 let selection = "all".parse::<RpcModuleSelection>().unwrap();
2218 assert_eq!(selection, RpcModuleSelection::All);
2219 }
2220
2221 #[test]
2222 fn parse_rpc_module_selection_none() {
2223 let selection = "none".parse::<RpcModuleSelection>().unwrap();
2224 assert_eq!(selection, RpcModuleSelection::Selection(Default::default()));
2225 }
2226
2227 #[test]
2228 fn parse_rpc_unique_module_selection() {
2229 let selection = "eth,admin,eth,net".parse::<RpcModuleSelection>().unwrap();
2230 assert_eq!(
2231 selection,
2232 RpcModuleSelection::Selection(
2233 [RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Net,].into()
2234 )
2235 );
2236 }
2237
2238 #[test]
2239 fn identical_selection() {
2240 assert!(RpcModuleSelection::are_identical(
2241 Some(&RpcModuleSelection::All),
2242 Some(&RpcModuleSelection::All),
2243 ));
2244 assert!(!RpcModuleSelection::are_identical(
2245 Some(&RpcModuleSelection::All),
2246 Some(&RpcModuleSelection::Standard),
2247 ));
2248 assert!(RpcModuleSelection::are_identical(
2249 Some(&RpcModuleSelection::Selection(RpcModuleSelection::Standard.to_selection())),
2250 Some(&RpcModuleSelection::Standard),
2251 ));
2252 assert!(RpcModuleSelection::are_identical(
2253 Some(&RpcModuleSelection::Selection([RethRpcModule::Eth].into())),
2254 Some(&RpcModuleSelection::Selection([RethRpcModule::Eth].into())),
2255 ));
2256 assert!(RpcModuleSelection::are_identical(
2257 None,
2258 Some(&RpcModuleSelection::Selection(Default::default())),
2259 ));
2260 assert!(RpcModuleSelection::are_identical(
2261 Some(&RpcModuleSelection::Selection(Default::default())),
2262 None,
2263 ));
2264 assert!(RpcModuleSelection::are_identical(None, None));
2265 }
2266
2267 #[test]
2268 fn test_rpc_module_str() {
2269 macro_rules! assert_rpc_module {
2270 ($($s:expr => $v:expr,)*) => {
2271 $(
2272 let val: RethRpcModule = $s.parse().unwrap();
2273 assert_eq!(val, $v);
2274 assert_eq!(val.to_string().as_str(), $s);
2275 )*
2276 };
2277 }
2278 assert_rpc_module!
2279 (
2280 "admin" => RethRpcModule::Admin,
2281 "debug" => RethRpcModule::Debug,
2282 "eth" => RethRpcModule::Eth,
2283 "net" => RethRpcModule::Net,
2284 "trace" => RethRpcModule::Trace,
2285 "web3" => RethRpcModule::Web3,
2286 "rpc" => RethRpcModule::Rpc,
2287 "ots" => RethRpcModule::Ots,
2288 "reth" => RethRpcModule::Reth,
2289 );
2290 }
2291
2292 #[test]
2293 fn test_default_selection() {
2294 let selection = RpcModuleSelection::Standard.to_selection();
2295 assert_eq!(selection, [RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3].into())
2296 }
2297
2298 #[test]
2299 fn test_create_rpc_module_config() {
2300 let selection = vec!["eth", "admin"];
2301 let config = RpcModuleSelection::try_from_selection(selection).unwrap();
2302 assert_eq!(
2303 config,
2304 RpcModuleSelection::Selection([RethRpcModule::Eth, RethRpcModule::Admin].into())
2305 );
2306 }
2307
2308 #[test]
2309 fn test_configure_transport_config() {
2310 let config = TransportRpcModuleConfig::default()
2311 .with_http([RethRpcModule::Eth, RethRpcModule::Admin]);
2312 assert_eq!(
2313 config,
2314 TransportRpcModuleConfig {
2315 http: Some(RpcModuleSelection::Selection(
2316 [RethRpcModule::Eth, RethRpcModule::Admin].into()
2317 )),
2318 ws: None,
2319 ipc: None,
2320 config: None,
2321 }
2322 )
2323 }
2324
2325 #[test]
2326 fn test_configure_transport_config_none() {
2327 let config = TransportRpcModuleConfig::default().with_http(Vec::<RethRpcModule>::new());
2328 assert_eq!(
2329 config,
2330 TransportRpcModuleConfig {
2331 http: Some(RpcModuleSelection::Selection(Default::default())),
2332 ws: None,
2333 ipc: None,
2334 config: None,
2335 }
2336 )
2337 }
2338
2339 fn create_test_module() -> RpcModule<()> {
2340 let mut module = RpcModule::new(());
2341 module.register_method("anything", |_, _, _| "succeed").unwrap();
2342 module
2343 }
2344
2345 #[test]
2346 fn test_remove_http_method() {
2347 let mut modules =
2348 TransportRpcModules { http: Some(create_test_module()), ..Default::default() };
2349 assert!(modules.remove_http_method("anything"));
2351
2352 assert!(!modules.remove_http_method("non_existent_method"));
2354
2355 assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2357 }
2358
2359 #[test]
2360 fn test_remove_ws_method() {
2361 let mut modules =
2362 TransportRpcModules { ws: Some(create_test_module()), ..Default::default() };
2363
2364 assert!(modules.remove_ws_method("anything"));
2366
2367 assert!(!modules.remove_ws_method("non_existent_method"));
2369
2370 assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2372 }
2373
2374 #[test]
2375 fn test_remove_ipc_method() {
2376 let mut modules =
2377 TransportRpcModules { ipc: Some(create_test_module()), ..Default::default() };
2378
2379 assert!(modules.remove_ipc_method("anything"));
2381
2382 assert!(!modules.remove_ipc_method("non_existent_method"));
2384
2385 assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2387 }
2388
2389 #[test]
2390 fn test_remove_method_from_configured() {
2391 let mut modules = TransportRpcModules {
2392 http: Some(create_test_module()),
2393 ws: Some(create_test_module()),
2394 ipc: Some(create_test_module()),
2395 ..Default::default()
2396 };
2397
2398 assert!(modules.remove_method_from_configured("anything"));
2400
2401 assert!(!modules.remove_method_from_configured("anything"));
2403
2404 assert!(!modules.remove_method_from_configured("non_existent_method"));
2406
2407 assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2409 assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2410 assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2411 }
2412
2413 #[test]
2414 fn test_transport_rpc_module_rename() {
2415 let mut modules = TransportRpcModules {
2416 http: Some(create_test_module()),
2417 ws: Some(create_test_module()),
2418 ipc: Some(create_test_module()),
2419 ..Default::default()
2420 };
2421
2422 assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2424 assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2425 assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2426
2427 assert!(modules.http.as_ref().unwrap().method("something").is_none());
2429 assert!(modules.ws.as_ref().unwrap().method("something").is_none());
2430 assert!(modules.ipc.as_ref().unwrap().method("something").is_none());
2431
2432 let mut other_module = RpcModule::new(());
2434 other_module.register_method("something", |_, _, _| "fails").unwrap();
2435
2436 modules.rename("anything", other_module).expect("rename failed");
2438
2439 assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2441 assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2442 assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2443
2444 assert!(modules.http.as_ref().unwrap().method("something").is_some());
2446 assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2447 assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2448 }
2449
2450 #[test]
2451 fn test_replace_http_method() {
2452 let mut modules =
2453 TransportRpcModules { http: Some(create_test_module()), ..Default::default() };
2454
2455 let mut other_module = RpcModule::new(());
2456 other_module.register_method("something", |_, _, _| "fails").unwrap();
2457
2458 assert!(modules.replace_http(other_module.clone()).unwrap());
2459
2460 assert!(modules.http.as_ref().unwrap().method("something").is_some());
2461
2462 other_module.register_method("anything", |_, _, _| "fails").unwrap();
2463 assert!(modules.replace_http(other_module.clone()).unwrap());
2464
2465 assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2466 }
2467 #[test]
2468 fn test_replace_ipc_method() {
2469 let mut modules =
2470 TransportRpcModules { ipc: Some(create_test_module()), ..Default::default() };
2471
2472 let mut other_module = RpcModule::new(());
2473 other_module.register_method("something", |_, _, _| "fails").unwrap();
2474
2475 assert!(modules.replace_ipc(other_module.clone()).unwrap());
2476
2477 assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2478
2479 other_module.register_method("anything", |_, _, _| "fails").unwrap();
2480 assert!(modules.replace_ipc(other_module.clone()).unwrap());
2481
2482 assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2483 }
2484 #[test]
2485 fn test_replace_ws_method() {
2486 let mut modules =
2487 TransportRpcModules { ws: Some(create_test_module()), ..Default::default() };
2488
2489 let mut other_module = RpcModule::new(());
2490 other_module.register_method("something", |_, _, _| "fails").unwrap();
2491
2492 assert!(modules.replace_ws(other_module.clone()).unwrap());
2493
2494 assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2495
2496 other_module.register_method("anything", |_, _, _| "fails").unwrap();
2497 assert!(modules.replace_ws(other_module.clone()).unwrap());
2498
2499 assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2500 }
2501
2502 #[test]
2503 fn test_replace_configured() {
2504 let mut modules = TransportRpcModules {
2505 http: Some(create_test_module()),
2506 ws: Some(create_test_module()),
2507 ipc: Some(create_test_module()),
2508 ..Default::default()
2509 };
2510 let mut other_module = RpcModule::new(());
2511 other_module.register_method("something", |_, _, _| "fails").unwrap();
2512
2513 assert!(modules.replace_configured(other_module).unwrap());
2514
2515 assert!(modules.http.as_ref().unwrap().method("something").is_some());
2517 assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2518 assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2519
2520 assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2521 assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2522 assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2523 }
2524}