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_provider::{fillers::RecommendedFillers, Provider, ProviderBuilder};
24use core::marker::PhantomData;
25use error::{ConflictingModules, RpcError, ServerKind};
26use http::{header::AUTHORIZATION, HeaderMap};
27use jsonrpsee::{
28 core::RegisterMethodError,
29 server::{
30 middleware::rpc::{RpcService, RpcServiceT},
31 AlreadyStoppedError, IdProvider, RpcServiceBuilder, ServerHandle,
32 },
33 Methods, RpcModule,
34};
35use reth_chainspec::EthereumHardforks;
36use reth_consensus::{ConsensusError, FullConsensus};
37use reth_evm::{execute::BlockExecutorProvider, ConfigureEvm};
38use reth_network_api::{noop::NoopNetwork, NetworkInfo, Peers};
39use reth_primitives_traits::NodePrimitives;
40use reth_provider::{
41 AccountReader, BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider,
42 ChangeSetReader, FullRpcProvider, ProviderBlock, StateProviderFactory,
43};
44use reth_rpc::{
45 AdminApi, DebugApi, EngineEthApi, EthApi, EthApiBuilder, EthBundle, MinerApi, NetApi,
46 OtterscanApi, RPCApi, RethApi, TraceApi, TxPoolApi, ValidationApiConfig, Web3Api,
47};
48use reth_rpc_api::servers::*;
49use reth_rpc_eth_api::{
50 helpers::{Call, EthApiSpec, EthTransactions, LoadPendingBlock, TraceExt},
51 EthApiServer, EthApiTypes, FullEthApiServer, RpcBlock, RpcHeader, RpcReceipt, RpcTransaction,
52};
53use reth_rpc_eth_types::{EthConfig, EthSubscriptionIdProvider};
54use reth_rpc_layer::{AuthLayer, Claims, CompressionLayer, JwtAuthValidator, JwtSecret};
55use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor};
56use reth_transaction_pool::{noop::NoopTransactionPool, PoolTransaction, TransactionPool};
57use serde::{Deserialize, Serialize};
58use std::{
59 collections::HashMap,
60 fmt::Debug,
61 net::{Ipv4Addr, SocketAddr, SocketAddrV4},
62 sync::Arc,
63 time::{Duration, SystemTime, UNIX_EPOCH},
64};
65use tower::Layer;
66use tower_http::cors::CorsLayer;
67
68pub use cors::CorsDomainError;
69
70pub use jsonrpsee::server::ServerBuilder;
72pub use reth_ipc::server::{
73 Builder as IpcServerBuilder, RpcServiceBuilder as IpcRpcServiceBuilder,
74};
75pub use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection};
76pub use tower::layer::util::{Identity, Stack};
77
78pub mod auth;
80
81pub mod config;
83
84mod cors;
86
87pub mod error;
89
90pub mod eth;
92pub use eth::EthHandlers;
93
94mod metrics;
96pub use metrics::{MeteredRequestFuture, RpcRequestMetricsService};
97use reth_rpc::eth::sim_bundle::EthSimBundle;
98
99pub mod rate_limiter;
101
102#[expect(clippy::too_many_arguments)]
104pub async fn launch<N, Provider, Pool, Network, Tasks, EvmConfig, EthApi, BlockExecutor>(
105 provider: Provider,
106 pool: Pool,
107 network: Network,
108 module_config: impl Into<TransportRpcModuleConfig>,
109 server_config: impl Into<RpcServerConfig>,
110 executor: Tasks,
111 evm_config: EvmConfig,
112 eth: EthApi,
113 block_executor: BlockExecutor,
114 consensus: Arc<dyn FullConsensus<N, Error = ConsensusError>>,
115) -> Result<RpcServerHandle, RpcError>
116where
117 N: NodePrimitives,
118 Provider: FullRpcProvider<Block = N::Block, Receipt = N::Receipt, Header = N::BlockHeader>
119 + CanonStateSubscriptions<Primitives = N>
120 + AccountReader
121 + ChangeSetReader,
122 Pool: TransactionPool + 'static,
123 Network: NetworkInfo + Peers + Clone + 'static,
124 Tasks: TaskSpawner + Clone + 'static,
125 EvmConfig: ConfigureEvm<Primitives = N>,
126 EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
127 BlockExecutor: BlockExecutorProvider<Primitives = N>,
128{
129 let module_config = module_config.into();
130 server_config
131 .into()
132 .start(
133 &RpcModuleBuilder::new(
134 provider,
135 pool,
136 network,
137 executor,
138 evm_config,
139 block_executor,
140 consensus,
141 )
142 .build(module_config, eth),
143 )
144 .await
145}
146
147#[derive(Debug, Clone)]
151pub struct RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
152{
153 provider: Provider,
155 pool: Pool,
157 network: Network,
159 executor: Tasks,
161 evm_config: EvmConfig,
163 block_executor: BlockExecutor,
165 consensus: Consensus,
167 _primitives: PhantomData<N>,
169}
170
171impl<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
174 RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
175where
176 N: NodePrimitives,
177{
178 pub const fn new(
180 provider: Provider,
181 pool: Pool,
182 network: Network,
183 executor: Tasks,
184 evm_config: EvmConfig,
185 block_executor: BlockExecutor,
186 consensus: Consensus,
187 ) -> Self {
188 Self {
189 provider,
190 pool,
191 network,
192 executor,
193 evm_config,
194 block_executor,
195 consensus,
196 _primitives: PhantomData,
197 }
198 }
199
200 pub fn with_provider<P>(
202 self,
203 provider: P,
204 ) -> RpcModuleBuilder<N, P, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
205 where
206 P: BlockReader<Block = N::Block, Header = N::BlockHeader, Receipt = N::Receipt>
207 + StateProviderFactory
208 + 'static,
209 {
210 let Self {
211 pool,
212 network,
213 executor,
214 evm_config,
215 block_executor,
216 consensus,
217 _primitives,
218 ..
219 } = self;
220 RpcModuleBuilder {
221 provider,
222 network,
223 pool,
224 executor,
225 evm_config,
226 block_executor,
227 consensus,
228 _primitives,
229 }
230 }
231
232 pub fn with_pool<P>(
234 self,
235 pool: P,
236 ) -> RpcModuleBuilder<N, Provider, P, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
237 where
238 P: TransactionPool<Transaction: PoolTransaction<Consensus = N::SignedTx>> + 'static,
239 {
240 let Self {
241 provider,
242 network,
243 executor,
244 evm_config,
245 block_executor,
246 consensus,
247 _primitives,
248 ..
249 } = self;
250 RpcModuleBuilder {
251 provider,
252 network,
253 pool,
254 executor,
255 evm_config,
256 block_executor,
257 consensus,
258 _primitives,
259 }
260 }
261
262 pub fn with_noop_pool(
268 self,
269 ) -> RpcModuleBuilder<
270 N,
271 Provider,
272 NoopTransactionPool,
273 Network,
274 Tasks,
275 EvmConfig,
276 BlockExecutor,
277 Consensus,
278 > {
279 let Self {
280 provider,
281 executor,
282 network,
283 evm_config,
284 block_executor,
285 consensus,
286 _primitives,
287 ..
288 } = self;
289 RpcModuleBuilder {
290 provider,
291 executor,
292 network,
293 evm_config,
294 block_executor,
295 pool: NoopTransactionPool::default(),
296 consensus,
297 _primitives,
298 }
299 }
300
301 pub fn with_network<Net>(
303 self,
304 network: Net,
305 ) -> RpcModuleBuilder<N, Provider, Pool, Net, Tasks, EvmConfig, BlockExecutor, Consensus>
306 where
307 Net: NetworkInfo + Peers + 'static,
308 {
309 let Self {
310 provider,
311 pool,
312 executor,
313 evm_config,
314 block_executor,
315 consensus,
316 _primitives,
317 ..
318 } = self;
319 RpcModuleBuilder {
320 provider,
321 network,
322 pool,
323 executor,
324 evm_config,
325 block_executor,
326 consensus,
327 _primitives,
328 }
329 }
330
331 pub fn with_noop_network(
337 self,
338 ) -> RpcModuleBuilder<N, Provider, Pool, NoopNetwork, Tasks, EvmConfig, BlockExecutor, Consensus>
339 {
340 let Self {
341 provider,
342 pool,
343 executor,
344 evm_config,
345 block_executor,
346 consensus,
347 _primitives,
348 ..
349 } = self;
350 RpcModuleBuilder {
351 provider,
352 pool,
353 executor,
354 network: NoopNetwork::default(),
355 evm_config,
356 block_executor,
357 consensus,
358 _primitives,
359 }
360 }
361
362 pub fn with_executor<T>(
364 self,
365 executor: T,
366 ) -> RpcModuleBuilder<N, Provider, Pool, Network, T, EvmConfig, BlockExecutor, Consensus>
367 where
368 T: TaskSpawner + 'static,
369 {
370 let Self {
371 pool,
372 network,
373 provider,
374 evm_config,
375 block_executor,
376 consensus,
377 _primitives,
378 ..
379 } = self;
380 RpcModuleBuilder {
381 provider,
382 network,
383 pool,
384 executor,
385 evm_config,
386 block_executor,
387 consensus,
388 _primitives,
389 }
390 }
391
392 pub fn with_tokio_executor(
397 self,
398 ) -> RpcModuleBuilder<
399 N,
400 Provider,
401 Pool,
402 Network,
403 TokioTaskExecutor,
404 EvmConfig,
405 BlockExecutor,
406 Consensus,
407 > {
408 let Self {
409 pool,
410 network,
411 provider,
412 evm_config,
413 block_executor,
414 consensus,
415 _primitives,
416 ..
417 } = self;
418 RpcModuleBuilder {
419 provider,
420 network,
421 pool,
422 executor: TokioTaskExecutor::default(),
423 evm_config,
424 block_executor,
425 consensus,
426 _primitives,
427 }
428 }
429
430 pub fn with_evm_config<E>(
432 self,
433 evm_config: E,
434 ) -> RpcModuleBuilder<N, Provider, Pool, Network, Tasks, E, BlockExecutor, Consensus>
435 where
436 EvmConfig: 'static,
437 {
438 let Self {
439 provider, pool, executor, network, block_executor, consensus, _primitives, ..
440 } = self;
441 RpcModuleBuilder {
442 provider,
443 network,
444 pool,
445 executor,
446 evm_config,
447 block_executor,
448 consensus,
449 _primitives,
450 }
451 }
452
453 pub fn with_block_executor<BE>(
455 self,
456 block_executor: BE,
457 ) -> RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, BE, Consensus>
458 where
459 BE: BlockExecutorProvider<Primitives = N> + 'static,
460 {
461 let Self { provider, network, pool, executor, evm_config, consensus, _primitives, .. } =
462 self;
463 RpcModuleBuilder {
464 provider,
465 network,
466 pool,
467 executor,
468 evm_config,
469 block_executor,
470 consensus,
471 _primitives,
472 }
473 }
474
475 pub fn with_consensus<C>(
477 self,
478 consensus: C,
479 ) -> RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, C> {
480 let Self {
481 provider, network, pool, executor, evm_config, block_executor, _primitives, ..
482 } = self;
483 RpcModuleBuilder {
484 provider,
485 network,
486 pool,
487 executor,
488 evm_config,
489 block_executor,
490 consensus,
491 _primitives,
492 }
493 }
494
495 pub fn eth_api_builder(&self) -> EthApiBuilder<Provider, Pool, Network, EvmConfig>
497 where
498 Provider: BlockReaderIdExt + Clone,
499 Pool: Clone,
500 Network: Clone,
501 EvmConfig: Clone,
502 {
503 EthApiBuilder::new(
504 self.provider.clone(),
505 self.pool.clone(),
506 self.network.clone(),
507 self.evm_config.clone(),
508 )
509 }
510
511 pub fn bootstrap_eth_api(&self) -> EthApi<Provider, Pool, Network, EvmConfig>
517 where
518 Provider: BlockReaderIdExt<Block = N::Block, Header = N::BlockHeader, Receipt = N::Receipt>
519 + StateProviderFactory
520 + CanonStateSubscriptions<Primitives = N>
521 + ChainSpecProvider
522 + Clone
523 + Unpin
524 + 'static,
525 Pool: Clone,
526 EvmConfig: Clone,
527 Network: Clone,
528 {
529 self.eth_api_builder().build()
530 }
531}
532
533impl<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
534 RpcModuleBuilder<N, Provider, Pool, Network, Tasks, EvmConfig, BlockExecutor, Consensus>
535where
536 N: NodePrimitives,
537 Provider: FullRpcProvider<Block = N::Block, Receipt = N::Receipt, Header = N::BlockHeader>
538 + CanonStateSubscriptions<Primitives = N>
539 + AccountReader
540 + ChangeSetReader,
541 Pool: TransactionPool + 'static,
542 Network: NetworkInfo + Peers + Clone + 'static,
543 Tasks: TaskSpawner + Clone + 'static,
544 EvmConfig: ConfigureEvm<Primitives = N>,
545 BlockExecutor: BlockExecutorProvider<Primitives = N>,
546 Consensus: FullConsensus<N, Error = ConsensusError> + Clone + 'static,
547{
548 #[expect(clippy::type_complexity)]
555 pub fn build_with_auth_server<EthApi>(
556 self,
557 module_config: TransportRpcModuleConfig,
558 engine: impl IntoEngineApiRpcModule,
559 eth: EthApi,
560 ) -> (
561 TransportRpcModules,
562 AuthRpcModule,
563 RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>,
564 )
565 where
566 EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
567 {
568 let Self {
569 provider, pool, network, executor, evm_config, block_executor, consensus, ..
570 } = self;
571
572 let config = module_config.config.clone().unwrap_or_default();
573
574 let mut registry = RpcRegistryInner::new(
575 provider,
576 pool,
577 network,
578 executor,
579 consensus,
580 config,
581 evm_config,
582 eth,
583 block_executor,
584 );
585
586 let modules = registry.create_transport_rpc_modules(module_config);
587
588 let auth_module = registry.create_auth_module(engine);
589
590 (modules, auth_module, registry)
591 }
592
593 pub fn into_registry<EthApi>(
598 self,
599 config: RpcModuleConfig,
600 eth: EthApi,
601 ) -> RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
602 where
603 EthApi: EthApiTypes + 'static,
604 {
605 let Self {
606 provider, pool, network, executor, evm_config, block_executor, consensus, ..
607 } = self;
608 RpcRegistryInner::new(
609 provider,
610 pool,
611 network,
612 executor,
613 consensus,
614 config,
615 evm_config,
616 eth,
617 block_executor,
618 )
619 }
620
621 pub fn build<EthApi>(
624 self,
625 module_config: TransportRpcModuleConfig,
626 eth: EthApi,
627 ) -> TransportRpcModules<()>
628 where
629 EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
630 {
631 let mut modules = TransportRpcModules::default();
632
633 let Self {
634 provider, pool, network, executor, evm_config, block_executor, consensus, ..
635 } = self;
636
637 if !module_config.is_empty() {
638 let TransportRpcModuleConfig { http, ws, ipc, config } = module_config.clone();
639
640 let mut registry = RpcRegistryInner::new(
641 provider,
642 pool,
643 network,
644 executor,
645 consensus,
646 config.unwrap_or_default(),
647 evm_config,
648 eth,
649 block_executor,
650 );
651
652 modules.config = module_config;
653 modules.http = registry.maybe_module(http.as_ref());
654 modules.ws = registry.maybe_module(ws.as_ref());
655 modules.ipc = registry.maybe_module(ipc.as_ref());
656 }
657
658 modules
659 }
660}
661
662impl<N: NodePrimitives> Default for RpcModuleBuilder<N, (), (), (), (), (), (), ()> {
663 fn default() -> Self {
664 Self::new((), (), (), (), (), (), ())
665 }
666}
667
668#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
670pub struct RpcModuleConfig {
671 eth: EthConfig,
673 flashbots: ValidationApiConfig,
675}
676
677impl RpcModuleConfig {
680 pub fn builder() -> RpcModuleConfigBuilder {
682 RpcModuleConfigBuilder::default()
683 }
684
685 pub const fn new(eth: EthConfig, flashbots: ValidationApiConfig) -> Self {
687 Self { eth, flashbots }
688 }
689
690 pub const fn eth(&self) -> &EthConfig {
692 &self.eth
693 }
694
695 pub const fn eth_mut(&mut self) -> &mut EthConfig {
697 &mut self.eth
698 }
699}
700
701#[derive(Clone, Debug, Default)]
703pub struct RpcModuleConfigBuilder {
704 eth: Option<EthConfig>,
705 flashbots: Option<ValidationApiConfig>,
706}
707
708impl RpcModuleConfigBuilder {
711 pub const fn eth(mut self, eth: EthConfig) -> Self {
713 self.eth = Some(eth);
714 self
715 }
716
717 pub fn flashbots(mut self, flashbots: ValidationApiConfig) -> Self {
719 self.flashbots = Some(flashbots);
720 self
721 }
722
723 pub fn build(self) -> RpcModuleConfig {
725 let Self { eth, flashbots } = self;
726 RpcModuleConfig { eth: eth.unwrap_or_default(), flashbots: flashbots.unwrap_or_default() }
727 }
728
729 pub const fn get_eth(&self) -> Option<&EthConfig> {
731 self.eth.as_ref()
732 }
733
734 pub const fn eth_mut(&mut self) -> &mut Option<EthConfig> {
736 &mut self.eth
737 }
738
739 pub fn eth_mut_or_default(&mut self) -> &mut EthConfig {
741 self.eth.get_or_insert_with(EthConfig::default)
742 }
743}
744
745#[derive(Debug, Clone)]
747#[expect(dead_code)] pub struct RpcRegistryInner<
749 Provider: BlockReader,
750 Pool,
751 Network,
752 Tasks,
753 EthApi: EthApiTypes,
754 BlockExecutor,
755 Consensus,
756> {
757 provider: Provider,
758 pool: Pool,
759 network: Network,
760 executor: Tasks,
761 block_executor: BlockExecutor,
762 consensus: Consensus,
763 eth: EthHandlers<EthApi>,
765 blocking_pool_guard: BlockingTaskGuard,
767 modules: HashMap<RethRpcModule, Methods>,
769 eth_config: EthConfig,
771}
772
773impl<N, Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
776 RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
777where
778 N: NodePrimitives,
779 Provider: StateProviderFactory
780 + CanonStateSubscriptions<Primitives = N>
781 + BlockReader<Block = N::Block, Receipt = N::Receipt>
782 + Clone
783 + Unpin
784 + 'static,
785 Pool: Send + Sync + Clone + 'static,
786 Network: Clone + 'static,
787 Tasks: TaskSpawner + Clone + 'static,
788 EthApi: EthApiTypes + 'static,
789 BlockExecutor: BlockExecutorProvider<Primitives = N>,
790{
791 #[expect(clippy::too_many_arguments)]
793 pub fn new<EvmConfig>(
794 provider: Provider,
795 pool: Pool,
796 network: Network,
797 executor: Tasks,
798 consensus: Consensus,
799 config: RpcModuleConfig,
800 _evm_config: EvmConfig,
801 eth_api: EthApi,
802 block_executor: BlockExecutor,
803 ) -> Self
804 where
805 EvmConfig: ConfigureEvm<Primitives = N>,
806 {
807 let blocking_pool_guard = BlockingTaskGuard::new(config.eth.max_tracing_requests);
808
809 let eth = EthHandlers::bootstrap(config.eth, executor.clone(), eth_api);
810
811 Self {
812 provider,
813 pool,
814 network,
815 eth,
816 executor,
817 consensus,
818 modules: Default::default(),
819 blocking_pool_guard,
820 block_executor,
821 eth_config: config.eth,
822 }
823 }
824}
825
826impl<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
827 RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
828where
829 Provider: BlockReader,
830 EthApi: EthApiTypes,
831{
832 pub const fn eth_api(&self) -> &EthApi {
834 &self.eth.api
835 }
836
837 pub const fn eth_handlers(&self) -> &EthHandlers<EthApi> {
839 &self.eth
840 }
841
842 pub const fn pool(&self) -> &Pool {
844 &self.pool
845 }
846
847 pub const fn tasks(&self) -> &Tasks {
849 &self.executor
850 }
851
852 pub const fn provider(&self) -> &Provider {
854 &self.provider
855 }
856
857 pub fn methods(&self) -> Vec<Methods> {
859 self.modules.values().cloned().collect()
860 }
861
862 pub fn module(&self) -> RpcModule<()> {
864 let mut module = RpcModule::new(());
865 for methods in self.modules.values().cloned() {
866 module.merge(methods).expect("No conflicts");
867 }
868 module
869 }
870}
871
872impl<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
873 RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
874where
875 Network: NetworkInfo + Clone + 'static,
876 EthApi: EthApiTypes,
877 Provider: BlockReader + ChainSpecProvider<ChainSpec: EthereumHardforks>,
878 BlockExecutor: BlockExecutorProvider,
879{
880 pub fn admin_api(&self) -> AdminApi<Network, Provider::ChainSpec>
882 where
883 Network: Peers,
884 {
885 AdminApi::new(self.network.clone(), self.provider.chain_spec())
886 }
887
888 pub fn web3_api(&self) -> Web3Api<Network> {
890 Web3Api::new(self.network.clone())
891 }
892
893 pub fn register_admin(&mut self) -> &mut Self
895 where
896 Network: Peers,
897 {
898 let adminapi = self.admin_api();
899 self.modules.insert(RethRpcModule::Admin, adminapi.into_rpc().into());
900 self
901 }
902
903 pub fn register_web3(&mut self) -> &mut Self {
905 let web3api = self.web3_api();
906 self.modules.insert(RethRpcModule::Web3, web3api.into_rpc().into());
907 self
908 }
909}
910
911impl<N, Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
912 RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
913where
914 N: NodePrimitives,
915 Provider: FullRpcProvider<
916 Header = N::BlockHeader,
917 Block = N::Block,
918 Receipt = N::Receipt,
919 Transaction = N::SignedTx,
920 > + AccountReader
921 + ChangeSetReader,
922 Network: NetworkInfo + Peers + Clone + 'static,
923 Tasks: TaskSpawner + Clone + 'static,
924 EthApi: EthApiServer<
925 RpcTransaction<EthApi::NetworkTypes>,
926 RpcBlock<EthApi::NetworkTypes>,
927 RpcReceipt<EthApi::NetworkTypes>,
928 RpcHeader<EthApi::NetworkTypes>,
929 > + EthApiTypes,
930 BlockExecutor: BlockExecutorProvider<Primitives = N>,
931{
932 pub fn register_eth(&mut self) -> &mut Self {
938 let eth_api = self.eth_api().clone();
939 self.modules.insert(RethRpcModule::Eth, eth_api.into_rpc().into());
940 self
941 }
942
943 pub fn register_ots(&mut self) -> &mut Self
949 where
950 EthApi: TraceExt + EthTransactions,
951 {
952 let otterscan_api = self.otterscan_api();
953 self.modules.insert(RethRpcModule::Ots, otterscan_api.into_rpc().into());
954 self
955 }
956
957 pub fn register_debug(&mut self) -> &mut Self
963 where
964 EthApi: EthApiSpec + EthTransactions + TraceExt,
965 BlockExecutor::Primitives: NodePrimitives<Block = ProviderBlock<EthApi::Provider>>,
966 {
967 let debug_api = self.debug_api();
968 self.modules.insert(RethRpcModule::Debug, debug_api.into_rpc().into());
969 self
970 }
971
972 pub fn register_trace(&mut self) -> &mut Self
978 where
979 EthApi: TraceExt,
980 {
981 let trace_api = self.trace_api();
982 self.modules.insert(RethRpcModule::Trace, trace_api.into_rpc().into());
983 self
984 }
985
986 pub fn register_net(&mut self) -> &mut Self
994 where
995 EthApi: EthApiSpec + 'static,
996 {
997 let netapi = self.net_api();
998 self.modules.insert(RethRpcModule::Net, netapi.into_rpc().into());
999 self
1000 }
1001
1002 pub fn register_reth(&mut self) -> &mut Self {
1010 let rethapi = self.reth_api();
1011 self.modules.insert(RethRpcModule::Reth, rethapi.into_rpc().into());
1012 self
1013 }
1014
1015 pub fn otterscan_api(&self) -> OtterscanApi<EthApi> {
1021 let eth_api = self.eth_api().clone();
1022 OtterscanApi::new(eth_api)
1023 }
1024}
1025
1026impl<N, Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
1027 RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
1028where
1029 N: NodePrimitives,
1030 Provider: FullRpcProvider<
1031 Block = N::Block,
1032 Header = N::BlockHeader,
1033 Transaction = N::SignedTx,
1034 Receipt = N::Receipt,
1035 > + AccountReader
1036 + ChangeSetReader,
1037 Network: NetworkInfo + Peers + Clone + 'static,
1038 Tasks: TaskSpawner + Clone + 'static,
1039 EthApi: EthApiTypes,
1040 BlockExecutor: BlockExecutorProvider<Primitives = N>,
1041{
1042 pub fn trace_api(&self) -> TraceApi<EthApi>
1048 where
1049 EthApi: TraceExt,
1050 {
1051 TraceApi::new(self.eth_api().clone(), self.blocking_pool_guard.clone(), self.eth_config)
1052 }
1053
1054 pub fn bundle_api(&self) -> EthBundle<EthApi>
1060 where
1061 EthApi: EthTransactions + LoadPendingBlock + Call,
1062 {
1063 let eth_api = self.eth_api().clone();
1064 EthBundle::new(eth_api, self.blocking_pool_guard.clone())
1065 }
1066
1067 pub fn debug_api(&self) -> DebugApi<EthApi, BlockExecutor>
1073 where
1074 EthApi: EthApiSpec + EthTransactions + TraceExt,
1075 BlockExecutor::Primitives: NodePrimitives<Block = ProviderBlock<EthApi::Provider>>,
1076 {
1077 DebugApi::new(
1078 self.eth_api().clone(),
1079 self.blocking_pool_guard.clone(),
1080 self.block_executor.clone(),
1081 )
1082 }
1083
1084 pub fn net_api(&self) -> NetApi<Network, EthApi>
1090 where
1091 EthApi: EthApiSpec + 'static,
1092 {
1093 let eth_api = self.eth_api().clone();
1094 NetApi::new(self.network.clone(), eth_api)
1095 }
1096
1097 pub fn reth_api(&self) -> RethApi<Provider> {
1099 RethApi::new(self.provider.clone(), Box::new(self.executor.clone()))
1100 }
1101}
1102
1103impl<N, Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
1104 RpcRegistryInner<Provider, Pool, Network, Tasks, EthApi, BlockExecutor, Consensus>
1105where
1106 N: NodePrimitives,
1107 Provider: FullRpcProvider<Block = N::Block>
1108 + CanonStateSubscriptions<Primitives = N>
1109 + AccountReader
1110 + ChangeSetReader,
1111 Pool: TransactionPool + 'static,
1112 Network: NetworkInfo + Peers + Clone + 'static,
1113 Tasks: TaskSpawner + Clone + 'static,
1114 EthApi: FullEthApiServer<Provider = Provider, Pool = Pool>,
1115 BlockExecutor: BlockExecutorProvider<Primitives = N>,
1116 Consensus: FullConsensus<N, Error = ConsensusError> + Clone + 'static,
1117{
1118 pub fn create_auth_module(&self, engine_api: impl IntoEngineApiRpcModule) -> AuthRpcModule {
1124 let mut module = engine_api.into_rpc_module();
1125
1126 let eth_handlers = self.eth_handlers();
1128 let engine_eth = EngineEthApi::new(eth_handlers.api.clone(), eth_handlers.filter.clone());
1129
1130 module.merge(engine_eth.into_rpc()).expect("No conflicting methods");
1131
1132 AuthRpcModule { inner: module }
1133 }
1134
1135 fn maybe_module(&mut self, config: Option<&RpcModuleSelection>) -> Option<RpcModule<()>> {
1137 config.map(|config| self.module_for(config))
1138 }
1139
1140 pub fn create_transport_rpc_modules(
1144 &mut self,
1145 config: TransportRpcModuleConfig,
1146 ) -> TransportRpcModules<()> {
1147 let mut modules = TransportRpcModules::default();
1148 let http = self.maybe_module(config.http.as_ref());
1149 let ws = self.maybe_module(config.ws.as_ref());
1150 let ipc = self.maybe_module(config.ipc.as_ref());
1151
1152 modules.config = config;
1153 modules.http = http;
1154 modules.ws = ws;
1155 modules.ipc = ipc;
1156 modules
1157 }
1158
1159 pub fn module_for(&mut self, config: &RpcModuleSelection) -> RpcModule<()> {
1162 let mut module = RpcModule::new(());
1163 let all_methods = self.reth_methods(config.iter_selection());
1164 for methods in all_methods {
1165 module.merge(methods).expect("No conflicts");
1166 }
1167 module
1168 }
1169
1170 pub fn reth_methods(
1179 &mut self,
1180 namespaces: impl Iterator<Item = RethRpcModule>,
1181 ) -> Vec<Methods> {
1182 let EthHandlers { api: eth_api, filter: eth_filter, pubsub: eth_pubsub, .. } =
1183 self.eth_handlers().clone();
1184
1185 let namespaces: Vec<_> = namespaces.collect();
1187 namespaces
1188 .iter()
1189 .copied()
1190 .map(|namespace| {
1191 self.modules
1192 .entry(namespace)
1193 .or_insert_with(|| match namespace {
1194 RethRpcModule::Admin => {
1195 AdminApi::new(self.network.clone(), self.provider.chain_spec())
1196 .into_rpc()
1197 .into()
1198 }
1199 RethRpcModule::Debug => DebugApi::new(
1200 eth_api.clone(),
1201 self.blocking_pool_guard.clone(),
1202 self.block_executor.clone(),
1203 )
1204 .into_rpc()
1205 .into(),
1206 RethRpcModule::Eth => {
1207 let mut module = eth_api.clone().into_rpc();
1209 module.merge(eth_filter.clone().into_rpc()).expect("No conflicts");
1210 module.merge(eth_pubsub.clone().into_rpc()).expect("No conflicts");
1211 module
1212 .merge(
1213 EthBundle::new(
1214 eth_api.clone(),
1215 self.blocking_pool_guard.clone(),
1216 )
1217 .into_rpc(),
1218 )
1219 .expect("No conflicts");
1220
1221 module.into()
1222 }
1223 RethRpcModule::Net => {
1224 NetApi::new(self.network.clone(), eth_api.clone()).into_rpc().into()
1225 }
1226 RethRpcModule::Trace => TraceApi::new(
1227 eth_api.clone(),
1228 self.blocking_pool_guard.clone(),
1229 self.eth_config,
1230 )
1231 .into_rpc()
1232 .into(),
1233 RethRpcModule::Web3 => Web3Api::new(self.network.clone()).into_rpc().into(),
1234 RethRpcModule::Txpool => TxPoolApi::new(
1235 self.eth.api.pool().clone(),
1236 self.eth.api.tx_resp_builder().clone(),
1237 )
1238 .into_rpc()
1239 .into(),
1240 RethRpcModule::Rpc => RPCApi::new(
1241 namespaces
1242 .iter()
1243 .map(|module| (module.to_string(), "1.0".to_string()))
1244 .collect(),
1245 )
1246 .into_rpc()
1247 .into(),
1248 RethRpcModule::Ots => OtterscanApi::new(eth_api.clone()).into_rpc().into(),
1249 RethRpcModule::Reth => {
1250 RethApi::new(self.provider.clone(), Box::new(self.executor.clone()))
1251 .into_rpc()
1252 .into()
1253 }
1254 RethRpcModule::Flashbots => Default::default(),
1258 RethRpcModule::Miner => MinerApi::default().into_rpc().into(),
1259 RethRpcModule::Mev => {
1260 EthSimBundle::new(eth_api.clone(), self.blocking_pool_guard.clone())
1261 .into_rpc()
1262 .into()
1263 }
1264 })
1265 .clone()
1266 })
1267 .collect::<Vec<_>>()
1268 }
1269}
1270
1271#[derive(Debug)]
1283pub struct RpcServerConfig<RpcMiddleware = Identity> {
1284 http_server_config: Option<ServerBuilder<Identity, Identity>>,
1286 http_cors_domains: Option<String>,
1288 http_addr: Option<SocketAddr>,
1290 ws_server_config: Option<ServerBuilder<Identity, Identity>>,
1292 ws_cors_domains: Option<String>,
1294 ws_addr: Option<SocketAddr>,
1296 ipc_server_config: Option<IpcServerBuilder<Identity, Identity>>,
1298 ipc_endpoint: Option<String>,
1300 jwt_secret: Option<JwtSecret>,
1302 rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
1304}
1305
1306impl Default for RpcServerConfig<Identity> {
1309 fn default() -> Self {
1311 Self {
1312 http_server_config: None,
1313 http_cors_domains: None,
1314 http_addr: None,
1315 ws_server_config: None,
1316 ws_cors_domains: None,
1317 ws_addr: None,
1318 ipc_server_config: None,
1319 ipc_endpoint: None,
1320 jwt_secret: None,
1321 rpc_middleware: RpcServiceBuilder::new(),
1322 }
1323 }
1324}
1325
1326impl RpcServerConfig {
1327 pub fn http(config: ServerBuilder<Identity, Identity>) -> Self {
1329 Self::default().with_http(config)
1330 }
1331
1332 pub fn ws(config: ServerBuilder<Identity, Identity>) -> Self {
1334 Self::default().with_ws(config)
1335 }
1336
1337 pub fn ipc(config: IpcServerBuilder<Identity, Identity>) -> Self {
1339 Self::default().with_ipc(config)
1340 }
1341
1342 pub fn with_http(mut self, config: ServerBuilder<Identity, Identity>) -> Self {
1347 self.http_server_config =
1348 Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1349 self
1350 }
1351
1352 pub fn with_ws(mut self, config: ServerBuilder<Identity, Identity>) -> Self {
1357 self.ws_server_config = Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1358 self
1359 }
1360
1361 pub fn with_ipc(mut self, config: IpcServerBuilder<Identity, Identity>) -> Self {
1366 self.ipc_server_config = Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
1367 self
1368 }
1369}
1370
1371impl<RpcMiddleware> RpcServerConfig<RpcMiddleware> {
1372 pub fn set_rpc_middleware<T>(self, rpc_middleware: RpcServiceBuilder<T>) -> RpcServerConfig<T> {
1374 RpcServerConfig {
1375 http_server_config: self.http_server_config,
1376 http_cors_domains: self.http_cors_domains,
1377 http_addr: self.http_addr,
1378 ws_server_config: self.ws_server_config,
1379 ws_cors_domains: self.ws_cors_domains,
1380 ws_addr: self.ws_addr,
1381 ipc_server_config: self.ipc_server_config,
1382 ipc_endpoint: self.ipc_endpoint,
1383 jwt_secret: self.jwt_secret,
1384 rpc_middleware,
1385 }
1386 }
1387
1388 pub fn with_cors(self, cors_domain: Option<String>) -> Self {
1390 self.with_http_cors(cors_domain.clone()).with_ws_cors(cors_domain)
1391 }
1392
1393 pub fn with_ws_cors(mut self, cors_domain: Option<String>) -> Self {
1395 self.ws_cors_domains = cors_domain;
1396 self
1397 }
1398
1399 pub fn with_http_cors(mut self, cors_domain: Option<String>) -> Self {
1401 self.http_cors_domains = cors_domain;
1402 self
1403 }
1404
1405 pub const fn with_http_address(mut self, addr: SocketAddr) -> Self {
1410 self.http_addr = Some(addr);
1411 self
1412 }
1413
1414 pub const fn with_ws_address(mut self, addr: SocketAddr) -> Self {
1419 self.ws_addr = Some(addr);
1420 self
1421 }
1422
1423 pub fn with_id_provider<I>(mut self, id_provider: I) -> Self
1427 where
1428 I: IdProvider + Clone + 'static,
1429 {
1430 if let Some(http) = self.http_server_config {
1431 self.http_server_config = Some(http.set_id_provider(id_provider.clone()));
1432 }
1433 if let Some(ws) = self.ws_server_config {
1434 self.ws_server_config = Some(ws.set_id_provider(id_provider.clone()));
1435 }
1436 if let Some(ipc) = self.ipc_server_config {
1437 self.ipc_server_config = Some(ipc.set_id_provider(id_provider));
1438 }
1439
1440 self
1441 }
1442
1443 pub fn with_ipc_endpoint(mut self, path: impl Into<String>) -> Self {
1447 self.ipc_endpoint = Some(path.into());
1448 self
1449 }
1450
1451 pub const fn with_jwt_secret(mut self, secret: Option<JwtSecret>) -> Self {
1453 self.jwt_secret = secret;
1454 self
1455 }
1456
1457 pub const fn has_server(&self) -> bool {
1461 self.http_server_config.is_some() ||
1462 self.ws_server_config.is_some() ||
1463 self.ipc_server_config.is_some()
1464 }
1465
1466 pub const fn http_address(&self) -> Option<SocketAddr> {
1468 self.http_addr
1469 }
1470
1471 pub const fn ws_address(&self) -> Option<SocketAddr> {
1473 self.ws_addr
1474 }
1475
1476 pub fn ipc_endpoint(&self) -> Option<String> {
1478 self.ipc_endpoint.clone()
1479 }
1480
1481 fn maybe_cors_layer(cors: Option<String>) -> Result<Option<CorsLayer>, CorsDomainError> {
1483 cors.as_deref().map(cors::create_cors_layer).transpose()
1484 }
1485
1486 fn maybe_jwt_layer(jwt_secret: Option<JwtSecret>) -> Option<AuthLayer<JwtAuthValidator>> {
1488 jwt_secret.map(|secret| AuthLayer::new(JwtAuthValidator::new(secret)))
1489 }
1490
1491 fn maybe_compression_layer() -> Option<CompressionLayer> {
1494 Some(CompressionLayer::new())
1495 }
1496
1497 pub async fn start(self, modules: &TransportRpcModules) -> Result<RpcServerHandle, RpcError>
1503 where
1504 RpcMiddleware: Layer<RpcRequestMetricsService<RpcService>> + Clone + Send + 'static,
1505 for<'a> <RpcMiddleware as Layer<RpcRequestMetricsService<RpcService>>>::Service:
1506 Send + Sync + 'static + RpcServiceT<'a>,
1507 {
1508 let mut http_handle = None;
1509 let mut ws_handle = None;
1510 let mut ipc_handle = None;
1511
1512 let http_socket_addr = self.http_addr.unwrap_or(SocketAddr::V4(SocketAddrV4::new(
1513 Ipv4Addr::LOCALHOST,
1514 constants::DEFAULT_HTTP_RPC_PORT,
1515 )));
1516
1517 let ws_socket_addr = self.ws_addr.unwrap_or(SocketAddr::V4(SocketAddrV4::new(
1518 Ipv4Addr::LOCALHOST,
1519 constants::DEFAULT_WS_RPC_PORT,
1520 )));
1521
1522 let metrics = modules.ipc.as_ref().map(RpcRequestMetrics::ipc).unwrap_or_default();
1523 let ipc_path =
1524 self.ipc_endpoint.clone().unwrap_or_else(|| constants::DEFAULT_IPC_ENDPOINT.into());
1525
1526 if let Some(builder) = self.ipc_server_config {
1527 let ipc = builder
1528 .set_rpc_middleware(IpcRpcServiceBuilder::new().layer(metrics))
1529 .build(ipc_path);
1530 ipc_handle = Some(ipc.start(modules.ipc.clone().expect("ipc server error")).await?);
1531 }
1532
1533 if self.http_addr == self.ws_addr &&
1535 self.http_server_config.is_some() &&
1536 self.ws_server_config.is_some()
1537 {
1538 let cors = match (self.ws_cors_domains.as_ref(), self.http_cors_domains.as_ref()) {
1539 (Some(ws_cors), Some(http_cors)) => {
1540 if ws_cors.trim() != http_cors.trim() {
1541 return Err(WsHttpSamePortError::ConflictingCorsDomains {
1542 http_cors_domains: Some(http_cors.clone()),
1543 ws_cors_domains: Some(ws_cors.clone()),
1544 }
1545 .into());
1546 }
1547 Some(ws_cors)
1548 }
1549 (a, b) => a.or(b),
1550 }
1551 .cloned();
1552
1553 modules.config.ensure_ws_http_identical()?;
1555
1556 if let Some(builder) = self.http_server_config {
1557 let server = builder
1558 .set_http_middleware(
1559 tower::ServiceBuilder::new()
1560 .option_layer(Self::maybe_cors_layer(cors)?)
1561 .option_layer(Self::maybe_jwt_layer(self.jwt_secret))
1562 .option_layer(Self::maybe_compression_layer()),
1563 )
1564 .set_rpc_middleware(
1565 self.rpc_middleware.clone().layer(
1566 modules
1567 .http
1568 .as_ref()
1569 .or(modules.ws.as_ref())
1570 .map(RpcRequestMetrics::same_port)
1571 .unwrap_or_default(),
1572 ),
1573 )
1574 .build(http_socket_addr)
1575 .await
1576 .map_err(|err| {
1577 RpcError::server_error(err, ServerKind::WsHttp(http_socket_addr))
1578 })?;
1579 let addr = server.local_addr().map_err(|err| {
1580 RpcError::server_error(err, ServerKind::WsHttp(http_socket_addr))
1581 })?;
1582 if let Some(module) = modules.http.as_ref().or(modules.ws.as_ref()) {
1583 let handle = server.start(module.clone());
1584 http_handle = Some(handle.clone());
1585 ws_handle = Some(handle);
1586 }
1587 return Ok(RpcServerHandle {
1588 http_local_addr: Some(addr),
1589 ws_local_addr: Some(addr),
1590 http: http_handle,
1591 ws: ws_handle,
1592 ipc_endpoint: self.ipc_endpoint.clone(),
1593 ipc: ipc_handle,
1594 jwt_secret: self.jwt_secret,
1595 });
1596 }
1597 }
1598
1599 let mut ws_local_addr = None;
1600 let mut ws_server = None;
1601 let mut http_local_addr = None;
1602 let mut http_server = None;
1603
1604 if let Some(builder) = self.ws_server_config {
1605 let server = builder
1606 .ws_only()
1607 .set_http_middleware(
1608 tower::ServiceBuilder::new()
1609 .option_layer(Self::maybe_cors_layer(self.ws_cors_domains.clone())?)
1610 .option_layer(Self::maybe_jwt_layer(self.jwt_secret)),
1611 )
1612 .set_rpc_middleware(
1613 self.rpc_middleware
1614 .clone()
1615 .layer(modules.ws.as_ref().map(RpcRequestMetrics::ws).unwrap_or_default()),
1616 )
1617 .build(ws_socket_addr)
1618 .await
1619 .map_err(|err| RpcError::server_error(err, ServerKind::WS(ws_socket_addr)))?;
1620
1621 let addr = server
1622 .local_addr()
1623 .map_err(|err| RpcError::server_error(err, ServerKind::WS(ws_socket_addr)))?;
1624
1625 ws_local_addr = Some(addr);
1626 ws_server = Some(server);
1627 }
1628
1629 if let Some(builder) = self.http_server_config {
1630 let server = builder
1631 .http_only()
1632 .set_http_middleware(
1633 tower::ServiceBuilder::new()
1634 .option_layer(Self::maybe_cors_layer(self.http_cors_domains.clone())?)
1635 .option_layer(Self::maybe_jwt_layer(self.jwt_secret))
1636 .option_layer(Self::maybe_compression_layer()),
1637 )
1638 .set_rpc_middleware(
1639 self.rpc_middleware.clone().layer(
1640 modules.http.as_ref().map(RpcRequestMetrics::http).unwrap_or_default(),
1641 ),
1642 )
1643 .build(http_socket_addr)
1644 .await
1645 .map_err(|err| RpcError::server_error(err, ServerKind::Http(http_socket_addr)))?;
1646 let local_addr = server
1647 .local_addr()
1648 .map_err(|err| RpcError::server_error(err, ServerKind::Http(http_socket_addr)))?;
1649 http_local_addr = Some(local_addr);
1650 http_server = Some(server);
1651 }
1652
1653 http_handle = http_server
1654 .map(|http_server| http_server.start(modules.http.clone().expect("http server error")));
1655 ws_handle = ws_server
1656 .map(|ws_server| ws_server.start(modules.ws.clone().expect("ws server error")));
1657 Ok(RpcServerHandle {
1658 http_local_addr,
1659 ws_local_addr,
1660 http: http_handle,
1661 ws: ws_handle,
1662 ipc_endpoint: self.ipc_endpoint.clone(),
1663 ipc: ipc_handle,
1664 jwt_secret: self.jwt_secret,
1665 })
1666 }
1667}
1668
1669#[derive(Debug, Clone, Default, Eq, PartialEq)]
1681pub struct TransportRpcModuleConfig {
1682 http: Option<RpcModuleSelection>,
1684 ws: Option<RpcModuleSelection>,
1686 ipc: Option<RpcModuleSelection>,
1688 config: Option<RpcModuleConfig>,
1690}
1691
1692impl TransportRpcModuleConfig {
1695 pub fn set_http(http: impl Into<RpcModuleSelection>) -> Self {
1697 Self::default().with_http(http)
1698 }
1699
1700 pub fn set_ws(ws: impl Into<RpcModuleSelection>) -> Self {
1702 Self::default().with_ws(ws)
1703 }
1704
1705 pub fn set_ipc(ipc: impl Into<RpcModuleSelection>) -> Self {
1707 Self::default().with_ipc(ipc)
1708 }
1709
1710 pub fn with_http(mut self, http: impl Into<RpcModuleSelection>) -> Self {
1712 self.http = Some(http.into());
1713 self
1714 }
1715
1716 pub fn with_ws(mut self, ws: impl Into<RpcModuleSelection>) -> Self {
1718 self.ws = Some(ws.into());
1719 self
1720 }
1721
1722 pub fn with_ipc(mut self, ipc: impl Into<RpcModuleSelection>) -> Self {
1724 self.ipc = Some(ipc.into());
1725 self
1726 }
1727
1728 pub fn with_config(mut self, config: RpcModuleConfig) -> Self {
1730 self.config = Some(config);
1731 self
1732 }
1733
1734 pub const fn http_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1736 &mut self.http
1737 }
1738
1739 pub const fn ws_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1741 &mut self.ws
1742 }
1743
1744 pub const fn ipc_mut(&mut self) -> &mut Option<RpcModuleSelection> {
1746 &mut self.ipc
1747 }
1748
1749 pub const fn config_mut(&mut self) -> &mut Option<RpcModuleConfig> {
1751 &mut self.config
1752 }
1753
1754 pub const fn is_empty(&self) -> bool {
1756 self.http.is_none() && self.ws.is_none() && self.ipc.is_none()
1757 }
1758
1759 pub const fn http(&self) -> Option<&RpcModuleSelection> {
1761 self.http.as_ref()
1762 }
1763
1764 pub const fn ws(&self) -> Option<&RpcModuleSelection> {
1766 self.ws.as_ref()
1767 }
1768
1769 pub const fn ipc(&self) -> Option<&RpcModuleSelection> {
1771 self.ipc.as_ref()
1772 }
1773
1774 pub const fn config(&self) -> Option<&RpcModuleConfig> {
1776 self.config.as_ref()
1777 }
1778
1779 pub fn contains_any(&self, module: &RethRpcModule) -> bool {
1781 self.contains_http(module) || self.contains_ws(module) || self.contains_ipc(module)
1782 }
1783
1784 pub fn contains_http(&self, module: &RethRpcModule) -> bool {
1786 self.http.as_ref().is_some_and(|http| http.contains(module))
1787 }
1788
1789 pub fn contains_ws(&self, module: &RethRpcModule) -> bool {
1791 self.ws.as_ref().is_some_and(|ws| ws.contains(module))
1792 }
1793
1794 pub fn contains_ipc(&self, module: &RethRpcModule) -> bool {
1796 self.ipc.as_ref().is_some_and(|ipc| ipc.contains(module))
1797 }
1798
1799 fn ensure_ws_http_identical(&self) -> Result<(), WsHttpSamePortError> {
1802 if RpcModuleSelection::are_identical(self.http.as_ref(), self.ws.as_ref()) {
1803 Ok(())
1804 } else {
1805 let http_modules =
1806 self.http.as_ref().map(RpcModuleSelection::to_selection).unwrap_or_default();
1807 let ws_modules =
1808 self.ws.as_ref().map(RpcModuleSelection::to_selection).unwrap_or_default();
1809
1810 let http_not_ws = http_modules.difference(&ws_modules).copied().collect();
1811 let ws_not_http = ws_modules.difference(&http_modules).copied().collect();
1812 let overlap = http_modules.intersection(&ws_modules).copied().collect();
1813
1814 Err(WsHttpSamePortError::ConflictingModules(Box::new(ConflictingModules {
1815 overlap,
1816 http_not_ws,
1817 ws_not_http,
1818 })))
1819 }
1820 }
1821}
1822
1823#[derive(Debug, Clone, Default)]
1825pub struct TransportRpcModules<Context = ()> {
1826 config: TransportRpcModuleConfig,
1828 http: Option<RpcModule<Context>>,
1830 ws: Option<RpcModule<Context>>,
1832 ipc: Option<RpcModule<Context>>,
1834}
1835
1836impl TransportRpcModules {
1839 pub fn with_config(mut self, config: TransportRpcModuleConfig) -> Self {
1842 self.config = config;
1843 self
1844 }
1845
1846 pub fn with_http(mut self, http: RpcModule<()>) -> Self {
1849 self.http = Some(http);
1850 self
1851 }
1852
1853 pub fn with_ws(mut self, ws: RpcModule<()>) -> Self {
1856 self.ws = Some(ws);
1857 self
1858 }
1859
1860 pub fn with_ipc(mut self, ipc: RpcModule<()>) -> Self {
1863 self.ipc = Some(ipc);
1864 self
1865 }
1866
1867 pub const fn module_config(&self) -> &TransportRpcModuleConfig {
1869 &self.config
1870 }
1871
1872 pub fn merge_if_module_configured(
1877 &mut self,
1878 module: RethRpcModule,
1879 other: impl Into<Methods>,
1880 ) -> Result<(), RegisterMethodError> {
1881 let other = other.into();
1882 if self.module_config().contains_http(&module) {
1883 self.merge_http(other.clone())?;
1884 }
1885 if self.module_config().contains_ws(&module) {
1886 self.merge_ws(other.clone())?;
1887 }
1888 if self.module_config().contains_ipc(&module) {
1889 self.merge_ipc(other)?;
1890 }
1891
1892 Ok(())
1893 }
1894
1895 pub fn merge_http(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1901 if let Some(ref mut http) = self.http {
1902 return http.merge(other.into()).map(|_| true)
1903 }
1904 Ok(false)
1905 }
1906
1907 pub fn merge_ws(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1913 if let Some(ref mut ws) = self.ws {
1914 return ws.merge(other.into()).map(|_| true)
1915 }
1916 Ok(false)
1917 }
1918
1919 pub fn merge_ipc(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
1925 if let Some(ref mut ipc) = self.ipc {
1926 return ipc.merge(other.into()).map(|_| true)
1927 }
1928 Ok(false)
1929 }
1930
1931 pub fn merge_configured(
1935 &mut self,
1936 other: impl Into<Methods>,
1937 ) -> Result<(), RegisterMethodError> {
1938 let other = other.into();
1939 self.merge_http(other.clone())?;
1940 self.merge_ws(other.clone())?;
1941 self.merge_ipc(other)?;
1942 Ok(())
1943 }
1944
1945 pub fn methods_by_module<F>(&self, module: RethRpcModule) -> Methods {
1949 self.methods_by(|name| name.starts_with(module.as_str()))
1950 }
1951
1952 pub fn methods_by<F>(&self, mut filter: F) -> Methods
1956 where
1957 F: FnMut(&str) -> bool,
1958 {
1959 let mut methods = Methods::new();
1960
1961 let mut f =
1963 |name: &str, mm: &Methods| filter(name) && !mm.method_names().any(|m| m == name);
1964
1965 if let Some(m) = self.http_methods(|name| f(name, &methods)) {
1966 let _ = methods.merge(m);
1967 }
1968 if let Some(m) = self.ws_methods(|name| f(name, &methods)) {
1969 let _ = methods.merge(m);
1970 }
1971 if let Some(m) = self.ipc_methods(|name| f(name, &methods)) {
1972 let _ = methods.merge(m);
1973 }
1974 methods
1975 }
1976
1977 pub fn http_methods<F>(&self, filter: F) -> Option<Methods>
1981 where
1982 F: FnMut(&str) -> bool,
1983 {
1984 self.http.as_ref().map(|module| methods_by(module, filter))
1985 }
1986
1987 pub fn ws_methods<F>(&self, filter: F) -> Option<Methods>
1991 where
1992 F: FnMut(&str) -> bool,
1993 {
1994 self.ws.as_ref().map(|module| methods_by(module, filter))
1995 }
1996
1997 pub fn ipc_methods<F>(&self, filter: F) -> Option<Methods>
2001 where
2002 F: FnMut(&str) -> bool,
2003 {
2004 self.ipc.as_ref().map(|module| methods_by(module, filter))
2005 }
2006
2007 pub fn remove_http_method(&mut self, method_name: &'static str) -> bool {
2015 if let Some(http_module) = &mut self.http {
2016 http_module.remove_method(method_name).is_some()
2017 } else {
2018 false
2019 }
2020 }
2021
2022 pub fn remove_http_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
2024 for name in methods {
2025 self.remove_http_method(name);
2026 }
2027 }
2028
2029 pub fn remove_ws_method(&mut self, method_name: &'static str) -> bool {
2037 if let Some(ws_module) = &mut self.ws {
2038 ws_module.remove_method(method_name).is_some()
2039 } else {
2040 false
2041 }
2042 }
2043
2044 pub fn remove_ws_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
2046 for name in methods {
2047 self.remove_ws_method(name);
2048 }
2049 }
2050
2051 pub fn remove_ipc_method(&mut self, method_name: &'static str) -> bool {
2059 if let Some(ipc_module) = &mut self.ipc {
2060 ipc_module.remove_method(method_name).is_some()
2061 } else {
2062 false
2063 }
2064 }
2065
2066 pub fn remove_ipc_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
2068 for name in methods {
2069 self.remove_ipc_method(name);
2070 }
2071 }
2072
2073 pub fn remove_method_from_configured(&mut self, method_name: &'static str) -> bool {
2077 let http_removed = self.remove_http_method(method_name);
2078 let ws_removed = self.remove_ws_method(method_name);
2079 let ipc_removed = self.remove_ipc_method(method_name);
2080
2081 http_removed || ws_removed || ipc_removed
2082 }
2083
2084 pub fn rename(
2088 &mut self,
2089 old_name: &'static str,
2090 new_method: impl Into<Methods>,
2091 ) -> Result<(), RegisterMethodError> {
2092 self.remove_method_from_configured(old_name);
2094
2095 self.merge_configured(new_method)
2097 }
2098
2099 pub fn replace_http(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
2106 let other = other.into();
2107 self.remove_http_methods(other.method_names());
2108 self.merge_http(other)
2109 }
2110
2111 pub fn replace_ipc(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
2118 let other = other.into();
2119 self.remove_ipc_methods(other.method_names());
2120 self.merge_ipc(other)
2121 }
2122
2123 pub fn replace_ws(&mut self, other: impl Into<Methods>) -> Result<bool, RegisterMethodError> {
2130 let other = other.into();
2131 self.remove_ws_methods(other.method_names());
2132 self.merge_ws(other)
2133 }
2134
2135 pub fn replace_configured(
2139 &mut self,
2140 other: impl Into<Methods>,
2141 ) -> Result<bool, RegisterMethodError> {
2142 let other = other.into();
2143 self.replace_http(other.clone())?;
2144 self.replace_ws(other.clone())?;
2145 self.replace_ipc(other)?;
2146 Ok(true)
2147 }
2148}
2149
2150fn methods_by<T, F>(module: &RpcModule<T>, mut filter: F) -> Methods
2152where
2153 F: FnMut(&str) -> bool,
2154{
2155 let mut methods = Methods::new();
2156 let method_names = module.method_names().filter(|name| filter(name));
2157
2158 for name in method_names {
2159 if let Some(matched_method) = module.method(name).cloned() {
2160 let _ = methods.verify_and_insert(name, matched_method);
2161 }
2162 }
2163
2164 methods
2165}
2166
2167#[derive(Clone, Debug)]
2172#[must_use = "Server stops if dropped"]
2173pub struct RpcServerHandle {
2174 http_local_addr: Option<SocketAddr>,
2176 ws_local_addr: Option<SocketAddr>,
2177 http: Option<ServerHandle>,
2178 ws: Option<ServerHandle>,
2179 ipc_endpoint: Option<String>,
2180 ipc: Option<jsonrpsee::server::ServerHandle>,
2181 jwt_secret: Option<JwtSecret>,
2182}
2183
2184impl RpcServerHandle {
2187 fn bearer_token(&self) -> Option<String> {
2189 self.jwt_secret.as_ref().map(|secret| {
2190 format!(
2191 "Bearer {}",
2192 secret
2193 .encode(&Claims {
2194 iat: (SystemTime::now().duration_since(UNIX_EPOCH).unwrap() +
2195 Duration::from_secs(60))
2196 .as_secs(),
2197 exp: None,
2198 })
2199 .unwrap()
2200 )
2201 })
2202 }
2203 pub const fn http_local_addr(&self) -> Option<SocketAddr> {
2205 self.http_local_addr
2206 }
2207
2208 pub const fn ws_local_addr(&self) -> Option<SocketAddr> {
2210 self.ws_local_addr
2211 }
2212
2213 pub fn stop(self) -> Result<(), AlreadyStoppedError> {
2215 if let Some(handle) = self.http {
2216 handle.stop()?
2217 }
2218
2219 if let Some(handle) = self.ws {
2220 handle.stop()?
2221 }
2222
2223 if let Some(handle) = self.ipc {
2224 handle.stop()?
2225 }
2226
2227 Ok(())
2228 }
2229
2230 pub fn ipc_endpoint(&self) -> Option<String> {
2232 self.ipc_endpoint.clone()
2233 }
2234
2235 pub fn http_url(&self) -> Option<String> {
2237 self.http_local_addr.map(|addr| format!("http://{addr}"))
2238 }
2239
2240 pub fn ws_url(&self) -> Option<String> {
2242 self.ws_local_addr.map(|addr| format!("ws://{addr}"))
2243 }
2244
2245 pub fn http_client(&self) -> Option<jsonrpsee::http_client::HttpClient> {
2247 let url = self.http_url()?;
2248
2249 let client = if let Some(token) = self.bearer_token() {
2250 jsonrpsee::http_client::HttpClientBuilder::default()
2251 .set_headers(HeaderMap::from_iter([(AUTHORIZATION, token.parse().unwrap())]))
2252 .build(url)
2253 } else {
2254 jsonrpsee::http_client::HttpClientBuilder::default().build(url)
2255 };
2256
2257 client.expect("failed to create http client").into()
2258 }
2259
2260 pub async fn ws_client(&self) -> Option<jsonrpsee::ws_client::WsClient> {
2262 let url = self.ws_url()?;
2263 let mut builder = jsonrpsee::ws_client::WsClientBuilder::default();
2264
2265 if let Some(token) = self.bearer_token() {
2266 let headers = HeaderMap::from_iter([(AUTHORIZATION, token.parse().unwrap())]);
2267 builder = builder.set_headers(headers);
2268 }
2269
2270 let client = builder.build(url).await.expect("failed to create ws client");
2271 Some(client)
2272 }
2273
2274 pub fn eth_http_provider(
2276 &self,
2277 ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2278 self.new_http_provider_for()
2279 }
2280
2281 pub fn new_http_provider_for<N>(&self) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2286 where
2287 N: RecommendedFillers<RecommendedFillers: Unpin>,
2288 {
2289 let rpc_url = self.http_url()?;
2290 let provider = ProviderBuilder::default()
2291 .with_recommended_fillers()
2292 .on_http(rpc_url.parse().expect("valid url"));
2293 Some(provider)
2294 }
2295
2296 pub async fn eth_ws_provider(
2298 &self,
2299 ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2300 self.new_ws_provider_for().await
2301 }
2302
2303 pub async fn new_ws_provider_for<N>(&self) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2308 where
2309 N: RecommendedFillers<RecommendedFillers: Unpin>,
2310 {
2311 let rpc_url = self.ws_url()?;
2312 let provider = ProviderBuilder::default()
2313 .with_recommended_fillers()
2314 .connect(&rpc_url)
2315 .await
2316 .expect("failed to create ws client");
2317 Some(provider)
2318 }
2319
2320 pub async fn eth_ipc_provider(
2322 &self,
2323 ) -> Option<impl Provider<alloy_network::Ethereum> + Clone + Unpin + 'static> {
2324 self.new_ws_provider_for().await
2325 }
2326
2327 pub async fn new_ipc_provider_for<N>(
2332 &self,
2333 ) -> Option<impl Provider<N> + Clone + Unpin + 'static>
2334 where
2335 N: RecommendedFillers<RecommendedFillers: Unpin>,
2336 {
2337 let rpc_url = self.ipc_endpoint()?;
2338 let provider = ProviderBuilder::default()
2339 .with_recommended_fillers()
2340 .connect(&rpc_url)
2341 .await
2342 .expect("failed to create ipc client");
2343 Some(provider)
2344 }
2345}
2346
2347#[cfg(test)]
2348mod tests {
2349 use super::*;
2350
2351 #[test]
2352 fn parse_eth_call_bundle_selection() {
2353 let selection = "eth,admin,debug".parse::<RpcModuleSelection>().unwrap();
2354 assert_eq!(
2355 selection,
2356 RpcModuleSelection::Selection(
2357 [RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Debug,].into()
2358 )
2359 );
2360 }
2361
2362 #[test]
2363 fn parse_rpc_module_selection() {
2364 let selection = "all".parse::<RpcModuleSelection>().unwrap();
2365 assert_eq!(selection, RpcModuleSelection::All);
2366 }
2367
2368 #[test]
2369 fn parse_rpc_module_selection_none() {
2370 let selection = "none".parse::<RpcModuleSelection>().unwrap();
2371 assert_eq!(selection, RpcModuleSelection::Selection(Default::default()));
2372 }
2373
2374 #[test]
2375 fn parse_rpc_unique_module_selection() {
2376 let selection = "eth,admin,eth,net".parse::<RpcModuleSelection>().unwrap();
2377 assert_eq!(
2378 selection,
2379 RpcModuleSelection::Selection(
2380 [RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Net,].into()
2381 )
2382 );
2383 }
2384
2385 #[test]
2386 fn identical_selection() {
2387 assert!(RpcModuleSelection::are_identical(
2388 Some(&RpcModuleSelection::All),
2389 Some(&RpcModuleSelection::All),
2390 ));
2391 assert!(!RpcModuleSelection::are_identical(
2392 Some(&RpcModuleSelection::All),
2393 Some(&RpcModuleSelection::Standard),
2394 ));
2395 assert!(RpcModuleSelection::are_identical(
2396 Some(&RpcModuleSelection::Selection(RpcModuleSelection::Standard.to_selection())),
2397 Some(&RpcModuleSelection::Standard),
2398 ));
2399 assert!(RpcModuleSelection::are_identical(
2400 Some(&RpcModuleSelection::Selection([RethRpcModule::Eth].into())),
2401 Some(&RpcModuleSelection::Selection([RethRpcModule::Eth].into())),
2402 ));
2403 assert!(RpcModuleSelection::are_identical(
2404 None,
2405 Some(&RpcModuleSelection::Selection(Default::default())),
2406 ));
2407 assert!(RpcModuleSelection::are_identical(
2408 Some(&RpcModuleSelection::Selection(Default::default())),
2409 None,
2410 ));
2411 assert!(RpcModuleSelection::are_identical(None, None));
2412 }
2413
2414 #[test]
2415 fn test_rpc_module_str() {
2416 macro_rules! assert_rpc_module {
2417 ($($s:expr => $v:expr,)*) => {
2418 $(
2419 let val: RethRpcModule = $s.parse().unwrap();
2420 assert_eq!(val, $v);
2421 assert_eq!(val.to_string().as_str(), $s);
2422 )*
2423 };
2424 }
2425 assert_rpc_module!
2426 (
2427 "admin" => RethRpcModule::Admin,
2428 "debug" => RethRpcModule::Debug,
2429 "eth" => RethRpcModule::Eth,
2430 "net" => RethRpcModule::Net,
2431 "trace" => RethRpcModule::Trace,
2432 "web3" => RethRpcModule::Web3,
2433 "rpc" => RethRpcModule::Rpc,
2434 "ots" => RethRpcModule::Ots,
2435 "reth" => RethRpcModule::Reth,
2436 );
2437 }
2438
2439 #[test]
2440 fn test_default_selection() {
2441 let selection = RpcModuleSelection::Standard.to_selection();
2442 assert_eq!(selection, [RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3].into())
2443 }
2444
2445 #[test]
2446 fn test_create_rpc_module_config() {
2447 let selection = vec!["eth", "admin"];
2448 let config = RpcModuleSelection::try_from_selection(selection).unwrap();
2449 assert_eq!(
2450 config,
2451 RpcModuleSelection::Selection([RethRpcModule::Eth, RethRpcModule::Admin].into())
2452 );
2453 }
2454
2455 #[test]
2456 fn test_configure_transport_config() {
2457 let config = TransportRpcModuleConfig::default()
2458 .with_http([RethRpcModule::Eth, RethRpcModule::Admin]);
2459 assert_eq!(
2460 config,
2461 TransportRpcModuleConfig {
2462 http: Some(RpcModuleSelection::Selection(
2463 [RethRpcModule::Eth, RethRpcModule::Admin].into()
2464 )),
2465 ws: None,
2466 ipc: None,
2467 config: None,
2468 }
2469 )
2470 }
2471
2472 #[test]
2473 fn test_configure_transport_config_none() {
2474 let config = TransportRpcModuleConfig::default().with_http(Vec::<RethRpcModule>::new());
2475 assert_eq!(
2476 config,
2477 TransportRpcModuleConfig {
2478 http: Some(RpcModuleSelection::Selection(Default::default())),
2479 ws: None,
2480 ipc: None,
2481 config: None,
2482 }
2483 )
2484 }
2485
2486 fn create_test_module() -> RpcModule<()> {
2487 let mut module = RpcModule::new(());
2488 module.register_method("anything", |_, _, _| "succeed").unwrap();
2489 module
2490 }
2491
2492 #[test]
2493 fn test_remove_http_method() {
2494 let mut modules =
2495 TransportRpcModules { http: Some(create_test_module()), ..Default::default() };
2496 assert!(modules.remove_http_method("anything"));
2498
2499 assert!(!modules.remove_http_method("non_existent_method"));
2501
2502 assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2504 }
2505
2506 #[test]
2507 fn test_remove_ws_method() {
2508 let mut modules =
2509 TransportRpcModules { ws: Some(create_test_module()), ..Default::default() };
2510
2511 assert!(modules.remove_ws_method("anything"));
2513
2514 assert!(!modules.remove_ws_method("non_existent_method"));
2516
2517 assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2519 }
2520
2521 #[test]
2522 fn test_remove_ipc_method() {
2523 let mut modules =
2524 TransportRpcModules { ipc: Some(create_test_module()), ..Default::default() };
2525
2526 assert!(modules.remove_ipc_method("anything"));
2528
2529 assert!(!modules.remove_ipc_method("non_existent_method"));
2531
2532 assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2534 }
2535
2536 #[test]
2537 fn test_remove_method_from_configured() {
2538 let mut modules = TransportRpcModules {
2539 http: Some(create_test_module()),
2540 ws: Some(create_test_module()),
2541 ipc: Some(create_test_module()),
2542 ..Default::default()
2543 };
2544
2545 assert!(modules.remove_method_from_configured("anything"));
2547
2548 assert!(!modules.remove_method_from_configured("anything"));
2550
2551 assert!(!modules.remove_method_from_configured("non_existent_method"));
2553
2554 assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2556 assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2557 assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2558 }
2559
2560 #[test]
2561 fn test_transport_rpc_module_rename() {
2562 let mut modules = TransportRpcModules {
2563 http: Some(create_test_module()),
2564 ws: Some(create_test_module()),
2565 ipc: Some(create_test_module()),
2566 ..Default::default()
2567 };
2568
2569 assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2571 assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2572 assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2573
2574 assert!(modules.http.as_ref().unwrap().method("something").is_none());
2576 assert!(modules.ws.as_ref().unwrap().method("something").is_none());
2577 assert!(modules.ipc.as_ref().unwrap().method("something").is_none());
2578
2579 let mut other_module = RpcModule::new(());
2581 other_module.register_method("something", |_, _, _| "fails").unwrap();
2582
2583 modules.rename("anything", other_module).expect("rename failed");
2585
2586 assert!(modules.http.as_ref().unwrap().method("anything").is_none());
2588 assert!(modules.ws.as_ref().unwrap().method("anything").is_none());
2589 assert!(modules.ipc.as_ref().unwrap().method("anything").is_none());
2590
2591 assert!(modules.http.as_ref().unwrap().method("something").is_some());
2593 assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2594 assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2595 }
2596
2597 #[test]
2598 fn test_replace_http_method() {
2599 let mut modules =
2600 TransportRpcModules { http: Some(create_test_module()), ..Default::default() };
2601
2602 let mut other_module = RpcModule::new(());
2603 other_module.register_method("something", |_, _, _| "fails").unwrap();
2604
2605 assert!(modules.replace_http(other_module.clone()).unwrap());
2606
2607 assert!(modules.http.as_ref().unwrap().method("something").is_some());
2608
2609 other_module.register_method("anything", |_, _, _| "fails").unwrap();
2610 assert!(modules.replace_http(other_module.clone()).unwrap());
2611
2612 assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2613 }
2614 #[test]
2615 fn test_replace_ipc_method() {
2616 let mut modules =
2617 TransportRpcModules { ipc: Some(create_test_module()), ..Default::default() };
2618
2619 let mut other_module = RpcModule::new(());
2620 other_module.register_method("something", |_, _, _| "fails").unwrap();
2621
2622 assert!(modules.replace_ipc(other_module.clone()).unwrap());
2623
2624 assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2625
2626 other_module.register_method("anything", |_, _, _| "fails").unwrap();
2627 assert!(modules.replace_ipc(other_module.clone()).unwrap());
2628
2629 assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2630 }
2631 #[test]
2632 fn test_replace_ws_method() {
2633 let mut modules =
2634 TransportRpcModules { ws: Some(create_test_module()), ..Default::default() };
2635
2636 let mut other_module = RpcModule::new(());
2637 other_module.register_method("something", |_, _, _| "fails").unwrap();
2638
2639 assert!(modules.replace_ws(other_module.clone()).unwrap());
2640
2641 assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2642
2643 other_module.register_method("anything", |_, _, _| "fails").unwrap();
2644 assert!(modules.replace_ws(other_module.clone()).unwrap());
2645
2646 assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2647 }
2648
2649 #[test]
2650 fn test_replace_configured() {
2651 let mut modules = TransportRpcModules {
2652 http: Some(create_test_module()),
2653 ws: Some(create_test_module()),
2654 ipc: Some(create_test_module()),
2655 ..Default::default()
2656 };
2657 let mut other_module = RpcModule::new(());
2658 other_module.register_method("something", |_, _, _| "fails").unwrap();
2659
2660 assert!(modules.replace_configured(other_module).unwrap());
2661
2662 assert!(modules.http.as_ref().unwrap().method("something").is_some());
2664 assert!(modules.ipc.as_ref().unwrap().method("something").is_some());
2665 assert!(modules.ws.as_ref().unwrap().method("something").is_some());
2666
2667 assert!(modules.http.as_ref().unwrap().method("anything").is_some());
2668 assert!(modules.ipc.as_ref().unwrap().method("anything").is_some());
2669 assert!(modules.ws.as_ref().unwrap().method("anything").is_some());
2670 }
2671}