consensus_config/
parameters.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{path::PathBuf, time::Duration};
6
7use serde::{Deserialize, Serialize};
8
9/// Operational configurations of a consensus authority.
10///
11/// All fields should tolerate inconsistencies among authorities, without
12/// affecting safety of the protocol. Otherwise, they need to be part of IOTA
13/// protocol config or epoch state on-chain.
14///
15/// NOTE: fields with default values are specified in the serde default
16/// functions. Most operators should not need to specify any field, except
17/// db_path.
18#[derive(Clone, Debug, Deserialize, Serialize)]
19pub struct Parameters {
20    /// Path to consensus DB for this epoch. Required when initializing
21    /// consensus. This is calculated based on user configuration for base
22    /// directory.
23    #[serde(skip)]
24    pub db_path: PathBuf,
25
26    /// Time to wait for parent round leader before sealing a block, from when
27    /// parent round has a quorum.
28    #[serde(default = "Parameters::default_leader_timeout")]
29    pub leader_timeout: Duration,
30
31    /// Minimum delay between rounds, to avoid generating too many rounds when
32    /// latency is low. This is especially necessary for tests running
33    /// locally. If setting a non-default value, it should be set low enough
34    /// to avoid reducing round rate and increasing latency in realistic and
35    /// distributed configurations.
36    #[serde(default = "Parameters::default_min_round_delay")]
37    pub min_round_delay: Duration,
38
39    /// Maximum forward time drift (how far in future) allowed for received
40    /// blocks.
41    #[serde(default = "Parameters::default_max_forward_time_drift")]
42    pub max_forward_time_drift: Duration,
43
44    /// Number of blocks to fetch per request.
45    #[serde(default = "Parameters::default_max_blocks_per_fetch")]
46    pub max_blocks_per_fetch: usize,
47
48    /// Time to wait during node start up until the node has synced the last
49    /// proposed block via the network peers. When set to `0` the sync
50    /// mechanism is disabled. This property is meant to be used for amnesia
51    /// recovery.
52    #[serde(default = "Parameters::default_sync_last_known_own_block_timeout")]
53    pub sync_last_known_own_block_timeout: Duration,
54
55    /// Interval in milliseconds to probe highest received rounds of peers.
56    #[serde(default = "Parameters::default_round_prober_interval_ms")]
57    pub round_prober_interval_ms: u64,
58
59    /// Timeout in milliseconds for a round prober request.
60    #[serde(default = "Parameters::default_round_prober_request_timeout_ms")]
61    pub round_prober_request_timeout_ms: u64,
62
63    /// Proposing new block is stopped when the propagation delay is greater
64    /// than this threshold. Propagation delay is the difference between the
65    /// round of the last proposed block and the the highest round from this
66    /// authority that is received by all validators in a quorum.
67    #[serde(default = "Parameters::default_propagation_delay_stop_proposal_threshold")]
68    pub propagation_delay_stop_proposal_threshold: u32,
69
70    /// The number of rounds of blocks to be kept in the Dag state cache per
71    /// authority. The larger the number the more the blocks that will be
72    /// kept in memory allowing minimising any potential disk access.
73    /// Value should be at minimum 50 rounds to ensure node performance, but
74    /// being too large can be expensive in memory usage.
75    #[serde(default = "Parameters::default_dag_state_cached_rounds")]
76    pub dag_state_cached_rounds: u32,
77
78    // Number of authorities commit syncer fetches in parallel.
79    // Both commits in a range and blocks referenced by the commits are fetched per authority.
80    #[serde(default = "Parameters::default_commit_sync_parallel_fetches")]
81    pub commit_sync_parallel_fetches: usize,
82
83    // Number of commits to fetch in a batch, also the maximum number of commits returned per
84    // fetch. If this value is set too small, fetching becomes inefficient.
85    // If this value is set too large, it can result in load imbalance and stragglers.
86    #[serde(default = "Parameters::default_commit_sync_batch_size")]
87    pub commit_sync_batch_size: u32,
88
89    // This affects the maximum number of commit batches being fetched, and those fetched but not
90    // processed as consensus output, before throttling of outgoing commit fetches starts.
91    #[serde(default = "Parameters::default_commit_sync_batches_ahead")]
92    pub commit_sync_batches_ahead: usize,
93
94    /// Tonic network settings.
95    #[serde(default = "TonicParameters::default")]
96    pub tonic: TonicParameters,
97}
98
99impl Parameters {
100    pub(crate) fn default_leader_timeout() -> Duration {
101        Duration::from_millis(250)
102    }
103
104    pub(crate) fn default_min_round_delay() -> Duration {
105        if cfg!(msim) || std::env::var("__TEST_ONLY_CONSENSUS_USE_LONG_MIN_ROUND_DELAY").is_ok() {
106            // Checkpoint building and execution cannot keep up with high commit rate in
107            // simtests, leading to long reconfiguration delays. This is because
108            // simtest is single threaded, and spending too much time in
109            // consensus can lead to starvation elsewhere.
110            Duration::from_millis(400)
111        } else if cfg!(test) {
112            // Avoid excessive CPU, data and logs in tests.
113            Duration::from_millis(250)
114        } else {
115            Duration::from_millis(50)
116        }
117    }
118
119    pub(crate) fn default_max_forward_time_drift() -> Duration {
120        Duration::from_millis(500)
121    }
122
123    pub(crate) fn default_max_blocks_per_fetch() -> usize {
124        if cfg!(msim) {
125            // Exercise hitting blocks per fetch limit.
126            10
127        } else {
128            1000
129        }
130    }
131
132    pub(crate) fn default_sync_last_known_own_block_timeout() -> Duration {
133        if cfg!(msim) {
134            Duration::from_millis(500)
135        } else {
136            // Here we prioritise liveness over the complete de-risking of block
137            // equivocation. 5 seconds in the majority of cases should be good
138            // enough for this given a healthy network.
139            Duration::from_secs(5)
140        }
141    }
142
143    pub(crate) fn default_round_prober_interval_ms() -> u64 {
144        if cfg!(msim) { 1000 } else { 5000 }
145    }
146
147    pub(crate) fn default_round_prober_request_timeout_ms() -> u64 {
148        if cfg!(msim) { 800 } else { 4000 }
149    }
150
151    pub(crate) fn default_propagation_delay_stop_proposal_threshold() -> u32 {
152        // Propagation delay is usually 0 round in production.
153        if cfg!(msim) { 2 } else { 5 }
154    }
155
156    pub(crate) fn default_dag_state_cached_rounds() -> u32 {
157        if cfg!(msim) {
158            // Exercise reading blocks from store.
159            5
160        } else {
161            500
162        }
163    }
164
165    pub(crate) fn default_commit_sync_parallel_fetches() -> usize {
166        8
167    }
168
169    pub(crate) fn default_commit_sync_batch_size() -> u32 {
170        if cfg!(msim) {
171            // Exercise commit sync.
172            5
173        } else {
174            100
175        }
176    }
177
178    pub(crate) fn default_commit_sync_batches_ahead() -> usize {
179        // This is set to be a multiple of default commit_sync_parallel_fetches to allow
180        // fetching ahead, while keeping the total number of inflight fetches
181        // and unprocessed fetched commits limited.
182        32
183    }
184}
185
186impl Default for Parameters {
187    fn default() -> Self {
188        Self {
189            db_path: PathBuf::default(),
190            leader_timeout: Parameters::default_leader_timeout(),
191            min_round_delay: Parameters::default_min_round_delay(),
192            max_forward_time_drift: Parameters::default_max_forward_time_drift(),
193            max_blocks_per_fetch: Parameters::default_max_blocks_per_fetch(),
194            sync_last_known_own_block_timeout:
195                Parameters::default_sync_last_known_own_block_timeout(),
196            round_prober_interval_ms: Parameters::default_round_prober_interval_ms(),
197            round_prober_request_timeout_ms: Parameters::default_round_prober_request_timeout_ms(),
198            propagation_delay_stop_proposal_threshold:
199                Parameters::default_propagation_delay_stop_proposal_threshold(),
200            dag_state_cached_rounds: Parameters::default_dag_state_cached_rounds(),
201            commit_sync_parallel_fetches: Parameters::default_commit_sync_parallel_fetches(),
202            commit_sync_batch_size: Parameters::default_commit_sync_batch_size(),
203            commit_sync_batches_ahead: Parameters::default_commit_sync_batches_ahead(),
204            tonic: TonicParameters::default(),
205        }
206    }
207}
208
209#[derive(Clone, Debug, Deserialize, Serialize)]
210pub struct TonicParameters {
211    /// Keepalive interval and timeouts for both client and server.
212    ///
213    /// If unspecified, this will default to 5s.
214    #[serde(default = "TonicParameters::default_keepalive_interval")]
215    pub keepalive_interval: Duration,
216
217    /// Size of various per-connection buffers.
218    ///
219    /// If unspecified, this will default to 32MiB.
220    #[serde(default = "TonicParameters::default_connection_buffer_size")]
221    pub connection_buffer_size: usize,
222
223    /// Messages over this size threshold will increment a counter.
224    ///
225    /// If unspecified, this will default to 16MiB.
226    #[serde(default = "TonicParameters::default_excessive_message_size")]
227    pub excessive_message_size: usize,
228
229    /// Hard message size limit for both requests and responses.
230    /// This value is higher than strictly necessary, to allow overheads.
231    /// Message size targets and soft limits are computed based on this value.
232    ///
233    /// If unspecified, this will default to 1GiB.
234    #[serde(default = "TonicParameters::default_message_size_limit")]
235    pub message_size_limit: usize,
236}
237
238impl TonicParameters {
239    fn default_keepalive_interval() -> Duration {
240        Duration::from_secs(5)
241    }
242
243    fn default_connection_buffer_size() -> usize {
244        32 << 20
245    }
246
247    fn default_excessive_message_size() -> usize {
248        16 << 20
249    }
250
251    fn default_message_size_limit() -> usize {
252        64 << 20
253    }
254}
255
256impl Default for TonicParameters {
257    fn default() -> Self {
258        Self {
259            keepalive_interval: TonicParameters::default_keepalive_interval(),
260            connection_buffer_size: TonicParameters::default_connection_buffer_size(),
261            excessive_message_size: TonicParameters::default_excessive_message_size(),
262            message_size_limit: TonicParameters::default_message_size_limit(),
263        }
264    }
265}