soil_client/consensus/mod.rs
1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! Common utilities for building and using consensus engines in substrate.
8//!
9//! Much of this crate is _unstable_ and thus the API is likely to undergo
10//! change. Implementors of traits should not rely on the interfaces to remain
11//! the same.
12
13use std::{sync::Arc, time::Duration};
14
15use futures::prelude::*;
16use subsoil::api::ProofRecorder;
17use subsoil::externalities::Extensions;
18use subsoil::runtime::{
19 traits::{Block as BlockT, HashingFor},
20 Digest,
21};
22
23pub mod block_validation;
24pub mod error;
25mod select_chain;
26
27pub use self::error::Error;
28pub use select_chain::SelectChain;
29pub use subsoil::inherents::InherentData;
30pub use subsoil::state_machine::Backend as StateBackend;
31
32/// Block status.
33#[derive(Debug, PartialEq, Eq, Clone)]
34pub enum BlockStatus {
35 /// Added to the import queue.
36 Queued,
37 /// Already in the blockchain and the state is available.
38 InChainWithState,
39 /// In the blockchain, but the state is not available.
40 InChainPruned,
41 /// Block or parent is known to be bad.
42 KnownBad,
43 /// Not in the queue or the blockchain.
44 Unknown,
45}
46
47/// Block data origin.
48#[derive(Debug, PartialEq, Eq, Clone, Copy)]
49pub enum BlockOrigin {
50 /// Genesis block built into the client.
51 Genesis,
52 /// Block is part of the initial sync with the network.
53 NetworkInitialSync,
54 /// Block was broadcasted on the network.
55 NetworkBroadcast,
56 /// Block that was received from the network and validated in the consensus process.
57 ConsensusBroadcast,
58 /// Block that was collated by this node.
59 Own,
60 /// Block was imported from a file.
61 File,
62 /// Block from warp sync proof, already cryptographically verified.
63 ///
64 /// These blocks have been verified through the warp sync protocol's finality proofs
65 /// and are part of the finalized chain. As such, certain consensus verification steps
66 /// can be safely skipped during import. These are the blocks that are used to verify the era
67 /// changes and not the target block to which the node is warp syncing to.
68 WarpSync,
69 /// Block imported during gap sync to fill historical gaps.
70 ///
71 /// Gap sync occurs after warp sync completes, downloading blocks between genesis
72 /// and the warp sync target to fill in the historical chain.
73 GapSync,
74}
75
76/// Environment for a Consensus instance.
77///
78/// Creates proposer instance.
79pub trait Environment<B: BlockT> {
80 /// The proposer type this creates.
81 type Proposer: Proposer<B> + Send + 'static;
82 /// A future that resolves to the proposer.
83 type CreateProposer: Future<Output = Result<Self::Proposer, Self::Error>>
84 + Send
85 + Unpin
86 + 'static;
87 /// Error which can occur upon creation.
88 type Error: From<Error> + Send + Sync + std::error::Error + 'static;
89
90 /// Initialize the proposal logic on top of a specific header. Provide
91 /// the authorities at that header.
92 fn init(&mut self, parent_header: &B::Header) -> Self::CreateProposer;
93}
94
95/// A proposal that is created by a [`Proposer`].
96pub struct Proposal<Block: BlockT> {
97 /// The block that was build.
98 pub block: Block,
99 /// The storage changes while building this block.
100 pub storage_changes: subsoil::state_machine::StorageChanges<HashingFor<Block>>,
101}
102
103/// Arguments for [`Proposer::propose`].
104pub struct ProposeArgs<B: BlockT> {
105 /// The inherent data to pass to the block production.
106 pub inherent_data: InherentData,
107 /// The inherent digests to include in the produced block.
108 pub inherent_digests: Digest,
109 /// Max duration for building the block.
110 pub max_duration: Duration,
111 /// Optional size limit for the produced block.
112 ///
113 /// When set, block production ends before hitting this limit. The limit includes the storage
114 /// proof, when proof recording is activated.
115 pub block_size_limit: Option<usize>,
116 /// Optional proof recorder for recording storage proofs during block production.
117 ///
118 /// When `Some`, the recorder will be used on block production to record all storage accesses.
119 pub storage_proof_recorder: Option<ProofRecorder<B>>,
120 /// Extra extensions for the runtime environment.
121 pub extra_extensions: Extensions,
122}
123
124impl<B: BlockT> Default for ProposeArgs<B> {
125 fn default() -> Self {
126 Self {
127 inherent_data: Default::default(),
128 inherent_digests: Default::default(),
129 max_duration: Default::default(),
130 block_size_limit: Default::default(),
131 storage_proof_recorder: Default::default(),
132 extra_extensions: Default::default(),
133 }
134 }
135}
136
137/// Logic for a proposer.
138///
139/// This will encapsulate creation and evaluation of proposals at a specific
140/// block.
141///
142/// Proposers are generic over bits of "consensus data" which are engine-specific.
143pub trait Proposer<B: BlockT> {
144 /// Error type which can occur when proposing or evaluating.
145 type Error: From<Error> + Send + Sync + std::error::Error + 'static;
146 /// Future that resolves to a committed proposal with an optional proof.
147 type Proposal: Future<Output = Result<Proposal<B>, Self::Error>> + Send + Unpin + 'static;
148
149 /// Create a proposal.
150 ///
151 /// Takes a [`ProposeArgs`] struct containing all the necessary parameters for block production
152 /// including inherent data, digests, duration limits, storage proof recorder, and extensions.
153 ///
154 /// # Return
155 ///
156 /// Returns a future that resolves to a [`Proposal`] or to [`Error`].
157 fn propose(self, args: ProposeArgs<B>) -> Self::Proposal;
158}
159
160/// An oracle for when major synchronization work is being undertaken.
161///
162/// Generally, consensus authoring work isn't undertaken while well behind
163/// the head of the chain.
164pub trait SyncOracle {
165 /// Whether the synchronization service is undergoing major sync.
166 /// Returns true if so.
167 fn is_major_syncing(&self) -> bool;
168 /// Whether the synchronization service is offline.
169 /// Returns true if so.
170 fn is_offline(&self) -> bool;
171}
172
173/// A synchronization oracle for when there is no network.
174#[derive(Clone, Copy, Debug)]
175pub struct NoNetwork;
176
177impl SyncOracle for NoNetwork {
178 fn is_major_syncing(&self) -> bool {
179 false
180 }
181 fn is_offline(&self) -> bool {
182 false
183 }
184}
185
186impl<T> SyncOracle for Arc<T>
187where
188 T: ?Sized,
189 T: SyncOracle,
190{
191 fn is_major_syncing(&self) -> bool {
192 T::is_major_syncing(self)
193 }
194
195 fn is_offline(&self) -> bool {
196 T::is_offline(self)
197 }
198}