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}