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