Skip to main content

commonware_consensus/simplex/
config.rs

1use super::{
2    elector::Config as Elector,
3    types::{Activity, Context},
4};
5use crate::{
6    types::{Epoch, ViewDelta},
7    CertifiableAutomaton, Relay, Reporter,
8};
9use commonware_cryptography::{certificate::Scheme, Digest};
10use commonware_p2p::Blocker;
11use commonware_parallel::Strategy;
12use commonware_runtime::buffer::paged::CacheRef;
13use std::{num::NonZeroUsize, time::Duration};
14
15/// Controls whether and how the engine proactively forwards certified blocks
16/// when entering the next view.
17///
18/// Forwarding is a best-effort liveness aid: when enabled, the batcher
19/// broadcasts only after we locally certify a proposal and enter the next
20/// view, avoiding sends for proposals that never pass certification.
21#[derive(Debug, Clone, Copy)]
22pub enum ForwardingPolicy {
23    /// Do nothing when a certified proposal becomes eligible for forwarding.
24    Disabled,
25    /// Forward the block to all participants that did not vote for the proposal.
26    ///
27    /// To only send to the leader of the newly entered view, see [ForwardingPolicy::SilentLeader].
28    SilentVoters,
29    /// Forward the block to the leader of the newly entered view if they did not
30    /// vote for the proposal.
31    ///
32    /// To forward to all participants that did not vote for the proposal, see [ForwardingPolicy::SilentVoters].
33    SilentLeader,
34}
35
36impl ForwardingPolicy {
37    /// Returns true if the policy is enabled.
38    pub const fn is_enabled(&self) -> bool {
39        !matches!(self, Self::Disabled)
40    }
41}
42
43/// Configuration for the consensus engine.
44pub struct Config<S, L, B, D, A, R, F, T>
45where
46    S: Scheme,
47    L: Elector<S>,
48    B: Blocker<PublicKey = S::PublicKey>,
49    D: Digest,
50    A: CertifiableAutomaton<Context = Context<D, S::PublicKey>>,
51    R: Relay,
52    F: Reporter<Activity = Activity<S, D>>,
53    T: Strategy,
54{
55    /// Signing scheme for the consensus engine.
56    ///
57    /// Consensus messages can be signed with a cryptosystem that differs from the static
58    /// participant identity keys exposed in `participants`. For example, we can authenticate peers
59    /// on the network with [commonware_cryptography::ed25519] keys while signing votes with shares distributed
60    /// via [commonware_cryptography::bls12381::dkg] (which change each epoch). The scheme implementation is
61    /// responsible for reusing the exact participant ordering carried by `participants` so that signer indices
62    /// remain stable across both key spaces; if the order diverges, validators will reject votes as coming from
63    /// the wrong validator.
64    pub scheme: S,
65
66    /// Leader election configuration.
67    ///
68    /// Determines how leaders are selected for each view. Built-in options include
69    /// [`RoundRobin`](super::elector::RoundRobin) for deterministic rotation and
70    /// [`Random`](super::elector::Random) for unpredictable selection using BLS
71    /// threshold signatures.
72    pub elector: L,
73
74    /// Blocker for the network.
75    ///
76    /// Blocking is handled by [commonware_p2p].
77    pub blocker: B,
78
79    /// Automaton for the consensus engine.
80    pub automaton: A,
81
82    /// Relay for the consensus engine.
83    pub relay: R,
84
85    /// Reporter for the consensus engine.
86    ///
87    /// All activity is exported for downstream applications that benefit from total observability,
88    /// consider wrapping with [`crate::simplex::scheme::reporter::AttributableReporter`] to
89    /// automatically filter and verify activities based on scheme attributability.
90    pub reporter: F,
91
92    /// Strategy for parallel operations.
93    pub strategy: T,
94
95    /// Partition for the consensus engine.
96    pub partition: String,
97
98    /// Maximum number of messages to buffer on channels inside the consensus
99    /// engine before blocking.
100    pub mailbox_size: usize,
101
102    /// Epoch for the consensus engine. Each running engine should have a unique epoch.
103    pub epoch: Epoch,
104
105    /// Number of bytes to buffer when replaying during startup.
106    pub replay_buffer: NonZeroUsize,
107
108    /// The size of the write buffer to use for each blob in the journal.
109    pub write_buffer: NonZeroUsize,
110
111    /// Page cache for the journal.
112    pub page_cache: CacheRef,
113
114    /// Amount of time to wait for a leader to propose a payload
115    /// in a view.
116    pub leader_timeout: Duration,
117
118    /// Amount of time to wait for certification progress in a view
119    /// before attempting to skip the view.
120    pub certification_timeout: Duration,
121
122    /// Amount of time to wait before retrying a nullify broadcast if
123    /// stuck in a view.
124    pub timeout_retry: Duration,
125
126    /// Number of views behind finalized tip to track
127    /// and persist activity derived from validator messages.
128    pub activity_timeout: ViewDelta,
129
130    /// Move to nullify immediately if the selected leader has been inactive
131    /// for this many recent known views (we ignore views we don't have data for).
132    ///
133    /// This number should be less than or equal to `activity_timeout` (how
134    /// many views we are tracking below the finalized tip).
135    pub skip_timeout: ViewDelta,
136
137    /// Timeout to wait for a peer to respond to a request.
138    pub fetch_timeout: Duration,
139
140    /// Number of concurrent requests to make at once.
141    pub fetch_concurrent: usize,
142
143    /// Policy for proactively forwarding certified blocks when entering the
144    /// next view.
145    pub forwarding: ForwardingPolicy,
146}
147
148impl<
149        S: Scheme,
150        L: Elector<S>,
151        B: Blocker<PublicKey = S::PublicKey>,
152        D: Digest,
153        A: CertifiableAutomaton<Context = Context<D, S::PublicKey>>,
154        R: Relay,
155        F: Reporter<Activity = Activity<S, D>>,
156        T: Strategy,
157    > Config<S, L, B, D, A, R, F, T>
158{
159    /// Assert enforces that all configuration values are valid.
160    pub fn assert(&self) {
161        assert!(
162            !self.scheme.participants().is_empty(),
163            "there must be at least one participant"
164        );
165        assert!(
166            self.leader_timeout > Duration::default(),
167            "leader timeout must be greater than zero"
168        );
169        assert!(
170            self.certification_timeout > Duration::default(),
171            "certification timeout must be greater than zero"
172        );
173        assert!(
174            self.leader_timeout <= self.certification_timeout,
175            "leader timeout must be less than or equal to certification timeout"
176        );
177        assert!(
178            self.timeout_retry > Duration::default(),
179            "timeout retry broadcast must be greater than zero"
180        );
181        assert!(
182            !self.activity_timeout.is_zero(),
183            "activity timeout must be greater than zero"
184        );
185        assert!(
186            !self.skip_timeout.is_zero(),
187            "skip timeout must be greater than zero"
188        );
189        assert!(
190            self.skip_timeout <= self.activity_timeout,
191            "skip timeout must be less than or equal to activity timeout"
192        );
193        assert!(
194            self.fetch_timeout > Duration::default(),
195            "fetch timeout must be greater than zero"
196        );
197        assert!(
198            self.fetch_concurrent > 0,
199            "it must be possible to fetch from at least one peer at a time"
200        );
201    }
202}