// This file is part of Substrate. // Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Common utilities for building and using consensus engines in substrate. //! //! Much of this crate is _unstable_ and thus the API is likely to undergo //! change. Implementors of traits should not rely on the interfaces to remain //! the same. // This provides "unused" building blocks to other crates #![allow(dead_code)] // our error-chain could potentially blow up otherwise #![recursion_limit="128"] #[macro_use] extern crate log; use std::sync::Arc; use std::time::Duration; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, DigestFor, NumberFor, HashFor}, }; use futures::prelude::*; pub use sp_inherents::InherentData; pub mod block_validation; pub mod offline_tracker; pub mod error; pub mod block_import; mod select_chain; pub mod import_queue; pub mod evaluation; mod metrics; pub use self::error::Error; pub use block_import::{ BlockImport, BlockOrigin, ForkChoiceStrategy, ImportedAux, BlockImportParams, BlockCheckParams, ImportResult, JustificationImport, }; pub use select_chain::SelectChain; pub use sp_state_machine::Backend as StateBackend; pub use import_queue::DefaultImportQueue; /// Block status. #[derive(Debug, PartialEq, Eq)] pub enum BlockStatus { /// Added to the import queue. Queued, /// Already in the blockchain and the state is available. InChainWithState, /// In the blockchain, but the state is not available. InChainPruned, /// Block or parent is known to be bad. KnownBad, /// Not in the queue or the blockchain. Unknown, } /// Environment for a Consensus instance. /// /// Creates proposer instance. pub trait Environment { /// The proposer type this creates. type Proposer: Proposer + Send + 'static; /// A future that resolves to the proposer. type CreateProposer: Future> + Send + Unpin + 'static; /// Error which can occur upon creation. type Error: From + std::fmt::Debug + 'static; /// Initialize the proposal logic on top of a specific header. Provide /// the authorities at that header. fn init(&mut self, parent_header: &B::Header) -> Self::CreateProposer; } /// A proposal that is created by a [`Proposer`]. pub struct Proposal { /// The block that was build. pub block: Block, /// Optional proof that was recorded while building the block. pub proof: Option, /// The storage changes while building this block. pub storage_changes: sp_state_machine::StorageChanges, NumberFor>, } /// Used as parameter to [`Proposer`] to tell the requirement on recording a proof. /// /// When `RecordProof::Yes` is given, all accessed trie nodes should be saved. These recorded /// trie nodes can be used by a third party to proof this proposal without having access to the /// full storage. #[derive(Copy, Clone, PartialEq)] pub enum RecordProof { /// `Yes`, record a proof. Yes, /// `No`, don't record any proof. No, } impl RecordProof { /// Returns if `Self` == `Yes`. pub fn yes(&self) -> bool { match self { Self::Yes => true, Self::No => false, } } } /// Will return [`RecordProof::No`] as default value. impl Default for RecordProof { fn default() -> Self { Self::No } } impl From for RecordProof { fn from(val: bool) -> Self { if val { Self::Yes } else { Self::No } } } /// Logic for a proposer. /// /// This will encapsulate creation and evaluation of proposals at a specific /// block. /// /// Proposers are generic over bits of "consensus data" which are engine-specific. pub trait Proposer { /// Error type which can occur when proposing or evaluating. type Error: From + std::fmt::Debug + 'static; /// The transaction type used by the backend. type Transaction: Default + Send + 'static; /// Future that resolves to a committed proposal with an optional proof. type Proposal: Future, Self::Error>> + Send + Unpin + 'static; /// Create a proposal. /// /// Gets the `inherent_data` and `inherent_digests` as input for the proposal. Additionally /// a maximum duration for building this proposal is given. If building the proposal takes /// longer than this maximum, the proposal will be very likely discarded. /// /// # Return /// /// Returns a future that resolves to a [`Proposal`] or to [`Error`]. fn propose( self, inherent_data: InherentData, inherent_digests: DigestFor, max_duration: Duration, record_proof: RecordProof, ) -> Self::Proposal; } /// An oracle for when major synchronization work is being undertaken. /// /// Generally, consensus authoring work isn't undertaken while well behind /// the head of the chain. pub trait SyncOracle { /// Whether the synchronization service is undergoing major sync. /// Returns true if so. fn is_major_syncing(&mut self) -> bool; /// Whether the synchronization service is offline. /// Returns true if so. fn is_offline(&mut self) -> bool; } /// A synchronization oracle for when there is no network. #[derive(Clone, Copy, Debug)] pub struct NoNetwork; impl SyncOracle for NoNetwork { fn is_major_syncing(&mut self) -> bool { false } fn is_offline(&mut self) -> bool { false } } impl SyncOracle for Arc where T: ?Sized, for<'r> &'r T: SyncOracle { fn is_major_syncing(&mut self) -> bool { <&T>::is_major_syncing(&mut &**self) } fn is_offline(&mut self) -> bool { <&T>::is_offline(&mut &**self) } } /// Checks if the current active native block authoring implementation can author with the runtime /// at the given block. pub trait CanAuthorWith { /// See trait docs for more information. /// /// # Return /// /// - Returns `Ok(())` when authoring is supported. /// - Returns `Err(_)` when authoring is not supported. fn can_author_with(&self, at: &BlockId) -> Result<(), String>; } /// Checks if the node can author blocks by using /// [`NativeVersion::can_author_with`](sp_version::NativeVersion::can_author_with). #[derive(Clone)] pub struct CanAuthorWithNativeVersion(T); impl CanAuthorWithNativeVersion { /// Creates a new instance of `Self`. pub fn new(inner: T) -> Self { Self(inner) } } impl, Block: BlockT> CanAuthorWith for CanAuthorWithNativeVersion { fn can_author_with(&self, at: &BlockId) -> Result<(), String> { match self.0.runtime_version(at) { Ok(version) => self.0.native_version().can_author_with(&version), Err(e) => { Err(format!( "Failed to get runtime version at `{}` and will disable authoring. Error: {}", at, e, )) } } } } /// Returns always `true` for `can_author_with`. This is useful for tests. #[derive(Clone)] pub struct AlwaysCanAuthor; impl CanAuthorWith for AlwaysCanAuthor { fn can_author_with(&self, _: &BlockId) -> Result<(), String> { Ok(()) } } /// Never can author. #[derive(Clone)] pub struct NeverCanAuthor; impl CanAuthorWith for NeverCanAuthor { fn can_author_with(&self, _: &BlockId) -> Result<(), String> { Err("Authoring is always disabled.".to_string()) } } /// A type from which a slot duration can be obtained. pub trait SlotData { /// Gets the slot duration. fn slot_duration(&self) -> u64; /// The static slot key const SLOT_KEY: &'static [u8]; } impl SlotData for u64 { fn slot_duration(&self) -> u64 { *self } const SLOT_KEY: &'static [u8] = b"aura_slot_duration"; }