// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Substrate 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.
// Substrate 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 Cumulus. If not, see .
//! Cumulus Collator implementation for Substrate.
use cumulus_client_network::WaitToAnnounce;
use cumulus_primitives_core::{
relay_chain::Hash as PHash, CollationInfo, CollectCollationInfo, ParachainBlockData,
PersistedValidationData,
};
use sc_client_api::BlockBackend;
use sp_api::{ApiExt, ProvideRuntimeApi};
use sp_consensus::BlockStatus;
use sp_core::traits::SpawnNamed;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, HashFor, Header as HeaderT, Zero},
};
use cumulus_client_consensus_common::ParachainConsensus;
use polkadot_node_primitives::{
BlockData, Collation, CollationGenerationConfig, CollationResult, MaybeCompressedPoV, PoV,
};
use polkadot_node_subsystem::messages::{CollationGenerationMessage, CollatorProtocolMessage};
use polkadot_overseer::Handle as OverseerHandle;
use polkadot_primitives::v2::{CollatorPair, Id as ParaId};
use codec::{Decode, Encode};
use futures::{channel::oneshot, FutureExt};
use parking_lot::Mutex;
use std::sync::Arc;
use tracing::Instrument;
/// The logging target.
const LOG_TARGET: &str = "cumulus-collator";
/// The implementation of the Cumulus `Collator`.
pub struct Collator {
block_status: Arc,
parachain_consensus: Box>,
wait_to_announce: Arc>>,
runtime_api: Arc,
}
impl Clone for Collator {
fn clone(&self) -> Self {
Self {
block_status: self.block_status.clone(),
wait_to_announce: self.wait_to_announce.clone(),
parachain_consensus: self.parachain_consensus.clone(),
runtime_api: self.runtime_api.clone(),
}
}
}
impl Collator
where
Block: BlockT,
BS: BlockBackend,
RA: ProvideRuntimeApi,
RA::Api: CollectCollationInfo,
{
/// Create a new instance.
fn new(
block_status: Arc,
spawner: Arc,
announce_block: Arc>) + Send + Sync>,
runtime_api: Arc,
parachain_consensus: Box>,
) -> Self {
let wait_to_announce = Arc::new(Mutex::new(WaitToAnnounce::new(spawner, announce_block)));
Self { block_status, wait_to_announce, runtime_api, parachain_consensus }
}
/// Checks the status of the given block hash in the Parachain.
///
/// Returns `true` if the block could be found and is good to be build on.
fn check_block_status(&self, hash: Block::Hash, header: &Block::Header) -> bool {
match self.block_status.block_status(&BlockId::Hash(hash)) {
Ok(BlockStatus::Queued) => {
tracing::debug!(
target: LOG_TARGET,
block_hash = ?hash,
"Skipping candidate production, because block is still queued for import.",
);
false
},
Ok(BlockStatus::InChainWithState) => true,
Ok(BlockStatus::InChainPruned) => {
tracing::error!(
target: LOG_TARGET,
"Skipping candidate production, because block `{:?}` is already pruned!",
hash,
);
false
},
Ok(BlockStatus::KnownBad) => {
tracing::error!(
target: LOG_TARGET,
block_hash = ?hash,
"Block is tagged as known bad and is included in the relay chain! Skipping candidate production!",
);
false
},
Ok(BlockStatus::Unknown) => {
if header.number().is_zero() {
tracing::error!(
target: LOG_TARGET,
block_hash = ?hash,
"Could not find the header of the genesis block in the database!",
);
} else {
tracing::debug!(
target: LOG_TARGET,
block_hash = ?hash,
"Skipping candidate production, because block is unknown.",
);
}
false
},
Err(e) => {
tracing::error!(
target: LOG_TARGET,
block_hash = ?hash,
error = ?e,
"Failed to get block status.",
);
false
},
}
}
/// Fetch the collation info from the runtime.
///
/// Returns `Ok(Some(_))` on success, `Err(_)` on error or `Ok(None)` if the runtime api isn't implemented by the runtime.
fn fetch_collation_info(
&self,
block_hash: Block::Hash,
header: &Block::Header,
) -> Result