lib.rs 39.7 KB
Newer Older
1
// Copyright 2017-2021 Parity Technologies (UK) Ltd.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.

//! Polkadot service. Specialized wrapper over substrate service.

19
20
#![deny(unused_results)]

21
pub mod chain_spec;
22
mod grandpa_support;
23
mod parachains_db;
24
mod relay_chain_selection;
25

26
27
28
29
30
#[cfg(feature = "full-node")]
mod overseer;

#[cfg(feature = "full-node")]
pub use self::overseer::{
Shawn Tabrizi's avatar
Shawn Tabrizi committed
31
	create_default_subsystems, OverseerGen, OverseerGenArgs, RealOverseerGen,
32
33
};

34
35
36
#[cfg(test)]
mod tests;

37
#[cfg(feature = "full-node")]
38
use {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
39
	grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider},
40
	polkadot_network_bridge::RequestMultiplexer,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
41
	polkadot_node_core_approval_voting::Config as ApprovalVotingConfig,
42
	polkadot_node_core_av_store::Config as AvailabilityConfig,
43
	polkadot_node_core_av_store::Error as AvailabilityError,
44
	polkadot_node_core_candidate_validation::Config as CandidateValidationConfig,
Andronik Ordian's avatar
Andronik Ordian committed
45
	polkadot_node_core_chain_selection::{
Shawn Tabrizi's avatar
Shawn Tabrizi committed
46
		self as chain_selection_subsystem, Config as ChainSelectionConfig,
Andronik Ordian's avatar
Andronik Ordian committed
47
48
	},
	polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig,
49
50
	polkadot_overseer::BlockInfo,
	sc_client_api::ExecutorProvider,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
51
52
	sp_trie::PrefixedMemoryDB,
	tracing::info,
53
54
};

Shawn Tabrizi's avatar
Shawn Tabrizi committed
55
pub use sp_core::traits::SpawnNamed;
56
57
#[cfg(feature = "full-node")]
pub use {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
58
59
60
61
	polkadot_overseer::{Handle, Overseer, OverseerHandle},
	polkadot_primitives::v1::ParachainHost,
	sc_client_api::AuxStore,
	sp_authority_discovery::AuthorityDiscoveryApi,
62
63
64
	sp_blockchain::HeaderBackend,
	sp_consensus_babe::BabeApi,
};
65

66
#[cfg(feature = "full-node")]
67
68
use polkadot_subsystem::jaeger;

Shawn Tabrizi's avatar
Shawn Tabrizi committed
69
use std::{sync::Arc, time::Duration};
70

71
use prometheus_endpoint::Registry;
72
use service::RpcHandlers;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
73
use telemetry::TelemetryWorker;
74
75
#[cfg(feature = "full-node")]
use telemetry::{Telemetry, TelemetryWorkerHandle};
76

77
78
79
80
81
82
83
84
85
#[cfg(feature = "rococo-native")]
pub use polkadot_client::RococoExecutor;

#[cfg(feature = "westend-native")]
pub use polkadot_client::WestendExecutor;

#[cfg(feature = "kusama-native")]
pub use polkadot_client::KusamaExecutor;

Shawn Tabrizi's avatar
Shawn Tabrizi committed
86
87
pub use chain_spec::{KusamaChainSpec, PolkadotChainSpec, RococoChainSpec, WestendChainSpec};
pub use consensus_common::{block_validation::Chain, Proposal, SelectChain};
88
pub use polkadot_client::{
Shawn Tabrizi's avatar
Shawn Tabrizi committed
89
90
	AbstractClient, Client, ClientHandle, ExecuteWithClient, FullBackend, FullClient,
	PolkadotExecutor, RuntimeApiCollection,
91
};
92
pub use polkadot_primitives::v1::{Block, BlockId, CollatorPair, Hash, Id as ParaId};
Shawn Tabrizi's avatar
Shawn Tabrizi committed
93
pub use sc_client_api::{Backend, CallExecutor, ExecutionStrategy};
94
pub use sc_consensus::{BlockImport, LongestChain};
95
pub use sc_executor::NativeExecutionDispatch;
96
pub use service::{
Shawn Tabrizi's avatar
Shawn Tabrizi committed
97
98
99
100
	config::{DatabaseConfig, PrometheusConfig},
	ChainSpec, Configuration, Error as SubstrateServiceError, PruningMode, Role, RuntimeGenesis,
	TFullBackend, TFullCallExecutor, TFullClient, TLightBackend, TLightCallExecutor, TLightClient,
	TaskManager, TransactionPoolOptions,
101
};
Shawn Tabrizi's avatar
Shawn Tabrizi committed
102
pub use sp_api::{ApiRef, ConstructRuntimeApi, Core as CoreApi, ProvideRuntimeApi, StateBackend};
103
104
105
pub use sp_runtime::{
	generic,
	traits::{
Shawn Tabrizi's avatar
Shawn Tabrizi committed
106
107
		self as runtime_traits, BlakeTwo256, Block as BlockT, DigestFor, HashFor,
		Header as HeaderT, NumberFor,
108
109
	},
};
110

