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 commit sync request.
45    #[serde(default = "Parameters::default_max_blocks_per_fetch")]
46    pub max_blocks_per_fetch: usize,
47
48    /// Number of blocks to fetch by the periodic or live sync mechanism after a
49    /// single request
50    #[serde(default = "Parameters::default_max_blocks_per_sync")]
51    pub max_blocks_per_sync: usize,
52
53    /// Time to wait during node start up until the node has synced the last
54    /// proposed block via the network peers. When set to `0` the sync
55    /// mechanism is disabled. This property is meant to be used for amnesia
56    /// 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
69    /// than this threshold. Propagation delay is the difference between the
70    /// round of the last proposed block and the highest round from this
71    /// authority that is received by all validators in a quorum.
72    #[serde(default = "Parameters::default_propagation_delay_stop_proposal_threshold")]
73    pub propagation_delay_stop_proposal_threshold: u32,
74
75    /// The number of rounds of blocks to be kept in the Dag state cache per
76    /// authority. The larger the number the more the blocks that will be
77    /// kept in memory allowing minimising any potential disk access.
78    /// Value should be at minimum 50 rounds to ensure node performance, but
79    /// being too large can be expensive in memory usage.
80    #[serde(default = "Parameters::default_dag_state_cached_rounds")]
81    pub dag_state_cached_rounds: u32,
82
83    // Number of authorities commit syncer fetches in parallel.
84    // Both commits in a range and blocks referenced by the commits are fetched per authority.
85    #[serde(default = "Parameters::default_commit_sync_parallel_fetches")]
86    pub commit_sync_parallel_fetches: usize,
87
88    // Number of commits to fetch in a batch, also the maximum number of commits returned per
89    // fetch. If this value is set too small, fetching becomes inefficient.
90    // If this value is set too large, it can result in load imbalance and stragglers.
91    #[serde(default = "Parameters::default_commit_sync_batch_size")]
92    pub commit_sync_batch_size: u32,
93
94    // This affects the maximum number of commit batches being fetched, and those fetched but not
95    // processed as consensus output, before throttling of outgoing commit fetches starts.
96    #[serde(default = "Parameters::default_commit_sync_batches_ahead")]
97    pub commit_sync_batches_ahead: usize,
98
99    /// Tonic network settings.
100    #[serde(default = "TonicParameters::default")]
101    pub tonic: TonicParameters,
102}
103
104impl Parameters {
105    pub(crate) fn default_leader_timeout() -> Duration {
106        Duration::from_millis(250)
107    }
108
109    pub(crate) fn default_min_round_delay() -> Duration {
110        if cfg!(msim) || std::env::var("__TEST_ONLY_CONSENSUS_USE_LONG_MIN_ROUND_DELAY").is_ok() {
111            // Checkpoint building and execution cannot keep up with high commit rate in
112            // simtests, leading to long reconfiguration delays. This is because
113            // simtest is single threaded, and spending too much time in
114            // consensus can lead to starvation elsewhere.
115            Duration::from_millis(400)
116        } else if cfg!(test) {
117            // Avoid excessive CPU, data and logs in tests.
118            Duration::from_millis(250)
119        } else {
120            Duration::from_millis(50)
121        }
122    }
123
124    pub(crate) fn default_max_forward_time_drift() -> Duration {
125        Duration::from_millis(500)
126    }
127
128    pub(crate) fn default_max_blocks_per_fetch() -> usize {
129        if cfg!(msim) {
130            // Exercise hitting blocks per fetch limit.
131            10
132        } else {
133            1000
134        }
135    }
136
137    pub(crate) fn default_max_blocks_per_sync() -> usize {
138        if cfg!(msim) { 4 } else { 32 }
139    }
140
141    pub(crate) fn default_sync_last_known_own_block_timeout() -> Duration {
142        if cfg!(msim) {
143            Duration::from_millis(500)
144        } else {
145            // Here we prioritise liveness over the complete de-risking of block
146            // equivocation. 5 seconds in the majority of cases should be good
147            // enough for this given a healthy network.
148            Duration::from_secs(5)
149        }
150    }
151
152    pub(crate) fn default_round_prober_interval_ms() -> u64 {
153        if cfg!(msim) { 1000 } else { 5000 }
154    }
155
156    pub(crate) fn default_round_prober_request_timeout_ms() -> u64 {
157        if cfg!(msim) { 800 } else { 4000 }
158    }
159
160    pub(crate) fn default_propagation_delay_stop_proposal_threshold() -> u32 {
161        // Propagation delay is usually 0 round in production.
162        if cfg!(msim) { 2 } else { 5 }
163    }
164
165    pub(crate) fn default_dag_state_cached_rounds() -> u32 {
166        if cfg!(msim) {
167            // Exercise reading blocks from store.
168            5
169        } else {
170            500
171        }
172    }
173
174    pub(crate) fn default_commit_sync_parallel_fetches() -> usize {
175        8
176    }
177
178    pub(crate) fn default_commit_sync_batch_size() -> u32 {
179        if cfg!(msim) {
180            // Exercise commit sync.
181            5
182        } else {
183            100
184        }
185    }
186
187    pub(crate) fn default_commit_sync_batches_ahead() -> usize {
188        // This is set to be a multiple of default commit_sync_parallel_fetches to allow
189        // fetching ahead, while keeping the total number of inflight fetches
190        // and unprocessed fetched commits limited.
191        32
192    }
193}
194
195impl Default for Parameters {
196    fn default() -> Self {
197        Self {
198            db_path: PathBuf::default(),
199            leader_timeout: Parameters::default_leader_timeout(),
200            min_round_delay: Parameters::default_min_round_delay(),
201            max_forward_time_drift: Parameters::default_max_forward_time_drift(),
202            max_blocks_per_fetch: Parameters::default_max_blocks_per_fetch(),
203            max_blocks_per_sync: Parameters::default_max_blocks_per_sync(),
204            sync_last_known_own_block_timeout:
205                Parameters::default_sync_last_known_own_block_timeout(),
206            round_prober_interval_ms: Parameters::default_round_prober_interval_ms(),
207            round_prober_request_timeout_ms: Parameters::default_round_prober_request_timeout_ms(),
208            propagation_delay_stop_proposal_threshold:
209                Parameters::default_propagation_delay_stop_proposal_threshold(),
210            dag_state_cached_rounds: Parameters::default_dag_state_cached_rounds(),
211            commit_sync_parallel_fetches: Parameters::default_commit_sync_parallel_fetches(),
212            commit_sync_batch_size: Parameters::default_commit_sync_batch_size(),
213            commit_sync_batches_ahead: Parameters::default_commit_sync_batches_ahead(),
214            tonic: TonicParameters::default(),
215        }
216    }
217}
218
219#[derive(Clone, Debug, Deserialize, Serialize)]
220pub struct TonicParameters {
221    /// Keepalive interval and timeouts for both client and server.
222    ///
223    /// If unspecified, this will default to 5s.
224    #[serde(default = "TonicParameters::default_keepalive_interval")]
225    pub keepalive_interval: Duration,
226
227    /// Size of various per-connection buffers.
228    ///
229    /// If unspecified, this will default to 32MiB.
230    #[serde(default = "TonicParameters::default_connection_buffer_size")]
231    pub connection_buffer_size: usize,
232
233    /// Messages over this size threshold will increment a counter.
234    ///
235    /// If unspecified, this will default to 16MiB.
236    #[serde(default = "TonicParameters::default_excessive_message_size")]
237    pub excessive_message_size: usize,
238
239    /// Hard message size limit for both requests and responses.
240    /// This value is higher than strictly necessary, to allow overheads.
241    /// Message size targets and soft limits are computed based on this value.
242    ///
243    /// If unspecified, this will default to 1GiB.
244    #[serde(default = "TonicParameters::default_message_size_limit")]
245    pub message_size_limit: usize,
246}
247
248impl TonicParameters {
249    fn default_keepalive_interval() -> Duration {
250        Duration::from_secs(5)
251    }
252
253    fn default_connection_buffer_size() -> usize {
254        32 << 20
255    }
256
257    fn default_excessive_message_size() -> usize {
258        16 << 20
259    }
260
261    fn default_message_size_limit() -> usize {
262        64 << 20
263    }
264}
265
266impl Default for TonicParameters {
267    fn default() -> Self {
268        Self {
269            keepalive_interval: TonicParameters::default_keepalive_interval(),
270            connection_buffer_size: TonicParameters::default_connection_buffer_size(),
271            excessive_message_size: TonicParameters::default_excessive_message_size(),
272            message_size_limit: TonicParameters::default_message_size_limit(),
273        }
274    }
275}