Newer
Older
let handle = Handle::new(overseer_handle.clone());
{
let handle = handle.clone();
task_manager.spawn_essential_handle().spawn_blocking(
"overseer",
Box::pin(async move {
use futures::{pin_mut, select, FutureExt};
let forward = polkadot_overseer::forward_events(overseer_client, handle);
let forward = forward.fuse();
let overseer_fut = overseer.run().fuse();
pin_mut!(overseer_fut);
pin_mut!(forward);
select! {
() = forward => (),
() = overseer_fut => (),
complete => (),
}
}),
);
!auth_or_collator,
"Precondition congruence (false) is guaranteed by manual checking. qed"
);
if role.is_authority() {
let proposer = sc_basic_authorship::ProposerFactory::new(
transaction_pool.clone(),
prometheus_registry.as_ref(),
telemetry.as_ref().map(|x| x.handle()),
let client_clone = client.clone();
let overseer_handle =
overseer_handle.as_ref().ok_or(Error::AuthoritiesRequireRealOverseer)?.clone();
let slot_duration = babe_link.config().slot_duration();
let babe_config = babe::BabeParams {
keystore: keystore_container.keystore(),
client: client.clone(),
select_chain,
block_import,
env: proposer,
sync_oracle: sync_service.clone(),
justification_sync_link: sync_service.clone(),
create_inherent_data_providers: move |parent, ()| {
let client_clone = client_clone.clone();
let parachain =
polkadot_node_core_parachains_inherent::ParachainsInherentDataProvider::new(
client_clone,
overseer_handle,
parent,
);
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot =
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
*timestamp,
slot_duration,
);
Ok((slot, timestamp, parachain))
block_proposal_slot_portion: babe::SlotProportion::new(2f32 / 3f32),
max_block_proposal_slot_portion: None,
telemetry: telemetry.as_ref().map(|x| x.handle()),
let babe = babe::start_babe(babe_config)?;
task_manager.spawn_essential_handle().spawn_blocking("babe", None, babe);
// if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below.
let keystore_opt = if role.is_authority() { Some(keystore_container.keystore()) } else { None };
if enable_beefy {
Adrian Catangiu
committed
let justifications_protocol_name = beefy_on_demand_justifications_handler.protocol_name();
let network_params = beefy::BeefyNetworkParams {
Adrian Catangiu
committed
network: network.clone(),
sync: sync_service.clone(),
Adrian Catangiu
committed
gossip_protocol_name: beefy_gossip_proto_name,
justifications_protocol_name,
_phantom: core::marker::PhantomData::<Block>,
};
Adrian Catangiu
committed
let payload_provider = beefy_primitives::mmr::MmrRootProvider::new(client.clone());
let beefy_params = beefy::BeefyParams {
client: client.clone(),
backend: backend.clone(),
Adrian Catangiu
committed
payload_provider,
Adrian Catangiu
committed
runtime: client.clone(),
Adrian Catangiu
committed
network_params,
min_block_delta: if chain_spec.is_wococo() { 4 } else { 8 },
prometheus_registry: prometheus_registry.clone(),
links: beefy_links,
Adrian Catangiu
committed
on_demand_justifications_handler: beefy_on_demand_justifications_handler,
let gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params);
// BEEFY currently only runs on testnets, if it fails we'll
// bring the node down with it to make sure it is noticed.
task_manager
.spawn_essential_handle()
.spawn_blocking("beefy-gadget", None, gadget);
if is_offchain_indexing_enabled {
task_manager.spawn_handle().spawn_blocking(
"mmr-gadget",
None,
MmrGadget::start(
client.clone(),
backend.clone(),
sp_mmr_primitives::INDEXING_PREFIX.to_vec(),
),
);
}
let config = grandpa::Config {
// FIXME substrate#1578 make this available through chainspec
// Grandpa performance can be improved a bit by tuning this parameter, see:
// https://github.com/paritytech/polkadot/issues/5464
gossip_duration: Duration::from_millis(1000),
justification_generation_period: GRANDPA_JUSTIFICATION_PERIOD,
name: Some(name),
observer_enabled: false,
keystore: keystore_opt,
telemetry: telemetry.as_ref().map(|x| x.handle()),
protocol_name: grandpa_protocol_name,
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.
let mut builder = grandpa::VotingRulesBuilder::default();
#[cfg(not(feature = "malus"))]
let _malus_finality_delay = None;
if let Some(delay) = _malus_finality_delay {
info!(?delay, "Enabling malus finality delay",);
builder = builder.add(grandpa::BeforeBestBlockBy(delay));
};
let voting_rule = match grandpa_pause {
Some((block, delay)) => {
info!(
block_number = %block,
delay = %delay,
"GRANDPA scheduled voting pause set for block #{} with a duration of {} blocks.",
block,
delay,
);
builder.add(grandpa_support::PauseAfterBlockFor(block, delay)).build()
},
None => builder.build(),
let grandpa_config = grandpa::GrandpaParams {
config,
link: link_half,
network: network.clone(),
sync: sync_service.clone(),
prometheus_registry: prometheus_registry.clone(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool.clone()),
task_manager.spawn_essential_handle().spawn_blocking(
"grandpa-voter",
None,
grandpa::run_grandpa_voter(grandpa_config)?,
);
network_starter.start_network();
Ok(NewFull {
task_manager,
client,
overseer_handle,
network,
sync_service,
rpc_handlers,
backend,
})
#[cfg(feature = "full-node")]
macro_rules! chain_ops {
($config:expr, $jaeger_agent:expr, $telemetry_worker_handle:expr) => {{
let telemetry_worker_handle = $telemetry_worker_handle;
let jaeger_agent = $jaeger_agent;
let mut config = $config;
let basics = new_partial_basics(config, jaeger_agent, telemetry_worker_handle)?;
use ::sc_consensus::LongestChain;
// use the longest chain selection, since there is no overseer available
let chain_selection = LongestChain::new(basics.backend.clone());
let service::PartialComponents { client, backend, import_queue, task_manager, .. } =
new_partial::<LongestChain<_, Block>>(&mut config, basics, chain_selection)?;
Ok((client, backend, import_queue, task_manager))
}};
}
/// Builds a new object suitable for chain operations.
#[cfg(feature = "full-node")]
jaeger_agent: Option<std::net::SocketAddr>,
) -> Result<
Arc<FullClient>,
sc_consensus::BasicQueue<Block, PrefixedMemoryDB<BlakeTwo256>>,
config.keystore = service::config::KeystoreConfig::InMemory;
if config.chain_spec.is_rococo() ||
config.chain_spec.is_wococo() ||
config.chain_spec.is_versi()
{
chain_ops!(config, jaeger_agent, None)
} else if config.chain_spec.is_kusama() {
chain_ops!(config, jaeger_agent, None)
} else if config.chain_spec.is_westend() {
return chain_ops!(config, jaeger_agent, None)
} else {
chain_ops!(config, jaeger_agent, None)
/// Build a full node.
///
/// The actual "flavor", aka if it will use `Polkadot`, `Rococo` or `Kusama` is determined based on
/// [`IdentifyVariant`] using the chain spec.
///
/// `overseer_enable_anyways` always enables the overseer, based on the provided `OverseerGenerator`,
/// regardless of the role the node has. The relay chain selection (longest or disputes-aware) is
/// still determined based on the role of the node. Likewise for authority discovery.
is_collator: IsCollator,
jaeger_agent: Option<std::net::SocketAddr>,
telemetry_worker_handle: Option<TelemetryWorkerHandle>,
overseer_enable_anyways: bool,
overseer_gen: impl OverseerGen,
overseer_message_channel_override: Option<usize>,
malus_finality_delay: Option<u32>,
hwbench: Option<sc_sysinfo::HwBench>,
) -> Result<NewFull, Error> {
let is_polkadot = config.chain_spec.is_polkadot();
new_full(
config,
is_collator,
grandpa_pause,
enable_beefy,
jaeger_agent,
telemetry_worker_handle,
None,
overseer_enable_anyways,
overseer_gen,
overseer_message_channel_override.map(move |capacity| {
if is_polkadot {
gum::warn!("Channel capacity should _never_ be tampered with on polkadot!");
}
capacity
}),
malus_finality_delay,
hwbench,
)
/// Reverts the node state down to at most the last finalized block.
///
/// In particular this reverts:
/// - `ApprovalVotingSubsystem` data in the parachains-db;
/// - `ChainSelectionSubsystem` data in the parachains-db;
/// - Low level Babe and Grandpa consensus data.
#[cfg(feature = "full-node")]
pub fn revert_backend(
client: Arc<FullClient>,
backend: Arc<FullBackend>,
blocks: BlockNumber,
config: Configuration,
) -> Result<(), Error> {
let best_number = client.info().best_number;
let finalized = client.info().finalized_number;
let revertible = blocks.min(best_number - finalized);
if revertible == 0 {
return Ok(())
}
let number = best_number - revertible;
let hash = client.block_hash_from_id(&BlockId::Number(number))?.ok_or(
sp_blockchain::Error::Backend(format!(
"Unexpected hash lookup failure for block number: {}",
number
)),
)?;
let parachains_db = open_database(&config.database)
.map_err(|err| sp_blockchain::Error::Backend(err.to_string()))?;
revert_approval_voting(parachains_db.clone(), hash)?;
revert_chain_selection(parachains_db, hash)?;
// Revert Substrate consensus related components
babe::revert(client.clone(), backend, blocks)?;
grandpa::revert(client, blocks)?;
Ok(())
}
fn revert_chain_selection(db: Arc<dyn Database>, hash: Hash) -> sp_blockchain::Result<()> {
let config = chain_selection_subsystem::Config {
col_data: parachains_db::REAL_COLUMNS.col_chain_selection_data,
stagnant_check_interval: chain_selection_subsystem::StagnantCheckInterval::never(),
stagnant_check_mode: chain_selection_subsystem::StagnantCheckMode::PruneOnly,
let chain_selection = chain_selection_subsystem::ChainSelectionSubsystem::new(config, db);
.revert_to(hash)
.map_err(|err| sp_blockchain::Error::Backend(err.to_string()))
}
fn revert_approval_voting(db: Arc<dyn Database>, hash: Hash) -> sp_blockchain::Result<()> {
let config = approval_voting_subsystem::Config {
col_approval_data: parachains_db::REAL_COLUMNS.col_approval_data,
slot_duration_millis: Default::default(),
};
let approval_voting = approval_voting_subsystem::ApprovalVotingSubsystem::with_config(
config,
db,
Arc::new(sc_keystore::LocalKeystore::in_memory()),
Box::new(consensus_common::NoNetwork),
approval_voting_subsystem::Metrics::default(),
);
approval_voting
.revert_to(hash)
.map_err(|err| sp_blockchain::Error::Backend(err.to_string()))
}