1#![warn(unused_extern_crates)]
20
21use polkadot_sdk::{
24 sc_consensus_beefy as beefy, sc_consensus_grandpa as grandpa,
25 sp_consensus_babe::inherents::BabeCreateInherentDataProviders,
26 sp_consensus_beefy as beefy_primitives, *,
27};
28
29use crate::Cli;
30use codec::Encode;
31use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE;
32use frame_system_rpc_runtime_api::AccountNonceApi;
33use futures::prelude::*;
34use kitchensink_runtime::RuntimeApi;
35use node_primitives::Block;
36use sc_client_api::{Backend, BlockBackend};
37use sc_consensus_babe::{self, SlotProportion};
38use sc_network::{
39 event::Event, service::traits::NetworkService, NetworkBackend, NetworkEventStream,
40};
41use sc_network_sync::{strategy::warp::WarpSyncConfig, SyncingService};
42use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager};
43use sc_statement_store::Store as StatementStore;
44use sc_telemetry::{Telemetry, TelemetryWorker};
45use sc_transaction_pool::TransactionPoolHandle;
46use sc_transaction_pool_api::OffchainTransactionPoolFactory;
47use sp_api::ProvideRuntimeApi;
48use sp_core::crypto::Pair;
49use sp_runtime::{generic, traits::Block as BlockT, SaturatedConversion};
50use std::{path::Path, sync::Arc};
51
52#[cfg(not(feature = "runtime-benchmarks"))]
54pub type HostFunctions =
55 (sp_io::SubstrateHostFunctions, sp_statement_store::runtime_api::HostFunctions);
56
57#[cfg(feature = "runtime-benchmarks")]
59pub type HostFunctions = (
60 sp_io::SubstrateHostFunctions,
61 sp_statement_store::runtime_api::HostFunctions,
62 frame_benchmarking::benchmarking::HostFunctions,
63);
64
65pub type RuntimeExecutor = sc_executor::WasmExecutor<HostFunctions>;
68
69pub type FullClient = sc_service::TFullClient<Block, RuntimeApi, RuntimeExecutor>;
71type FullBackend = sc_service::TFullBackend<Block>;
72type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
73type FullGrandpaBlockImport =
74 grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>;
75type FullBeefyBlockImport<InnerBlockImport> = beefy::import::BeefyBlockImport<
76 Block,
77 FullBackend,
78 FullClient,
79 InnerBlockImport,
80 beefy_primitives::ecdsa_crypto::AuthorityId,
81>;
82
83pub type TransactionPool = sc_transaction_pool::TransactionPoolHandle<Block, FullClient>;
85
86const GRANDPA_JUSTIFICATION_PERIOD: u32 = 512;
89
90pub fn fetch_nonce(client: &FullClient, account: sp_core::sr25519::Pair) -> u32 {
94 let best_hash = client.chain_info().best_hash;
95 client
96 .runtime_api()
97 .account_nonce(best_hash, account.public().into())
98 .expect("Fetching account nonce works; qed")
99}
100
101pub fn create_extrinsic(
108 client: &FullClient,
109 sender: sp_core::sr25519::Pair,
110 function: impl Into<kitchensink_runtime::RuntimeCall>,
111 nonce: Option<u32>,
112) -> kitchensink_runtime::UncheckedExtrinsic {
113 let function = function.into();
114 let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed");
115 let best_hash = client.chain_info().best_hash;
116 let best_block = client.chain_info().best_number;
117 let nonce = nonce.unwrap_or_else(|| fetch_nonce(client, sender.clone()));
118
119 let period = kitchensink_runtime::BlockHashCount::get()
120 .checked_next_power_of_two()
121 .map(|c| c / 2)
122 .unwrap_or(2) as u64;
123 let tip = 0;
124 let tx_ext: kitchensink_runtime::TxExtension =
125 (
126 frame_system::AuthorizeCall::<kitchensink_runtime::Runtime>::new(),
127 frame_system::CheckNonZeroSender::<kitchensink_runtime::Runtime>::new(),
128 frame_system::CheckSpecVersion::<kitchensink_runtime::Runtime>::new(),
129 frame_system::CheckTxVersion::<kitchensink_runtime::Runtime>::new(),
130 frame_system::CheckGenesis::<kitchensink_runtime::Runtime>::new(),
131 frame_system::CheckEra::<kitchensink_runtime::Runtime>::from(generic::Era::mortal(
132 period,
133 best_block.saturated_into(),
134 )),
135 frame_system::CheckNonce::<kitchensink_runtime::Runtime>::from(nonce),
136 frame_system::CheckWeight::<kitchensink_runtime::Runtime>::new(),
137 pallet_skip_feeless_payment::SkipCheckIfFeeless::from(
138 pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::<
139 kitchensink_runtime::Runtime,
140 >::from(tip, None),
141 ),
142 frame_metadata_hash_extension::CheckMetadataHash::new(false),
143 frame_system::WeightReclaim::<kitchensink_runtime::Runtime>::new(),
144 );
145
146 let raw_payload = kitchensink_runtime::SignedPayload::from_raw(
147 function.clone(),
148 tx_ext.clone(),
149 (
150 (),
151 (),
152 kitchensink_runtime::VERSION.spec_version,
153 kitchensink_runtime::VERSION.transaction_version,
154 genesis_hash,
155 best_hash,
156 (),
157 (),
158 (),
159 None,
160 (),
161 ),
162 );
163 let signature = raw_payload.using_encoded(|e| sender.sign(e));
164
165 generic::UncheckedExtrinsic::new_signed(
166 function,
167 sp_runtime::AccountId32::from(sender.public()).into(),
168 kitchensink_runtime::Signature::Sr25519(signature),
169 tx_ext,
170 )
171 .into()
172}
173
174pub fn new_partial(
176 config: &Configuration,
177 mixnet_config: Option<&sc_mixnet::Config>,
178) -> Result<
179 sc_service::PartialComponents<
180 FullClient,
181 FullBackend,
182 FullSelectChain,
183 sc_consensus::DefaultImportQueue<Block>,
184 sc_transaction_pool::TransactionPoolHandle<Block, FullClient>,
185 (
186 impl Fn(
187 sc_rpc::SubscriptionTaskExecutor,
188 ) -> Result<jsonrpsee::RpcModule<()>, sc_service::Error>,
189 (
190 sc_consensus_babe::BabeBlockImport<
191 Block,
192 FullClient,
193 FullBeefyBlockImport<FullGrandpaBlockImport>,
194 BabeCreateInherentDataProviders<Block>,
195 FullSelectChain,
196 >,
197 grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
198 sc_consensus_babe::BabeLink<Block>,
199 beefy::BeefyVoterLinks<Block, beefy_primitives::ecdsa_crypto::AuthorityId>,
200 ),
201 grandpa::SharedVoterState,
202 Option<Telemetry>,
203 Arc<StatementStore>,
204 Option<sc_mixnet::ApiBackend>,
205 ),
206 >,
207 ServiceError,
208> {
209 let telemetry = config
210 .telemetry_endpoints
211 .clone()
212 .filter(|x| !x.is_empty())
213 .map(|endpoints| -> Result<_, sc_telemetry::Error> {
214 let worker = TelemetryWorker::new(16)?;
215 let telemetry = worker.handle().new_telemetry(endpoints);
216 Ok((worker, telemetry))
217 })
218 .transpose()?;
219
220 let executor = sc_service::new_wasm_executor(&config.executor);
221
222 let (client, backend, keystore_container, task_manager) =
223 sc_service::new_full_parts::<Block, RuntimeApi, _>(
224 config,
225 telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
226 executor,
227 )?;
228 let client = Arc::new(client);
229
230 let telemetry = telemetry.map(|(worker, telemetry)| {
231 task_manager.spawn_handle().spawn("telemetry", None, worker.run());
232 telemetry
233 });
234
235 let select_chain = sc_consensus::LongestChain::new(backend.clone());
236
237 let transaction_pool = Arc::from(
238 sc_transaction_pool::Builder::new(
239 task_manager.spawn_essential_handle(),
240 client.clone(),
241 config.role.is_authority().into(),
242 )
243 .with_options(config.transaction_pool.clone())
244 .with_prometheus(config.prometheus_registry())
245 .build(),
246 );
247
248 let (grandpa_block_import, grandpa_link) = grandpa::block_import(
249 client.clone(),
250 GRANDPA_JUSTIFICATION_PERIOD,
251 &(client.clone() as Arc<_>),
252 select_chain.clone(),
253 telemetry.as_ref().map(|x| x.handle()),
254 )?;
255 let justification_import = grandpa_block_import.clone();
256
257 let (beefy_block_import, beefy_voter_links, beefy_rpc_links) =
258 beefy::beefy_block_import_and_links(
259 grandpa_block_import,
260 backend.clone(),
261 client.clone(),
262 config.prometheus_registry().cloned(),
263 );
264
265 let babe_config = sc_consensus_babe::configuration(&*client)?;
266 let slot_duration = babe_config.slot_duration();
267 let (block_import, babe_link) = sc_consensus_babe::block_import(
268 babe_config,
269 beefy_block_import,
270 client.clone(),
271 Arc::new(move |_, _| async move {
272 let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
273 let slot =
274 sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
275 *timestamp,
276 slot_duration,
277 );
278 Ok((slot, timestamp))
279 }) as BabeCreateInherentDataProviders<Block>,
280 select_chain.clone(),
281 OffchainTransactionPoolFactory::new(transaction_pool.clone()),
282 )?;
283
284 let (import_queue, babe_worker_handle) =
285 sc_consensus_babe::import_queue(sc_consensus_babe::ImportQueueParams {
286 link: babe_link.clone(),
287 block_import: block_import.clone(),
288 justification_import: Some(Box::new(justification_import)),
289 client: client.clone(),
290 slot_duration,
291 spawner: &task_manager.spawn_essential_handle(),
292 registry: config.prometheus_registry(),
293 telemetry: telemetry.as_ref().map(|x| x.handle()),
294 })?;
295
296 let import_setup = (block_import, grandpa_link, babe_link, beefy_voter_links);
297
298 let statement_store = sc_statement_store::Store::new_shared(
299 &config.data_path,
300 Default::default(),
301 client.clone(),
302 keystore_container.local_keystore(),
303 config.prometheus_registry(),
304 &task_manager.spawn_handle(),
305 )
306 .map_err(|e| ServiceError::Other(format!("Statement store error: {:?}", e)))?;
307
308 let (mixnet_api, mixnet_api_backend) = mixnet_config.map(sc_mixnet::Api::new).unzip();
309
310 let (rpc_extensions_builder, rpc_setup) = {
311 let (_, grandpa_link, _, _) = &import_setup;
312
313 let justification_stream = grandpa_link.justification_stream();
314 let shared_authority_set = grandpa_link.shared_authority_set().clone();
315 let shared_voter_state = grandpa::SharedVoterState::empty();
316 let shared_voter_state2 = shared_voter_state.clone();
317
318 let finality_proof_provider = grandpa::FinalityProofProvider::new_for_service(
319 backend.clone(),
320 Some(shared_authority_set.clone()),
321 );
322
323 let client = client.clone();
324 let pool = transaction_pool.clone();
325 let select_chain = select_chain.clone();
326 let keystore = keystore_container.keystore();
327 let chain_spec = config.chain_spec.cloned_box();
328
329 let rpc_backend = backend.clone();
330 let rpc_statement_store = statement_store.clone();
331 let rpc_extensions_builder =
332 move |subscription_executor: node_rpc::SubscriptionTaskExecutor| {
333 let deps = node_rpc::FullDeps {
334 client: client.clone(),
335 pool: pool.clone(),
336 select_chain: select_chain.clone(),
337 chain_spec: chain_spec.cloned_box(),
338 babe: node_rpc::BabeDeps {
339 keystore: keystore.clone(),
340 babe_worker_handle: babe_worker_handle.clone(),
341 },
342 grandpa: node_rpc::GrandpaDeps {
343 shared_voter_state: shared_voter_state.clone(),
344 shared_authority_set: shared_authority_set.clone(),
345 justification_stream: justification_stream.clone(),
346 subscription_executor: subscription_executor.clone(),
347 finality_provider: finality_proof_provider.clone(),
348 },
349 beefy: node_rpc::BeefyDeps::<beefy_primitives::ecdsa_crypto::AuthorityId> {
350 beefy_finality_proof_stream: beefy_rpc_links
351 .from_voter_justif_stream
352 .clone(),
353 beefy_best_block_stream: beefy_rpc_links
354 .from_voter_best_beefy_stream
355 .clone(),
356 subscription_executor,
357 },
358 statement_store: rpc_statement_store.clone(),
359 backend: rpc_backend.clone(),
360 mixnet_api: mixnet_api.as_ref().cloned(),
361 };
362
363 node_rpc::create_full(deps).map_err(Into::into)
364 };
365
366 (rpc_extensions_builder, shared_voter_state2)
367 };
368
369 Ok(sc_service::PartialComponents {
370 client,
371 backend,
372 task_manager,
373 keystore_container,
374 select_chain,
375 import_queue,
376 transaction_pool,
377 other: (
378 rpc_extensions_builder,
379 import_setup,
380 rpc_setup,
381 telemetry,
382 statement_store,
383 mixnet_api_backend,
384 ),
385 })
386}
387
388pub struct NewFullBase {
390 pub task_manager: TaskManager,
392 pub client: Arc<FullClient>,
394 pub network: Arc<dyn NetworkService>,
396 pub sync: Arc<SyncingService<Block>>,
398 pub transaction_pool: Arc<TransactionPoolHandle<Block, FullClient>>,
400 pub rpc_handlers: RpcHandlers,
402}
403
404pub fn new_full_base<N: NetworkBackend<Block, <Block as BlockT>::Hash>>(
406 config: Configuration,
407 mixnet_config: Option<sc_mixnet::Config>,
408 disable_hardware_benchmarks: bool,
409 with_startup_data: impl FnOnce(
410 &sc_consensus_babe::BabeBlockImport<
411 Block,
412 FullClient,
413 FullBeefyBlockImport<FullGrandpaBlockImport>,
414 BabeCreateInherentDataProviders<Block>,
415 FullSelectChain,
416 >,
417 &sc_consensus_babe::BabeLink<Block>,
418 ),
419) -> Result<NewFullBase, ServiceError> {
420 let is_offchain_indexing_enabled = config.offchain_worker.indexing_enabled;
421 let role = config.role;
422 let force_authoring = config.force_authoring;
423 let backoff_authoring_blocks =
424 Some(sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default());
425 let name = config.network.node_name.clone();
426 let enable_grandpa = !config.disable_grandpa;
427 let prometheus_registry = config.prometheus_registry().cloned();
428 let enable_offchain_worker = config.offchain_worker.enabled;
429
430 let hwbench = (!disable_hardware_benchmarks)
431 .then(|| {
432 config.database.path().map(|database_path| {
433 let _ = std::fs::create_dir_all(&database_path);
434 sc_sysinfo::gather_hwbench(Some(database_path), &SUBSTRATE_REFERENCE_HARDWARE)
435 })
436 })
437 .flatten();
438
439 let sc_service::PartialComponents {
440 client,
441 backend,
442 mut task_manager,
443 import_queue,
444 keystore_container,
445 select_chain,
446 transaction_pool,
447 other:
448 (rpc_builder, import_setup, rpc_setup, mut telemetry, statement_store, mixnet_api_backend),
449 } = new_partial(&config, mixnet_config.as_ref())?;
450
451 let metrics = N::register_notification_metrics(
452 config.prometheus_config.as_ref().map(|cfg| &cfg.registry),
453 );
454 let shared_voter_state = rpc_setup;
455 let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht;
456 let auth_disc_public_addresses = config.network.public_addresses.clone();
457
458 let mut net_config = sc_network::config::FullNetworkConfiguration::<_, _, N>::new(
459 &config.network,
460 config.prometheus_config.as_ref().map(|cfg| cfg.registry.clone()),
461 );
462
463 let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed");
464 let peer_store_handle = net_config.peer_store_handle();
465
466 let grandpa_protocol_name = grandpa::protocol_standard_name(&genesis_hash, &config.chain_spec);
467 let (grandpa_protocol_config, grandpa_notification_service) =
468 grandpa::grandpa_peers_set_config::<_, N>(
469 grandpa_protocol_name.clone(),
470 metrics.clone(),
471 Arc::clone(&peer_store_handle),
472 );
473 net_config.add_notification_protocol(grandpa_protocol_config);
474
475 let beefy_gossip_proto_name =
476 beefy::gossip_protocol_name(&genesis_hash, config.chain_spec.fork_id());
477 let (beefy_on_demand_justifications_handler, beefy_req_resp_cfg) =
480 beefy::communication::request_response::BeefyJustifsRequestHandler::new::<_, N>(
481 &genesis_hash,
482 config.chain_spec.fork_id(),
483 client.clone(),
484 prometheus_registry.clone(),
485 );
486
487 let (beefy_notification_config, beefy_notification_service) =
488 beefy::communication::beefy_peers_set_config::<_, N>(
489 beefy_gossip_proto_name.clone(),
490 metrics.clone(),
491 Arc::clone(&peer_store_handle),
492 );
493
494 net_config.add_notification_protocol(beefy_notification_config);
495 net_config.add_request_response_protocol(beefy_req_resp_cfg);
496
497 let (statement_handler_proto, statement_config) =
498 sc_network_statement::StatementHandlerPrototype::new::<_, _, N>(
499 genesis_hash,
500 config.chain_spec.fork_id(),
501 metrics.clone(),
502 Arc::clone(&peer_store_handle),
503 );
504 net_config.add_notification_protocol(statement_config);
505
506 let mixnet_protocol_name =
507 sc_mixnet::protocol_name(genesis_hash.as_ref(), config.chain_spec.fork_id());
508 let mixnet_notification_service = mixnet_config.as_ref().map(|mixnet_config| {
509 let (config, notification_service) = sc_mixnet::peers_set_config::<_, N>(
510 mixnet_protocol_name.clone(),
511 mixnet_config,
512 metrics.clone(),
513 Arc::clone(&peer_store_handle),
514 );
515 net_config.add_notification_protocol(config);
516 notification_service
517 });
518
519 let warp_sync = Arc::new(grandpa::warp_proof::NetworkProvider::new(
520 backend.clone(),
521 import_setup.1.shared_authority_set().clone(),
522 Vec::default(),
523 ));
524
525 let (network, system_rpc_tx, tx_handler_controller, sync_service) =
526 sc_service::build_network(sc_service::BuildNetworkParams {
527 config: &config,
528 net_config,
529 client: client.clone(),
530 transaction_pool: transaction_pool.clone(),
531 spawn_handle: task_manager.spawn_handle(),
532 import_queue,
533 block_announce_validator_builder: None,
534 warp_sync_config: Some(WarpSyncConfig::WithProvider(warp_sync)),
535 block_relay: None,
536 metrics,
537 })?;
538
539 if let Some(mixnet_config) = mixnet_config {
540 let mixnet = sc_mixnet::run(
541 mixnet_config,
542 mixnet_api_backend.expect("Mixnet API backend created if mixnet enabled"),
543 client.clone(),
544 sync_service.clone(),
545 network.clone(),
546 mixnet_protocol_name,
547 transaction_pool.clone(),
548 Some(keystore_container.keystore()),
549 mixnet_notification_service
550 .expect("`NotificationService` exists since mixnet was enabled; qed"),
551 );
552 task_manager.spawn_handle().spawn("mixnet", None, mixnet);
553 }
554
555 let net_config_path = config.network.net_config_path.clone();
556 let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
557 config,
558 backend: backend.clone(),
559 client: client.clone(),
560 keystore: keystore_container.keystore(),
561 network: network.clone(),
562 rpc_builder: Box::new(rpc_builder),
563 transaction_pool: transaction_pool.clone(),
564 task_manager: &mut task_manager,
565 system_rpc_tx,
566 tx_handler_controller,
567 sync_service: sync_service.clone(),
568 telemetry: telemetry.as_mut(),
569 })?;
570
571 if let Some(hwbench) = hwbench {
572 sc_sysinfo::print_hwbench(&hwbench);
573 match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench, false) {
574 Err(err) if role.is_authority() => {
575 log::warn!(
576 "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority'.",
577 err
578 );
579 },
580 _ => {},
581 }
582
583 if let Some(ref mut telemetry) = telemetry {
584 let telemetry_handle = telemetry.handle();
585 task_manager.spawn_handle().spawn(
586 "telemetry_hwbench",
587 None,
588 sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench),
589 );
590 }
591 }
592
593 let (block_import, grandpa_link, babe_link, beefy_links) = import_setup;
594
595 (with_startup_data)(&block_import, &babe_link);
596
597 if let sc_service::config::Role::Authority { .. } = &role {
598 let proposer = sc_basic_authorship::ProposerFactory::new(
599 task_manager.spawn_handle(),
600 client.clone(),
601 transaction_pool.clone(),
602 prometheus_registry.as_ref(),
603 telemetry.as_ref().map(|x| x.handle()),
604 );
605
606 let client_clone = client.clone();
607 let slot_duration = babe_link.config().slot_duration();
608 let babe_config = sc_consensus_babe::BabeParams {
609 keystore: keystore_container.keystore(),
610 client: client.clone(),
611 select_chain,
612 env: proposer,
613 block_import,
614 sync_oracle: sync_service.clone(),
615 justification_sync_link: sync_service.clone(),
616 create_inherent_data_providers: move |parent, ()| {
617 let client_clone = client_clone.clone();
618 async move {
619 let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
620
621 let slot =
622 sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
623 *timestamp,
624 slot_duration,
625 );
626
627 let storage_proof =
628 sp_transaction_storage_proof::registration::new_data_provider(
629 &*client_clone,
630 &parent,
631 )?;
632
633 Ok((slot, timestamp, storage_proof))
634 }
635 },
636 force_authoring,
637 backoff_authoring_blocks,
638 babe_link,
639 block_proposal_slot_portion: SlotProportion::new(0.5),
640 max_block_proposal_slot_portion: None,
641 telemetry: telemetry.as_ref().map(|x| x.handle()),
642 };
643
644 let babe = sc_consensus_babe::start_babe(babe_config)?;
645 task_manager.spawn_essential_handle().spawn_blocking(
646 "babe-proposer",
647 Some("block-authoring"),
648 babe,
649 );
650 }
651
652 if role.is_authority() {
654 let authority_discovery_role =
655 sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore());
656 let dht_event_stream =
657 network.event_stream("authority-discovery").filter_map(|e| async move {
658 match e {
659 Event::Dht(e) => Some(e),
660 _ => None,
661 }
662 });
663 let (authority_discovery_worker, _service) =
664 sc_authority_discovery::new_worker_and_service_with_config(
665 sc_authority_discovery::WorkerConfig {
666 publish_non_global_ips: auth_disc_publish_non_global_ips,
667 public_addresses: auth_disc_public_addresses,
668 persisted_cache_directory: net_config_path,
669 ..Default::default()
670 },
671 client.clone(),
672 Arc::new(network.clone()),
673 Box::pin(dht_event_stream),
674 authority_discovery_role,
675 prometheus_registry.clone(),
676 task_manager.spawn_handle(),
677 );
678
679 task_manager.spawn_handle().spawn(
680 "authority-discovery-worker",
681 Some("networking"),
682 authority_discovery_worker.run(),
683 );
684 }
685
686 let keystore = if role.is_authority() { Some(keystore_container.keystore()) } else { None };
689
690 let network_params = beefy::BeefyNetworkParams {
692 network: Arc::new(network.clone()),
693 sync: sync_service.clone(),
694 gossip_protocol_name: beefy_gossip_proto_name,
695 justifications_protocol_name: beefy_on_demand_justifications_handler.protocol_name(),
696 notification_service: beefy_notification_service,
697 _phantom: core::marker::PhantomData::<Block>,
698 };
699 let beefy_params = beefy::BeefyParams {
700 client: client.clone(),
701 backend: backend.clone(),
702 payload_provider: sp_consensus_beefy::mmr::MmrRootProvider::new(client.clone()),
703 runtime: client.clone(),
704 key_store: keystore.clone(),
705 network_params,
706 min_block_delta: 8,
707 prometheus_registry: prometheus_registry.clone(),
708 links: beefy_links,
709 on_demand_justifications_handler: beefy_on_demand_justifications_handler,
710 is_authority: role.is_authority(),
711 };
712
713 let beefy_gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _, _>(beefy_params);
714 task_manager
717 .spawn_essential_handle()
718 .spawn_blocking("beefy-gadget", None, beefy_gadget);
719 if is_offchain_indexing_enabled {
721 task_manager.spawn_essential_handle().spawn_blocking(
722 "mmr-gadget",
723 None,
724 mmr_gadget::MmrGadget::start(
725 client.clone(),
726 backend.clone(),
727 sp_mmr_primitives::INDEXING_PREFIX.to_vec(),
728 ),
729 );
730 }
731
732 let grandpa_config = grandpa::Config {
733 gossip_duration: std::time::Duration::from_millis(333),
735 justification_generation_period: GRANDPA_JUSTIFICATION_PERIOD,
736 name: Some(name),
737 observer_enabled: false,
738 keystore,
739 local_role: role,
740 telemetry: telemetry.as_ref().map(|x| x.handle()),
741 protocol_name: grandpa_protocol_name,
742 };
743
744 if enable_grandpa {
745 let grandpa_params = grandpa::GrandpaParams {
752 config: grandpa_config,
753 link: grandpa_link,
754 network: network.clone(),
755 sync: Arc::new(sync_service.clone()),
756 notification_service: grandpa_notification_service,
757 telemetry: telemetry.as_ref().map(|x| x.handle()),
758 voting_rule: grandpa::VotingRulesBuilder::default().build(),
759 prometheus_registry: prometheus_registry.clone(),
760 shared_voter_state,
761 offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool.clone()),
762 };
763
764 task_manager.spawn_essential_handle().spawn_blocking(
767 "grandpa-voter",
768 None,
769 grandpa::run_grandpa_voter(grandpa_params)?,
770 );
771 }
772
773 let statement_protocol_executor = {
775 let spawn_handle = task_manager.spawn_handle();
776 Box::new(move |fut| {
777 spawn_handle.spawn("network-statement-validator", Some("networking"), fut);
778 })
779 };
780 let statement_handler = statement_handler_proto.build(
781 network.clone(),
782 sync_service.clone(),
783 statement_store.clone(),
784 prometheus_registry.as_ref(),
785 statement_protocol_executor,
786 )?;
787 task_manager.spawn_handle().spawn(
788 "network-statement-handler",
789 Some("networking"),
790 statement_handler.run(),
791 );
792
793 if enable_offchain_worker {
794 let offchain_workers =
795 sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
796 runtime_api_provider: client.clone(),
797 keystore: Some(keystore_container.keystore()),
798 offchain_db: backend.offchain_storage(),
799 transaction_pool: Some(OffchainTransactionPoolFactory::new(
800 transaction_pool.clone(),
801 )),
802 network_provider: Arc::new(network.clone()),
803 is_validator: role.is_authority(),
804 enable_http_requests: true,
805 custom_extensions: move |_| {
806 vec![Box::new(statement_store.clone().as_statement_store_ext()) as Box<_>]
807 },
808 })?;
809 task_manager.spawn_handle().spawn(
810 "offchain-workers-runner",
811 "offchain-work",
812 offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(),
813 );
814 }
815
816 Ok(NewFullBase {
817 task_manager,
818 client,
819 network,
820 sync: sync_service,
821 transaction_pool,
822 rpc_handlers,
823 })
824}
825
826pub fn new_full(config: Configuration, cli: Cli) -> Result<TaskManager, ServiceError> {
828 let mixnet_config = cli.mixnet_params.config(config.role.is_authority());
829 let database_path = config.database.path().map(Path::to_path_buf);
830
831 let task_manager = match config.network.network_backend {
832 sc_network::config::NetworkBackendType::Libp2p => {
833 let task_manager = new_full_base::<sc_network::NetworkWorker<_, _>>(
834 config,
835 mixnet_config,
836 cli.no_hardware_benchmarks,
837 |_, _| (),
838 )
839 .map(|NewFullBase { task_manager, .. }| task_manager)?;
840 task_manager
841 },
842 sc_network::config::NetworkBackendType::Litep2p => {
843 let task_manager = new_full_base::<sc_network::Litep2pNetworkBackend>(
844 config,
845 mixnet_config,
846 cli.no_hardware_benchmarks,
847 |_, _| (),
848 )
849 .map(|NewFullBase { task_manager, .. }| task_manager)?;
850 task_manager
851 },
852 };
853
854 if let Some(database_path) = database_path {
855 sc_storage_monitor::StorageMonitorService::try_spawn(
856 cli.storage_monitor,
857 database_path,
858 &task_manager.spawn_essential_handle(),
859 )
860 .map_err(|e| ServiceError::Application(e.into()))?;
861 }
862
863 Ok(task_manager)
864}
865
866#[cfg(test)]
867mod tests {
868 use crate::service::{new_full_base, NewFullBase};
869 use codec::Encode;
870 use kitchensink_runtime::{
871 constants::{currency::CENTS, time::SLOT_DURATION},
872 Address, BalancesCall, RuntimeCall, TxExtension,
873 };
874 use node_primitives::{Block, DigestItem, Signature};
875 use polkadot_sdk::{sc_transaction_pool_api::MaintainedTransactionPool, *};
876 use sc_client_api::BlockBackend;
877 use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy};
878 use sc_consensus_babe::{BabeIntermediate, CompatibleDigestItem, INTERMEDIATE_KEY};
879 use sc_consensus_epochs::descendent_query;
880 use sc_keystore::LocalKeystore;
881 use sc_service_test::TestNetNode;
882 use sc_transaction_pool_api::ChainEvent;
883 use sp_consensus::{BlockOrigin, Environment, Proposer};
884 use sp_core::crypto::Pair;
885 use sp_inherents::InherentDataProvider;
886 use sp_keyring::Sr25519Keyring;
887 use sp_keystore::KeystorePtr;
888 use sp_runtime::{
889 generic::{self, Digest, Era, SignedPayload},
890 key_types::BABE,
891 traits::{Block as BlockT, Header as HeaderT, IdentifyAccount, Verify},
892 RuntimeAppPublic,
893 };
894 use sp_timestamp;
895 use std::sync::Arc;
896
897 type AccountPublic = <Signature as Verify>::Signer;
898
899 #[test]
900 #[ignore]
903 fn test_sync() {
904 sp_tracing::try_init_simple();
905
906 let keystore_path = tempfile::tempdir().expect("Creates keystore path");
907 let keystore: KeystorePtr = LocalKeystore::open(keystore_path.path(), None)
908 .expect("Creates keystore")
909 .into();
910 let alice: sp_consensus_babe::AuthorityId = keystore
911 .sr25519_generate_new(BABE, Some("//Alice"))
912 .expect("Creates authority pair")
913 .into();
914
915 let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
916
917 let mut slot = 1u64;
919
920 let bob = Arc::new(Sr25519Keyring::Bob.pair());
922 let charlie = Arc::new(Sr25519Keyring::Charlie.pair());
923 let mut index = 0;
924
925 sc_service_test::sync(
926 chain_spec,
927 |config| {
928 let mut setup_handles = None;
929 let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } =
930 new_full_base::<sc_network::NetworkWorker<_, _>>(
931 config,
932 None,
933 false,
934 |block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _, _, _>,
935 babe_link: &sc_consensus_babe::BabeLink<Block>| {
936 setup_handles = Some((block_import.clone(), babe_link.clone()));
937 },
938 )?;
939
940 let node = sc_service_test::TestNetComponents::new(
941 task_manager,
942 client,
943 network,
944 sync,
945 transaction_pool,
946 );
947 Ok((node, setup_handles.unwrap()))
948 },
949 |service, &mut (ref mut block_import, ref babe_link)| {
950 let parent_hash = service.client().chain_info().best_hash;
951 let parent_header = service.client().header(parent_hash).unwrap().unwrap();
952 let parent_number = *parent_header.number();
953
954 futures::executor::block_on(service.transaction_pool().maintain(
955 ChainEvent::NewBestBlock { hash: parent_header.hash(), tree_route: None },
956 ));
957
958 let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
959 service.spawn_handle(),
960 service.client(),
961 service.transaction_pool(),
962 None,
963 None,
964 );
965
966 let mut digest = Digest::default();
967
968 let (babe_pre_digest, epoch_descriptor) = loop {
971 let epoch_descriptor = babe_link
972 .epoch_changes()
973 .shared_data()
974 .epoch_descriptor_for_child_of(
975 descendent_query(&*service.client()),
976 &parent_hash,
977 parent_number,
978 slot.into(),
979 )
980 .unwrap()
981 .unwrap();
982
983 let epoch = babe_link
984 .epoch_changes()
985 .shared_data()
986 .epoch_data(&epoch_descriptor, |slot| {
987 sc_consensus_babe::Epoch::genesis(babe_link.config(), slot)
988 })
989 .unwrap();
990
991 if let Some(babe_pre_digest) =
992 sc_consensus_babe::authorship::claim_slot(slot.into(), &epoch, &keystore)
993 .map(|(digest, _)| digest)
994 {
995 break (babe_pre_digest, epoch_descriptor);
996 }
997
998 slot += 1;
999 };
1000
1001 let inherent_data = futures::executor::block_on(
1002 (
1003 sp_timestamp::InherentDataProvider::new(
1004 std::time::Duration::from_millis(SLOT_DURATION * slot).into(),
1005 ),
1006 sp_consensus_babe::inherents::InherentDataProvider::new(slot.into()),
1007 )
1008 .create_inherent_data(),
1009 )
1010 .expect("Creates inherent data");
1011
1012 digest.push(<DigestItem as CompatibleDigestItem>::babe_pre_digest(babe_pre_digest));
1013
1014 let new_block = futures::executor::block_on(async move {
1015 let proposer = proposer_factory.init(&parent_header).await.unwrap();
1016 Proposer::propose(
1017 proposer,
1018 inherent_data,
1019 digest,
1020 std::time::Duration::from_secs(1),
1021 None,
1022 )
1023 .await
1024 })
1025 .expect("Error making test block")
1026 .block;
1027
1028 let (new_header, new_body) = new_block.deconstruct();
1029 let pre_hash = new_header.hash();
1030 let to_sign = pre_hash.encode();
1033 let signature = keystore
1034 .sr25519_sign(sp_consensus_babe::AuthorityId::ID, alice.as_ref(), &to_sign)
1035 .unwrap()
1036 .unwrap();
1037 let item = <DigestItem as CompatibleDigestItem>::babe_seal(signature.into());
1038 slot += 1;
1039
1040 let mut params = BlockImportParams::new(BlockOrigin::File, new_header);
1041 params.post_digests.push(item);
1042 params.body = Some(new_body);
1043 params.insert_intermediate(
1044 INTERMEDIATE_KEY,
1045 BabeIntermediate::<Block> { epoch_descriptor },
1046 );
1047 params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
1048
1049 futures::executor::block_on(block_import.import_block(params))
1050 .expect("error importing test block");
1051 },
1052 |service, _| {
1053 let amount = 5 * CENTS;
1054 let to: Address = AccountPublic::from(bob.public()).into_account().into();
1055 let from: Address = AccountPublic::from(charlie.public()).into_account().into();
1056 let genesis_hash = service.client().block_hash(0).unwrap().unwrap();
1057 let best_hash = service.client().chain_info().best_hash;
1058 let (spec_version, transaction_version) = {
1059 let version = service.client().runtime_version_at(best_hash).unwrap();
1060 (version.spec_version, version.transaction_version)
1061 };
1062 let signer = charlie.clone();
1063
1064 let function = RuntimeCall::Balances(BalancesCall::transfer_allow_death {
1065 dest: to.into(),
1066 value: amount,
1067 });
1068
1069 let authorize_call = frame_system::AuthorizeCall::new();
1070 let check_non_zero_sender = frame_system::CheckNonZeroSender::new();
1071 let check_spec_version = frame_system::CheckSpecVersion::new();
1072 let check_tx_version = frame_system::CheckTxVersion::new();
1073 let check_genesis = frame_system::CheckGenesis::new();
1074 let check_era = frame_system::CheckEra::from(Era::Immortal);
1075 let check_nonce = frame_system::CheckNonce::from(index);
1076 let check_weight = frame_system::CheckWeight::new();
1077 let tx_payment = pallet_skip_feeless_payment::SkipCheckIfFeeless::from(
1078 pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(0, None),
1079 );
1080 let weight_reclaim = frame_system::WeightReclaim::new();
1081 let metadata_hash = frame_metadata_hash_extension::CheckMetadataHash::new(false);
1082 let tx_ext: TxExtension = (
1083 authorize_call,
1084 check_non_zero_sender,
1085 check_spec_version,
1086 check_tx_version,
1087 check_genesis,
1088 check_era,
1089 check_nonce,
1090 check_weight,
1091 tx_payment,
1092 metadata_hash,
1093 weight_reclaim,
1094 );
1095 let raw_payload = SignedPayload::from_raw(
1096 function,
1097 tx_ext,
1098 (
1099 (),
1100 (),
1101 spec_version,
1102 transaction_version,
1103 genesis_hash,
1104 genesis_hash,
1105 (),
1106 (),
1107 (),
1108 None,
1109 (),
1110 ),
1111 );
1112 let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
1113 let (function, tx_ext, _) = raw_payload.deconstruct();
1114 index += 1;
1115 let utx: kitchensink_runtime::UncheckedExtrinsic =
1116 generic::UncheckedExtrinsic::new_signed(
1117 function,
1118 from.into(),
1119 signature.into(),
1120 tx_ext,
1121 )
1122 .into();
1123
1124 utx.into()
1125 },
1126 );
1127 }
1128
1129 #[test]
1130 #[ignore]
1131 fn test_consensus() {
1132 sp_tracing::try_init_simple();
1133
1134 sc_service_test::consensus(
1135 crate::chain_spec::tests::integration_test_config_with_two_authorities(),
1136 |config| {
1137 let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } =
1138 new_full_base::<sc_network::NetworkWorker<_, _>>(
1139 config,
1140 None,
1141 false,
1142 |_, _| (),
1143 )?;
1144 Ok(sc_service_test::TestNetComponents::new(
1145 task_manager,
1146 client,
1147 network,
1148 sync,
1149 transaction_pool,
1150 ))
1151 },
1152 vec!["//Alice".into(), "//Bob".into()],
1153 )
1154 }
1155}