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