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/// Ceiling on the number of headers, and on the number of shards, a bundle may
10/// declare. Enforced while decoding, before the entries are materialised, so a
11/// peer cannot make the decoder build a vector far larger than the configured
12/// caps allow it to keep. Both caps are validated against it at startup.
13pub const MAX_HEADERS_OR_SHARDS_PER_BUNDLE: usize = 1024;
14
15/// Ceiling on the headers a fetch response may carry, for header sync and
16/// commit sync alike. The server truncates its response to its own
17/// `max_headers_per_header_sync_fetch` or `max_headers_per_commit_sync_fetch`,
18/// both validated against this at startup, so a client can reject a response
19/// past it as misbehaviour while still accepting a peer configured above its
20/// own cap. Enforced while decoding each response message, before its entries
21/// are materialised.
22pub const HEADERS_PER_FETCH_CEILING: usize = 1024;
23
24/// Ceiling on the transaction entries a fetch request or response may carry,
25/// for transaction sync and regular commit sync alike. A client requests at
26/// most its own `max_transactions_per_transaction_sync_fetch` or
27/// `max_transactions_per_commit_sync_fetch`, both validated against this at
28/// startup, and the server returns at most one entry per requested reference.
29/// Enforced while decoding each message, before its entries are materialised.
30pub const TRANSACTIONS_PER_FETCH_CEILING: usize = 1024;
31
32/// Ceiling on the commits a commit-sync fetch may request, for regular and
33/// fast commit sync alike. A client requests at most its own
34/// `commit_sync_batch_size` or `fast_commit_sync_batch_size` commits, both
35/// validated against this at startup. Enforced while decoding each response
36/// message, before its entries are materialised.
37pub const COMMITS_PER_FETCH_CEILING: usize = 1024;
38
39/// Operational configurations of a consensus authority.
40///
41/// All fields should tolerate inconsistencies among authorities, without
42/// affecting safety of the protocol. Otherwise, they need to be part of IOTA
43/// protocol config or epoch state on-chain.
44///
45/// NOTE: fields with default values are specified in the serde default
46/// functions. Most operators should not need to specify any field, except
47/// db_path.
48#[derive(Clone, Debug, Deserialize, Serialize)]
49pub struct Parameters {
50 /// Path to consensus DB for this epoch. Required when initializing
51 /// consensus. This is calculated based on user configuration for base
52 /// directory.
53 #[serde(skip)]
54 pub db_path: PathBuf,
55
56 /// Time to wait for parent round leader before sealing a block, from when
57 /// parent round has a quorum.
58 #[serde(default = "Parameters::default_leader_timeout")]
59 pub leader_timeout: Duration,
60
61 /// Sustained spacing between own blocks: long-run production never exceeds
62 /// one block per `min_block_delay`. This avoids generating too many rounds
63 /// when latency is low. This is especially necessary for tests running
64 /// locally. If setting a non-default value, it should be set low enough
65 /// to avoid reducing round rate and increasing latency in realistic and
66 /// distributed configurations.
67 #[serde(default = "Parameters::default_min_block_delay")]
68 pub min_block_delay: Duration,
69
70 /// Soft counterpart of `leader_timeout`: after this duration we are
71 /// willing to propose a block even without a strong-vote quorum, to avoid
72 /// liveness stalls when leader data is slow to propagate. Fires earlier
73 /// than `leader_timeout` and does not force block creation on its own.
74 #[serde(default = "Parameters::default_soft_leader_timeout")]
75 pub soft_leader_timeout: Duration,
76
77 /// Window bounding own block production together with `min_block_delay`:
78 /// idle time accrues budget for bursts of up to `block_rate_window /
79 /// min_block_delay` back-to-back blocks, letting a validator that fell
80 /// behind catch up on rounds instead of skipping them. Set at or below
81 /// `min_block_delay` to disable bursting (fixed spacing between blocks).
82 #[serde(default = "Parameters::default_block_rate_window")]
83 pub block_rate_window: Duration,
84
85 /// Number of block headers to fetch per commit sync request.
86 #[serde(default = "Parameters::default_max_headers_per_commit_sync_fetch")]
87 pub max_headers_per_commit_sync_fetch: usize,
88
89 /// Number of transactions to fetch per commit sync request.
90 #[serde(default = "Parameters::default_max_transactions_per_commit_sync_fetch")]
91 pub max_transactions_per_commit_sync_fetch: usize,
92
93 /// Number of block headers to fetch per header sync (periodic or live)
94 /// request.
95 #[serde(default = "Parameters::default_max_headers_per_header_sync_fetch")]
96 pub max_headers_per_header_sync_fetch: usize,
97
98 /// Number of transactions to fetch per transaction sync request.
99 #[serde(default = "Parameters::default_max_transactions_per_transaction_sync_fetch")]
100 pub max_transactions_per_transaction_sync_fetch: usize,
101
102 /// Time to wait during node start up until the node has synced the last
103 /// proposed block via the network peers. When set to `0` the sync
104 /// mechanism is disabled. This property is meant to be used for amnesia
105 /// recovery.
106 #[serde(default = "Parameters::default_sync_last_known_own_block_timeout")]
107 pub sync_last_known_own_block_timeout: Duration,
108
109 /// The number of rounds of blocks to be kept in the Dag state cache per
110 /// authority. The larger the number the more the blocks that will be
111 /// kept in memory allowing minimising any potential disk access.
112 /// Value should be at minimum 50 rounds to ensure node performance, but
113 /// being too large can be expensive in memory usage.
114 #[serde(default = "Parameters::default_dag_state_cached_rounds")]
115 pub dag_state_cached_rounds: u32,
116
117 /// Rounds a header from a far-future-bounded source may lead the locally
118 /// accepted frontier, in addition to `dag_state_cached_rounds`, before it
119 /// is dropped as too far ahead to connect.
120 #[serde(default = "Parameters::default_peer_round_ahead_margin")]
121 pub peer_round_ahead_margin: u32,
122
123 // Number of authorities commit syncer fetches in parallel.
124 // Both commits in a range and blocks referenced by the commits are fetched per authority.
125 #[serde(default = "Parameters::default_commit_sync_parallel_fetches")]
126 pub commit_sync_parallel_fetches: usize,
127
128 // Number of commits to fetch in a batch, also the maximum number of commits returned per
129 // fetch. If this value is set too small, fetching becomes inefficient.
130 // If this value is set too large, it can result in load imbalance and stragglers.
131 #[serde(default = "Parameters::default_commit_sync_batch_size")]
132 pub commit_sync_batch_size: u32,
133
134 // This affects the maximum number of commit batches being fetched, and those fetched but not
135 // processed as consensus output, before throttling of outgoing commit fetches starts.
136 #[serde(default = "Parameters::default_commit_sync_batches_ahead")]
137 pub commit_sync_batches_ahead: usize,
138
139 /// Maximum number of commits scanned and replayed per batch during
140 /// recovery, bounding peak memory when a large unprocessed range is
141 /// replayed at startup.
142 #[serde(default = "Parameters::default_commit_recovery_batch_size")]
143 pub commit_recovery_batch_size: u32,
144
145 /// Maximum number of headers to be included in a bundle. Headers exceeding
146 /// the max allowed limit will be truncated.
147 #[serde(default = "Parameters::default_max_headers_per_bundle")]
148 pub max_headers_per_bundle: usize,
149
150 /// Maximum number of transaction shards to be included in a bundle. Shards
151 /// exceeding the max allowed limit will be truncated.
152 #[serde(default = "Parameters::default_max_shards_per_bundle")]
153 pub max_shards_per_bundle: usize,
154
155 /// Tonic network settings.
156 #[serde(default = "TonicParameters::default")]
157 pub tonic: TonicParameters,
158
159 /// Number of commits requested per fast commit sync fetch. A response may
160 /// carry up to twice this many, since it extends past the requested end to
161 /// reach a certifiable commit. Set too small, fetching is inefficient and
162 /// the server has little room to reach one; set too large, it causes load
163 /// imbalance and stragglers.
164 #[serde(default = "Parameters::default_fast_commit_sync_batch_size")]
165 pub fast_commit_sync_batch_size: u32,
166
167 // Gap threshold for switching between commit syncers. When the gap between quorum and local
168 // commit index is larger than this threshold, FastCommitSyncer fetches. Otherwise,
169 // CommitSyncer fetches.
170 #[serde(default = "Parameters::default_commit_sync_gap_threshold")]
171 pub commit_sync_gap_threshold: u32,
172
173 /// Enable FastCommitSyncer for faster recovery from large commit gaps.
174 /// Enabled by default; operators can disable it locally if bugs are
175 /// discovered.
176 #[serde(default = "Parameters::default_enable_fast_commit_syncer")]
177 pub enable_fast_commit_syncer: bool,
178
179 /// Reconnect block streams after fast commit sync reinitializes consensus,
180 /// discarding bundles buffered against the previous state. Enabled by
181 /// default; operators can disable it locally. Has no effect unless
182 /// `enable_fast_commit_syncer` is also enabled, since only fast sync
183 /// signals the reset.
184 #[serde(default = "Parameters::default_enable_block_stream_reset_on_fast_sync_exit")]
185 pub enable_block_stream_reset_on_fast_sync_exit: bool,
186
187 /// Ask commit-sync peers that have voted for the end of the requested
188 /// range before those that have not, since a vote means the peer has
189 /// solidified every commit in the range. Peers without an observed vote
190 /// are ordered behind; each fetch round tries a bounded number of peers,
191 /// so on a committee larger than that bound they can stay outside the
192 /// round until their votes are observed. The header fetch that
193 /// reinitializes the node at the end of fast sync likewise asks peers that
194 /// have voted for the last commit first. Enabled by default; disabling it
195 /// leaves peers in the order `enable_peer_responsiveness_ranking` gives
196 /// them.
197 #[serde(default = "Parameters::default_enable_commit_sync_peer_selection_by_commit_votes")]
198 pub enable_commit_sync_peer_selection_by_commit_votes: bool,
199
200 /// Enable adaptive acknowledgment filtering for StarfishSpeed.
201 /// Local heuristic that leaves out of leader blocks the acknowledgments
202 /// that the voters are not expected to hold at the next round, judged
203 /// from how soon they acknowledged recent blocks. Voters count by how
204 /// often this node's blocks reference them. Deferred acknowledgments go
205 /// into later blocks. Effective only when the
206 /// protocol-level `consensus_starfish_speed` flag is also on.
207 #[serde(default = "Parameters::default_enable_starfish_speed_adaptive_acknowledgments")]
208 pub enable_starfish_speed_adaptive_acknowledgments: bool,
209
210 /// Prefer more responsive peers when the transactions synchronizer, the
211 /// commit syncer and the header synchronizer select peers to fetch from.
212 /// Responses are verified the same way regardless, so it cannot affect
213 /// safety. Enabled by default; disabling it restores the previous
214 /// selection: for the transactions synchronizer a uniform random order
215 /// that excludes the most recently failed peers (up to less than f+1 by
216 /// stake), and for the commit syncer and the header synchronizer a uniform
217 /// random order.
218 #[serde(default = "Parameters::default_enable_peer_responsiveness_ranking")]
219 pub enable_peer_responsiveness_ranking: bool,
220
221 /// Ask only a bounded number of peers that recently supplied a new header
222 /// or referenced a missing one to push more headers from that author.
223 #[serde(default = "Parameters::default_enable_bounded_header_advertisement")]
224 pub enable_bounded_header_advertisement: bool,
225
226 /// Ask only the fastest peers that together provide enough shards and
227 /// stake for reconstruction. Enabled by default; disabling it asks every
228 /// peer.
229 #[serde(default = "Parameters::default_enable_shard_peer_selection")]
230 pub enable_shard_peer_selection: bool,
231
232 /// Port for the DAG visualizer gRPC server (localhost only).
233 /// When set, starts a debugging server for real-time DAG visualization.
234 /// Only has an effect when the `dag-visualizer` feature is compiled in.
235 /// Disabled by default (None).
236 #[serde(default)]
237 pub dag_visualizer_port: Option<u16>,
238
239 /// Maximum number of rounds the last commit's leader may run ahead of the
240 /// last solid commit's leader before the node stops accepting new block
241 /// bundles and restricts header fetching, until solidification catches up.
242 #[serde(default = "Parameters::default_solid_commit_lag_threshold")]
243 pub solid_commit_lag_threshold: u32,
244
245 /// Maximum number of shards from one relaying authority retained across
246 /// all pending shard accumulators. At the budget, admitting a new shard
247 /// from the authority evicts its oldest retained one, so reconstructor
248 /// memory stays bounded by `committee size × budget × shard size`
249 /// regardless of how far commits run ahead of solidification.
250 #[serde(default = "Parameters::default_shard_budget_per_authority")]
251 pub shard_budget_per_authority: u32,
252
253 /// Maximum transaction payload bytes one fast commit-sync response carries.
254 /// A fetch covering more commits than this is answered with the commits
255 /// whose payloads fit, and the requester asks for the rest in its next
256 /// fetch. When the range's first commit exceeds this on its own it is
257 /// still served whole. A requester stops reading a response once it passes
258 /// this and its first commit is complete.
259 #[serde(default = "Parameters::default_max_fast_commit_sync_transaction_bytes")]
260 pub max_fast_commit_sync_transaction_bytes: usize,
261}
262
263impl Parameters {
264 /// Threshold for the number of commits sent to the consumer but not yet
265 /// handled, above which commit producers (commit syncers, commit observer
266 /// recovery) pause to let the consumer catch up.
267 pub fn unhandled_commits_threshold(&self) -> u32 {
268 self.commit_sync_batch_size * (self.commit_sync_batches_ahead as u32)
269 }
270
271 pub(crate) fn default_leader_timeout() -> Duration {
272 Duration::from_millis(200)
273 }
274
275 pub(crate) fn default_min_block_delay() -> Duration {
276 if cfg!(msim) || std::env::var("__TEST_ONLY_CONSENSUS_USE_LONG_MIN_BLOCK_DELAY").is_ok() {
277 // Checkpoint building and execution cannot keep up with high commit rate in
278 // simtests, leading to long reconfiguration delays. This is because
279 // simtest is single threaded, and spending too much time in
280 // consensus can lead to starvation elsewhere.
281 Duration::from_millis(400)
282 } else if cfg!(test) {
283 // Avoid excessive CPU, data and logs in tests.
284 Duration::from_millis(250)
285 } else {
286 // For production, use min delay between block being set to 50ms, reducing the
287 // block rate to 20 blocks/sec
288 Duration::from_millis(50)
289 }
290 }
291
292 pub(crate) fn default_soft_leader_timeout() -> Duration {
293 Duration::from_millis(5)
294 }
295
296 pub(crate) fn default_block_rate_window() -> Duration {
297 Duration::from_secs(2)
298 }
299
300 /// Burst capacity: maximum number of own blocks within `block_rate_window`
301 /// (40 in production, 5 in msim, 8 in tests with the default window).
302 pub fn block_rate_burst(&self) -> u64 {
303 let interval_ms = self.min_block_delay.as_millis().max(1) as u64;
304 (self.block_rate_window.as_millis() as u64 / interval_ms).max(1)
305 }
306
307 /// Highest round a header from a far-future-bounded source may have,
308 /// relative to the accepted `frontier`, to still be close enough to
309 /// connect; headers above this are too far ahead and dropped.
310 pub fn far_future_round_ceiling(&self, frontier: u32) -> u32 {
311 frontier
312 .saturating_add(self.dag_state_cached_rounds)
313 .saturating_add(self.peer_round_ahead_margin)
314 }
315
316 /// Maximum number of block headers served per fetch request, depending on
317 /// whether the request comes from commit sync or the header synchronizer.
318 pub fn max_headers_per_fetch(&self, commit_sync: bool) -> usize {
319 if commit_sync {
320 self.max_headers_per_commit_sync_fetch
321 } else {
322 self.max_headers_per_header_sync_fetch
323 }
324 }
325
326 /// Validates local consensus parameters, rejecting zero values that can
327 /// lead to synchronization problems. Returns a description of the first
328 /// offending field.
329 pub fn validate(&self) -> Result<(), String> {
330 let positive_fields = [
331 (
332 "max_headers_per_commit_sync_fetch",
333 self.max_headers_per_commit_sync_fetch as u128,
334 ),
335 (
336 "max_transactions_per_commit_sync_fetch",
337 self.max_transactions_per_commit_sync_fetch as u128,
338 ),
339 (
340 "max_headers_per_header_sync_fetch",
341 self.max_headers_per_header_sync_fetch as u128,
342 ),
343 (
344 "max_transactions_per_transaction_sync_fetch",
345 self.max_transactions_per_transaction_sync_fetch as u128,
346 ),
347 (
348 "dag_state_cached_rounds",
349 self.dag_state_cached_rounds as u128,
350 ),
351 (
352 "commit_sync_parallel_fetches",
353 self.commit_sync_parallel_fetches as u128,
354 ),
355 (
356 "commit_sync_batch_size",
357 self.commit_sync_batch_size as u128,
358 ),
359 (
360 "commit_recovery_batch_size",
361 self.commit_recovery_batch_size as u128,
362 ),
363 (
364 "commit_sync_batches_ahead",
365 self.commit_sync_batches_ahead as u128,
366 ),
367 (
368 "max_headers_per_bundle",
369 self.max_headers_per_bundle as u128,
370 ),
371 ("max_shards_per_bundle", self.max_shards_per_bundle as u128),
372 (
373 "fast_commit_sync_batch_size",
374 self.fast_commit_sync_batch_size as u128,
375 ),
376 (
377 "max_fast_commit_sync_transaction_bytes",
378 self.max_fast_commit_sync_transaction_bytes as u128,
379 ),
380 (
381 "tonic.connection_buffer_size",
382 self.tonic.connection_buffer_size as u128,
383 ),
384 (
385 "tonic.excessive_message_size",
386 self.tonic.excessive_message_size as u128,
387 ),
388 (
389 "tonic.message_size_limit",
390 self.tonic.message_size_limit as u128,
391 ),
392 (
393 "tonic.keepalive_interval",
394 self.tonic.keepalive_interval.as_nanos(),
395 ),
396 (
397 "shard_budget_per_authority",
398 self.shard_budget_per_authority as u128,
399 ),
400 ];
401 for (name, value) in positive_fields {
402 if value == 0 {
403 return Err(format!("{name} must be positive"));
404 }
405 }
406 let bundle_fields = [
407 ("max_headers_per_bundle", self.max_headers_per_bundle),
408 ("max_shards_per_bundle", self.max_shards_per_bundle),
409 ];
410 for (name, value) in bundle_fields {
411 if value > MAX_HEADERS_OR_SHARDS_PER_BUNDLE {
412 return Err(format!(
413 "{name} must not exceed {MAX_HEADERS_OR_SHARDS_PER_BUNDLE}"
414 ));
415 }
416 }
417 let header_fetch_fields = [
418 (
419 "max_headers_per_header_sync_fetch",
420 self.max_headers_per_header_sync_fetch,
421 ),
422 (
423 "max_headers_per_commit_sync_fetch",
424 self.max_headers_per_commit_sync_fetch,
425 ),
426 ];
427 for (name, value) in header_fetch_fields {
428 if value > HEADERS_PER_FETCH_CEILING {
429 return Err(format!(
430 "{name} must not exceed {HEADERS_PER_FETCH_CEILING}"
431 ));
432 }
433 }
434 let transaction_fetch_fields = [
435 (
436 "max_transactions_per_transaction_sync_fetch",
437 self.max_transactions_per_transaction_sync_fetch,
438 ),
439 (
440 "max_transactions_per_commit_sync_fetch",
441 self.max_transactions_per_commit_sync_fetch,
442 ),
443 ];
444 for (name, value) in transaction_fetch_fields {
445 if value > TRANSACTIONS_PER_FETCH_CEILING {
446 return Err(format!(
447 "{name} must not exceed {TRANSACTIONS_PER_FETCH_CEILING}"
448 ));
449 }
450 }
451 let commit_fetch_fields = [
452 ("commit_sync_batch_size", self.commit_sync_batch_size),
453 (
454 "fast_commit_sync_batch_size",
455 self.fast_commit_sync_batch_size,
456 ),
457 ];
458 for (name, value) in commit_fetch_fields {
459 if value as usize > COMMITS_PER_FETCH_CEILING {
460 return Err(format!(
461 "{name} must not exceed {COMMITS_PER_FETCH_CEILING}"
462 ));
463 }
464 }
465 Ok(())
466 }
467
468 // Maximum number of block headers to fetch per commit sync request.
469 pub(crate) fn default_max_headers_per_commit_sync_fetch() -> usize {
470 if cfg!(msim) {
471 // Exercise hitting blocks per fetch limit.
472 10
473 } else {
474 1000
475 }
476 }
477
478 // Maximum number of transactions to fetch per commit sync request.
479 pub(crate) fn default_max_transactions_per_commit_sync_fetch() -> usize {
480 if cfg!(msim) {
481 // Exercise hitting transactions per fetch limit.
482 10
483 } else {
484 1000
485 }
486 }
487
488 // Maximum number of block headers to fetch per header sync (periodic or
489 // live) request.
490 pub(crate) fn default_max_headers_per_header_sync_fetch() -> usize {
491 if cfg!(msim) {
492 // Exercise hitting blocks per fetch limit.
493 10
494 } else {
495 // TODO: This might should match the value of block headers in the bundle.
496 100
497 }
498 }
499
500 // Maximum number of transactions to fetch per transaction sync request.
501 pub(crate) fn default_max_transactions_per_transaction_sync_fetch() -> usize {
502 if cfg!(msim) { 10 } else { 1000 }
503 }
504
505 pub(crate) fn default_sync_last_known_own_block_timeout() -> Duration {
506 if cfg!(msim) {
507 Duration::from_millis(500)
508 } else {
509 // Here we prioritise liveness over the complete de-risking of block
510 // equivocation. 5 seconds in the majority of cases should be good
511 // enough for this given a healthy network.
512 Duration::from_secs(5)
513 }
514 }
515
516 pub(crate) fn default_dag_state_cached_rounds() -> u32 {
517 if cfg!(msim) {
518 // Exercise reading blocks from store.
519 5
520 } else {
521 500
522 }
523 }
524
525 pub(crate) fn default_peer_round_ahead_margin() -> u32 {
526 1000
527 }
528
529 pub(crate) fn default_commit_sync_parallel_fetches() -> usize {
530 8
531 }
532
533 pub(crate) fn default_commit_sync_batch_size() -> u32 {
534 if cfg!(msim) {
535 // Exercise commit sync.
536 5
537 } else {
538 100
539 }
540 }
541
542 pub(crate) fn default_commit_recovery_batch_size() -> u32 {
543 if cfg!(msim) { 3 } else { 250 }
544 }
545
546 pub(crate) fn default_commit_sync_batches_ahead() -> usize {
547 // This is set to be a multiple of default commit_sync_parallel_fetches to allow
548 // fetching ahead, while keeping the total number of inflight fetches
549 // and unprocessed fetched commits limited.
550 32
551 }
552
553 pub(crate) fn default_max_headers_per_bundle() -> usize {
554 150
555 }
556
557 pub(crate) fn default_max_shards_per_bundle() -> usize {
558 150
559 }
560
561 pub(crate) fn default_fast_commit_sync_batch_size() -> u32 {
562 if cfg!(msim) {
563 // Exercise fast commit sync.
564 5
565 } else {
566 // Sized so that commit_sync_parallel_fetches ranges fit under the
567 // unhandled-commits threshold (8 x 400 <= 3200), letting fast sync
568 // actually run its fetches in parallel. The server chunks larger
569 // responses across multiple messages either way.
570 400
571 }
572 }
573
574 pub(crate) fn default_commit_sync_gap_threshold() -> u32 {
575 if cfg!(msim) {
576 // Use smaller threshold for testing.
577 10
578 } else {
579 // When gap > 1000, FastCommitSyncer is more efficient.
580 // When gap <= 1000, CommitSyncer handles incremental sync.
581 1000
582 }
583 }
584
585 pub(crate) fn default_enable_fast_commit_syncer() -> bool {
586 // Enabled by default. Operators can disable it locally if bugs are discovered,
587 // without waiting for a protocol upgrade.
588 true
589 }
590
591 pub(crate) fn default_enable_block_stream_reset_on_fast_sync_exit() -> bool {
592 true
593 }
594
595 pub(crate) fn default_enable_commit_sync_peer_selection_by_commit_votes() -> bool {
596 // Enabled by default. Ordering only, so it cannot diverge consensus.
597 true
598 }
599
600 pub(crate) fn default_enable_starfish_speed_adaptive_acknowledgments() -> bool {
601 true
602 }
603
604 pub(crate) fn default_enable_peer_responsiveness_ranking() -> bool {
605 true
606 }
607
608 pub(crate) fn default_enable_bounded_header_advertisement() -> bool {
609 true
610 }
611
612 pub(crate) fn default_enable_shard_peer_selection() -> bool {
613 true
614 }
615
616 pub(crate) fn default_solid_commit_lag_threshold() -> u32 {
617 // The healthy gap is a few rounds at most; 500 rounds (a few minutes of
618 // commits) is far above live jitter yet caps how long a solidification
619 // stall can keep widening the shard/payload retention window.
620 500
621 }
622
623 pub(crate) fn default_max_fast_commit_sync_transaction_bytes() -> usize {
624 64 * 1024 * 1024
625 }
626
627 pub(crate) fn default_shard_budget_per_authority() -> u32 {
628 // Honest need per authority is one shard per slot times a few rounds
629 // until decode, well under the budget at any realistic committee size.
630 // Worst-case total pool ≈ 3 × budget × the maximum payload size.
631 1000
632 }
633}
634
635impl Default for Parameters {
636 fn default() -> Self {
637 Self {
638 db_path: PathBuf::default(),
639 leader_timeout: Parameters::default_leader_timeout(),
640 min_block_delay: Parameters::default_min_block_delay(),
641 soft_leader_timeout: Parameters::default_soft_leader_timeout(),
642 block_rate_window: Parameters::default_block_rate_window(),
643 max_headers_per_commit_sync_fetch:
644 Parameters::default_max_headers_per_commit_sync_fetch(),
645 max_transactions_per_commit_sync_fetch:
646 Parameters::default_max_transactions_per_commit_sync_fetch(),
647 max_headers_per_header_sync_fetch:
648 Parameters::default_max_headers_per_header_sync_fetch(),
649 max_transactions_per_transaction_sync_fetch:
650 Parameters::default_max_transactions_per_transaction_sync_fetch(),
651 sync_last_known_own_block_timeout:
652 Parameters::default_sync_last_known_own_block_timeout(),
653 dag_state_cached_rounds: Parameters::default_dag_state_cached_rounds(),
654 peer_round_ahead_margin: Parameters::default_peer_round_ahead_margin(),
655 commit_sync_parallel_fetches: Parameters::default_commit_sync_parallel_fetches(),
656 commit_sync_batch_size: Parameters::default_commit_sync_batch_size(),
657 commit_sync_batches_ahead: Parameters::default_commit_sync_batches_ahead(),
658 commit_recovery_batch_size: Parameters::default_commit_recovery_batch_size(),
659 max_headers_per_bundle: Parameters::default_max_headers_per_bundle(),
660 max_shards_per_bundle: Parameters::default_max_shards_per_bundle(),
661 tonic: TonicParameters::default(),
662 fast_commit_sync_batch_size: Parameters::default_fast_commit_sync_batch_size(),
663 commit_sync_gap_threshold: Parameters::default_commit_sync_gap_threshold(),
664 enable_fast_commit_syncer: Parameters::default_enable_fast_commit_syncer(),
665 enable_block_stream_reset_on_fast_sync_exit:
666 Parameters::default_enable_block_stream_reset_on_fast_sync_exit(),
667 enable_commit_sync_peer_selection_by_commit_votes:
668 Parameters::default_enable_commit_sync_peer_selection_by_commit_votes(),
669 enable_starfish_speed_adaptive_acknowledgments:
670 Parameters::default_enable_starfish_speed_adaptive_acknowledgments(),
671 enable_peer_responsiveness_ranking:
672 Parameters::default_enable_peer_responsiveness_ranking(),
673 enable_bounded_header_advertisement:
674 Parameters::default_enable_bounded_header_advertisement(),
675 enable_shard_peer_selection: Parameters::default_enable_shard_peer_selection(),
676 dag_visualizer_port: None,
677 solid_commit_lag_threshold: Parameters::default_solid_commit_lag_threshold(),
678 shard_budget_per_authority: Parameters::default_shard_budget_per_authority(),
679 max_fast_commit_sync_transaction_bytes:
680 Parameters::default_max_fast_commit_sync_transaction_bytes(),
681 }
682 }
683}
684
685#[derive(Clone, Debug, Deserialize, Serialize)]
686pub struct TonicParameters {
687 /// Keepalive interval and timeouts for both client and server.
688 ///
689 /// If unspecified, this will default to 5s.
690 #[serde(default = "TonicParameters::default_keepalive_interval")]
691 pub keepalive_interval: Duration,
692
693 /// Size of various per-connection buffers.
694 ///
695 /// If unspecified, this will default to 32MiB.
696 #[serde(default = "TonicParameters::default_connection_buffer_size")]
697 pub connection_buffer_size: usize,
698
699 /// Response messages over this wire size, prefix plus compressed payload,
700 /// increment a counter.
701 ///
702 /// If unspecified, this will default to 16MiB.
703 #[serde(default = "TonicParameters::default_excessive_message_size")]
704 pub excessive_message_size: usize,
705
706 /// Hard message size limit for both requests and responses.
707 /// This value is higher than strictly necessary, to allow overheads.
708 /// Message size targets and soft limits are computed based on this value.
709 ///
710 /// If unspecified, this will default to 64MiB.
711 #[serde(default = "TonicParameters::default_message_size_limit")]
712 pub message_size_limit: usize,
713
714 /// Maximum number of concurrent HTTP/2 streams a peer may open on a single
715 /// connection. Bounds per-connection request fan-out.
716 ///
717 /// If unspecified, this will default to 64. `0` disables the limit, leaving
718 /// the transport default.
719 #[serde(default = "TonicParameters::default_max_concurrent_streams")]
720 pub max_concurrent_streams: u32,
721
722 /// Server-side fallback deadline for requests that omit a `grpc-timeout`
723 /// header. The long-lived block-subscription stream is always exempt.
724 ///
725 /// If unspecified, this will default to 120s. A zero duration disables the
726 /// fallback deadline.
727 #[serde(default = "TonicParameters::default_request_timeout")]
728 pub request_timeout: Duration,
729
730 /// Hard size limit for request messages: inbound requests when decoding
731 /// and outbound requests when encoding. Consensus requests are small (ref
732 /// lists); large payloads belong to responses, bounded by
733 /// `message_size_limit`. A smaller request bound shrinks the memory a
734 /// single in-flight request can pin before its handler runs.
735 ///
736 /// If unspecified, this will default to 1MiB. `0` falls back to
737 /// `message_size_limit`.
738 #[serde(
739 default = "TonicParameters::default_max_request_message_size",
740 alias = "max_inbound_message_size"
741 )]
742 pub max_request_message_size: usize,
743
744 /// Per-peer, per-RPC admission caps for the inbound consensus server.
745 #[serde(default)]
746 pub admission: AdmissionParameters,
747
748 /// Deadline for receiving the request message that opens a block
749 /// subscription stream. A peer that opens the stream and withholds the
750 /// request is disconnected once it expires; the stream itself stays exempt
751 /// from `request_timeout`.
752 ///
753 /// If unspecified, this will default to 30s. A zero duration disables the
754 /// deadline.
755 #[serde(default = "TonicParameters::default_subscribe_request_timeout")]
756 pub subscribe_request_timeout: Duration,
757}
758
759impl TonicParameters {
760 /// Hard size limit for request messages, `message_size_limit` when
761 /// `max_request_message_size` is `0`.
762 pub fn request_message_size_limit(&self) -> usize {
763 if self.max_request_message_size == 0 {
764 self.message_size_limit
765 } else {
766 self.max_request_message_size
767 }
768 }
769
770 fn default_keepalive_interval() -> Duration {
771 Duration::from_secs(5)
772 }
773
774 fn default_connection_buffer_size() -> usize {
775 32 << 20
776 }
777
778 fn default_excessive_message_size() -> usize {
779 16 << 20
780 }
781
782 fn default_message_size_limit() -> usize {
783 64 << 20
784 }
785
786 fn default_max_concurrent_streams() -> u32 {
787 64
788 }
789
790 fn default_request_timeout() -> Duration {
791 Duration::from_secs(120)
792 }
793
794 fn default_max_request_message_size() -> usize {
795 1 << 20
796 }
797
798 fn default_subscribe_request_timeout() -> Duration {
799 Duration::from_secs(30)
800 }
801}
802
803impl Default for TonicParameters {
804 fn default() -> Self {
805 Self {
806 keepalive_interval: TonicParameters::default_keepalive_interval(),
807 connection_buffer_size: TonicParameters::default_connection_buffer_size(),
808 excessive_message_size: TonicParameters::default_excessive_message_size(),
809 message_size_limit: TonicParameters::default_message_size_limit(),
810 max_concurrent_streams: TonicParameters::default_max_concurrent_streams(),
811 request_timeout: TonicParameters::default_request_timeout(),
812 max_request_message_size: TonicParameters::default_max_request_message_size(),
813 admission: AdmissionParameters::default(),
814 subscribe_request_timeout: TonicParameters::default_subscribe_request_timeout(),
815 }
816 }
817}
818
819/// Per-peer, per-RPC concurrency caps for the inbound consensus gRPC server.
820///
821/// Each cap bounds how many concurrent requests of one RPC group a single
822/// committee peer (keyed on its authenticated authority index) may have in
823/// flight; a peer cannot consume another peer's budget. These are local,
824/// non-protocol parameters — heterogeneous values across authorities are safe,
825/// so they can be rolled out and tuned per node.
826///
827/// The defaults are sized for ~100-validator committees and the local
828/// synchronizer fan-out toward one server. `0` turns a cap off; each cap is
829/// checked on its own.
830#[derive(Clone, Debug, Deserialize, Serialize)]
831pub struct AdmissionParameters {
832 /// Max concurrent block-subscription streams per peer.
833 ///
834 /// If unspecified, this will default to 2.
835 #[serde(default = "AdmissionParameters::default_max_subscriptions_per_peer")]
836 pub max_subscriptions_per_peer: u32,
837
838 /// Max concurrent header fetches per peer
839 /// (`fetch_block_headers` + `fetch_latest_block_headers`).
840 ///
841 /// If unspecified, this will default to 32.
842 #[serde(default = "AdmissionParameters::default_max_header_fetches_per_peer")]
843 pub max_header_fetches_per_peer: u32,
844
845 /// Max concurrent transaction fetches per peer (`fetch_transactions`).
846 ///
847 /// If unspecified, this will default to 16.
848 #[serde(default = "AdmissionParameters::default_max_transaction_fetches_per_peer")]
849 pub max_transaction_fetches_per_peer: u32,
850
851 /// Max concurrent commit fetches per peer
852 /// (`fetch_commits` + `fetch_commits_and_transactions`).
853 ///
854 /// If unspecified, this will default to 8.
855 #[serde(default = "AdmissionParameters::default_max_commit_fetches_per_peer")]
856 pub max_commit_fetches_per_peer: u32,
857
858 /// Max concurrent commit fetches across all peers, beyond which a peer is
859 /// still granted its first. A fast commit-sync response holds its commits
860 /// and certifier headers until it has been sent, and reads its transactions
861 /// from the store while it is being sent, so this caps what serving them
862 /// can cost the node at once, short of one response per peer.
863 ///
864 /// If unspecified, this will default to 16.
865 #[serde(default = "AdmissionParameters::default_max_commit_fetches_total")]
866 pub max_commit_fetches_total: u32,
867}
868
869impl AdmissionParameters {
870 fn default_max_subscriptions_per_peer() -> u32 {
871 2
872 }
873
874 fn default_max_header_fetches_per_peer() -> u32 {
875 32
876 }
877
878 fn default_max_transaction_fetches_per_peer() -> u32 {
879 16
880 }
881
882 fn default_max_commit_fetches_per_peer() -> u32 {
883 Parameters::default_commit_sync_parallel_fetches() as u32
884 }
885
886 fn default_max_commit_fetches_total() -> u32 {
887 2 * AdmissionParameters::default_max_commit_fetches_per_peer()
888 }
889}
890
891impl Default for AdmissionParameters {
892 fn default() -> Self {
893 Self {
894 max_subscriptions_per_peer: AdmissionParameters::default_max_subscriptions_per_peer(),
895 max_header_fetches_per_peer: AdmissionParameters::default_max_header_fetches_per_peer(),
896 max_transaction_fetches_per_peer:
897 AdmissionParameters::default_max_transaction_fetches_per_peer(),
898 max_commit_fetches_per_peer: AdmissionParameters::default_max_commit_fetches_per_peer(),
899 max_commit_fetches_total: AdmissionParameters::default_max_commit_fetches_total(),
900 }
901 }
902}