111
#[cfg(feature = "kusama-native")]
112
pub use kusama_runtime;
113
pub use polkadot_runtime;
114
#[cfg(feature = "rococo-native")]
115
pub use rococo_runtime;
116
#[cfg(feature = "westend-native")]
117
118
pub use westend_runtime;

119
/// The maximum number of active leaves we forward to the [`Overseer`] on startup.
120
#[cfg(any(test, feature = "full-node"))]
121
122
const MAX_ACTIVE_LEAVES: usize = 4;

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/// Provides the header and block number for a hash.
///
/// Decouples `sc_client_api::Backend` and `sp_blockchain::HeaderBackend`.
pub trait HeaderProvider<Block, Error = sp_blockchain::Error>: Send + Sync + 'static
where
	Block: BlockT,
	Error: std::fmt::Debug + Send + Sync + 'static,
{
	/// Obtain the header for a hash.
	fn header(
		&self,
		hash: <Block as BlockT>::Hash,
	) -> Result<Option<<Block as BlockT>::Header>, Error>;
	/// Obtain the block number for a hash.
	fn number(
		&self,
		hash: <Block as BlockT>::Hash,
	) -> Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>, Error>;
}

impl<Block, T> HeaderProvider<Block> for T
where
	Block: BlockT,
	T: sp_blockchain::HeaderBackend<Block> + 'static,
{
	fn header(
		&self,
		hash: Block::Hash,
	) -> sp_blockchain::Result<Option<<Block as BlockT>::Header>> {
		<Self as sp_blockchain::HeaderBackend<Block>>::header(
			self,
			generic::BlockId::<Block>::Hash(hash),
		)
	}
	fn number(
		&self,
		hash: Block::Hash,
	) -> sp_blockchain::Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>> {
		<Self as sp_blockchain::HeaderBackend<Block>>::number(self, hash)
	}
}

/// Decoupling the provider.
///
/// Mandated since `trait HeaderProvider` can only be
/// implemented once for a generic `T`.
pub trait HeaderProviderProvider<Block>: Send + Sync + 'static
where
	Block: BlockT,
{
	type Provider: HeaderProvider<Block> + 'static;

	fn header_provider(&self) -> &Self::Provider;
}

