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 /// Sustained spacing between own blocks: long-run production never exceeds
32 /// one block per `min_block_delay`. This avoids generating too many rounds
33 /// when latency is low. This is especially necessary for tests running
34 /// locally. If setting a non-default value, it should be set low enough
35 /// to avoid reducing round rate and increasing latency in realistic and
36 /// distributed configurations.
37 #[serde(default = "Parameters::default_min_block_delay")]
38 pub min_block_delay: Duration,
39
40 /// Soft counterpart of `leader_timeout`: after this duration we are
41 /// willing to propose a block even without a strong-vote quorum, to avoid
42 /// liveness stalls when leader data is slow to propagate. Fires earlier
43 /// than `leader_timeout` and does not force block creation on its own.
44 #[serde(default = "Parameters::default_soft_leader_timeout")]
45 pub soft_leader_timeout: Duration,
46
47 /// Window bounding own block production together with `min_block_delay`:
48 /// idle time accrues budget for bursts of up to `block_rate_window /
49 /// min_block_delay` back-to-back blocks, letting a validator that fell
50 /// behind catch up on rounds instead of skipping them. Set at or below
51 /// `min_block_delay` to disable bursting (fixed spacing between blocks).
52 #[serde(default = "Parameters::default_block_rate_window")]
53 pub block_rate_window: Duration,
54
55 /// Number of block headers to fetch per commit sync request.
56 #[serde(default = "Parameters::default_max_headers_per_commit_sync_fetch")]
57 pub max_headers_per_commit_sync_fetch: usize,
58
59 /// Number of transactions to fetch per commit sync request.
60 #[serde(default = "Parameters::default_max_transactions_per_commit_sync_fetch")]
61 pub max_transactions_per_commit_sync_fetch: usize,
62
63 /// Number of block headers to fetch per header sync (periodic or live)
64 /// request.
65 #[serde(default = "Parameters::default_max_headers_per_header_sync_fetch")]
66 pub max_headers_per_header_sync_fetch: usize,
67
68 /// Number of transactions to fetch per transaction sync request.
69 #[serde(default = "Parameters::default_max_transactions_per_transaction_sync_fetch")]
70 pub max_transactions_per_transaction_sync_fetch: usize,
71
72 /// Time to wait during node start up until the node has synced the last
73 /// proposed block via the network peers. When set to `0` the sync
74 /// mechanism is disabled. This property is meant to be used for amnesia
75 /// recovery.
76 #[serde(default = "Parameters::default_sync_last_known_own_block_timeout")]
77 pub sync_last_known_own_block_timeout: Duration,
78
79 /// The number of rounds of blocks to be kept in the Dag state cache per
80 /// authority. The larger the number the more the blocks that will be
81 /// kept in memory allowing minimising any potential disk access.
82 /// Value should be at minimum 50 rounds to ensure node performance, but
83 /// being too large can be expensive in memory usage.
84 #[serde(default = "Parameters::default_dag_state_cached_rounds")]
85 pub dag_state_cached_rounds: u32,
86
87 /// Rounds a header from a far-future-bounded source may lead the locally
88 /// accepted frontier, in addition to `dag_state_cached_rounds`, before it
89 /// is dropped as too far ahead to connect.
90 #[serde(default = "Parameters::default_peer_round_ahead_margin")]
91 pub peer_round_ahead_margin: u32,
92
93 // Number of authorities commit syncer fetches in parallel.
94 // Both commits in a range and blocks referenced by the commits are fetched per authority.
95 #[serde(default = "Parameters::default_commit_sync_parallel_fetches")]
96 pub commit_sync_parallel_fetches: usize,
97
98 // Number of commits to fetch in a batch, also the maximum number of commits returned per
99 // fetch. If this value is set too small, fetching becomes inefficient.
100 // If this value is set too large, it can result in load imbalance and stragglers.
101 #[serde(default = "Parameters::default_commit_sync_batch_size")]
102 pub commit_sync_batch_size: u32,
103
104 // This affects the maximum number of commit batches being fetched, and those fetched but not
105 // processed as consensus output, before throttling of outgoing commit fetches starts.
106 #[serde(default = "Parameters::default_commit_sync_batches_ahead")]
107 pub commit_sync_batches_ahead: usize,
108
109 /// Maximum number of commits scanned and replayed per batch during
110 /// recovery, bounding peak memory when a large unprocessed range is
111 /// replayed at startup.
112 #[serde(default = "Parameters::default_commit_recovery_batch_size")]
113 pub commit_recovery_batch_size: u32,
114
115 /// Maximum number of headers to be included in a bundle. Headers exceeding
116 /// the max allowed limit will be truncated.
117 #[serde(default = "Parameters::default_max_headers_per_bundle")]
118 pub max_headers_per_bundle: usize,
119
120 /// Maximum number of transaction shards to be included in a bundle. Shards
121 /// exceeding the max allowed limit will be truncated.
122 #[serde(default = "Parameters::default_max_shards_per_bundle")]
123 pub max_shards_per_bundle: usize,
124
125 /// Tonic network settings.
126 #[serde(default = "TonicParameters::default")]
127 pub tonic: TonicParameters,
128
129 // Number of commits to fetch in a batch for fast commit syncer, also the maximum number of
130 // commits returned per fetch. If this value is set too small, fetching becomes
131 // inefficient. If this value is set too large, it can result in load imbalance and
132 // stragglers.
133 #[serde(default = "Parameters::default_fast_commit_sync_batch_size")]
134 pub fast_commit_sync_batch_size: u32,
135
136 // Gap threshold for switching between commit syncers. When the gap between quorum and local
137 // commit index is larger than this threshold, FastCommitSyncer fetches. Otherwise,
138 // CommitSyncer fetches.
139 #[serde(default = "Parameters::default_commit_sync_gap_threshold")]
140 pub commit_sync_gap_threshold: u32,
141
142 /// Enable FastCommitSyncer for faster recovery from large commit gaps.
143 /// Enabled by default; operators can disable it locally if bugs are
144 /// discovered.
145 #[serde(default = "Parameters::default_enable_fast_commit_syncer")]
146 pub enable_fast_commit_syncer: bool,
147
148 /// Ask commit-sync peers that have voted for the end of the requested
149 /// range before those that have not, since a vote means the peer has
150 /// solidified every commit in the range. Peers without an observed vote
151 /// are ordered behind; each fetch round tries a bounded number of peers,
152 /// so on a committee larger than that bound they can stay outside the
153 /// round until their votes are observed. Enabled by default; disabling it
154 /// restores a plain uniform order.
155 #[serde(default = "Parameters::default_enable_commit_sync_peer_selection_by_commit_votes")]
156 pub enable_commit_sync_peer_selection_by_commit_votes: bool,
157
158 /// Enable adaptive acknowledgment filtering for StarfishSpeed.
159 /// Local heuristic that drops acks for authorities persistently blamed
160 /// by recent strong-vote masks. Effective only when the protocol-level
161 /// `consensus_starfish_speed` flag is also on. Enabled by default;
162 /// operators can disable it locally without a protocol change.
163 #[serde(default = "Parameters::default_enable_starfish_speed_adaptive_acknowledgments")]
164 pub enable_starfish_speed_adaptive_acknowledgments: bool,
165
166 /// Prefer more responsive peers when the transactions synchronizer, the
167 /// commit syncer and the header synchronizer select peers to fetch from.
168 /// Responses are verified the same way regardless, so it cannot affect
169 /// safety. Enabled by default; disabling it restores the previous
170 /// selection: for the transactions synchronizer a uniform random order
171 /// that excludes the most recently failed peers (up to less than f+1 by
172 /// stake), and for the commit syncer and the header synchronizer a uniform
173 /// random order.
174 #[serde(default = "Parameters::default_enable_peer_responsiveness_ranking")]
175 pub enable_peer_responsiveness_ranking: bool,
176
177 /// Port for the DAG visualizer gRPC server (localhost only).
178 /// When set, starts a debugging server for real-time DAG visualization.
179 /// Only has an effect when the `dag-visualizer` feature is compiled in.
180 /// Disabled by default (None).
181 #[serde(default)]
182 pub dag_visualizer_port: Option<u16>,
183}
184
185impl Parameters {
186 /// Threshold for the number of commits sent to the consumer but not yet
187 /// handled, above which commit producers (commit syncers, commit observer
188 /// recovery) pause to let the consumer catch up.
189 pub fn unhandled_commits_threshold(&self) -> u32 {
190 self.commit_sync_batch_size * (self.commit_sync_batches_ahead as u32)
191 }
192
193 pub(crate) fn default_leader_timeout() -> Duration {
194 Duration::from_millis(200)
195 }
196
197 pub(crate) fn default_min_block_delay() -> Duration {
198 if cfg!(msim) || std::env::var("__TEST_ONLY_CONSENSUS_USE_LONG_MIN_BLOCK_DELAY").is_ok() {
199 // Checkpoint building and execution cannot keep up with high commit rate in
200 // simtests, leading to long reconfiguration delays. This is because
201 // simtest is single threaded, and spending too much time in
202 // consensus can lead to starvation elsewhere.
203 Duration::from_millis(400)
204 } else if cfg!(test) {
205 // Avoid excessive CPU, data and logs in tests.
206 Duration::from_millis(250)
207 } else {
208 // For production, use min delay between block being set to 50ms, reducing the
209 // block rate to 20 blocks/sec
210 Duration::from_millis(50)
211 }
212 }
213
214 pub(crate) fn default_soft_leader_timeout() -> Duration {
215 Duration::from_millis(5)
216 }
217
218 pub(crate) fn default_block_rate_window() -> Duration {
219 Duration::from_secs(2)
220 }
221
222 /// Burst capacity: maximum number of own blocks within `block_rate_window`
223 /// (40 in production, 5 in msim, 8 in tests with the default window).
224 pub fn block_rate_burst(&self) -> u64 {
225 let interval_ms = self.min_block_delay.as_millis().max(1) as u64;
226 (self.block_rate_window.as_millis() as u64 / interval_ms).max(1)
227 }
228
229 /// Highest round a header from a far-future-bounded source may have,
230 /// relative to the accepted `frontier`, to still be close enough to
231 /// connect; headers above this are too far ahead and dropped.
232 pub fn far_future_round_ceiling(&self, frontier: u32) -> u32 {
233 frontier
234 .saturating_add(self.dag_state_cached_rounds)
235 .saturating_add(self.peer_round_ahead_margin)
236 }
237
238 /// Maximum number of block headers served per fetch request, depending on
239 /// whether the request comes from commit sync or the header synchronizer.
240 pub fn max_headers_per_fetch(&self, commit_sync: bool) -> usize {
241 if commit_sync {
242 self.max_headers_per_commit_sync_fetch
243 } else {
244 self.max_headers_per_header_sync_fetch
245 }
246 }
247
248 /// Validates local consensus parameters, rejecting zero values that can
249 /// lead to synchronization problems. Returns a description of the first
250 /// offending field.
251 pub fn validate(&self) -> Result<(), String> {
252 let positive_fields = [
253 (
254 "max_headers_per_commit_sync_fetch",
255 self.max_headers_per_commit_sync_fetch as u128,
256 ),
257 (
258 "max_transactions_per_commit_sync_fetch",
259 self.max_transactions_per_commit_sync_fetch as u128,
260 ),
261 (
262 "max_headers_per_header_sync_fetch",
263 self.max_headers_per_header_sync_fetch as u128,
264 ),
265 (
266 "max_transactions_per_transaction_sync_fetch",
267 self.max_transactions_per_transaction_sync_fetch as u128,
268 ),
269 (
270 "dag_state_cached_rounds",
271 self.dag_state_cached_rounds as u128,
272 ),
273 (
274 "commit_sync_parallel_fetches",
275 self.commit_sync_parallel_fetches as u128,
276 ),
277 (
278 "commit_sync_batch_size",
279 self.commit_sync_batch_size as u128,
280 ),
281 (
282 "commit_recovery_batch_size",
283 self.commit_recovery_batch_size as u128,
284 ),
285 (
286 "commit_sync_batches_ahead",
287 self.commit_sync_batches_ahead as u128,
288 ),
289 (
290 "max_headers_per_bundle",
291 self.max_headers_per_bundle as u128,
292 ),
293 ("max_shards_per_bundle", self.max_shards_per_bundle as u128),
294 (
295 "fast_commit_sync_batch_size",
296 self.fast_commit_sync_batch_size as u128,
297 ),
298 (
299 "tonic.connection_buffer_size",
300 self.tonic.connection_buffer_size as u128,
301 ),
302 (
303 "tonic.excessive_message_size",
304 self.tonic.excessive_message_size as u128,
305 ),
306 (
307 "tonic.message_size_limit",
308 self.tonic.message_size_limit as u128,
309 ),
310 (
311 "tonic.keepalive_interval",
312 self.tonic.keepalive_interval.as_nanos(),
313 ),
314 ];
315 for (name, value) in positive_fields {
316 if value == 0 {
317 return Err(format!("{name} must be positive"));
318 }
319 }
320 Ok(())
321 }
322
323 // Maximum number of block headers to fetch per commit sync request.
324 pub(crate) fn default_max_headers_per_commit_sync_fetch() -> usize {
325 if cfg!(msim) {
326 // Exercise hitting blocks per fetch limit.
327 10
328 } else {
329 1000
330 }
331 }
332
333 // Maximum number of transactions to fetch per commit sync request.
334 pub(crate) fn default_max_transactions_per_commit_sync_fetch() -> usize {
335 if cfg!(msim) {
336 // Exercise hitting transactions per fetch limit.
337 10
338 } else {
339 1000
340 }
341 }
342
343 // Maximum number of block headers to fetch per header sync (periodic or
344 // live) request.
345 pub(crate) fn default_max_headers_per_header_sync_fetch() -> usize {
346 if cfg!(msim) {
347 // Exercise hitting blocks per fetch limit.
348 10
349 } else {
350 // TODO: This might should match the value of block headers in the bundle.
351 100
352 }
353 }
354
355 // Maximum number of transactions to fetch per transaction sync request.
356 pub(crate) fn default_max_transactions_per_transaction_sync_fetch() -> usize {
357 if cfg!(msim) { 10 } else { 1000 }
358 }
359
360 pub(crate) fn default_sync_last_known_own_block_timeout() -> Duration {
361 if cfg!(msim) {
362 Duration::from_millis(500)
363 } else {
364 // Here we prioritise liveness over the complete de-risking of block
365 // equivocation. 5 seconds in the majority of cases should be good
366 // enough for this given a healthy network.
367 Duration::from_secs(5)
368 }
369 }
370
371 pub(crate) fn default_dag_state_cached_rounds() -> u32 {
372 if cfg!(msim) {
373 // Exercise reading blocks from store.
374 5
375 } else {
376 500
377 }
378 }
379
380 pub(crate) fn default_peer_round_ahead_margin() -> u32 {
381 1000
382 }
383
384 pub(crate) fn default_commit_sync_parallel_fetches() -> usize {
385 8
386 }
387
388 pub(crate) fn default_commit_sync_batch_size() -> u32 {
389 if cfg!(msim) {
390 // Exercise commit sync.
391 5
392 } else {
393 100
394 }
395 }
396
397 pub(crate) fn default_commit_recovery_batch_size() -> u32 {
398 if cfg!(msim) { 3 } else { 250 }
399 }
400
401 pub(crate) fn default_commit_sync_batches_ahead() -> usize {
402 // This is set to be a multiple of default commit_sync_parallel_fetches to allow
403 // fetching ahead, while keeping the total number of inflight fetches
404 // and unprocessed fetched commits limited.
405 32
406 }
407
408 pub(crate) fn default_max_headers_per_bundle() -> usize {
409 150
410 }
411
412 pub(crate) fn default_max_shards_per_bundle() -> usize {
413 150
414 }
415
416 pub(crate) fn default_fast_commit_sync_batch_size() -> u32 {
417 if cfg!(msim) {
418 // Exercise fast commit sync.
419 5
420 } else {
421 // Sized so that commit_sync_parallel_fetches ranges fit under the
422 // unhandled-commits threshold (8 x 400 <= 3200), letting fast sync
423 // actually run its fetches in parallel. The server chunks larger
424 // responses across multiple messages either way.
425 400
426 }
427 }
428
429 pub(crate) fn default_commit_sync_gap_threshold() -> u32 {
430 if cfg!(msim) {
431 // Use smaller threshold for testing.
432 10
433 } else {
434 // When gap > 1000, FastCommitSyncer is more efficient.
435 // When gap <= 1000, CommitSyncer handles incremental sync.
436 1000
437 }
438 }
439
440 pub(crate) fn default_enable_fast_commit_syncer() -> bool {
441 // Enabled by default. Operators can disable it locally if bugs are discovered,
442 // without waiting for a protocol upgrade.
443 true
444 }
445
446 pub(crate) fn default_enable_commit_sync_peer_selection_by_commit_votes() -> bool {
447 // Enabled by default. Ordering only, so it cannot diverge consensus.
448 true
449 }
450
451 pub(crate) fn default_enable_starfish_speed_adaptive_acknowledgments() -> bool {
452 true
453 }
454
455 pub(crate) fn default_enable_peer_responsiveness_ranking() -> bool {
456 true
457 }
458}
459
460impl Default for Parameters {
461 fn default() -> Self {
462 Self {
463 db_path: PathBuf::default(),
464 leader_timeout: Parameters::default_leader_timeout(),
465 min_block_delay: Parameters::default_min_block_delay(),
466 soft_leader_timeout: Parameters::default_soft_leader_timeout(),
467 block_rate_window: Parameters::default_block_rate_window(),
468 max_headers_per_commit_sync_fetch:
469 Parameters::default_max_headers_per_commit_sync_fetch(),
470 max_transactions_per_commit_sync_fetch:
471 Parameters::default_max_transactions_per_commit_sync_fetch(),
472 max_headers_per_header_sync_fetch:
473 Parameters::default_max_headers_per_header_sync_fetch(),
474 max_transactions_per_transaction_sync_fetch:
475 Parameters::default_max_transactions_per_transaction_sync_fetch(),
476 sync_last_known_own_block_timeout:
477 Parameters::default_sync_last_known_own_block_timeout(),
478 dag_state_cached_rounds: Parameters::default_dag_state_cached_rounds(),
479 peer_round_ahead_margin: Parameters::default_peer_round_ahead_margin(),
480 commit_sync_parallel_fetches: Parameters::default_commit_sync_parallel_fetches(),
481 commit_sync_batch_size: Parameters::default_commit_sync_batch_size(),
482 commit_sync_batches_ahead: Parameters::default_commit_sync_batches_ahead(),
483 commit_recovery_batch_size: Parameters::default_commit_recovery_batch_size(),
484 max_headers_per_bundle: Parameters::default_max_headers_per_bundle(),
485 max_shards_per_bundle: Parameters::default_max_shards_per_bundle(),
486 tonic: TonicParameters::default(),
487 fast_commit_sync_batch_size: Parameters::default_fast_commit_sync_batch_size(),
488 commit_sync_gap_threshold: Parameters::default_commit_sync_gap_threshold(),
489 enable_fast_commit_syncer: Parameters::default_enable_fast_commit_syncer(),
490 enable_commit_sync_peer_selection_by_commit_votes:
491 Parameters::default_enable_commit_sync_peer_selection_by_commit_votes(),
492 enable_starfish_speed_adaptive_acknowledgments:
493 Parameters::default_enable_starfish_speed_adaptive_acknowledgments(),
494 enable_peer_responsiveness_ranking:
495 Parameters::default_enable_peer_responsiveness_ranking(),
496 dag_visualizer_port: None,
497 }
498 }
499}
500
501#[derive(Clone, Debug, Deserialize, Serialize)]
502pub struct TonicParameters {
503 /// Keepalive interval and timeouts for both client and server.
504 ///
505 /// If unspecified, this will default to 5s.
506 #[serde(default = "TonicParameters::default_keepalive_interval")]
507 pub keepalive_interval: Duration,
508
509 /// Size of various per-connection buffers.
510 ///
511 /// If unspecified, this will default to 32MiB.
512 #[serde(default = "TonicParameters::default_connection_buffer_size")]
513 pub connection_buffer_size: usize,
514
515 /// Messages over this size threshold will increment a counter.
516 ///
517 /// If unspecified, this will default to 16MiB.
518 #[serde(default = "TonicParameters::default_excessive_message_size")]
519 pub excessive_message_size: usize,
520
521 /// Hard message size limit for both requests and responses.
522 /// This value is higher than strictly necessary, to allow overheads.
523 /// Message size targets and soft limits are computed based on this value.
524 ///
525 /// If unspecified, this will default to 1GiB.
526 #[serde(default = "TonicParameters::default_message_size_limit")]
527 pub message_size_limit: usize,
528
529 /// Maximum number of concurrent HTTP/2 streams a peer may open on a single
530 /// connection. Bounds per-connection request fan-out.
531 ///
532 /// If unspecified, this will default to 64. `0` disables the limit, leaving
533 /// the transport default.
534 #[serde(default = "TonicParameters::default_max_concurrent_streams")]
535 pub max_concurrent_streams: u32,
536
537 /// Server-side fallback deadline for requests that omit a `grpc-timeout`
538 /// header. The long-lived block-subscription stream is always exempt.
539 ///
540 /// If unspecified, this will default to 120s. A zero duration disables the
541 /// fallback deadline.
542 #[serde(default = "TonicParameters::default_request_timeout")]
543 pub request_timeout: Duration,
544
545 /// Hard size limit for inbound (decoded) requests. Consensus requests are
546 /// small (ref lists); large payloads belong to responses, bounded by
547 /// `message_size_limit`. A smaller inbound bound shrinks the memory a
548 /// single in-flight request can pin before its handler runs.
549 ///
550 /// If unspecified, this will default to 1MiB. `0` falls back to
551 /// `message_size_limit`.
552 #[serde(default = "TonicParameters::default_max_inbound_message_size")]
553 pub max_inbound_message_size: usize,
554
555 /// Per-peer, per-RPC admission caps for the inbound consensus server.
556 #[serde(default)]
557 pub admission: AdmissionParameters,
558
559 /// Deadline for receiving the request message that opens a block
560 /// subscription stream. A peer that opens the stream and withholds the
561 /// request is disconnected once it expires; the stream itself stays exempt
562 /// from `request_timeout`.
563 ///
564 /// If unspecified, this will default to 30s. A zero duration disables the
565 /// deadline.
566 #[serde(default = "TonicParameters::default_subscribe_request_timeout")]
567 pub subscribe_request_timeout: Duration,
568}
569
570impl TonicParameters {
571 fn default_keepalive_interval() -> Duration {
572 Duration::from_secs(5)
573 }
574
575 fn default_connection_buffer_size() -> usize {
576 32 << 20
577 }
578
579 fn default_excessive_message_size() -> usize {
580 16 << 20
581 }
582
583 fn default_message_size_limit() -> usize {
584 64 << 20
585 }
586
587 fn default_max_concurrent_streams() -> u32 {
588 64
589 }
590
591 fn default_request_timeout() -> Duration {
592 Duration::from_secs(120)
593 }
594
595 fn default_max_inbound_message_size() -> usize {
596 1 << 20
597 }
598
599 fn default_subscribe_request_timeout() -> Duration {
600 Duration::from_secs(30)
601 }
602}
603
604impl Default for TonicParameters {
605 fn default() -> Self {
606 Self {
607 keepalive_interval: TonicParameters::default_keepalive_interval(),
608 connection_buffer_size: TonicParameters::default_connection_buffer_size(),
609 excessive_message_size: TonicParameters::default_excessive_message_size(),
610 message_size_limit: TonicParameters::default_message_size_limit(),
611 max_concurrent_streams: TonicParameters::default_max_concurrent_streams(),
612 request_timeout: TonicParameters::default_request_timeout(),
613 max_inbound_message_size: TonicParameters::default_max_inbound_message_size(),
614 admission: AdmissionParameters::default(),
615 subscribe_request_timeout: TonicParameters::default_subscribe_request_timeout(),
616 }
617 }
618}
619
620/// Per-peer, per-RPC concurrency caps for the inbound consensus gRPC server.
621///
622/// Each cap bounds how many concurrent requests of one RPC group a single
623/// committee peer (keyed on its authenticated authority index) may have in
624/// flight; a peer cannot consume another peer's budget. These are local,
625/// non-protocol parameters — heterogeneous values across authorities are safe,
626/// so they can be rolled out and tuned per node.
627///
628/// The defaults are sized for ~100-validator committees and the local
629/// synchronizer fan-out toward one server. `0` disables admission for that
630/// group.
631#[derive(Clone, Debug, Deserialize, Serialize)]
632pub struct AdmissionParameters {
633 /// Max concurrent block-subscription streams per peer.
634 ///
635 /// If unspecified, this will default to 2.
636 #[serde(default = "AdmissionParameters::default_max_subscriptions_per_peer")]
637 pub max_subscriptions_per_peer: u32,
638
639 /// Max concurrent header fetches per peer
640 /// (`fetch_block_headers` + `fetch_latest_block_headers`).
641 ///
642 /// If unspecified, this will default to 32.
643 #[serde(default = "AdmissionParameters::default_max_header_fetches_per_peer")]
644 pub max_header_fetches_per_peer: u32,
645
646 /// Max concurrent transaction fetches per peer (`fetch_transactions`).
647 ///
648 /// If unspecified, this will default to 16.
649 #[serde(default = "AdmissionParameters::default_max_transaction_fetches_per_peer")]
650 pub max_transaction_fetches_per_peer: u32,
651
652 /// Max concurrent commit fetches per peer
653 /// (`fetch_commits` + `fetch_commits_and_transactions`).
654 ///
655 /// If unspecified, this will default to 8.
656 #[serde(default = "AdmissionParameters::default_max_commit_fetches_per_peer")]
657 pub max_commit_fetches_per_peer: u32,
658}
659
660impl AdmissionParameters {
661 fn default_max_subscriptions_per_peer() -> u32 {
662 2
663 }
664
665 fn default_max_header_fetches_per_peer() -> u32 {
666 32
667 }
668
669 fn default_max_transaction_fetches_per_peer() -> u32 {
670 16
671 }
672
673 fn default_max_commit_fetches_per_peer() -> u32 {
674 Parameters::default_commit_sync_parallel_fetches() as u32
675 }
676}
677
678impl Default for AdmissionParameters {
679 fn default() -> Self {
680 Self {
681 max_subscriptions_per_peer: AdmissionParameters::default_max_subscriptions_per_peer(),
682 max_header_fetches_per_peer: AdmissionParameters::default_max_header_fetches_per_peer(),
683 max_transaction_fetches_per_peer:
684 AdmissionParameters::default_max_transaction_fetches_per_peer(),
685 max_commit_fetches_per_peer: AdmissionParameters::default_max_commit_fetches_per_peer(),
686 }
687 }
688}