commonware_consensus/
lib.rs

1//! Order opaque messages in a Byzantine environment.
2//!
3//! # Status
4//!
5//! `commonware-consensus` is **ALPHA** software and is not yet recommended for production use. Developers should
6//! expect breaking changes and occasional instability.
7
8#![doc(
9    html_logo_url = "https://commonware.xyz/imgs/rustdoc_logo.svg",
10    html_favicon_url = "https://commonware.xyz/favicon.ico"
11)]
12
13use commonware_codec::Codec;
14use commonware_cryptography::{Committable, Digestible};
15
16pub mod aggregation;
17pub mod ordered_broadcast;
18pub mod simplex;
19pub mod types;
20
21use types::{Epoch, View};
22
23/// Epochable is a trait that provides access to the epoch number.
24/// Any consensus message or object that is associated with a specific epoch should implement this.
25pub trait Epochable {
26    /// Returns the epoch associated with this object.
27    fn epoch(&self) -> Epoch;
28}
29
30/// Viewable is a trait that provides access to the view (round) number.
31/// Any consensus message or object that is associated with a specific view should implement this.
32pub trait Viewable {
33    /// Returns the view associated with this object.
34    fn view(&self) -> View;
35}
36
37/// Block is the interface for a block in the blockchain.
38///
39/// Blocks are used to track the progress of the consensus engine.
40pub trait Block: Codec + Digestible + Committable + Send + Sync + 'static {
41    /// Get the height of the block.
42    fn height(&self) -> u64;
43
44    /// Get the parent block's digest.
45    fn parent(&self) -> Self::Commitment;
46}
47
48cfg_if::cfg_if! {
49    if #[cfg(not(target_arch = "wasm32"))] {
50        use commonware_cryptography::Digest;
51        use futures::channel::{oneshot, mpsc};
52        use std::future::Future;
53        use commonware_runtime::{Spawner, Metrics, Clock};
54        use rand::Rng;
55        use crate::marshal::ingress::mailbox::AncestorStream;
56        use commonware_cryptography::certificate::Scheme;
57
58        pub mod application;
59        pub mod marshal;
60        mod reporter;
61        pub use reporter::*;
62
63        /// Histogram buckets for measuring consensus latency.
64        const LATENCY: [f64; 36] = [
65            0.05, 0.1, 0.125, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35,
66            0.36, 0.37, 0.38, 0.39, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
67        ];
68
69        /// Automaton is the interface responsible for driving the consensus forward by proposing new payloads
70        /// and verifying payloads proposed by other participants.
71        pub trait Automaton: Clone + Send + 'static {
72            /// Context is metadata provided by the consensus engine associated with a given payload.
73            ///
74            /// This often includes things like the proposer, view number, the height, or the epoch.
75            type Context;
76
77            /// Hash of an arbitrary payload.
78            type Digest: Digest;
79
80            /// Payload used to initialize the consensus engine.
81            fn genesis(&mut self, epoch: Epoch) -> impl Future<Output = Self::Digest> + Send;
82
83            /// Generate a new payload for the given context.
84            ///
85            /// If it is possible to generate a payload, the Digest should be returned over the provided
86            /// channel. If it is not possible to generate a payload, the channel can be dropped. If construction
87            /// takes too long, the consensus engine may drop the provided proposal.
88            fn propose(
89                &mut self,
90                context: Self::Context,
91            ) -> impl Future<Output = oneshot::Receiver<Self::Digest>> + Send;
92
93            /// Verify the payload is valid.
94            ///
95            /// If it is possible to verify the payload, a boolean should be returned indicating whether
96            /// the payload is valid. If it is not possible to verify the payload, the channel can be dropped.
97            fn verify(
98                &mut self,
99                context: Self::Context,
100                payload: Self::Digest,
101            ) -> impl Future<Output = oneshot::Receiver<bool>> + Send;
102        }
103
104        /// CertifiableAutomaton extends [Automaton] with the ability to certify payloads before finalization.
105        ///
106        /// This trait is required by consensus implementations (like Simplex) that support a certification
107        /// phase between notarization and finalization. Applications that do not need custom certification
108        /// logic can use the default implementation which always certifies.
109        pub trait CertifiableAutomaton: Automaton {
110            /// Determine whether a verified payload is safe to commit.
111            ///
112            /// If context is required during certify, it must be included in the
113            /// data associated with the payload.
114            ///
115            /// Applications that employ erasure coding can override this method to delay or prevent
116            /// finalization until they have reconstructed and validated the full block (e.g. after
117            /// receiving enough shards).
118            fn certify(
119                &mut self,
120                _payload: Self::Digest,
121            ) -> impl Future<Output = oneshot::Receiver<bool>> + Send {
122                #[allow(clippy::async_yields_async)]
123                async move {
124                    let (sender, receiver) = oneshot::channel();
125                    let _ = sender.send(true);
126                    receiver
127                }
128            }
129        }
130
131        /// Application is a minimal interface for standard implementations that operate over a stream
132        /// of epoched blocks.
133        pub trait Application<E>: Clone + Send + 'static
134        where
135            E: Rng + Spawner + Metrics + Clock
136        {
137            /// The signing scheme used by the application.
138            type SigningScheme: Scheme;
139
140            /// Context is metadata provided by the consensus engine associated with a given payload.
141            ///
142            /// This often includes things like the proposer, view number, the height, or the epoch.
143            type Context: Epochable;
144
145            /// The block type produced by the application's builder.
146            type Block: Block;
147
148            /// Payload used to initialize the consensus engine in the first epoch.
149            fn genesis(&mut self) -> impl Future<Output = Self::Block> + Send;
150
151            /// Build a new block on top of the provided parent ancestry. If the build job fails,
152            /// the implementor should return [None].
153            fn propose(
154                &mut self,
155                context: (E, Self::Context),
156                ancestry: AncestorStream<Self::SigningScheme, Self::Block>,
157            ) -> impl Future<Output = Option<Self::Block>> + Send;
158        }
159
160        /// An extension of [Application] that provides the ability to implementations to verify blocks.
161        ///
162        /// Some [Application]s may not require this functionality. When employing
163        /// erasure coding, for example, verification only serves to verify the integrity of the
164        /// received shard relative to the consensus commitment, and can therefore be
165        /// hidden from the application.
166        pub trait VerifyingApplication<E>: Application<E>
167        where
168            E: Rng + Spawner + Metrics + Clock
169        {
170            /// Verify a block produced by the application's proposer, relative to its ancestry.
171            fn verify(
172                &mut self,
173                context: (E, Self::Context),
174                ancestry: AncestorStream<Self::SigningScheme, Self::Block>,
175            ) -> impl Future<Output = bool> + Send;
176        }
177
178        /// Relay is the interface responsible for broadcasting payloads to the network.
179        ///
180        /// The consensus engine is only aware of a payload's digest, not its contents. It is up
181        /// to the relay to efficiently broadcast the full payload to other participants.
182        pub trait Relay: Clone + Send + 'static {
183            /// Hash of an arbitrary payload.
184            type Digest: Digest;
185
186            /// Called once consensus begins working towards a proposal provided by `Automaton` (i.e.
187            /// it isn't dropped).
188            ///
189            /// Other participants may not begin voting on a proposal until they have the full contents,
190            /// so timely delivery often yields better performance.
191            fn broadcast(&mut self, payload: Self::Digest) -> impl Future<Output = ()> + Send;
192        }
193
194        /// Reporter is the interface responsible for reporting activity to some external actor.
195        pub trait Reporter: Clone + Send + 'static {
196            /// Activity is specified by the underlying consensus implementation and can be interpreted if desired.
197            ///
198            /// Examples of activity would be "vote", "finalize", or "fault". Various consensus implementations may
199            /// want to reward (or penalize) participation in different ways and in different places. For example,
200            /// validators could be required to send multiple types of messages (i.e. vote and finalize) and rewarding
201            /// both equally may better align incentives with desired behavior.
202            type Activity;
203
204            /// Report some activity observed by the consensus implementation.
205            fn report(&mut self, activity: Self::Activity) -> impl Future<Output = ()> + Send;
206        }
207
208        /// Monitor is the interface an external actor can use to observe the progress of a consensus implementation.
209        ///
210        /// Monitor is used to implement mechanisms that share the same set of active participants as consensus and/or
211        /// perform some activity that requires some synchronization with the progress of consensus.
212        ///
213        /// Monitor can be implemented using [crate::Reporter] to avoid introducing complexity
214        /// into any particular consensus implementation.
215        pub trait Monitor: Clone + Send + 'static {
216            /// Index is the type used to indicate the in-progress consensus decision.
217            type Index;
218
219            /// Create a channel that will receive updates when the latest index (also provided) changes.
220            fn subscribe(&mut self) -> impl Future<Output = (Self::Index, mpsc::Receiver<Self::Index>)> + Send;
221        }
222    }
223}