impl<Block, T> HeaderProviderProvider<Block> for T
where
	Block: BlockT,
	T: sc_client_api::Backend<Block> + 'static,
{
	type Provider = <T as sc_client_api::Backend<Block>>::Blockchain;

	fn header_provider(&self) -> &Self::Provider {
		self.blockchain()
	}
}

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#[derive(thiserror::Error, Debug)]
pub enum Error {
	#[error(transparent)]
	Io(#[from] std::io::Error),

	#[error(transparent)]
	AddrFormatInvalid(#[from] std::net::AddrParseError),

	#[error(transparent)]
	Sub(#[from] SubstrateServiceError),

	#[error(transparent)]
	Blockchain(#[from] sp_blockchain::Error),

	#[error(transparent)]
	Consensus(#[from] consensus_common::Error),

	#[error("Failed to create an overseer")]
	Overseer(#[from] polkadot_overseer::SubsystemError),

	#[error(transparent)]
	Prometheus(#[from] prometheus_endpoint::PrometheusError),

213
214
215
	#[error(transparent)]
	Telemetry(#[from] telemetry::Error),

216
217
218
	#[error(transparent)]
	Jaeger(#[from] polkadot_subsystem::jaeger::JaegerError),

219
220
221
222
223
224
	#[cfg(feature = "full-node")]
	#[error(transparent)]
	Availability(#[from] AvailabilityError),

	#[error("Authorities require the real overseer implementation")]
	AuthoritiesRequireRealOverseer,
225
226
227
228

	#[cfg(feature = "full-node")]
	#[error("Creating a custom database is required for validators")]
	DatabasePathRequired,
229
230
}

231
/// Can be called for a `Configuration` to identify which network the configuration targets.
232
233
234
235
236
237
pub trait IdentifyVariant {
	/// Returns if this is a configuration for the `Kusama` network.
	fn is_kusama(&self) -> bool;

	/// Returns if this is a configuration for the `Westend` network.
	fn is_westend(&self) -> bool;
238
239
240

	/// Returns if this is a configuration for the `Rococo` network.
	fn is_rococo(&self) -> bool;
241

242
243
244
	/// Returns if this is a configuration for the `Wococo` test network.
	fn is_wococo(&self) -> bool;

245
246
	/// Returns true if this configuration is for a development network.
	fn is_dev(&self) -> bool;
247
248
249
250
251
252
253
254
255
}

impl IdentifyVariant for Box<dyn ChainSpec> {
	fn is_kusama(&self) -> bool {
		self.id().starts_with("kusama") || self.id().starts_with("ksm")
	}
	fn is_westend(&self) -> bool {
		self.id().starts_with("westend") || self.id().starts_with("wnd")
	}
256
257
258
	fn is_rococo(&self) -> bool {
		self.id().starts_with("rococo") || self.id().starts_with("rco")
	}
259
260
261
	fn is_wococo(&self) -> bool {
		self.id().starts_with("wococo") || self.id().starts_with("wco")
	}
262
263
264
	fn is_dev(&self) -> bool {
		self.id().ends_with("dev")
	}
265
266
267
}

// If we're using prometheus, use a registry with a prefix of `polkadot`.
268
fn set_prometheus_registry(config: &mut Configuration) -> Result<(), Error> {
269
270
271
272
273
274
275
	if let Some(PrometheusConfig { registry, .. }) = config.prometheus_config.as_mut() {
		*registry = Registry::new_custom(Some("polkadot".into()), None)?;
	}

	Ok(())
}

276
277
/// Initialize the `Jeager` collector. The destination must listen
/// on the given address and port for `UDP` packets.
278
279
280
281
282
283
#[cfg(any(test, feature = "full-node"))]
fn jaeger_launch_collector_with_agent(
	spawner: impl SpawnNamed,
	config: &Configuration,
	agent: Option<std::net::SocketAddr>,
) -> Result<(), Error> {
284
285
286
287
288
289
290
291
292
293
294
	if let Some(agent) = agent {
		let cfg = jaeger::JaegerConfig::builder()
			.agent(agent)
			.named(&config.network.node_name)
			.build();

		jaeger::Jaeger::new(cfg).launch(spawner)?;
	}
	Ok(())
}

295
#[cfg(feature = "full-node")]
296
type FullSelectChain = relay_chain_selection::SelectRelayChainWithFallback<FullBackend>;
297
#[cfg(feature = "full-node")]
298
type FullGrandpaBlockImport<RuntimeApi, Executor> = grandpa::GrandpaBlockImport<
Shawn Tabrizi's avatar
Shawn Tabrizi committed
299
300
301
302
	FullBackend,
	Block,
	FullClient<RuntimeApi, Executor>,
	FullSelectChain,
303
304
>;

305
#[cfg(feature = "light-node")]
306
307
type LightBackend = service::TLightBackendWithHash<Block, sp_runtime::traits::BlakeTwo256>;

308
#[cfg(feature = "light-node")]
309
310
311
312
type LightClient<RuntimeApi, Executor> =
	service::TLightClientWithBackend<Block, RuntimeApi, Executor, LightBackend>;

#[cfg(feature = "full-node")]
313
314
315
316
317
fn new_partial<RuntimeApi, Executor>(
	config: &mut Configuration,
	jaeger_agent: Option<std::net::SocketAddr>,
	telemetry_worker_handle: Option<TelemetryWorkerHandle>,
) -> Result<
318
	service::PartialComponents<
Shawn Tabrizi's avatar
Shawn Tabrizi committed
319
320
321
		FullClient<RuntimeApi, Executor>,
		FullBackend,
		FullSelectChain,
322
		sc_consensus::DefaultImportQueue<Block, FullClient<RuntimeApi, Executor>>,
323
		sc_transaction_pool::FullPool<Block, FullClient<RuntimeApi, Executor>>,
324
		(
325
			impl service::RpcExtensionBuilder,
326
327
			(
				babe::BabeBlockImport<
Shawn Tabrizi's avatar
Shawn Tabrizi committed
328
329
330
					Block,
					FullClient<RuntimeApi, Executor>,
					FullGrandpaBlockImport<RuntimeApi, Executor>,
331
332
				>,
				grandpa::LinkHalf<Block, FullClient<RuntimeApi, Executor>, FullSelectChain>,
333
				babe::BabeLink<Block>,
Andreas Doerr's avatar
Andreas Doerr committed
334
				beefy_gadget::notification::BeefySignedCommitmentSender<Block>,
335
			),
336
			grandpa::SharedVoterState,
337
			std::time::Duration, // slot-duration
338
			Option<Telemetry>,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
339
		),
340
	>,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
341
	Error,
342
>
Shawn Tabrizi's avatar
Shawn Tabrizi committed
343
344
345
346
where
	RuntimeApi:
		ConstructRuntimeApi<Block, FullClient<RuntimeApi, Executor>> + Send + Sync + 'static,
	RuntimeApi::RuntimeApi:
347
		RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
348
	Executor: NativeExecutionDispatch + 'static,
349
{
350
	set_prometheus_registry(config)?;
351

Shawn Tabrizi's avatar
Shawn Tabrizi committed
352
353
354
	let telemetry = config
		.telemetry_endpoints
		.clone()
355
356
357
358
359
360
361
362
363
364
365
366
367
368
		.filter(|x| !x.is_empty())
		.map(move |endpoints| -> Result<_, telemetry::Error> {
			let (worker, mut worker_handle) = if let Some(worker_handle) = telemetry_worker_handle {
				(None, worker_handle)
			} else {
				let worker = TelemetryWorker::new(16)?;
				let worker_handle = worker.handle();
				(Some(worker), worker_handle)
			};
			let telemetry = worker_handle.new_telemetry(endpoints);
			Ok((worker, telemetry))
		})
		.transpose()?;

369
	let (client, backend, keystore_container, task_manager) =
370
371
372
373
		service::new_full_parts::<Block, RuntimeApi, Executor>(
			&config,
			telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
		)?;
374
375
	let client = Arc::new(client);

Shawn Tabrizi's avatar
Shawn Tabrizi committed
376
377
378
379
380
381
	let telemetry = telemetry.map(|(worker, telemetry)| {
		if let Some(worker) = worker {
			task_manager.spawn_handle().spawn("telemetry", worker.run());
		}
		telemetry
	});
382

383
384
	jaeger_launch_collector_with_agent(task_manager.spawn_handle(), &*config, jaeger_agent)?;

385
	let select_chain = relay_chain_selection::SelectRelayChainWithFallback::new(
Andronik Ordian's avatar
Andronik Ordian committed
386
387
388
389
		backend.clone(),
		Handle::new_disconnected(),
		polkadot_node_subsystem_util::metrics::Metrics::register(config.prometheus_registry())?,
	);
390
391
392

	let transaction_pool = sc_transaction_pool::BasicPool::new_full(
		config.transaction_pool.clone(),
393
		config.role.is_authority().into(),
394
		config.prometheus_registry(),
395
		task_manager.spawn_essential_handle(),
396
397
398
399
400
401
402
403
404
		client.clone(),
	);

	let grandpa_hard_forks = if config.chain_spec.is_kusama() {
		grandpa_support::kusama_hard_forks()
	} else {
		Vec::new()
	};

Shawn Tabrizi's avatar
Shawn Tabrizi committed
405
406
407
408
409
410
411
	let (grandpa_block_import, grandpa_link) = grandpa::block_import_with_authority_set_hard_forks(
		client.clone(),
		&(client.clone() as Arc<_>),
		select_chain.clone(),
		grandpa_hard_forks,
		telemetry.as_ref().map(|x| x.handle()),
	)?;
412
413
414

	let justification_import = grandpa_block_import.clone();

415
	let babe_config = babe::Config::get_or_compute(&*client)?;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
416
417
	let (block_import, babe_link) =
		babe::block_import(babe_config.clone(), grandpa_block_import, client.clone())?;
418

419
	let slot_duration = babe_link.config().slot_duration();
420
421
422
423
424
425
	let import_queue = babe::import_queue(
		babe_link.clone(),
		block_import.clone(),
		Some(Box::new(justification_import)),
		client.clone(),
		select_chain.clone(),
426
427
428
429
430
431
432
433
434
435
436
		move |_, ()| async move {
			let timestamp = sp_timestamp::InherentDataProvider::from_system_time();

			let slot =
				sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
					*timestamp,
					slot_duration,
				);

			Ok((timestamp, slot))
		},
437
		&task_manager.spawn_essential_handle(),
438
		config.prometheus_registry(),
Wei Tang's avatar
Wei Tang committed
439
		consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone()),
440
		telemetry.as_ref().map(|x| x.handle()),
441
442
	)?;

443
444
445
	let (beefy_link, beefy_commitment_stream) =
		beefy_gadget::notification::BeefySignedCommitmentStream::channel();

446
	let justification_stream = grandpa_link.justification_stream();
447
448
	let shared_authority_set = grandpa_link.shared_authority_set().clone();
	let shared_voter_state = grandpa::SharedVoterState::empty();
449
450
451
452
	let finality_proof_provider = GrandpaFinalityProofProvider::new_for_service(
		backend.clone(),
		Some(shared_authority_set.clone()),
	);
453

454
	let import_setup = (block_import.clone(), grandpa_link, babe_link.clone(), beefy_link);
455
	let rpc_setup = shared_voter_state.clone();
456
457

	let shared_epoch_changes = babe_link.epoch_changes().clone();
458
	let slot_duration = babe_config.slot_duration();
459
460
461

	let rpc_extensions_builder = {
		let client = client.clone();
462
		let keystore = keystore_container.sync_keystore();
463
464
		let transaction_pool = transaction_pool.clone();
		let select_chain = select_chain.clone();
465
		let chain_spec = config.chain_spec.cloned_box();
466

Shawn Tabrizi's avatar
Shawn Tabrizi committed
467
468
		move |deny_unsafe,
		      subscription_executor: polkadot_rpc::SubscriptionTaskExecutor|
469
		      -> Result<polkadot_rpc::RpcExtension, service::Error> {
470
471
472
473
			let deps = polkadot_rpc::FullDeps {
				client: client.clone(),
				pool: transaction_pool.clone(),
				select_chain: select_chain.clone(),
474
				chain_spec: chain_spec.cloned_box(),
475
476
477
478
479
480
481
482
483
				deny_unsafe,
				babe: polkadot_rpc::BabeDeps {
					babe_config: babe_config.clone(),
					shared_epoch_changes: shared_epoch_changes.clone(),
					keystore: keystore.clone(),
				},
				grandpa: polkadot_rpc::GrandpaDeps {
					shared_voter_state: shared_voter_state.clone(),
					shared_authority_set: shared_authority_set.clone(),
484
					justification_stream: justification_stream.clone(),
485
					subscription_executor: subscription_executor.clone(),
Jon Häggblad's avatar
Jon Häggblad committed
486
					finality_provider: finality_proof_provider.clone(),
487
				},
488
489
490
491
				beefy: polkadot_rpc::BeefyDeps {
					beefy_commitment_stream: beefy_commitment_stream.clone(),
					subscription_executor,
				},
492
493
			};

494
			polkadot_rpc::create_full(deps).map_err(Into::into)
495
		}
496
497
	};

498
	Ok(service::PartialComponents {
499
500
501
502
503
504
505
		client,
		backend,
		task_manager,
		keystore_container,
		select_chain,
		import_queue,
		transaction_pool,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
506
		other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, telemetry),
507
	})
508
509
}

510
#[cfg(feature = "full-node")]
511
512
513
pub struct NewFull<C> {
	pub task_manager: TaskManager,
	pub client: C,
Andronik Ordian's avatar
Andronik Ordian committed
514
	pub overseer_handle: Option<Handle>,
515
516
	pub network: Arc<sc_network::NetworkService<Block, <Block as BlockT>::Hash>>,
	pub rpc_handlers: RpcHandlers,
517
	pub backend: Arc<FullBackend>,
518
519
520
521
}

#[cfg(feature = "full-node")]
impl<C> NewFull<C> {
522
523
	/// Convert the client type using the given `func`.
	pub fn with_client<NC>(self, func: impl FnOnce(C) -> NC) -> NewFull<NC> {
524
525
526
		NewFull {
			client: func(self.client),
			task_manager: self.task_manager,
Andronik Ordian's avatar
Andronik Ordian committed
527
			overseer_handle: self.overseer_handle,
528
529
			network: self.network,
			rpc_handlers: self.rpc_handlers,
530
			backend: self.backend,
531
532
533
534
		}
	}
}

535
536
/// Is this node a collator?
#[cfg(feature = "full-node")]
537
#[derive(Clone)]
538
539
pub enum IsCollator {
	/// This node is a collator.
540
	Yes(CollatorPair),
541
542
543
544
	/// This node is not a collator.
	No,
}

545
546
547
548
549
550
551
552
553
554
555
#[cfg(feature = "full-node")]
impl std::fmt::Debug for IsCollator {
	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
		use sp_core::Pair;
		match self {
			IsCollator::Yes(pair) => write!(fmt, "Yes({})", pair.public()),
			IsCollator::No => write!(fmt, "No"),
		}
	}
}

556
557
558
559
#[cfg(feature = "full-node")]
impl IsCollator {
	/// Is this a collator?
	fn is_collator(&self) -> bool {
560
		matches!(self, Self::Yes(_))
561
562
563
	}
}

564
565
/// Returns the active leaves the overseer should start with.
#[cfg(feature = "full-node")]
566
async fn active_leaves<RuntimeApi, Executor>(
Andronik Ordian's avatar
Andronik Ordian committed
567
	select_chain: &impl SelectChain<Block>,
568
569
570
	client: &FullClient<RuntimeApi, Executor>,
) -> Result<Vec<BlockInfo>, Error>
where
Shawn Tabrizi's avatar
Shawn Tabrizi committed
571
572
573
	RuntimeApi:
		ConstructRuntimeApi<Block, FullClient<RuntimeApi, Executor>> + Send + Sync + 'static,
	RuntimeApi::RuntimeApi:
574
		RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
575
	Executor: NativeExecutionDispatch + 'static,
576
{
577
	let best_block = select_chain.best_chain().await?;
578
579
580

	let mut leaves = select_chain
		.leaves()
581
		.await
582
583
584
		.unwrap_or_default()
		.into_iter()
		.filter_map(|hash| {
585
			let number = HeaderBackend::number(client, hash).ok()??;
586
587
588
589
590
591
592
593
594
595

			// Only consider leaves that are in maximum an uncle of the best block.
			if number < best_block.number().saturating_sub(1) {
				return None
			} else if hash == best_block.hash() {
				return None
			};

			let parent_hash = client.header(&BlockId::Hash(hash)).ok()??.parent_hash;

Shawn Tabrizi's avatar
Shawn Tabrizi committed
596
			Some(BlockInfo { hash, parent_hash, number })
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
		})
		.collect::<Vec<_>>();

	// Sort by block number and get the maximum number of leaves
	leaves.sort_by_key(|b| b.number);

	leaves.push(BlockInfo {
		hash: best_block.hash(),
		parent_hash: *best_block.parent_hash(),
		number: *best_block.number(),
	});

	Ok(leaves.into_iter().rev().take(MAX_ACTIVE_LEAVES).collect())
}

612
613
614
615
616
/// Create a new full node of arbitrary runtime and executor.
///
/// This is an advanced feature and not recommended for general use. Generally, `build_full` is
/// a better choice.
#[cfg(feature = "full-node")]
617
pub fn new_full<RuntimeApi, Executor, OverseerGenerator>(
618
	mut config: Configuration,
619
	is_collator: IsCollator,
620
	grandpa_pause: Option<(u32, u32)>,
621
	disable_beefy: bool,
622
	jaeger_agent: Option<std::net::SocketAddr>,
623
	telemetry_worker_handle: Option<TelemetryWorkerHandle>,
624
	program_path: Option<std::path::PathBuf>,
625
	overseer_gen: OverseerGenerator,
626
) -> Result<NewFull<Arc<FullClient<RuntimeApi, Executor>>>, Error>
Shawn Tabrizi's avatar
Shawn Tabrizi committed
627
628
629
630
where
	RuntimeApi:
		ConstructRuntimeApi<Block, FullClient<RuntimeApi, Executor>> + Send + Sync + 'static,
	RuntimeApi::RuntimeApi:
631
		RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
632
633
	Executor: NativeExecutionDispatch + 'static,
	OverseerGenerator: OverseerGen,
634
635
636
{
	let role = config.role.clone();
	let force_authoring = config.force_authoring;
637
	let backoff_authoring_blocks = {
638
		let mut backoff = sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default();
639

640
		if config.chain_spec.is_rococo() || config.chain_spec.is_wococo() {
641
642
643
644
645
646
647
648
			// it's a testnet that's in flux, finality has stalled sometimes due
			// to operational issues and it's annoying to slow down block
			// production to 1 block per hour.
			backoff.max_interval = 10;
		}

		Some(backoff)
	};
649

650
651
652
	let disable_grandpa = config.disable_grandpa;
	let name = config.network.node_name.clone();

653
	let service::PartialComponents {
654
655
656
		client,
		backend,
		mut task_manager,
657
		keystore_container,
Andronik Ordian's avatar
Andronik Ordian committed
658
		mut select_chain,
659
660
		import_queue,
		transaction_pool,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
661
		other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, mut telemetry),
662
	} = new_partial::<RuntimeApi, Executor>(&mut config, jaeger_agent, telemetry_worker_handle)?;
663

664
665
	let prometheus_registry = config.prometheus_registry().cloned();

666
	let shared_voter_state = rpc_setup;
667
	let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht;
668

669
670
671
672
	// Note: GrandPa is pushed before the Polkadot-specific protocols. This doesn't change
	// anything in terms of behaviour, but makes the logs more consistent with the other
	// Substrate nodes.
	config.network.extra_sets.push(grandpa::grandpa_peers_set_config());
673

674
	if config.chain_spec.is_rococo() || config.chain_spec.is_wococo() {
675
676
677
		config.network.extra_sets.push(beefy_gadget::beefy_peers_set_config());
	}

678
679
	{
		use polkadot_network_bridge::{peer_sets_info, IsAuthority};
Shawn Tabrizi's avatar
Shawn Tabrizi committed
680
		let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No };
681
682
		config.network.extra_sets.extend(peer_sets_info(is_authority));
	}
683

684
	let request_multiplexer = {
685
		let (multiplexer, configs) = RequestMultiplexer::new();
686
		config.network.request_response_protocols.extend(configs);
687
		multiplexer
688
	};
689

690
	let warp_sync = Arc::new(grandpa::warp_proof::NetworkProvider::new(
Shawn Tabrizi's avatar
Shawn Tabrizi committed
691
692
		backend.clone(),
		import_setup.1.shared_authority_set().clone(),
693
694
	));

695
	let (network, system_rpc_tx, network_starter) =
696
697
698
699
700
701
702
703
		service::build_network(service::BuildNetworkParams {
			config: &config,
			client: client.clone(),
			transaction_pool: transaction_pool.clone(),
			spawn_handle: task_manager.spawn_handle(),
			import_queue,
			on_demand: None,
			block_announce_validator_builder: None,
704
			warp_sync: Some(warp_sync),
705
706
707
		})?;

	if config.offchain_worker.enabled {
708
		let _ = service::build_offchain_workers(
Shawn Tabrizi's avatar
Shawn Tabrizi committed
709
710
711
712
			&config,
			task_manager.spawn_handle(),
			client.clone(),
			network.clone(),
713
714
		);
	}
715

716
717
718
719
720
721
722
723
724
	let parachains_db = crate::parachains_db::open_creating(
		config.database.path().ok_or(Error::DatabasePathRequired)?.into(),
		crate::parachains_db::CacheSizes::default(),
	)?;

	let availability_config = AvailabilityConfig {
		col_data: crate::parachains_db::REAL_COLUMNS.col_availability_data,
		col_meta: crate::parachains_db::REAL_COLUMNS.col_availability_meta,
	};
725

726
	let approval_voting_config = ApprovalVotingConfig {
727
		col_data: crate::parachains_db::REAL_COLUMNS.col_approval_data,
728
		slot_duration_millis: slot_duration.as_millis() as u64,
729
730
	};

731
	let candidate_validation_config = CandidateValidationConfig {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
732
733
		artifacts_cache_path: config
			.database
734
735
736
737
738
739
740
741
742
			.path()
			.ok_or(Error::DatabasePathRequired)?
			.join("pvf-artifacts"),
		program_path: match program_path {
			None => std::env::current_exe()?,
			Some(p) => p,
		},
	};

Andronik Ordian's avatar
Andronik Ordian committed
743
744
745
746
747
748
749
750
751
	let chain_selection_config = ChainSelectionConfig {
		col_data: crate::parachains_db::REAL_COLUMNS.col_chain_selection_data,
		stagnant_check_interval: chain_selection_subsystem::StagnantCheckInterval::never(),
	};

	let dispute_coordinator_config = DisputeCoordinatorConfig {
		col_data: crate::parachains_db::REAL_COLUMNS.col_dispute_coordinator_data,
	};

752
	let chain_spec = config.chain_spec.cloned_box();
753
	let rpc_handlers = service::spawn_tasks(service::SpawnTasksParams {
754
755
756
		config,
		backend: backend.clone(),
		client: client.clone(),
757
		keystore: keystore_container.sync_keystore(),
758
759
760
761
762
763
		network: network.clone(),
		rpc_extensions_builder: Box::new(rpc_extensions_builder),
		transaction_pool: transaction_pool.clone(),
		task_manager: &mut task_manager,
		on_demand: None,
		remote_blockchain: None,
764
		system_rpc_tx,
765
		telemetry: telemetry.as_mut(),
766
	})?;
767

768
	let (block_import, link_half, babe_link, beefy_link) = import_setup;
769
770
771

	let overseer_client = client.clone();
	let spawner = task_manager.spawn_handle();
Shawn Tabrizi's avatar
Shawn Tabrizi committed
772
	let active_leaves = futures::executor::block_on(active_leaves(&select_chain, &*client))?;
773

774
775
	let authority_discovery_service = if role.is_authority() || is_collator.is_collator() {
		use futures::StreamExt;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
776
		use sc_network::Event;
777

778
		let authority_discovery_role = if role.is_authority() {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
779
			sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore())
780
781
		} else {
			// don't publish our addresses when we're only a collator
782
			sc_authority_discovery::Role::Discover
783
		};
Shawn Tabrizi's avatar
Shawn Tabrizi committed
784
785
786
787
788
789
790
		let dht_event_stream =
			network.event_stream("authority-discovery").filter_map(|e| async move {
				match e {
					Event::Dht(e) => Some(e),
					_ => None,
				}
			});
791
792
793
794
795
		let (worker, service) = sc_authority_discovery::new_worker_and_service_with_config(
			sc_authority_discovery::WorkerConfig {
				publish_non_global_ips: auth_disc_publish_non_global_ips,
				..Default::default()
			},
796
797
798
799
800
801
			client.clone(),
			network.clone(),
			Box::pin(dht_event_stream),
			authority_discovery_role,
			prometheus_registry.clone(),
		);
802

803
804
805
806
807
808
		task_manager.spawn_handle().spawn("authority-discovery-worker", worker.run());
		Some(service)
	} else {
		None
	};

809
810
811
812
813
	let local_keystore = keystore_container.local_keystore();
	if local_keystore.is_none() {
		tracing::info!("Cannot run as validator without local keystore.");
	}

Shawn Tabrizi's avatar
Shawn Tabrizi committed
814
815
	let maybe_params =
		local_keystore.and_then(move |k| authority_discovery_service.map(|a| (a, k)));
816

Andronik Ordian's avatar
Andronik Ordian committed
817
	let overseer_handle = if let Some((authority_discovery_service, keystore)) = maybe_params {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
		let (overseer, overseer_handle) = overseer_gen
			.generate::<service::SpawnTaskHandle, FullClient<RuntimeApi, Executor>>(
				OverseerGenArgs {
					leaves: active_leaves,
					keystore,
					runtime_client: overseer_client.clone(),
					parachains_db,
					network_service: network.clone(),
					authority_discovery_service,
					request_multiplexer,
					registry: prometheus_registry.as_ref(),
					spawner,
					is_collator,
					approval_voting_config,
					availability_config,
					candidate_validation_config,
					chain_selection_config,
					dispute_coordinator_config,
				},
			)?;
Andronik Ordian's avatar
Andronik Ordian committed
838
839
		let handle = Handle::Connected(overseer_handle.clone());
		let handle_clone = handle.clone();
840

Shawn Tabrizi's avatar
Shawn Tabrizi committed
841
842
843
844
		task_manager.spawn_essential_handle().spawn_blocking(
			"overseer",
			Box::pin(async move {
				use futures::{pin_mut, select, FutureExt};
845

Shawn Tabrizi's avatar
Shawn Tabrizi committed
846
				let forward = polkadot_overseer::forward_events(overseer_client, handle_clone);
847

Shawn Tabrizi's avatar
Shawn Tabrizi committed
848
849
				let forward = forward.fuse();
				let overseer_fut = overseer.run().fuse();
850

Shawn Tabrizi's avatar
Shawn Tabrizi committed
851
852
				pin_mut!(overseer_fut);
				pin_mut!(forward);
853

Shawn Tabrizi's avatar
Shawn Tabrizi committed
854
855
856
857
858
859
860
				select! {
					_ = forward => (),
					_ = overseer_fut => (),
					complete => (),
				}
			}),
		);
Andronik Ordian's avatar
Andronik Ordian committed
861
862
		// we should remove this check before we deploy parachains on polkadot
		// TODO: https://github.com/paritytech/polkadot/issues/3326
Shawn Tabrizi's avatar
Shawn Tabrizi committed
863
864
865
866
		let should_connect_overseer = chain_spec.is_kusama() ||
			chain_spec.is_westend() ||
			chain_spec.is_rococo() ||
			chain_spec.is_wococo();
867

Andronik Ordian's avatar
Andronik Ordian committed
868
869
870
871
872
873
		if should_connect_overseer {
			select_chain.connect_to_overseer(overseer_handle.clone());
		} else {
			tracing::info!("Overseer is running in the disconnected state");
		}
		Some(handle)
874
875
876
	} else {
		None
	};
877
878
879
880
881

	if role.is_authority() {
		let can_author_with =
			consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone());

882
		let proposer = sc_basic_authorship::ProposerFactory::new(
883
			task_manager.spawn_handle(),
884
885
			client.clone(),
			transaction_pool,
886
			prometheus_registry.as_ref(),
887
			telemetry.as_ref().map(|x| x.handle()),
888
889
		);

890
		let client_clone = client.clone();
Shawn Tabrizi's avatar
Shawn Tabrizi committed
891
892
		let overseer_handle =
			overseer_handle.as_ref().ok_or(Error::AuthoritiesRequireRealOverseer)?.clone();
893
		let slot_duration = babe_link.config().slot_duration();
894
		let babe_config = babe::BabeParams {
895
			keystore: keystore_container.sync_keystore(),
896
897
898
899
900
			client: client.clone(),
			select_chain,
			block_import,
			env: proposer,
			sync_oracle: network.clone(),
901
			justification_sync_link: network.clone(),
902
903
			create_inherent_data_providers: move |parent, ()| {
				let client_clone = client_clone.clone();
Andronik Ordian's avatar
Andronik Ordian committed
904
				let overseer_handle = overseer_handle.clone();
905
906
907
				async move {
					let parachain = polkadot_node_core_parachains_inherent::ParachainsInherentDataProvider::create(
						&*client_clone,
Andronik Ordian's avatar
Andronik Ordian committed
908
						overseer_handle,
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
						parent,
					).await.map_err(|e| Box::new(e))?;

					let uncles = sc_consensus_uncles::create_uncles_inherent_data_provider(
						&*client_clone,
						parent,
					)?;

					let timestamp = sp_timestamp::InherentDataProvider::from_system_time();

					let slot =
						sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
							*timestamp,
							slot_duration,
						);

					Ok((timestamp, slot, uncles, parachain))
				}
			},
928
			force_authoring,
929
			backoff_authoring_blocks,
930
931
			babe_link,
			can_author_with,
932
			block_proposal_slot_portion: babe::SlotProportion::new(2f32 / 3f32),
933
			max_block_proposal_slot_portion: None,
934
			telemetry: telemetry.as_ref().map(|x| x.handle()),
935
		};
936

937
938
939
		let babe = babe::start_babe(babe_config)?;
		task_manager.spawn_essential_handle().spawn_blocking("babe", babe);
	}
940

Andreas Doerr's avatar
Andreas Doerr committed
941
942
	// if the node isn't actively participating in consensus then it doesn't
	// need a keystore, regardless of which protocol we use below.
Shawn Tabrizi's avatar
Shawn Tabrizi committed
943
944
	let keystore_opt =
		if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
Andreas Doerr's avatar
Andreas Doerr committed
945

946
	// We currently only run the BEEFY gadget on the Rococo and Wococo testnets.
947
	if !disable_beefy && (chain_spec.is_rococo() || chain_spec.is_wococo()) {
Andreas Doerr's avatar
Andreas Doerr committed
948
949
950
951
952
953
954
955
956
		let beefy_params = beefy_gadget::BeefyParams {
			client: client.clone(),
			backend: backend.clone(),
			key_store: keystore_opt.clone(),
			network: network.clone(),
			signed_commitment_sender: beefy_link,
			min_block_delta: if chain_spec.is_wococo() { 4 } else { 8 },
			prometheus_registry: prometheus_registry.clone(),
		};
957

Shawn Tabrizi's avatar
Shawn Tabrizi committed
958
		let gadget = beefy_gadget::start_beefy_gadget::<_, _, _, _>(beefy_params);
959

960
961
962
963
964
965
966
		// Wococo's purpose is to be a testbed for BEEFY, so if it fails we'll
		// bring the node down with it to make sure it is noticed.
		if chain_spec.is_wococo() {
			task_manager.spawn_essential_handle().spawn_blocking("beefy-gadget", gadget);
		} else {
			task_manager.spawn_handle().spawn_blocking("beefy-gadget", gadget);
		}
967
968
	}

969
970
971
972
973
974
	let config = grandpa::Config {
		// FIXME substrate#1578 make this available through chainspec
		gossip_duration: Duration::from_millis(1000),
		justification_period: 512,
		name: Some(name),
		observer_enabled: false,
975
		keystore: keystore_opt,
976
		local_role: role,
977
		telemetry: telemetry.as_ref().map(|x| x.handle()),
978
	};
979

980
981
982
983
984
985
986
987
988
989
990
991
	let enable_grandpa = !disable_grandpa;
	if enable_grandpa {
		// start the full GRANDPA voter
		// NOTE: unlike in substrate we are currently running the full
		// GRANDPA voter protocol for all full nodes (regardless of whether
		// they're validators or not). at this point the full voter should
		// provide better guarantees of block and vote data availability than
		// the observer.

		// add a custom voting rule to temporarily stop voting for new blocks
		// after the given pause block is finalized and restarting after the
		// given delay.
992
993
		let builder = grandpa::VotingRulesBuilder::default();

994
995
		let voting_rule = match grandpa_pause {
			Some((block, delay)) => {
996
997
998
999
				info!(
					block_number = %block,
					delay = %delay,
					"GRANDPA scheduled voting pause set for block #{} with a duration of {} blocks.",
1000
					block,
For faster browsing, not all history is shown. View entire blame