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