1#![warn(missing_docs)]
23#![recursion_limit = "1024"]
24
25pub mod chain_ops;
26pub mod client;
27pub mod config;
28pub mod error;
29
30mod builder;
31mod metrics;
32mod task_manager;
33
34use crate::config::Multiaddr;
35use std::{
36 collections::HashMap,
37 net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
38};
39
40use codec::{Decode, Encode};
41use futures::{pin_mut, FutureExt, StreamExt};
42use jsonrpsee::RpcModule;
43use log::{debug, error, trace, warn};
44use sc_client_api::{blockchain::HeaderBackend, BlockBackend, BlockchainEvents, ProofProvider};
45use sc_network::{
46 config::MultiaddrWithPeerId, multiaddr::Protocol, service::traits::NetworkService,
47 NetworkBackend, NetworkBlock, NetworkPeers, NetworkStateInfo,
48};
49use sc_network_sync::SyncingService;
50use sc_network_types::PeerId;
51pub use sc_rpc_server::create_rpc_runtime;
52use sc_rpc_server::Server;
53use sc_utils::mpsc::TracingUnboundedReceiver;
54use sp_blockchain::HeaderMetadata;
55use sp_consensus::SyncOracle;
56use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
57
58pub use self::{
59 builder::{
60 build_default_block_downloader, build_default_syncing_engine, build_network,
61 build_network_advanced, build_polkadot_syncing_strategy, default_gap_sync_body_policy,
62 gen_rpc_module, init_telemetry, new_client, new_db_backend, new_full_client,
63 new_full_parts, new_full_parts_record_import, new_full_parts_with_genesis_builder,
64 new_wasm_executor, propagate_transaction_notifications, spawn_tasks,
65 BuildNetworkAdvancedParams, BuildNetworkParams, ClientForService,
66 DefaultSyncingEngineConfig, KeystoreContainer, SpawnTasksParams, TFullBackend,
67 TFullCallExecutor, TFullClient,
68 },
69 client::{ClientConfig, LocalCallExecutor},
70 error::Error,
71 metrics::MetricsService,
72};
73pub use sc_chain_spec::{
74 construct_genesis_block, resolve_state_version_from_wasm, BuildGenesisBlock,
75 GenesisBlockBuilder,
76};
77
78pub use config::{
79 BasePath, BlocksPruning, Configuration, DatabaseSource, PruningMode, Role, RpcMethods, TaskType,
80};
81pub use sc_chain_spec::{
82 ChainSpec, ChainType, Extension as ChainSpecExtension, GenericChainSpec, NoExtension,
83 Properties,
84};
85pub use sc_client_db::PruningFilter;
86
87use crate::config::RpcConfiguration;
88use prometheus_endpoint::Registry;
89pub use sc_consensus::ImportQueue;
90pub use sc_network_sync::WarpSyncConfig;
91#[doc(hidden)]
92pub use sc_network_transactions::config::{TransactionImport, TransactionImportFuture};
93pub use sc_rpc::{RandomIntegerSubscriptionId, RandomStringSubscriptionId};
94pub use sc_tracing::TracingReceiver;
95pub use sc_transaction_pool::TransactionPoolOptions;
96pub use sc_transaction_pool_api::{error::IntoPoolError, InPoolTransaction, TransactionPool};
97#[doc(hidden)]
98pub use std::{ops::Deref, result::Result, sync::Arc};
99pub use task_manager::{
100 SpawnEssentialTaskHandle, SpawnTaskHandle, Task, TaskManager, TaskRegistry, DEFAULT_GROUP_NAME,
101};
102use tokio::runtime::Handle;
103
104const DEFAULT_PROTOCOL_ID: &str = "sup";
105
106#[derive(Clone)]
108pub struct RpcHandlers {
109 rpc_module: Arc<RpcModule<()>>,
112
113 listen_addresses: Vec<Multiaddr>,
116}
117
118impl RpcHandlers {
119 pub fn new(rpc_module: Arc<RpcModule<()>>, listen_addresses: Vec<Multiaddr>) -> Self {
121 Self { rpc_module, listen_addresses }
122 }
123
124 pub async fn rpc_query(
134 &self,
135 json_query: &str,
136 ) -> Result<(String, tokio::sync::mpsc::Receiver<String>), serde_json::Error> {
137 const TOKIO_MPSC_MAX_SIZE: usize = tokio::sync::Semaphore::MAX_PERMITS;
142
143 self.rpc_module.raw_json_request(json_query, TOKIO_MPSC_MAX_SIZE).await
144 }
145
146 pub fn handle(&self) -> Arc<RpcModule<()>> {
148 self.rpc_module.clone()
149 }
150
151 pub fn listen_addresses(&self) -> &[Multiaddr] {
153 &self.listen_addresses[..]
154 }
155}
156
157pub struct PartialComponents<
159 Client,
160 Backend,
161 SelectChain,
162 ImportQueue,
163 TransactionPool: ?Sized,
164 Other,
165> {
166 pub client: Arc<Client>,
168 pub backend: Arc<Backend>,
170 pub task_manager: TaskManager,
172 pub keystore_container: KeystoreContainer,
174 pub select_chain: SelectChain,
176 pub import_queue: ImportQueue,
178 pub transaction_pool: Arc<TransactionPool>,
180 pub other: Other,
182}
183
184async fn build_network_future<
186 B: BlockT,
187 C: BlockchainEvents<B>
188 + HeaderBackend<B>
189 + BlockBackend<B>
190 + HeaderMetadata<B, Error = sp_blockchain::Error>
191 + ProofProvider<B>
192 + Send
193 + Sync
194 + 'static,
195 H: sc_network_common::ExHashT,
196 N: NetworkBackend<B, <B as BlockT>::Hash>,
197>(
198 network: N,
199 client: Arc<C>,
200 sync_service: Arc<SyncingService<B>>,
201 announce_imported_blocks: bool,
202) {
203 let mut imported_blocks_stream = client.import_notification_stream().fuse();
204
205 let mut finality_notification_stream = client.finality_notification_stream().fuse();
207
208 let network_run = network.run().fuse();
209 pin_mut!(network_run);
210
211 loop {
212 futures::select! {
213 notification = imported_blocks_stream.next() => {
215 let notification = match notification {
216 Some(n) => n,
217 None => {
220 warn!("Block import stream has terminated, shutting down the network future. Ignore if the node is stopping.");
221 return
222 },
223 };
224
225 if announce_imported_blocks {
226 sync_service.announce_block(notification.hash, None);
227 }
228
229 if notification.is_new_best {
230 sync_service.new_best_block_imported(
231 notification.hash,
232 *notification.header.number(),
233 );
234 }
235 }
236
237 notification = finality_notification_stream.select_next_some() => {
239 sync_service.on_block_finalized(notification.hash, notification.header);
240 }
241
242 _ = network_run => {
244 warn!("`NetworkWorker` has terminated, shutting down the network future. Ignore if the node is stopping.");
245 return
246 }
247 }
248 }
249}
250
251pub async fn build_system_rpc_future<
253 B: BlockT,
254 C: BlockchainEvents<B>
255 + HeaderBackend<B>
256 + BlockBackend<B>
257 + HeaderMetadata<B, Error = sp_blockchain::Error>
258 + ProofProvider<B>
259 + Send
260 + Sync
261 + 'static,
262 H: sc_network_common::ExHashT,
263>(
264 role: Role,
265 network_service: Arc<dyn NetworkService>,
266 sync_service: Arc<SyncingService<B>>,
267 client: Arc<C>,
268 mut rpc_rx: TracingUnboundedReceiver<sc_rpc::system::Request<B>>,
269 should_have_peers: bool,
270) {
271 let starting_block = client.info().best_number;
273
274 loop {
275 let Some(req) = rpc_rx.next().await else {
277 debug!("RPC requests stream has terminated, shutting down the system RPC future.");
278 return;
279 };
280
281 match req {
282 sc_rpc::system::Request::Health(sender) => match sync_service.peers_info().await {
283 Ok(info) => {
284 let _ = sender.send(sc_rpc::system::Health {
285 peers: info.len(),
286 is_syncing: sync_service.is_major_syncing(),
287 should_have_peers,
288 });
289 },
290 Err(_) => log::error!("`SyncingEngine` shut down"),
291 },
292 sc_rpc::system::Request::LocalPeerId(sender) => {
293 let _ = sender.send(network_service.local_peer_id().to_base58());
294 },
295 sc_rpc::system::Request::LocalListenAddresses(sender) => {
296 let local_peer_id = network_service.local_peer_id();
297 let addresses = network_service
298 .listen_addresses()
299 .iter()
300 .map(|address| with_local_peer_id(address.clone(), local_peer_id).to_string())
301 .collect();
302 let _ = sender.send(addresses);
303 },
304 sc_rpc::system::Request::Peers(sender) => match sync_service.peers_info().await {
305 Ok(info) => {
306 let _ = sender.send(
307 info.into_iter()
308 .map(|(peer_id, p)| sc_rpc::system::PeerInfo {
309 peer_id: peer_id.to_base58(),
310 roles: format!("{:?}", p.roles),
311 best_hash: p.best_hash,
312 best_number: p.best_number,
313 })
314 .collect(),
315 );
316 },
317 Err(_) => log::error!("`SyncingEngine` shut down"),
318 },
319 sc_rpc::system::Request::NetworkState(sender) => {
320 let network_state = network_service.network_state().await;
321 if let Ok(network_state) = network_state {
322 if let Ok(network_state) = serde_json::to_value(network_state) {
323 let _ = sender.send(network_state);
324 }
325 } else {
326 break;
327 }
328 },
329 sc_rpc::system::Request::NetworkAddReservedPeer(peer_addr, sender) => {
330 let result = match MultiaddrWithPeerId::try_from(peer_addr) {
331 Ok(peer) => network_service.add_reserved_peer(peer),
332 Err(err) => Err(err.to_string()),
333 };
334 let x = result.map_err(sc_rpc::system::error::Error::MalformattedPeerArg);
335 let _ = sender.send(x);
336 },
337 sc_rpc::system::Request::NetworkRemoveReservedPeer(peer_id, sender) => {
338 let _ = match peer_id.parse::<PeerId>() {
339 Ok(peer_id) => {
340 network_service.remove_reserved_peer(peer_id);
341 sender.send(Ok(()))
342 },
343 Err(e) => sender.send(Err(sc_rpc::system::error::Error::MalformattedPeerArg(
344 e.to_string(),
345 ))),
346 };
347 },
348 sc_rpc::system::Request::NetworkReservedPeers(sender) => {
349 let Ok(reserved_peers) = network_service.reserved_peers().await else {
350 break;
351 };
352
353 let _ =
354 sender.send(reserved_peers.iter().map(|peer_id| peer_id.to_base58()).collect());
355 },
356 sc_rpc::system::Request::NodeRoles(sender) => {
357 use sc_rpc::system::NodeRole;
358
359 let node_role = match role {
360 Role::Authority { .. } => NodeRole::Authority,
361 Role::Full => NodeRole::Full,
362 };
363
364 let _ = sender.send(vec![node_role]);
365 },
366 sc_rpc::system::Request::SyncState(sender) => {
367 use sc_rpc::system::SyncState;
368
369 match sync_service.status().await.map(|status| status.best_seen_block) {
370 Ok(best_seen_block) => {
371 let best_number = client.info().best_number;
372 let _ = sender.send(SyncState {
373 starting_block,
374 current_block: best_number,
375 highest_block: best_seen_block.unwrap_or(best_number),
376 });
377 },
378 Err(_) => log::error!("`SyncingEngine` shut down"),
379 }
380 },
381 }
382 }
383
384 debug!("`NetworkWorker` has terminated, shutting down the system RPC future.");
385}
386
387fn with_local_peer_id(address: Multiaddr, local_peer_id: PeerId) -> Multiaddr {
389 match address.iter().last() {
392 Some(Protocol::P2p(_)) => address,
393 _ => address.with(Protocol::P2p(local_peer_id.into())),
394 }
395}
396
397pub fn start_rpc_servers(
399 rpc_configuration: &RpcConfiguration,
400 registry: Option<&Registry>,
401 tokio_handle: &Handle,
402 rpc_api: RpcModule<()>,
403 rpc_runtime: tokio::runtime::Runtime,
404 rpc_id_provider: Option<Box<dyn sc_rpc_server::SubscriptionIdProvider>>,
405) -> Result<Server, error::Error> {
406 let endpoints: Vec<sc_rpc_server::RpcEndpoint> = if let Some(endpoints) =
407 rpc_configuration.addr.as_ref()
408 {
409 endpoints.clone()
410 } else {
411 let ipv6 =
412 SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::LOCALHOST, rpc_configuration.port, 0, 0));
413 let ipv4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, rpc_configuration.port));
414
415 vec![
416 sc_rpc_server::RpcEndpoint {
417 batch_config: rpc_configuration.batch_config,
418 cors: rpc_configuration.cors.clone(),
419 listen_addr: ipv4,
420 max_buffer_capacity_per_connection: rpc_configuration.message_buffer_capacity,
421 max_connections: rpc_configuration.max_connections,
422 max_payload_in_mb: rpc_configuration.max_request_size,
423 max_payload_out_mb: rpc_configuration.max_response_size,
424 max_subscriptions_per_connection: rpc_configuration.max_subs_per_conn,
425 rpc_methods: rpc_configuration.methods.into(),
426 rate_limit: rpc_configuration.rate_limit,
427 rate_limit_trust_proxy_headers: rpc_configuration.rate_limit_trust_proxy_headers,
428 rate_limit_whitelisted_ips: rpc_configuration.rate_limit_whitelisted_ips.clone(),
429 retry_random_port: true,
430 is_optional: false,
431 },
432 sc_rpc_server::RpcEndpoint {
433 batch_config: rpc_configuration.batch_config,
434 cors: rpc_configuration.cors.clone(),
435 listen_addr: ipv6,
436 max_buffer_capacity_per_connection: rpc_configuration.message_buffer_capacity,
437 max_connections: rpc_configuration.max_connections,
438 max_payload_in_mb: rpc_configuration.max_request_size,
439 max_payload_out_mb: rpc_configuration.max_response_size,
440 max_subscriptions_per_connection: rpc_configuration.max_subs_per_conn,
441 rpc_methods: rpc_configuration.methods.into(),
442 rate_limit: rpc_configuration.rate_limit,
443 rate_limit_trust_proxy_headers: rpc_configuration.rate_limit_trust_proxy_headers,
444 rate_limit_whitelisted_ips: rpc_configuration.rate_limit_whitelisted_ips.clone(),
445 retry_random_port: true,
446 is_optional: true,
447 },
448 ]
449 };
450
451 let metrics = sc_rpc_server::RpcMetrics::new(registry)?;
452
453 let server_config = sc_rpc_server::Config {
454 endpoints,
455 metrics,
456 rpc_api,
457 id_provider: rpc_id_provider,
458 request_logger_limit: rpc_configuration.request_logger_limit,
459 rpc_runtime,
460 };
461
462 match tokio::task::block_in_place(|| {
467 tokio_handle.block_on(sc_rpc_server::start_server(server_config))
468 }) {
469 Ok(server) => Ok(server),
470 Err(e) => Err(Error::Application(e)),
471 }
472}
473
474pub struct TransactionPoolAdapter<C, P: ?Sized> {
476 pool: Arc<P>,
477 client: Arc<C>,
478}
479
480impl<C, P: ?Sized> TransactionPoolAdapter<C, P> {
481 pub fn new(pool: Arc<P>, client: Arc<C>) -> Self {
483 Self { pool, client }
484 }
485}
486
487fn transactions_to_propagate<Pool, B, H, E>(pool: &Pool) -> Vec<(H, Arc<B::Extrinsic>)>
491where
492 Pool: TransactionPool<Block = B, Hash = H, Error = E> + ?Sized,
493 B: BlockT,
494 H: std::hash::Hash + Eq + sp_runtime::traits::Member + sp_runtime::traits::MaybeSerialize,
495 E: IntoPoolError + From<sc_transaction_pool_api::error::Error>,
496{
497 pool.ready()
498 .filter(|t| t.is_propagable())
499 .map(|t| {
500 let hash = t.hash().clone();
501 let ex = t.data().clone();
502 (hash, ex)
503 })
504 .collect()
505}
506
507impl<B, H, C, Pool, E> sc_network_transactions::config::TransactionPool<H, B>
508 for TransactionPoolAdapter<C, Pool>
509where
510 C: HeaderBackend<B>
511 + BlockBackend<B>
512 + HeaderMetadata<B, Error = sp_blockchain::Error>
513 + ProofProvider<B>
514 + Send
515 + Sync
516 + 'static,
517 Pool: 'static + TransactionPool<Block = B, Hash = H, Error = E> + ?Sized,
518 B: BlockT,
519 H: std::hash::Hash + Eq + sp_runtime::traits::Member + sp_runtime::traits::MaybeSerialize,
520 E: 'static + IntoPoolError + From<sc_transaction_pool_api::error::Error>,
521{
522 fn transactions(&self) -> Vec<(H, Arc<B::Extrinsic>)> {
523 transactions_to_propagate(&*self.pool)
524 }
525
526 fn hash_of(&self, transaction: &B::Extrinsic) -> H {
527 self.pool.hash_of(transaction)
528 }
529
530 fn import(&self, transaction: B::Extrinsic) -> TransactionImportFuture {
531 let encoded = transaction.encode();
532 let uxt = match Decode::decode(&mut &encoded[..]) {
533 Ok(uxt) => uxt,
534 Err(e) => {
535 debug!(target: sc_transaction_pool::LOG_TARGET, "Transaction invalid: {:?}", e);
536 return Box::pin(futures::future::ready(TransactionImport::Bad));
537 },
538 };
539
540 let start = std::time::Instant::now();
541 let pool = self.pool.clone();
542 let client = self.client.clone();
543 Box::pin(async move {
544 match pool
545 .submit_one(
546 client.info().best_hash,
547 sc_transaction_pool_api::TransactionSource::External,
548 uxt,
549 )
550 .await
551 {
552 Ok(_) => {
553 let elapsed = start.elapsed();
554 trace!(target: sc_transaction_pool::LOG_TARGET, "import transaction: {elapsed:?}");
555 TransactionImport::NewGood
556 },
557 Err(e) => match e.into_pool_error() {
558 Ok(sc_transaction_pool_api::error::Error::AlreadyImported(_)) => {
559 TransactionImport::KnownGood
560 },
561 Ok(_) => TransactionImport::Bad,
562 Err(_) => {
563 TransactionImport::KnownGood
566 },
567 },
568 }
569 })
570 }
571
572 fn on_broadcasted(&self, propagations: HashMap<H, Vec<String>>) {
573 self.pool.on_broadcasted(propagations)
574 }
575
576 fn transaction(&self, hash: &H) -> Option<Arc<B::Extrinsic>> {
577 self.pool.ready_transaction(hash).and_then(
578 |tx| tx.is_propagable().then(|| tx.data().clone()),
580 )
581 }
582}
583
584#[cfg(test)]
585mod tests {
586 use super::*;
587 use futures::executor::block_on;
588 use sc_network_types::multihash::Code;
589 use sc_transaction_pool::BasicPool;
590 use sp_consensus::SelectChain;
591 use substrate_test_runtime_client::{
592 prelude::*,
593 runtime::{ExtrinsicBuilder, Transfer, TransferData},
594 };
595
596 fn tcp_address() -> Multiaddr {
598 Multiaddr::empty()
599 .with(Protocol::Ip4([1, 2, 3, 4].into()))
600 .with(Protocol::Tcp(30333))
601 }
602
603 #[test]
604 fn peer_id_appended_when_missing() {
605 let peer_id = PeerId::random();
606
607 assert_eq!(
608 with_local_peer_id(tcp_address(), peer_id),
609 tcp_address().with(Protocol::P2p(peer_id.into())),
610 );
611 }
612
613 #[test]
614 fn peer_id_not_appended_twice() {
615 let peer_id = PeerId::random();
617 let address = tcp_address().with(Protocol::P2p(peer_id.into()));
618
619 assert_eq!(with_local_peer_id(address.clone(), peer_id), address);
620 }
621
622 #[test]
623 fn webrtc_certhash_preserved() {
624 let peer_id = PeerId::random();
626 let address = Multiaddr::empty()
627 .with(Protocol::Ip4([1, 2, 3, 4].into()))
628 .with(Protocol::Udp(30334))
629 .with(Protocol::WebRTCDirect)
630 .with(Protocol::Certhash(Code::Sha2_256.digest(b"certificate")))
631 .with(Protocol::P2p(peer_id.into()));
632
633 assert_eq!(with_local_peer_id(address.clone(), peer_id), address);
634 }
635
636 #[test]
637 fn should_not_propagate_transactions_that_are_marked_as_such() {
638 let (client, longest_chain) = TestClientBuilder::new().build_with_longest_chain();
640 let client = Arc::new(client);
641 let spawner = sp_core::testing::TaskExecutor::new();
642 let pool = Arc::from(BasicPool::new_full(
643 Default::default(),
644 true.into(),
645 None,
646 spawner,
647 client.clone(),
648 ));
649 let source = sp_runtime::transaction_validity::TransactionSource::External;
650 let best = block_on(longest_chain.best_chain()).unwrap();
651 let transaction = Transfer {
652 amount: 5,
653 nonce: 0,
654 from: Sr25519Keyring::Alice.into(),
655 to: Sr25519Keyring::Bob.into(),
656 }
657 .into_unchecked_extrinsic();
658 block_on(pool.submit_one(best.hash(), source, transaction.clone())).unwrap();
659 block_on(pool.submit_one(
660 best.hash(),
661 source,
662 ExtrinsicBuilder::new_call_do_not_propagate().nonce(1).build(),
663 ))
664 .unwrap();
665 assert_eq!(pool.status().ready, 2);
666
667 let transactions = transactions_to_propagate(&*pool);
669
670 assert_eq!(transactions.len(), 1);
672 assert!(TransferData::try_from(&*transactions[0].1).is_ok());
673 }
674}