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
8use bytes::Bytes;
9use commonware_cryptography::Digest;
10use commonware_utils::Array;
11
12pub mod simplex;
13pub mod threshold_simplex;
14
15/// Activity is specified by the underlying consensus implementation and can be interpreted if desired.
16///
17/// Examples of activity would be "vote", "finalize", or "fault". Various consensus implementations may
18/// want to reward (or penalize) participation in different ways and in different places. For example,
19/// validators could be required to send multiple types of messages (i.e. vote and finalize) and rewarding
20/// both equally may better align incentives with desired behavior.
21pub type Activity = u8;
22
23/// Proof is a blob that attests to some data.
24pub type Proof = Bytes;
25
26cfg_if::cfg_if! {
27    if #[cfg(not(target_arch = "wasm32"))] {
28        use futures::channel::oneshot;
29        use std::future::Future;
30
31        /// Histogram buckets for measuring consensus latency.
32        const LATENCY: [f64; 20] = [
33            0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8,
34            0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 3.0,
35        ];
36
37        /// Parsed is a wrapper around a message that has a parsable digest.
38        #[derive(Clone)]
39        struct Parsed<Message, Digest> {
40            /// Raw message that has some field that can be parsed into a digest.
41            pub message: Message,
42
43            /// Parsed digest.
44            pub digest: Digest,
45        }
46
47        /// Automaton is the interface responsible for driving the consensus forward by proposing new payloads
48        /// and verifying payloads proposed by other participants.
49        pub trait Automaton: Clone + Send + 'static {
50            /// Context is metadata provided by the consensus engine associated with a given payload.
51            ///
52            /// This often includes things like the proposer, view number, the height, or the epoch.
53            type Context;
54
55            /// Hash of an arbitrary payload.
56            type Digest: Digest;
57
58            /// Payload used to initialize the consensus engine.
59            fn genesis(&mut self) -> impl Future<Output = Self::Digest> + Send;
60
61            /// Generate a new payload for the given context.
62            ///
63            /// If it is possible to generate a payload, the Digest should be returned over the provided
64            /// channel. If it is not possible to generate a payload, the channel can be dropped. If construction
65            /// takes too long, the consensus engine may drop the provided proposal.
66            fn propose(
67                &mut self,
68                context: Self::Context,
69            ) -> impl Future<Output = oneshot::Receiver<Self::Digest>> + Send;
70
71            /// Verify the payload is valid.
72            ///
73            /// If it is possible to verify the payload, a boolean should be returned indicating whether
74            /// the payload is valid. If it is not possible to verify the payload, the channel can be dropped.
75            fn verify(
76                &mut self,
77                context: Self::Context,
78                payload: Self::Digest,
79            ) -> impl Future<Output = oneshot::Receiver<bool>> + Send;
80        }
81
82        /// Relay is the interface responsible for broadcasting payloads to the network.
83        ///
84        /// The consensus engine is only aware of a payload's digest, not its contents. It is up
85        /// to the relay to efficiently broadcast the full payload to other participants.
86        pub trait Relay: Clone + Send + 'static {
87            /// Hash of an arbitrary payload.
88            type Digest: Digest;
89
90            /// Called once consensus begins working towards a proposal provided by `Automaton` (i.e.
91            /// it isn't dropped).
92            ///
93            /// Other participants may not begin voting on a proposal until they have the full contents,
94            /// so timely delivery often yields better performance.
95            fn broadcast(&mut self, payload: Self::Digest) -> impl Future<Output = ()> + Send;
96        }
97
98        /// Committer is the interface responsible for handling notifications of payload status.
99        pub trait Committer: Clone + Send + 'static {
100            /// Hash of an arbitrary payload.
101            type Digest: Digest;
102
103            /// Event that a payload has made some progress towards finalization but is not yet finalized.
104            ///
105            /// This is often used to provide an early ("best guess") confirmation to users.
106            fn prepared(&mut self, proof: Proof, payload: Self::Digest) -> impl Future<Output = ()> + Send;
107
108            /// Event indicating the container has been finalized.
109            fn finalized(&mut self, proof: Proof, payload: Self::Digest) -> impl Future<Output = ()> + Send;
110        }
111
112        /// Supervisor is the interface responsible for managing which participants are active at a given time.
113        ///
114        /// ## Synchronization
115        ///
116        /// It is up to the user to ensure changes in this list are synchronized across nodes in the network
117        /// at a given `Index`. If care is not taken to do this, consensus could halt (as different participants
118        /// may have a different view of who is active at a given time).
119        ///
120        /// The simplest way to avoid this complexity is to use a consensus implementation that reaches finalization
121        /// on application data before transitioning to a new `Index` (i.e. [Tendermint](https://arxiv.org/abs/1807.04938)).
122        ///
123        /// Implementations that do not work this way (like `simplex`) must introduce some synchrony bound for changes
124        /// (where it is assumed all participants have finalized some previous set change by some point) or "sync points"
125        /// (i.e. epochs) where participants agree that some finalization occurred at some point in the past.
126        pub trait Supervisor: Clone + Send + Sync + 'static {
127            /// Index is the type used to indicate the in-progress consensus decision.
128            type Index;
129
130            /// Public key used to identify participants.
131            type PublicKey: Array;
132
133            /// Return the leader at a given index for the provided seed.
134            fn leader(&self, index: Self::Index) -> Option<Self::PublicKey>;
135
136            /// Get the **sorted** participants for the given view. This is called when entering a new view before
137            /// listening for proposals or votes. If nothing is returned, the view will not be entered.
138            fn participants(&self, index: Self::Index) -> Option<&Vec<Self::PublicKey>>;
139
140            // Indicate whether some candidate is a participant at the given view.
141            fn is_participant(&self, index: Self::Index, candidate: &Self::PublicKey) -> Option<u32>;
142
143            /// Report some activity observed by the consensus implementation.
144            fn report(&self, activity: Activity, proof: Proof) -> impl Future<Output = ()> + Send;
145        }
146
147        /// ThresholdSupervisor is the interface responsible for managing which `identity` (typically a group polynomial with
148        /// a fixed constant factor) and `share` for a participant is active at a given time.
149        ///
150        /// ## Synchronization
151        ///
152        /// The same considerations for `Supervisor` apply here.
153        pub trait ThresholdSupervisor: Supervisor {
154            /// Seed is some random value used to bias the leader selection process.
155            type Seed;
156
157            /// Identity is the type against which partial signatures are verified.
158            type Identity;
159
160            /// Share is the type used to generate a partial signature that can be verified
161            /// against `Identity`.
162            type Share;
163
164            /// Return the leader at a given index over the provided seed.
165            fn leader(&self, index: Self::Index, seed: Self::Seed) -> Option<Self::PublicKey>;
166
167            /// Returns the identity (typically a group polynomial with a fixed constant factor)
168            /// at the given index. This is used to verify partial signatures from participants
169            /// enumerated in `Supervisor::participants`.
170            fn identity(&self, index: Self::Index) -> Option<&Self::Identity>;
171
172            /// Returns share to sign with at a given index. After resharing, the share
173            /// may change (and old shares may be deleted).
174            fn share(&self, index: Self::Index) -> Option<&Self::Share>;
175        }
176    }
177}