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