consensus_config/
parameters.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{path::PathBuf, time::Duration};
5
6use mysten_network::Multiaddr;
7use serde::{Deserialize, Serialize};
8
9use crate::NetworkPublicKey;
10
11/// Operational configurations of a consensus authority.
12///
13/// All fields should tolerate inconsistencies among authorities, without affecting safety of the
14/// protocol. Otherwise, they need to be part of Sui protocol config or epoch state on-chain.
15///
16/// NOTE: fields with default values are specified in the serde default functions. Most operators
17/// should not need to specify any field, except db_path.
18#[derive(Clone, Debug, Deserialize, Serialize)]
19pub struct Parameters {
20    /// Path to consensus DB for this epoch. Required when initializing consensus.
21    /// This is calculated based on user configuration for base directory.
22    #[serde(skip)]
23    pub db_path: PathBuf,
24
25    /// Time to wait for parent round leader before sealing a block, from when parent round
26    /// has a quorum.
27    #[serde(default = "Parameters::default_leader_timeout")]
28    pub leader_timeout: Duration,
29
30    /// Minimum delay between rounds, to avoid generating too many rounds when latency is low.
31    /// This is especially necessary for tests running locally.
32    /// If setting a non-default value, it should be set low enough to avoid reducing
33    /// round rate and increasing latency in realistic and distributed configurations.
34    #[serde(default = "Parameters::default_min_round_delay")]
35    pub min_round_delay: Duration,
36
37    /// Maximum forward time drift (how far in future) allowed for received blocks.
38    #[serde(default = "Parameters::default_max_forward_time_drift")]
39    pub max_forward_time_drift: Duration,
40
41    /// Max number of blocks to fetch per block sync request.
42    /// Block sync requests have very short (~2s) timeouts.
43    /// So this value should be limited to allow the requests
44    /// to finish on hosts with good network with this timeout.
45    /// Usually a host sends 14-16 blocks per sec to a peer, so
46    /// sending 32 blocks in 2 seconds should be reasonable.
47    #[serde(default = "Parameters::default_max_blocks_per_sync")]
48    pub max_blocks_per_sync: usize,
49
50    /// Max number of blocks to fetch per commit sync request.
51    #[serde(default = "Parameters::default_max_blocks_per_fetch")]
52    pub max_blocks_per_fetch: usize,
53
54    /// Time to wait during node start up until the node has synced the last proposed block via the
55    /// network peers. When set to `0` the sync mechanism is disabled. This property is meant to be
56    /// used for amnesia recovery.
57    #[serde(default = "Parameters::default_sync_last_known_own_block_timeout")]
58    pub sync_last_known_own_block_timeout: Duration,
59
60    /// Interval in milliseconds to probe highest received rounds of peers.
61    #[serde(default = "Parameters::default_round_prober_interval_ms")]
62    pub round_prober_interval_ms: u64,
63
64    /// Timeout in milliseconds for a round prober request.
65    #[serde(default = "Parameters::default_round_prober_request_timeout_ms")]
66    pub round_prober_request_timeout_ms: u64,
67
68    /// Proposing new block is stopped when the propagation delay is greater than this threshold.
69    /// Propagation delay is the difference between the round of the last proposed block and the
70    /// the highest round from this authority that is received by all validators in a quorum.
71    #[serde(default = "Parameters::default_propagation_delay_stop_proposal_threshold")]
72    pub propagation_delay_stop_proposal_threshold: u32,
73
74    /// The number of rounds of blocks to be kept in the Dag state cache per authority. The larger
75    /// the number the more the blocks that will be kept in memory allowing minimising any potential
76    /// disk access.
77    /// Value should be at minimum 50 rounds to ensure node performance, but being too large can be
78    /// expensive in memory usage.
79    #[serde(default = "Parameters::default_dag_state_cached_rounds")]
80    pub dag_state_cached_rounds: u32,
81
82    // Number of authorities commit syncer fetches in parallel.
83    // Both commits in a range and blocks referenced by the commits are fetched per authority.
84    #[serde(default = "Parameters::default_commit_sync_parallel_fetches")]
85    pub commit_sync_parallel_fetches: usize,
86
87    // Number of commits to fetch in a batch, also the maximum number of commits returned per fetch.
88    // If this value is set too small, fetching becomes inefficient.
89    // If this value is set too large, it can result in load imbalance and stragglers.
90    #[serde(default = "Parameters::default_commit_sync_batch_size")]
91    pub commit_sync_batch_size: u32,
92
93    // This affects the maximum number of commit batches being fetched, and those fetched but not
94    // processed as consensus output, before throttling of outgoing commit fetches starts.
95    #[serde(default = "Parameters::default_commit_sync_batches_ahead")]
96    pub commit_sync_batches_ahead: usize,
97
98    // Base per-request timeout for commit sync fetches. The actual timeout grows progressively
99    // with a multiplier to allow larger commit batches to finish downloading.
100    #[serde(default = "Parameters::default_commit_sync_request_timeout")]
101    pub commit_sync_request_timeout: Duration,
102
103    // Timeout for the connectivity probe against a peer before committing to a full fetch.
104    // Should be short to quickly skip unreachable peers.
105    #[serde(default = "Parameters::default_commit_sync_probe_timeout")]
106    pub commit_sync_probe_timeout: Duration,
107
108    /// Whether to use FIFO compaction for RocksDB.
109    #[serde(default = "Parameters::default_use_fifo_compaction")]
110    pub use_fifo_compaction: bool,
111
112    /// Tonic network settings.
113    #[serde(default = "TonicParameters::default")]
114    pub tonic: TonicParameters,
115
116    /// Observer node settings.
117    #[serde(default = "ObserverParameters::default")]
118    pub observer: ObserverParameters,
119
120    /// Internal consensus parameters.
121    #[serde(default = "InternalParameters::default")]
122    pub internal: InternalParameters,
123
124    /// Override for the address to listen on. When set, this is used instead of
125    /// deriving from the committee address.
126    #[serde(skip)]
127    pub listen_address_override: Option<Multiaddr>,
128}
129
130impl Parameters {
131    pub(crate) fn default_leader_timeout() -> Duration {
132        Duration::from_millis(200)
133    }
134
135    pub(crate) fn default_min_round_delay() -> Duration {
136        if cfg!(msim) || std::env::var("__TEST_ONLY_CONSENSUS_USE_LONG_MIN_ROUND_DELAY").is_ok() {
137            // Checkpoint building and execution cannot keep up with high commit rate in simtests,
138            // leading to long reconfiguration delays. This is because simtest is single threaded,
139            // and spending too much time in consensus can lead to starvation elsewhere.
140            Duration::from_millis(400)
141        } else if cfg!(test) {
142            // Avoid excessive CPU, data and logs in tests.
143            Duration::from_millis(250)
144        } else {
145            Duration::from_millis(50)
146        }
147    }
148
149    pub(crate) fn default_max_forward_time_drift() -> Duration {
150        Duration::from_millis(500)
151    }
152
153    pub(crate) fn default_max_blocks_per_sync() -> usize {
154        if cfg!(msim) {
155            // Exercise hitting blocks per sync limit.
156            4
157        } else {
158            32
159        }
160    }
161
162    pub(crate) fn default_max_blocks_per_fetch() -> usize {
163        if cfg!(msim) {
164            // Exercise hitting blocks per fetch limit.
165            10
166        } else {
167            1000
168        }
169    }
170
171    pub(crate) fn default_sync_last_known_own_block_timeout() -> Duration {
172        if cfg!(msim) {
173            Duration::from_millis(500)
174        } else {
175            // Here we prioritise liveness over the complete de-risking of block equivocation. 5 seconds
176            // in the majority of cases should be good enough for this given a healthy network.
177            Duration::from_secs(5)
178        }
179    }
180
181    pub(crate) fn default_round_prober_interval_ms() -> u64 {
182        if cfg!(msim) { 1000 } else { 5000 }
183    }
184
185    pub(crate) fn default_round_prober_request_timeout_ms() -> u64 {
186        if cfg!(msim) { 800 } else { 4000 }
187    }
188
189    pub(crate) fn default_propagation_delay_stop_proposal_threshold() -> u32 {
190        // Propagation delay is usually 0 round in production.
191        if cfg!(msim) { 2 } else { 5 }
192    }
193
194    pub(crate) fn default_dag_state_cached_rounds() -> u32 {
195        if cfg!(msim) {
196            // Exercise reading blocks from store.
197            5
198        } else {
199            500
200        }
201    }
202
203    pub(crate) fn default_commit_sync_parallel_fetches() -> usize {
204        8
205    }
206
207    pub(crate) fn default_commit_sync_batch_size() -> u32 {
208        if cfg!(msim) {
209            // Exercise commit sync.
210            5
211        } else {
212            100
213        }
214    }
215
216    pub(crate) fn default_commit_sync_request_timeout() -> Duration {
217        Duration::from_secs(10)
218    }
219
220    pub(crate) fn default_commit_sync_probe_timeout() -> Duration {
221        Duration::from_secs(2)
222    }
223
224    pub(crate) fn default_commit_sync_batches_ahead() -> usize {
225        // This is set to be a multiple of default commit_sync_parallel_fetches to allow fetching ahead,
226        // while keeping the total number of inflight fetches and unprocessed fetched commits limited.
227        32
228    }
229
230    pub(crate) fn default_use_fifo_compaction() -> bool {
231        true
232    }
233}
234
235impl Default for Parameters {
236    fn default() -> Self {
237        Self {
238            db_path: PathBuf::default(),
239            leader_timeout: Parameters::default_leader_timeout(),
240            min_round_delay: Parameters::default_min_round_delay(),
241            max_forward_time_drift: Parameters::default_max_forward_time_drift(),
242            max_blocks_per_sync: Parameters::default_max_blocks_per_sync(),
243            max_blocks_per_fetch: Parameters::default_max_blocks_per_fetch(),
244            sync_last_known_own_block_timeout:
245                Parameters::default_sync_last_known_own_block_timeout(),
246            round_prober_interval_ms: Parameters::default_round_prober_interval_ms(),
247            round_prober_request_timeout_ms: Parameters::default_round_prober_request_timeout_ms(),
248            propagation_delay_stop_proposal_threshold:
249                Parameters::default_propagation_delay_stop_proposal_threshold(),
250            dag_state_cached_rounds: Parameters::default_dag_state_cached_rounds(),
251            commit_sync_parallel_fetches: Parameters::default_commit_sync_parallel_fetches(),
252            commit_sync_batch_size: Parameters::default_commit_sync_batch_size(),
253            commit_sync_batches_ahead: Parameters::default_commit_sync_batches_ahead(),
254            commit_sync_request_timeout: Parameters::default_commit_sync_request_timeout(),
255            commit_sync_probe_timeout: Parameters::default_commit_sync_probe_timeout(),
256            use_fifo_compaction: Parameters::default_use_fifo_compaction(),
257            tonic: TonicParameters::default(),
258            observer: ObserverParameters::default(),
259            internal: InternalParameters::default(),
260            listen_address_override: None,
261        }
262    }
263}
264
265/// Represents a peer observer node with its network key and address.
266#[derive(Clone, Debug, Deserialize, Serialize)]
267pub struct PeerRecord {
268    /// Network public key of the peer observer node (hex-encoded).
269    #[serde(
270        serialize_with = "serialize_public_key_as_hex",
271        deserialize_with = "deserialize_public_key_from_hex"
272    )]
273    pub public_key: NetworkPublicKey,
274    /// Multi-address of the peer observer node.
275    pub address: Multiaddr,
276}
277
278fn serialize_public_key_as_hex<S>(key: &NetworkPublicKey, serializer: S) -> Result<S::Ok, S::Error>
279where
280    S: serde::Serializer,
281{
282    use fastcrypto::encoding::Encoding;
283    let hex_str = fastcrypto::encoding::Hex::encode(key.to_bytes());
284    serializer.serialize_str(&hex_str)
285}
286
287fn deserialize_public_key_from_hex<'de, D>(deserializer: D) -> Result<NetworkPublicKey, D::Error>
288where
289    D: serde::Deserializer<'de>,
290{
291    use fastcrypto::{encoding::Encoding, traits::ToFromBytes};
292    let hex_str = String::deserialize(deserializer)?;
293    let bytes = fastcrypto::encoding::Hex::decode(&hex_str).map_err(serde::de::Error::custom)?;
294    let inner_key = fastcrypto::ed25519::Ed25519PublicKey::from_bytes(bytes.as_ref())
295        .map_err(serde::de::Error::custom)?;
296    Ok(NetworkPublicKey::new(inner_key))
297}
298
299#[derive(Clone, Debug, Deserialize, Serialize)]
300pub struct TonicParameters {
301    /// Keepalive interval and timeouts for both client and server.
302    ///
303    /// If unspecified, this will default to 5s.
304    #[serde(default = "TonicParameters::default_keepalive_interval")]
305    pub keepalive_interval: Duration,
306
307    /// Size of various per-connection buffers.
308    ///
309    /// If unspecified, this will default to 32MiB.
310    #[serde(default = "TonicParameters::default_connection_buffer_size")]
311    pub connection_buffer_size: usize,
312
313    /// Messages over this size threshold will increment a counter.
314    ///
315    /// If unspecified, this will default to 16MiB.
316    #[serde(default = "TonicParameters::default_excessive_message_size")]
317    pub excessive_message_size: usize,
318
319    /// Hard message size limit for both requests and responses.
320    /// This value is higher than strictly necessary, to allow overheads.
321    /// Message size targets and soft limits are computed based on this value.
322    ///
323    /// If unspecified, this will default to 1GiB.
324    #[serde(default = "TonicParameters::default_message_size_limit")]
325    pub message_size_limit: usize,
326}
327
328impl TonicParameters {
329    fn default_keepalive_interval() -> Duration {
330        Duration::from_secs(10)
331    }
332
333    fn default_connection_buffer_size() -> usize {
334        32 << 20
335    }
336
337    fn default_excessive_message_size() -> usize {
338        16 << 20
339    }
340
341    fn default_message_size_limit() -> usize {
342        64 << 20
343    }
344}
345
346impl Default for TonicParameters {
347    fn default() -> Self {
348        Self {
349            keepalive_interval: TonicParameters::default_keepalive_interval(),
350            connection_buffer_size: TonicParameters::default_connection_buffer_size(),
351            excessive_message_size: TonicParameters::default_excessive_message_size(),
352            message_size_limit: TonicParameters::default_message_size_limit(),
353        }
354    }
355}
356
357/// Observer node configuration parameters.
358#[derive(Clone, Debug, Deserialize, Serialize)]
359pub struct ObserverParameters {
360    /// Port for the observer server. If configured, then the node will run the observer server on this port.
361    ///
362    /// If unspecified, this will default to `None`.
363    #[serde(default = "ObserverParameters::default_server_port")]
364    pub server_port: Option<u16>,
365
366    /// Allowlist of observer public keys (hex encoded). If empty, all observers are allowed.
367    /// If non-empty, only observers with these public keys will be allowed to connect.
368    ///
369    /// If unspecified, this will default to an empty Vec (no allowlist, all observers allowed).
370    #[serde(default = "ObserverParameters::default_allowlist")]
371    pub allowlist: Vec<String>,
372
373    /// List of observer peers to connect to when acting as an observer client.
374    /// Each record contains the network public key and multi-address of a peer observer server.
375    ///
376    /// If unspecified, this will default to an empty Vec.
377    #[serde(default = "ObserverParameters::default_peers")]
378    pub peers: Vec<PeerRecord>,
379}
380
381impl ObserverParameters {
382    pub fn is_server_enabled(&self) -> bool {
383        self.server_port.is_some()
384    }
385
386    fn default_server_port() -> Option<u16> {
387        None
388    }
389
390    fn default_allowlist() -> Vec<String> {
391        Vec::new()
392    }
393
394    fn default_peers() -> Vec<PeerRecord> {
395        Vec::new()
396    }
397}
398
399impl Default for ObserverParameters {
400    fn default() -> Self {
401        Self {
402            server_port: ObserverParameters::default_server_port(),
403            allowlist: ObserverParameters::default_allowlist(),
404            peers: ObserverParameters::default_peers(),
405        }
406    }
407}
408
409/// Internal parameters unrelated to operating a consensus node in the real world.
410#[derive(Clone, Debug, Deserialize, Serialize)]
411pub struct InternalParameters {
412    /// Whether to skip equivocation validation, when testing with equivocators.
413    #[serde(default = "InternalParameters::default_skip_equivocation_validation")]
414    pub skip_equivocation_validation: bool,
415}
416
417impl InternalParameters {
418    fn default_skip_equivocation_validation() -> bool {
419        false
420    }
421}
422
423impl Default for InternalParameters {
424    fn default() -> Self {
425        Self {
426            skip_equivocation_validation: InternalParameters::default_skip_equivocation_validation(
427            ),
428        }
429    }
430}