1#![allow(unused)]
30mod module;
31
32pub use crate::{
33 error::*, id_provider::SubscriptionIdProvider, RpcServerHandle,
34};
35use cfx_rpc_middlewares::{
36 load_throttling_manager, maybe_cors_layer, Logger, Metrics, Throttle,
37};
38pub use module::{EthRpcModule, RpcModuleSelection};
39
40use cfx_rpc_cfx_types::RpcImplConfiguration;
41use cfx_rpc_eth_api::*;
42use cfx_rpc_eth_impl::{helpers::ChainInfo, *};
43use cfx_tasks::TaskExecutor;
44use cfxcore::{
45 Notifications, SharedConsensusGraph, SharedSynchronizationService,
46 SharedTransactionPool,
47};
48pub use jsonrpsee::server::ServerBuilder;
49use jsonrpsee::{
50 core::RegisterMethodError,
51 server::{
52 middleware::rpc::RpcServiceBuilder, AlreadyStoppedError, IdProvider,
53 ServerConfigBuilder, ServerHandle,
54 },
55 Methods, RpcModule,
56};
57use std::{
58 collections::HashMap,
59 net::{Ipv4Addr, SocketAddr, SocketAddrV4},
60 sync::Arc,
61};
62
63pub const DEFAULT_HTTP_PORT: u16 = 8545;
64pub const DEFAULT_WS_PORT: u16 = 8546;
65
66#[derive(Clone)]
70pub struct RpcModuleBuilder {
71 config: RpcImplConfiguration,
72 consensus: SharedConsensusGraph,
73 sync: SharedSynchronizationService,
74 tx_pool: SharedTransactionPool,
75 executor: TaskExecutor,
76 notifications: Arc<Notifications>,
77}
78
79impl RpcModuleBuilder {
80 pub fn new(
81 config: RpcImplConfiguration, consensus: SharedConsensusGraph,
82 sync: SharedSynchronizationService, tx_pool: SharedTransactionPool,
83 executor: TaskExecutor, notifications: Arc<Notifications>,
84 ) -> Self {
85 Self {
86 config,
87 consensus,
88 sync,
89 tx_pool,
90 executor,
91 notifications,
92 }
93 }
94
95 pub fn build(
99 self, module_config: TransportRpcModuleConfig,
100 ) -> TransportRpcModules<()> {
101 let mut modules = TransportRpcModules::default();
102
103 if !module_config.is_empty() {
104 let TransportRpcModuleConfig { http, ws } = module_config.clone();
105
106 let Self {
107 config,
108 consensus,
109 sync,
110 tx_pool,
111 executor,
112 notifications,
113 } = self;
114
115 let mut registry = RpcRegistryInner::new(
116 config,
117 consensus,
118 sync,
119 tx_pool,
120 executor,
121 notifications,
122 );
123
124 modules.config = module_config;
125 modules.http = registry.maybe_module(http.as_ref());
126 modules.ws = registry.maybe_module(ws.as_ref());
127 }
128
129 modules
130 }
131}
132
133#[derive(Clone)]
135pub struct RpcRegistryInner {
136 consensus: SharedConsensusGraph,
137 config: RpcImplConfiguration,
138 sync: SharedSynchronizationService,
139 tx_pool: SharedTransactionPool,
140 modules: HashMap<EthRpcModule, Methods>,
141 executor: TaskExecutor,
142 notifications: Arc<Notifications>,
143}
144
145impl RpcRegistryInner {
146 pub fn new(
147 config: RpcImplConfiguration, consensus: SharedConsensusGraph,
148 sync: SharedSynchronizationService, tx_pool: SharedTransactionPool,
149 executor: TaskExecutor, notifications: Arc<Notifications>,
150 ) -> Self {
151 Self {
152 consensus,
153 config,
154 sync,
155 tx_pool,
156 modules: Default::default(),
157 executor,
158 notifications,
159 }
160 }
161
162 pub fn methods(&self) -> Vec<Methods> {
164 self.modules.values().cloned().collect()
165 }
166
167 pub fn module(&self) -> RpcModule<()> {
169 let mut module = RpcModule::new(());
170 for methods in self.modules.values().cloned() {
171 module.merge(methods).expect("No conflicts");
172 }
173 module
174 }
175}
176
177impl RpcRegistryInner {
178 pub fn web3_api(&self) -> Web3Api { Web3Api }
179
180 pub fn register_web3(&mut self) -> &mut Self {
181 let web3api = self.web3_api();
182 self.modules
183 .insert(EthRpcModule::Web3, web3api.into_rpc().into());
184 self
185 }
186
187 pub fn trace_api(&self) -> TraceApi {
188 TraceApi::new(
189 self.consensus.clone(),
190 self.sync.network.get_network_type().clone(),
191 self.config.max_estimation_gas_limit,
192 )
193 }
194
195 pub fn debug_api(&self) -> DebugApi {
196 DebugApi::new(
197 self.consensus.clone(),
198 self.config.max_estimation_gas_limit,
199 )
200 }
201
202 pub fn net_api(&self) -> NetApi {
203 NetApi::new(Box::new(ChainInfo::new(self.consensus.clone())))
204 }
205
206 fn maybe_module(
208 &mut self, config: Option<&RpcModuleSelection>,
209 ) -> Option<RpcModule<()>> {
210 config.map(|config| self.module_for(config))
211 }
212
213 pub fn module_for(&mut self, config: &RpcModuleSelection) -> RpcModule<()> {
216 let mut module = RpcModule::new(());
217 let all_methods = self.eth_methods(config.iter_selection());
218 for methods in all_methods {
219 module.merge(methods).expect("No conflicts");
220 }
221 module
222 }
223
224 pub fn eth_methods(
225 &mut self, namespaces: impl Iterator<Item = EthRpcModule>,
226 ) -> Vec<Methods> {
227 let namespaces: Vec<_> = namespaces.collect();
228 let module_version = namespaces
229 .iter()
230 .map(|module| (module.to_string(), "1.0".to_string()))
231 .collect::<HashMap<String, String>>();
232
233 let namespace_methods = |namespace| {
234 self.modules
235 .entry(namespace)
236 .or_insert_with(|| match namespace {
237 EthRpcModule::Debug => DebugApi::new(
238 self.consensus.clone(),
239 self.config.max_estimation_gas_limit,
240 )
241 .into_rpc()
242 .into(),
243 EthRpcModule::Eth => {
244 let mut module = EthApi::new(
245 self.config.clone(),
246 self.consensus.clone(),
247 self.sync.clone(),
248 self.tx_pool.clone(),
249 self.executor.clone(),
250 )
251 .into_rpc();
252 if self.config.poll_lifetime_in_seconds.is_some() {
253 let filter_module = EthFilterApi::new(
254 self.consensus.clone(),
255 self.tx_pool.clone(),
256 self.notifications.epochs_ordered.clone(),
257 self.executor.clone(),
258 self.config.poll_lifetime_in_seconds.unwrap(),
259 self.config.get_logs_filter_max_limit,
260 )
261 .into_rpc();
262 module.merge(filter_module).expect("No conflicts");
263 }
264 module.into()
265 }
266 EthRpcModule::Net => NetApi::new(Box::new(ChainInfo::new(
267 self.consensus.clone(),
268 )))
269 .into_rpc()
270 .into(),
271 EthRpcModule::Trace => TraceApi::new(
272 self.consensus.clone(),
273 self.sync.network.get_network_type().clone(),
274 self.config.max_estimation_gas_limit,
275 )
276 .into_rpc()
277 .into(),
278 EthRpcModule::Web3 => Web3Api.into_rpc().into(),
279 EthRpcModule::Rpc => {
280 RPCApi::new(module_version.clone()).into_rpc().into()
281 }
282 EthRpcModule::Parity => {
283 let eth_api = EthApi::new(
284 self.config.clone(),
285 self.consensus.clone(),
286 self.sync.clone(),
287 self.tx_pool.clone(),
288 self.executor.clone(),
289 );
290 ParityApi::new(eth_api).into_rpc().into()
291 }
292 EthRpcModule::Txpool => {
293 TxPoolApi::new(self.tx_pool.clone()).into_rpc().into()
294 }
295 EthRpcModule::PubSub => PubSubApi::new(
296 self.consensus.clone(),
297 self.notifications.clone(),
298 self.executor.clone(),
299 )
300 .into_rpc()
301 .into(),
302 })
303 .clone()
304 };
305
306 namespaces
307 .iter()
308 .copied()
309 .map(namespace_methods)
310 .collect::<Vec<_>>()
311 }
312}
313
314#[derive(Debug)]
327pub struct RpcServerConfig {
328 http_server_config: Option<ServerConfigBuilder>,
330 http_cors_domains: Option<String>,
332 http_addr: Option<SocketAddr>,
334 ws_server_config: Option<ServerConfigBuilder>,
336 ws_cors_domains: Option<String>,
338 ws_addr: Option<SocketAddr>,
340}
341
342impl Default for RpcServerConfig {
343 fn default() -> Self {
344 Self {
345 http_server_config: None,
346 http_cors_domains: None,
347 http_addr: None,
348 ws_server_config: None,
349 ws_cors_domains: None,
350 ws_addr: None,
351 }
353 }
354}
355
356impl RpcServerConfig {
357 pub fn http(config: ServerConfigBuilder) -> Self {
359 Self::default().with_http(config)
360 }
361
362 pub fn ws(config: ServerConfigBuilder) -> Self {
364 Self::default().with_ws(config)
365 }
366
367 pub fn with_http(mut self, config: ServerConfigBuilder) -> Self {
373 self.http_server_config =
374 Some(config.set_id_provider(SubscriptionIdProvider::default()));
375 self
376 }
377
378 pub fn with_ws(mut self, config: ServerConfigBuilder) -> Self {
384 self.ws_server_config =
385 Some(config.set_id_provider(SubscriptionIdProvider::default()));
386 self
387 }
388}
389
390impl RpcServerConfig {
391 pub fn with_cors(self, cors_domain: Option<String>) -> Self {
393 self.with_http_cors(cors_domain.clone())
394 .with_ws_cors(cors_domain)
395 }
396
397 pub fn with_ws_cors(mut self, cors_domain: Option<String>) -> Self {
399 self.ws_cors_domains = cors_domain;
400 self
401 }
402
403 pub fn with_http_cors(mut self, cors_domain: Option<String>) -> Self {
405 self.http_cors_domains = cors_domain;
406 self
407 }
408
409 pub const fn with_http_address(mut self, addr: SocketAddr) -> Self {
413 self.http_addr = Some(addr);
414 self
415 }
416
417 pub const fn with_ws_address(mut self, addr: SocketAddr) -> Self {
421 self.ws_addr = Some(addr);
422 self
423 }
424
425 pub fn with_id_provider<I>(mut self, id_provider: I) -> Self
429 where I: IdProvider + Clone + 'static {
430 if let Some(http) = self.http_server_config {
431 self.http_server_config =
432 Some(http.set_id_provider(id_provider.clone()));
433 }
434 if let Some(ws) = self.ws_server_config {
435 self.ws_server_config =
436 Some(ws.set_id_provider(id_provider.clone()));
437 }
438
439 self
440 }
441
442 pub const fn has_server(&self) -> bool {
447 self.http_server_config.is_some() || self.ws_server_config.is_some()
448 }
449
450 pub const fn http_address(&self) -> Option<SocketAddr> { self.http_addr }
452
453 pub const fn ws_address(&self) -> Option<SocketAddr> { self.ws_addr }
455
456 pub async fn start(
463 self, modules: &TransportRpcModules,
464 throttling_conf_file: Option<String>, enable_metrics: bool,
465 ) -> Result<RpcServerHandle, RpcError> {
466 if !self.has_server() {
468 return Ok(RpcServerHandle {
469 http_local_addr: None,
470 ws_local_addr: None,
471 http: None,
472 ws: None,
473 });
474 }
475
476 let throttle_manager =
477 load_throttling_manager(throttling_conf_file.as_deref(), "rpc");
478 let rpc_middleware = RpcServiceBuilder::new()
479 .layer_fn(move |s| Throttle::new(throttle_manager.clone(), s))
480 .layer_fn(move |s| Metrics::new(s, enable_metrics))
481 .layer_fn(|s| Logger::new(s));
482
483 let http_socket_addr = self.http_addr.unwrap_or(SocketAddr::V4(
484 SocketAddrV4::new(Ipv4Addr::LOCALHOST, DEFAULT_HTTP_PORT),
485 ));
486
487 let ws_socket_addr = self.ws_addr.unwrap_or(SocketAddr::V4(
488 SocketAddrV4::new(Ipv4Addr::LOCALHOST, DEFAULT_WS_PORT),
489 ));
490
491 if self.http_addr == self.ws_addr
494 && self.http_server_config.is_some()
495 && self.ws_server_config.is_some()
496 {
497 modules.config.ensure_ws_http_identical()?;
499
500 let cors = match (
501 self.ws_cors_domains.as_ref(),
502 self.http_cors_domains.as_ref(),
503 ) {
504 (Some(ws_cors), Some(http_cors)) => {
505 if ws_cors.trim() != http_cors.trim() {
506 return Err(
507 WsHttpSamePortError::ConflictingCorsDomains {
508 http_cors_domains: Some(http_cors.clone()),
509 ws_cors_domains: Some(ws_cors.clone()),
510 }
511 .into(),
512 );
513 }
514 Some(ws_cors)
515 }
516 (a, b) => a.or(b),
517 }
518 .cloned();
519
520 if let Some(config) = self.http_server_config {
521 let server = ServerBuilder::new()
522 .set_http_middleware(
523 tower::ServiceBuilder::new()
524 .option_layer(maybe_cors_layer(cors)?),
525 )
526 .set_rpc_middleware(rpc_middleware)
527 .set_config(config.build())
528 .build(http_socket_addr)
529 .await
530 .map_err(|err| {
531 RpcError::server_error(
532 err,
533 ServerKind::WsHttp(http_socket_addr),
534 )
535 })?;
536 let addr = server.local_addr().map_err(|err| {
537 RpcError::server_error(
538 err,
539 ServerKind::WsHttp(http_socket_addr),
540 )
541 })?;
542 if let Some(module) =
543 modules.http.as_ref().or(modules.ws.as_ref())
544 {
545 let handle = server.start(module.clone());
546 let http_handle = Some(handle.clone());
547 let ws_handle = Some(handle);
548
549 return Ok(RpcServerHandle {
550 http_local_addr: Some(addr),
551 ws_local_addr: Some(addr),
552 http: http_handle,
553 ws: ws_handle,
554 });
555 }
556
557 return Err(RpcError::Custom(
558 "No valid RpcModule found from modules".to_string(),
559 ));
560 }
561 }
562
563 let mut result = RpcServerHandle {
564 http_local_addr: None,
565 ws_local_addr: None,
566 http: None,
567 ws: None,
568 };
569 if let Some(config) = self.ws_server_config {
570 let server = ServerBuilder::new()
571 .set_config(config.ws_only().build())
572 .set_http_middleware(tower::ServiceBuilder::new().option_layer(
573 maybe_cors_layer(self.ws_cors_domains.clone())?,
574 ))
575 .set_rpc_middleware(rpc_middleware.clone())
576 .build(ws_socket_addr)
577 .await
578 .map_err(|err| {
579 RpcError::server_error(err, ServerKind::WS(ws_socket_addr))
580 })?;
581
582 let addr = server.local_addr().map_err(|err| {
583 RpcError::server_error(err, ServerKind::WS(ws_socket_addr))
584 })?;
585
586 let ws_local_addr = Some(addr);
587 let ws_server = Some(server);
588 let ws_handle = ws_server.map(|ws_server| {
589 ws_server.start(modules.ws.clone().expect("ws server error"))
590 });
591
592 result.ws = ws_handle;
593 result.ws_local_addr = ws_local_addr;
594 }
595
596 if let Some(config) = self.http_server_config {
597 let server = ServerBuilder::new()
598 .set_config(config.http_only().build())
599 .set_http_middleware(tower::ServiceBuilder::new().option_layer(
600 maybe_cors_layer(self.http_cors_domains.clone())?,
601 ))
602 .set_rpc_middleware(rpc_middleware)
603 .build(http_socket_addr)
604 .await
605 .map_err(|err| {
606 RpcError::server_error(
607 err,
608 ServerKind::Http(http_socket_addr),
609 )
610 })?;
611 let local_addr = server.local_addr().map_err(|err| {
612 RpcError::server_error(err, ServerKind::Http(http_socket_addr))
613 })?;
614 let http_local_addr = Some(local_addr);
615 let http_server = Some(server);
616 let http_handle = http_server.map(|http_server| {
617 http_server
618 .start(modules.http.clone().expect("http server error"))
619 });
620
621 result.http = http_handle;
622 result.http_local_addr = http_local_addr;
623 }
624
625 Ok(result)
626 }
627}
628
629#[derive(Debug, Clone, Default, Eq, PartialEq)]
631pub struct TransportRpcModuleConfig {
632 http: Option<RpcModuleSelection>,
634 ws: Option<RpcModuleSelection>,
636}
637
638impl TransportRpcModuleConfig {
639 pub fn set_http(http: impl Into<RpcModuleSelection>) -> Self {
641 Self::default().with_http(http)
642 }
643
644 pub fn set_ws(ws: impl Into<RpcModuleSelection>) -> Self {
646 Self::default().with_ws(ws)
647 }
648
649 pub fn with_http(mut self, http: impl Into<RpcModuleSelection>) -> Self {
651 self.http = Some(http.into());
652 self
653 }
654
655 pub fn with_ws(mut self, ws: impl Into<RpcModuleSelection>) -> Self {
657 self.ws = Some(ws.into());
658 self
659 }
660
661 pub fn http_mut(&mut self) -> &mut Option<RpcModuleSelection> {
663 &mut self.http
664 }
665
666 pub fn ws_mut(&mut self) -> &mut Option<RpcModuleSelection> { &mut self.ws }
668
669 pub const fn is_empty(&self) -> bool {
671 self.http.is_none() && self.ws.is_none()
672 }
673
674 pub const fn http(&self) -> Option<&RpcModuleSelection> {
676 self.http.as_ref()
677 }
678
679 pub const fn ws(&self) -> Option<&RpcModuleSelection> { self.ws.as_ref() }
681
682 fn ensure_ws_http_identical(&self) -> Result<(), WsHttpSamePortError> {
685 if RpcModuleSelection::are_identical(
686 self.http.as_ref(),
687 self.ws.as_ref(),
688 ) {
689 Ok(())
690 } else {
691 let http_modules = self
692 .http
693 .as_ref()
694 .map(RpcModuleSelection::to_selection)
695 .unwrap_or_default();
696 let ws_modules = self
697 .ws
698 .as_ref()
699 .map(RpcModuleSelection::to_selection)
700 .unwrap_or_default();
701
702 let http_not_ws =
703 http_modules.difference(&ws_modules).copied().collect();
704 let ws_not_http =
705 ws_modules.difference(&http_modules).copied().collect();
706 let overlap =
707 http_modules.intersection(&ws_modules).copied().collect();
708
709 Err(WsHttpSamePortError::ConflictingModules(Box::new(
710 ConflictingModules {
711 overlap,
712 http_not_ws,
713 ws_not_http,
714 },
715 )))
716 }
717 }
718}
719
720#[derive(Debug, Clone, Default)]
722pub struct TransportRpcModules<Context = ()> {
723 config: TransportRpcModuleConfig,
725 http: Option<RpcModule<Context>>,
727 ws: Option<RpcModule<Context>>,
729}
730
731impl TransportRpcModules {
734 pub const fn module_config(&self) -> &TransportRpcModuleConfig {
737 &self.config
738 }
739
740 pub fn merge_http(
746 &mut self, other: impl Into<Methods>,
747 ) -> Result<bool, RegisterMethodError> {
748 if let Some(ref mut http) = self.http {
749 return http.merge(other.into()).map(|_| true);
750 }
751 Ok(false)
752 }
753
754 pub fn merge_ws(
760 &mut self, other: impl Into<Methods>,
761 ) -> Result<bool, RegisterMethodError> {
762 if let Some(ref mut ws) = self.ws {
763 return ws.merge(other.into()).map(|_| true);
764 }
765 Ok(false)
766 }
767
768 pub fn merge_configured(
772 &mut self, other: impl Into<Methods>,
773 ) -> Result<(), RegisterMethodError> {
774 let other = other.into();
775 self.merge_http(other.clone())?;
776 self.merge_ws(other.clone())?;
777 Ok(())
778 }
779
780 pub fn remove_http_method(&mut self, method_name: &'static str) -> bool {
788 if let Some(http_module) = &mut self.http {
789 http_module.remove_method(method_name).is_some()
790 } else {
791 false
792 }
793 }
794
795 pub fn remove_ws_method(&mut self, method_name: &'static str) -> bool {
803 if let Some(ws_module) = &mut self.ws {
804 ws_module.remove_method(method_name).is_some()
805 } else {
806 false
807 }
808 }
809
810 pub fn remove_method_from_configured(
814 &mut self, method_name: &'static str,
815 ) -> bool {
816 let http_removed = self.remove_http_method(method_name);
817 let ws_removed = self.remove_ws_method(method_name);
818
819 http_removed || ws_removed
820 }
821}