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