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 // Number of commits to fetch in a batch for fast commit syncer, also the maximum number of
106 // commits returned per fetch. If this value is set too small, fetching becomes
107 // inefficient. If this value is set too large, it can result in load imbalance and
108 // stragglers.
109 #[serde(default = "Parameters::default_fast_commit_sync_batch_size")]
110 pub fast_commit_sync_batch_size: u32,
111
112 // Gap threshold for switching between commit syncers. When the gap between quorum and local
113 // commit index is larger than this threshold, FastCommitSyncer fetches. Otherwise,
114 // CommitSyncer fetches.
115 #[serde(default = "Parameters::default_commit_sync_gap_threshold")]
116 pub commit_sync_gap_threshold: u32,
117
118 /// Enable FastCommitSyncer for faster recovery from large commit gaps.
119 /// This is a local node configuration that works in conjunction with the
120 /// protocol-level consensus_fast_commit_sync feature flag. Both must be
121 /// enabled for FastCommitSyncer to run. The protocol flag controls
122 /// whether gRPC endpoints are available, while this local flag controls
123 /// whether this specific node creates and runs the FastCommitSyncer.
124 /// Disabled by default; operators can enable it locally once the protocol
125 /// flag is active, or disable it again if bugs are discovered, without
126 /// affecting protocol-level endpoint availability.
127 #[serde(default = "Parameters::default_enable_fast_commit_syncer")]
128 pub enable_fast_commit_syncer: bool,
129}
130
131impl Parameters {
132 pub(crate) fn default_leader_timeout() -> Duration {
133 Duration::from_millis(250)
134 }
135
136 pub(crate) fn default_min_block_delay() -> Duration {
137 if cfg!(msim) || std::env::var("__TEST_ONLY_CONSENSUS_USE_LONG_MIN_BLOCK_DELAY").is_ok() {
138 // Checkpoint building and execution cannot keep up with high commit rate in
139 // simtests, leading to long reconfiguration delays. This is because
140 // simtest is single threaded, and spending too much time in
141 // consensus can lead to starvation elsewhere.
142 Duration::from_millis(400)
143 } else if cfg!(test) {
144 // Avoid excessive CPU, data and logs in tests.
145 Duration::from_millis(250)
146 } else {
147 // For production, use min delay between block being set to 50ms, reducing the
148 // block rate to 20 blocks/sec
149 Duration::from_millis(50)
150 }
151 }
152
153 pub(crate) fn default_max_forward_time_drift() -> Duration {
154 Duration::from_millis(500)
155 }
156
157 // Maximum number of block headers to fetch per commit sync request.
158 pub(crate) fn default_max_headers_per_commit_sync_fetch() -> usize {
159 if cfg!(msim) {
160 // Exercise hitting blocks per fetch limit.
161 10
162 } else {
163 1000
164 }
165 }
166
167 // Maximum number of transactions to fetch per commit sync request.
168 pub(crate) fn default_max_transactions_per_commit_sync_fetch() -> usize {
169 if cfg!(msim) {
170 // Exercise hitting transactions per fetch limit.
171 10
172 } else {
173 1000
174 }
175 }
176
177 // Maximum number of block headers to fetch per periodic or live sync request.
178 pub(crate) fn default_max_headers_per_regular_sync_fetch() -> usize {
179 if cfg!(msim) {
180 // Exercise hitting blocks per fetch limit.
181 10
182 } else {
183 // TODO: This might should match the value of block headers in the bundle.
184 100
185 }
186 }
187
188 // Maximum number of transactions to fetch per request.
189 pub(crate) fn default_max_transactions_per_regular_sync_fetch() -> usize {
190 if cfg!(msim) { 10 } else { 1000 }
191 }
192
193 pub(crate) fn default_sync_last_known_own_block_timeout() -> Duration {
194 if cfg!(msim) {
195 Duration::from_millis(500)
196 } else {
197 // Here we prioritise liveness over the complete de-risking of block
198 // equivocation. 5 seconds in the majority of cases should be good
199 // enough for this given a healthy network.
200 Duration::from_secs(5)
201 }
202 }
203
204 pub(crate) fn default_dag_state_cached_rounds() -> u32 {
205 if cfg!(msim) {
206 // Exercise reading blocks from store.
207 5
208 } else {
209 500
210 }
211 }
212
213 pub(crate) fn default_commit_sync_parallel_fetches() -> usize {
214 8
215 }
216
217 pub(crate) fn default_commit_sync_batch_size() -> u32 {
218 if cfg!(msim) {
219 // Exercise commit sync.
220 5
221 } else {
222 100
223 }
224 }
225
226 pub(crate) fn default_commit_sync_batches_ahead() -> usize {
227 // This is set to be a multiple of default commit_sync_parallel_fetches to allow
228 // fetching ahead, while keeping the total number of inflight fetches
229 // and unprocessed fetched commits limited.
230 32
231 }
232
233 pub(crate) fn default_max_headers_per_bundle() -> usize {
234 150
235 }
236
237 pub(crate) fn default_max_shards_per_bundle() -> usize {
238 150
239 }
240
241 pub(crate) fn default_fast_commit_sync_batch_size() -> u32 {
242 if cfg!(msim) {
243 // Exercise fast commit sync.
244 5
245 } else {
246 // With ~10KB per commit and 4MB max message size, 1000 commits (~10MB) requires
247 // chunking. The server will chunk commits across multiple response messages.
248 1000
249 }
250 }
251
252 pub(crate) fn default_commit_sync_gap_threshold() -> u32 {
253 if cfg!(msim) {
254 // Use smaller threshold for testing.
255 10
256 } else {
257 // When gap > 1000, FastCommitSyncer is more efficient.
258 // When gap <= 1000, CommitSyncer handles incremental sync.
259 1000
260 }
261 }
262
263 pub(crate) fn default_enable_fast_commit_syncer() -> bool {
264 // Disabled by default. Operators can enable it locally once the protocol-level
265 // consensus_fast_commit_sync flag is active, or disable it again if bugs are
266 // discovered, without waiting for a protocol upgrade.
267 false
268 }
269}
270
271impl Default for Parameters {
272 fn default() -> Self {
273 Self {
274 db_path: PathBuf::default(),
275 leader_timeout: Parameters::default_leader_timeout(),
276 min_block_delay: Parameters::default_min_block_delay(),
277 max_forward_time_drift: Parameters::default_max_forward_time_drift(),
278 max_headers_per_commit_sync_fetch:
279 Parameters::default_max_headers_per_commit_sync_fetch(),
280 max_transactions_per_commit_sync_fetch:
281 Parameters::default_max_transactions_per_commit_sync_fetch(),
282 max_headers_per_regular_sync_fetch:
283 Parameters::default_max_headers_per_regular_sync_fetch(),
284 max_transactions_per_regular_sync_fetch:
285 Parameters::default_max_transactions_per_regular_sync_fetch(),
286 sync_last_known_own_block_timeout:
287 Parameters::default_sync_last_known_own_block_timeout(),
288 dag_state_cached_rounds: Parameters::default_dag_state_cached_rounds(),
289 commit_sync_parallel_fetches: Parameters::default_commit_sync_parallel_fetches(),
290 commit_sync_batch_size: Parameters::default_commit_sync_batch_size(),
291 commit_sync_batches_ahead: Parameters::default_commit_sync_batches_ahead(),
292 max_headers_per_bundle: Parameters::default_max_headers_per_bundle(),
293 max_shards_per_bundle: Parameters::default_max_shards_per_bundle(),
294 tonic: TonicParameters::default(),
295 fast_commit_sync_batch_size: Parameters::default_fast_commit_sync_batch_size(),
296 commit_sync_gap_threshold: Parameters::default_commit_sync_gap_threshold(),
297 enable_fast_commit_syncer: Parameters::default_enable_fast_commit_syncer(),
298 }
299 }
300}
301
302#[derive(Clone, Debug, Deserialize, Serialize)]
303pub struct TonicParameters {
304 /// Keepalive interval and timeouts for both client and server.
305 ///
306 /// If unspecified, this will default to 5s.
307 #[serde(default = "TonicParameters::default_keepalive_interval")]
308 pub keepalive_interval: Duration,
309
310 /// Size of various per-connection buffers.
311 ///
312 /// If unspecified, this will default to 32MiB.
313 #[serde(default = "TonicParameters::default_connection_buffer_size")]
314 pub connection_buffer_size: usize,
315
316 /// Messages over this size threshold will increment a counter.
317 ///
318 /// If unspecified, this will default to 16MiB.
319 #[serde(default = "TonicParameters::default_excessive_message_size")]
320 pub excessive_message_size: usize,
321
322 /// Hard message size limit for both requests and responses.
323 /// This value is higher than strictly necessary, to allow overheads.
324 /// Message size targets and soft limits are computed based on this value.
325 ///
326 /// If unspecified, this will default to 1GiB.
327 #[serde(default = "TonicParameters::default_message_size_limit")]
328 pub message_size_limit: usize,
329}
330
331impl TonicParameters {
332 fn default_keepalive_interval() -> Duration {
333 Duration::from_secs(5)
334 }
335
336 fn default_connection_buffer_size() -> usize {
337 32 << 20
338 }
339
340 fn default_excessive_message_size() -> usize {
341 16 << 20
342 }
343
344 fn default_message_size_limit() -> usize {
345 64 << 20
346 }
347}
348
349impl Default for TonicParameters {
350 fn default() -> Self {
351 Self {
352 keepalive_interval: TonicParameters::default_keepalive_interval(),
353 connection_buffer_size: TonicParameters::default_connection_buffer_size(),
354 excessive_message_size: TonicParameters::default_excessive_message_size(),
355 message_size_limit: TonicParameters::default_message_size_limit(),
356 }
357 }
358}