// Copyright 2019-2021 Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus 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. // Cumulus 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 . use polkadot_primitives::v2::{Hash as PHash, PersistedValidationData}; use sc_consensus::BlockImport; use sp_runtime::traits::Block as BlockT; mod parachain_consensus; #[cfg(test)] mod tests; pub use parachain_consensus::run_parachain_consensus; /// The result of [`ParachainConsensus::produce_candidate`]. pub struct ParachainCandidate { /// The block that was built for this candidate. pub block: B, /// The proof that was recorded while building the block. pub proof: sp_trie::StorageProof, } /// A specific parachain consensus implementation that can be used by a collator to produce candidates. /// /// The collator will call [`Self::produce_candidate`] every time there is a free core for the parachain /// this collator is collating for. It is the job of the consensus implementation to decide if this /// specific collator should build a candidate for the given relay chain block. The consensus /// implementation could, for example, check whether this specific collator is part of a staked set. #[async_trait::async_trait] pub trait ParachainConsensus: Send + Sync + dyn_clone::DynClone { /// Produce a new candidate at the given parent block and relay-parent blocks. /// /// Should return `None` if the consensus implementation decided that it shouldn't build a /// candidate or if there occurred any error. /// /// # NOTE /// /// It is expected that the block is already imported when the future resolves. async fn produce_candidate( &mut self, parent: &B::Header, relay_parent: PHash, validation_data: &PersistedValidationData, ) -> Option>; } dyn_clone::clone_trait_object!( ParachainConsensus where B: BlockT); #[async_trait::async_trait] impl ParachainConsensus for Box + Send + Sync> { async fn produce_candidate( &mut self, parent: &B::Header, relay_parent: PHash, validation_data: &PersistedValidationData, ) -> Option> { (*self).produce_candidate(parent, relay_parent, validation_data).await } } /// Parachain specific block import. /// /// This is used to set `block_import_params.fork_choice` to `false` as long as the block origin is /// not `NetworkInitialSync`. The best block for parachains is determined by the relay chain. Meaning /// we will update the best block, as it is included by the relay-chain. pub struct ParachainBlockImport(I); impl ParachainBlockImport { /// Create a new instance. pub fn new(inner: I) -> Self { Self(inner) } } impl Clone for ParachainBlockImport { fn clone(&self) -> Self { ParachainBlockImport(self.0.clone()) } } #[async_trait::async_trait] impl BlockImport for ParachainBlockImport where Block: BlockT, I: BlockImport + Send, { type Error = I::Error; type Transaction = I::Transaction; async fn check_block( &mut self, block: sc_consensus::BlockCheckParams, ) -> Result { self.0.check_block(block).await } async fn import_block( &mut self, mut block_import_params: sc_consensus::BlockImportParams, cache: std::collections::HashMap>, ) -> Result { // Best block is determined by the relay chain, or if we are doing the initial sync // we import all blocks as new best. block_import_params.fork_choice = Some(sc_consensus::ForkChoiceStrategy::Custom( block_import_params.origin == sp_consensus::BlockOrigin::NetworkInitialSync, )); self.0.import_block(block_import_params, cache).await } }