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