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}