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, service::traits::NetworkService, NetworkBackend, NetworkBlock,
47 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, gen_rpc_module, init_telemetry,
62 new_client, new_db_backend, new_full_client, new_full_parts, new_full_parts_record_import,
63 new_full_parts_with_genesis_builder, new_wasm_executor,
64 propagate_transaction_notifications, spawn_tasks, BuildNetworkAdvancedParams,
65 BuildNetworkParams, DefaultSyncingEngineConfig, KeystoreContainer, SpawnTasksParams,
66 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_executor::NativeExecutionDispatch;
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<Client, Backend, SelectChain, ImportQueue, TransactionPool, Other> {
159 pub client: Arc<Client>,
161 pub backend: Arc<Backend>,
163 pub task_manager: TaskManager,
165 pub keystore_container: KeystoreContainer,
167 pub select_chain: SelectChain,
169 pub import_queue: ImportQueue,
171 pub transaction_pool: Arc<TransactionPool>,
173 pub other: Other,
175}
176
177async fn build_network_future<
179 B: BlockT,
180 C: BlockchainEvents<B>
181 + HeaderBackend<B>
182 + BlockBackend<B>
183 + HeaderMetadata<B, Error = sp_blockchain::Error>
184 + ProofProvider<B>
185 + Send
186 + Sync
187 + 'static,
188 H: sc_network_common::ExHashT,
189 N: NetworkBackend<B, <B as BlockT>::Hash>,
190>(
191 network: N,
192 client: Arc<C>,
193 sync_service: Arc<SyncingService<B>>,
194 announce_imported_blocks: bool,
195) {
196 let mut imported_blocks_stream = client.import_notification_stream().fuse();
197
198 let mut finality_notification_stream = client.finality_notification_stream().fuse();
200
201 let network_run = network.run().fuse();
202 pin_mut!(network_run);
203
204 loop {
205 futures::select! {
206 notification = imported_blocks_stream.next() => {
208 let notification = match notification {
209 Some(n) => n,
210 None => {
213 warn!("Block import stream has terminated, shutting down the network future. Ignore if the node is stopping.");
214 return
215 },
216 };
217
218 if announce_imported_blocks {
219 sync_service.announce_block(notification.hash, None);
220 }
221
222 if notification.is_new_best {
223 sync_service.new_best_block_imported(
224 notification.hash,
225 *notification.header.number(),
226 );
227 }
228 }
229
230 notification = finality_notification_stream.select_next_some() => {
232 sync_service.on_block_finalized(notification.hash, notification.header);
233 }
234
235 _ = network_run => {
237 warn!("`NetworkWorker` has terminated, shutting down the network future. Ignore if the node is stopping.");
238 return
239 }
240 }
241 }
242}
243
244pub async fn build_system_rpc_future<
246 B: BlockT,
247 C: BlockchainEvents<B>
248 + HeaderBackend<B>
249 + BlockBackend<B>
250 + HeaderMetadata<B, Error = sp_blockchain::Error>
251 + ProofProvider<B>
252 + Send
253 + Sync
254 + 'static,
255 H: sc_network_common::ExHashT,
256>(
257 role: Role,
258 network_service: Arc<dyn NetworkService>,
259 sync_service: Arc<SyncingService<B>>,
260 client: Arc<C>,
261 mut rpc_rx: TracingUnboundedReceiver<sc_rpc::system::Request<B>>,
262 should_have_peers: bool,
263) {
264 let starting_block = client.info().best_number;
266
267 loop {
268 let Some(req) = rpc_rx.next().await else {
270 debug!("RPC requests stream has terminated, shutting down the system RPC future.");
271 return;
272 };
273
274 match req {
275 sc_rpc::system::Request::Health(sender) => match sync_service.peers_info().await {
276 Ok(info) => {
277 let _ = sender.send(sc_rpc::system::Health {
278 peers: info.len(),
279 is_syncing: sync_service.is_major_syncing(),
280 should_have_peers,
281 });
282 },
283 Err(_) => log::error!("`SyncingEngine` shut down"),
284 },
285 sc_rpc::system::Request::LocalPeerId(sender) => {
286 let _ = sender.send(network_service.local_peer_id().to_base58());
287 },
288 sc_rpc::system::Request::LocalListenAddresses(sender) => {
289 let peer_id = (network_service.local_peer_id()).into();
290 let p2p_proto_suffix = sc_network::multiaddr::Protocol::P2p(peer_id);
291 let addresses = network_service
292 .listen_addresses()
293 .iter()
294 .map(|addr| addr.clone().with(p2p_proto_suffix.clone()).to_string())
295 .collect();
296 let _ = sender.send(addresses);
297 },
298 sc_rpc::system::Request::Peers(sender) => match sync_service.peers_info().await {
299 Ok(info) => {
300 let _ = sender.send(
301 info.into_iter()
302 .map(|(peer_id, p)| sc_rpc::system::PeerInfo {
303 peer_id: peer_id.to_base58(),
304 roles: format!("{:?}", p.roles),
305 best_hash: p.best_hash,
306 best_number: p.best_number,
307 })
308 .collect(),
309 );
310 },
311 Err(_) => log::error!("`SyncingEngine` shut down"),
312 },
313 sc_rpc::system::Request::NetworkState(sender) => {
314 let network_state = network_service.network_state().await;
315 if let Ok(network_state) = network_state {
316 if let Ok(network_state) = serde_json::to_value(network_state) {
317 let _ = sender.send(network_state);
318 }
319 } else {
320 break;
321 }
322 },
323 sc_rpc::system::Request::NetworkAddReservedPeer(peer_addr, sender) => {
324 let result = match MultiaddrWithPeerId::try_from(peer_addr) {
325 Ok(peer) => network_service.add_reserved_peer(peer),
326 Err(err) => Err(err.to_string()),
327 };
328 let x = result.map_err(sc_rpc::system::error::Error::MalformattedPeerArg);
329 let _ = sender.send(x);
330 },
331 sc_rpc::system::Request::NetworkRemoveReservedPeer(peer_id, sender) => {
332 let _ = match peer_id.parse::<PeerId>() {
333 Ok(peer_id) => {
334 network_service.remove_reserved_peer(peer_id);
335 sender.send(Ok(()))
336 },
337 Err(e) => sender.send(Err(sc_rpc::system::error::Error::MalformattedPeerArg(
338 e.to_string(),
339 ))),
340 };
341 },
342 sc_rpc::system::Request::NetworkReservedPeers(sender) => {
343 let Ok(reserved_peers) = network_service.reserved_peers().await else {
344 break;
345 };
346
347 let _ =
348 sender.send(reserved_peers.iter().map(|peer_id| peer_id.to_base58()).collect());
349 },
350 sc_rpc::system::Request::NodeRoles(sender) => {
351 use sc_rpc::system::NodeRole;
352
353 let node_role = match role {
354 Role::Authority { .. } => NodeRole::Authority,
355 Role::Full => NodeRole::Full,
356 };
357
358 let _ = sender.send(vec![node_role]);
359 },
360 sc_rpc::system::Request::SyncState(sender) => {
361 use sc_rpc::system::SyncState;
362
363 match sync_service.status().await.map(|status| status.best_seen_block) {
364 Ok(best_seen_block) => {
365 let best_number = client.info().best_number;
366 let _ = sender.send(SyncState {
367 starting_block,
368 current_block: best_number,
369 highest_block: best_seen_block.unwrap_or(best_number),
370 });
371 },
372 Err(_) => log::error!("`SyncingEngine` shut down"),
373 }
374 },
375 }
376 }
377
378 debug!("`NetworkWorker` has terminated, shutting down the system RPC future.");
379}
380
381pub fn start_rpc_servers(
383 rpc_configuration: &RpcConfiguration,
384 registry: Option<&Registry>,
385 tokio_handle: &Handle,
386 rpc_api: RpcModule<()>,
387 rpc_runtime: tokio::runtime::Runtime,
388 rpc_id_provider: Option<Box<dyn sc_rpc_server::SubscriptionIdProvider>>,
389) -> Result<Server, error::Error> {
390 let endpoints: Vec<sc_rpc_server::RpcEndpoint> = if let Some(endpoints) =
391 rpc_configuration.addr.as_ref()
392 {
393 endpoints.clone()
394 } else {
395 let ipv6 =
396 SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::LOCALHOST, rpc_configuration.port, 0, 0));
397 let ipv4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, rpc_configuration.port));
398
399 vec![
400 sc_rpc_server::RpcEndpoint {
401 batch_config: rpc_configuration.batch_config,
402 cors: rpc_configuration.cors.clone(),
403 listen_addr: ipv4,
404 max_buffer_capacity_per_connection: rpc_configuration.message_buffer_capacity,
405 max_connections: rpc_configuration.max_connections,
406 max_payload_in_mb: rpc_configuration.max_request_size,
407 max_payload_out_mb: rpc_configuration.max_response_size,
408 max_subscriptions_per_connection: rpc_configuration.max_subs_per_conn,
409 rpc_methods: rpc_configuration.methods.into(),
410 rate_limit: rpc_configuration.rate_limit,
411 rate_limit_trust_proxy_headers: rpc_configuration.rate_limit_trust_proxy_headers,
412 rate_limit_whitelisted_ips: rpc_configuration.rate_limit_whitelisted_ips.clone(),
413 retry_random_port: true,
414 is_optional: false,
415 },
416 sc_rpc_server::RpcEndpoint {
417 batch_config: rpc_configuration.batch_config,
418 cors: rpc_configuration.cors.clone(),
419 listen_addr: ipv6,
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: true,
431 },
432 ]
433 };
434
435 let metrics = sc_rpc_server::RpcMetrics::new(registry)?;
436
437 let server_config = sc_rpc_server::Config {
438 endpoints,
439 metrics,
440 rpc_api,
441 id_provider: rpc_id_provider,
442 request_logger_limit: rpc_configuration.request_logger_limit,
443 rpc_runtime,
444 };
445
446 match tokio::task::block_in_place(|| {
451 tokio_handle.block_on(sc_rpc_server::start_server(server_config))
452 }) {
453 Ok(server) => Ok(server),
454 Err(e) => Err(Error::Application(e)),
455 }
456}
457
458pub struct TransactionPoolAdapter<C, P> {
460 pool: Arc<P>,
461 client: Arc<C>,
462}
463
464impl<C, P> TransactionPoolAdapter<C, P> {
465 pub fn new(pool: Arc<P>, client: Arc<C>) -> Self {
467 Self { pool, client }
468 }
469}
470
471fn transactions_to_propagate<Pool, B, H, E>(pool: &Pool) -> Vec<(H, Arc<B::Extrinsic>)>
475where
476 Pool: TransactionPool<Block = B, Hash = H, Error = E>,
477 B: BlockT,
478 H: std::hash::Hash + Eq + sp_runtime::traits::Member + sp_runtime::traits::MaybeSerialize,
479 E: IntoPoolError + From<sc_transaction_pool_api::error::Error>,
480{
481 pool.ready()
482 .filter(|t| t.is_propagable())
483 .map(|t| {
484 let hash = t.hash().clone();
485 let ex = t.data().clone();
486 (hash, ex)
487 })
488 .collect()
489}
490
491impl<B, H, C, Pool, E> sc_network_transactions::config::TransactionPool<H, B>
492 for TransactionPoolAdapter<C, Pool>
493where
494 C: HeaderBackend<B>
495 + BlockBackend<B>
496 + HeaderMetadata<B, Error = sp_blockchain::Error>
497 + ProofProvider<B>
498 + Send
499 + Sync
500 + 'static,
501 Pool: 'static + TransactionPool<Block = B, Hash = H, Error = E>,
502 B: BlockT,
503 H: std::hash::Hash + Eq + sp_runtime::traits::Member + sp_runtime::traits::MaybeSerialize,
504 E: 'static + IntoPoolError + From<sc_transaction_pool_api::error::Error>,
505{
506 fn transactions(&self) -> Vec<(H, Arc<B::Extrinsic>)> {
507 transactions_to_propagate(&*self.pool)
508 }
509
510 fn hash_of(&self, transaction: &B::Extrinsic) -> H {
511 self.pool.hash_of(transaction)
512 }
513
514 fn import(&self, transaction: B::Extrinsic) -> TransactionImportFuture {
515 let encoded = transaction.encode();
516 let uxt = match Decode::decode(&mut &encoded[..]) {
517 Ok(uxt) => uxt,
518 Err(e) => {
519 debug!(target: sc_transaction_pool::LOG_TARGET, "Transaction invalid: {:?}", e);
520 return Box::pin(futures::future::ready(TransactionImport::Bad));
521 },
522 };
523
524 let start = std::time::Instant::now();
525 let pool = self.pool.clone();
526 let client = self.client.clone();
527 Box::pin(async move {
528 match pool
529 .submit_one(
530 client.info().best_hash,
531 sc_transaction_pool_api::TransactionSource::External,
532 uxt,
533 )
534 .await
535 {
536 Ok(_) => {
537 let elapsed = start.elapsed();
538 trace!(target: sc_transaction_pool::LOG_TARGET, "import transaction: {elapsed:?}");
539 TransactionImport::NewGood
540 },
541 Err(e) => match e.into_pool_error() {
542 Ok(sc_transaction_pool_api::error::Error::AlreadyImported(_)) => {
543 TransactionImport::KnownGood
544 },
545 Ok(_) => TransactionImport::Bad,
546 Err(_) => {
547 TransactionImport::KnownGood
550 },
551 },
552 }
553 })
554 }
555
556 fn on_broadcasted(&self, propagations: HashMap<H, Vec<String>>) {
557 self.pool.on_broadcasted(propagations)
558 }
559
560 fn transaction(&self, hash: &H) -> Option<Arc<B::Extrinsic>> {
561 self.pool.ready_transaction(hash).and_then(
562 |tx| tx.is_propagable().then(|| tx.data().clone()),
564 )
565 }
566}
567
568#[cfg(test)]
569mod tests {
570 use super::*;
571 use futures::executor::block_on;
572 use sc_transaction_pool::BasicPool;
573 use sp_consensus::SelectChain;
574 use substrate_test_runtime_client::{
575 prelude::*,
576 runtime::{ExtrinsicBuilder, Transfer, TransferData},
577 };
578
579 #[test]
580 fn should_not_propagate_transactions_that_are_marked_as_such() {
581 let (client, longest_chain) = TestClientBuilder::new().build_with_longest_chain();
583 let client = Arc::new(client);
584 let spawner = sp_core::testing::TaskExecutor::new();
585 let pool = Arc::from(BasicPool::new_full(
586 Default::default(),
587 true.into(),
588 None,
589 spawner,
590 client.clone(),
591 ));
592 let source = sp_runtime::transaction_validity::TransactionSource::External;
593 let best = block_on(longest_chain.best_chain()).unwrap();
594 let transaction = Transfer {
595 amount: 5,
596 nonce: 0,
597 from: Sr25519Keyring::Alice.into(),
598 to: Sr25519Keyring::Bob.into(),
599 }
600 .into_unchecked_extrinsic();
601 block_on(pool.submit_one(best.hash(), source, transaction.clone())).unwrap();
602 block_on(pool.submit_one(
603 best.hash(),
604 source,
605 ExtrinsicBuilder::new_call_do_not_propagate().nonce(1).build(),
606 ))
607 .unwrap();
608 assert_eq!(pool.status().ready, 2);
609
610 let transactions = transactions_to_propagate(&*pool);
612
613 assert_eq!(transactions.len(), 1);
615 assert!(TransferData::try_from(&*transactions[0].1).is_ok());
616 }
617}