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 /// Enable adaptive acknowledgment filtering for StarfishSpeed.
149 /// Local heuristic that drops acks for authorities persistently blamed
150 /// by recent strong-vote masks. Effective only when the protocol-level
151 /// `consensus_starfish_speed` flag is also on. Enabled by default;
152 /// operators can disable it locally without a protocol change.
153 #[serde(default = "Parameters::default_enable_starfish_speed_adaptive_acknowledgments")]
154 pub enable_starfish_speed_adaptive_acknowledgments: bool,
155
156 /// Prefer more responsive peers when the transactions synchronizer selects
157 /// peers to fetch from. Ranking is a preference within the already-eligible
158 /// candidate set, not a change of eligibility, so it cannot affect safety.
159 /// Enabled by default; disabling it restores the previous selection: a
160 /// uniform random order that excludes the most recently failed peers (up
161 /// to less than f+1 by stake).
162 #[serde(default = "Parameters::default_enable_peer_responsiveness_ranking")]
163 pub enable_peer_responsiveness_ranking: bool,
164
165 /// Port for the DAG visualizer gRPC server (localhost only).
166 /// When set, starts a debugging server for real-time DAG visualization.
167 /// Only has an effect when the `dag-visualizer` feature is compiled in.
168 /// Disabled by default (None).
169 #[serde(default)]
170 pub dag_visualizer_port: Option<u16>,
171}
172
173impl Parameters {
174 /// Threshold for the number of commits sent to the consumer but not yet
175 /// handled, above which commit producers (commit syncers, commit observer
176 /// recovery) pause to let the consumer catch up.
177 pub fn unhandled_commits_threshold(&self) -> u32 {
178 self.commit_sync_batch_size * (self.commit_sync_batches_ahead as u32)
179 }
180
181 pub(crate) fn default_leader_timeout() -> Duration {
182 Duration::from_millis(200)
183 }
184
185 pub(crate) fn default_min_block_delay() -> Duration {
186 if cfg!(msim) || std::env::var("__TEST_ONLY_CONSENSUS_USE_LONG_MIN_BLOCK_DELAY").is_ok() {
187 // Checkpoint building and execution cannot keep up with high commit rate in
188 // simtests, leading to long reconfiguration delays. This is because
189 // simtest is single threaded, and spending too much time in
190 // consensus can lead to starvation elsewhere.
191 Duration::from_millis(400)
192 } else if cfg!(test) {
193 // Avoid excessive CPU, data and logs in tests.
194 Duration::from_millis(250)
195 } else {
196 // For production, use min delay between block being set to 50ms, reducing the
197 // block rate to 20 blocks/sec
198 Duration::from_millis(50)
199 }
200 }
201
202 pub(crate) fn default_soft_leader_timeout() -> Duration {
203 Duration::from_millis(5)
204 }
205
206 pub(crate) fn default_block_rate_window() -> Duration {
207 Duration::from_secs(2)
208 }
209
210 /// Burst capacity: maximum number of own blocks within `block_rate_window`
211 /// (40 in production, 5 in msim, 8 in tests with the default window).
212 pub fn block_rate_burst(&self) -> u64 {
213 let interval_ms = self.min_block_delay.as_millis().max(1) as u64;
214 (self.block_rate_window.as_millis() as u64 / interval_ms).max(1)
215 }
216
217 /// Highest round a header from a far-future-bounded source may have,
218 /// relative to the accepted `frontier`, to still be close enough to
219 /// connect; headers above this are too far ahead and dropped.
220 pub fn far_future_round_ceiling(&self, frontier: u32) -> u32 {
221 frontier
222 .saturating_add(self.dag_state_cached_rounds)
223 .saturating_add(self.peer_round_ahead_margin)
224 }
225
226 /// Maximum number of block headers served per fetch request, depending on
227 /// whether the request comes from commit sync or the header synchronizer.
228 pub fn max_headers_per_fetch(&self, commit_sync: bool) -> usize {
229 if commit_sync {
230 self.max_headers_per_commit_sync_fetch
231 } else {
232 self.max_headers_per_header_sync_fetch
233 }
234 }
235
236 /// Validates local consensus parameters, rejecting zero values that can
237 /// lead to synchronization problems. Returns a description of the first
238 /// offending field.
239 pub fn validate(&self) -> Result<(), String> {
240 let positive_fields = [
241 (
242 "max_headers_per_commit_sync_fetch",
243 self.max_headers_per_commit_sync_fetch as u128,
244 ),
245 (
246 "max_transactions_per_commit_sync_fetch",
247 self.max_transactions_per_commit_sync_fetch as u128,
248 ),
249 (
250 "max_headers_per_header_sync_fetch",
251 self.max_headers_per_header_sync_fetch as u128,
252 ),
253 (
254 "max_transactions_per_transaction_sync_fetch",
255 self.max_transactions_per_transaction_sync_fetch as u128,
256 ),
257 (
258 "dag_state_cached_rounds",
259 self.dag_state_cached_rounds as u128,
260 ),
261 (
262 "commit_sync_parallel_fetches",
263 self.commit_sync_parallel_fetches as u128,
264 ),
265 (
266 "commit_sync_batch_size",
267 self.commit_sync_batch_size as u128,
268 ),
269 (
270 "commit_recovery_batch_size",
271 self.commit_recovery_batch_size as u128,
272 ),
273 (
274 "commit_sync_batches_ahead",
275 self.commit_sync_batches_ahead as u128,
276 ),
277 (
278 "max_headers_per_bundle",
279 self.max_headers_per_bundle as u128,
280 ),
281 ("max_shards_per_bundle", self.max_shards_per_bundle as u128),
282 (
283 "fast_commit_sync_batch_size",
284 self.fast_commit_sync_batch_size as u128,
285 ),
286 (
287 "tonic.connection_buffer_size",
288 self.tonic.connection_buffer_size as u128,
289 ),
290 (
291 "tonic.excessive_message_size",
292 self.tonic.excessive_message_size as u128,
293 ),
294 (
295 "tonic.message_size_limit",
296 self.tonic.message_size_limit as u128,
297 ),
298 (
299 "tonic.keepalive_interval",
300 self.tonic.keepalive_interval.as_nanos(),
301 ),
302 ];
303 for (name, value) in positive_fields {
304 if value == 0 {
305 return Err(format!("{name} must be positive"));
306 }
307 }
308 Ok(())
309 }
310
311 // Maximum number of block headers to fetch per commit sync request.
312 pub(crate) fn default_max_headers_per_commit_sync_fetch() -> usize {
313 if cfg!(msim) {
314 // Exercise hitting blocks per fetch limit.
315 10
316 } else {
317 1000
318 }
319 }
320
321 // Maximum number of transactions to fetch per commit sync request.
322 pub(crate) fn default_max_transactions_per_commit_sync_fetch() -> usize {
323 if cfg!(msim) {
324 // Exercise hitting transactions per fetch limit.
325 10
326 } else {
327 1000
328 }
329 }
330
331 // Maximum number of block headers to fetch per header sync (periodic or
332 // live) request.
333 pub(crate) fn default_max_headers_per_header_sync_fetch() -> usize {
334 if cfg!(msim) {
335 // Exercise hitting blocks per fetch limit.
336 10
337 } else {
338 // TODO: This might should match the value of block headers in the bundle.
339 100
340 }
341 }
342
343 // Maximum number of transactions to fetch per transaction sync request.
344 pub(crate) fn default_max_transactions_per_transaction_sync_fetch() -> usize {
345 if cfg!(msim) { 10 } else { 1000 }
346 }
347
348 pub(crate) fn default_sync_last_known_own_block_timeout() -> Duration {
349 if cfg!(msim) {
350 Duration::from_millis(500)
351 } else {
352 // Here we prioritise liveness over the complete de-risking of block
353 // equivocation. 5 seconds in the majority of cases should be good
354 // enough for this given a healthy network.
355 Duration::from_secs(5)
356 }
357 }
358
359 pub(crate) fn default_dag_state_cached_rounds() -> u32 {
360 if cfg!(msim) {
361 // Exercise reading blocks from store.
362 5
363 } else {
364 500
365 }
366 }
367
368 pub(crate) fn default_peer_round_ahead_margin() -> u32 {
369 1000
370 }
371
372 pub(crate) fn default_commit_sync_parallel_fetches() -> usize {
373 8
374 }
375
376 pub(crate) fn default_commit_sync_batch_size() -> u32 {
377 if cfg!(msim) {
378 // Exercise commit sync.
379 5
380 } else {
381 100
382 }
383 }
384
385 pub(crate) fn default_commit_recovery_batch_size() -> u32 {
386 if cfg!(msim) { 3 } else { 250 }
387 }
388
389 pub(crate) fn default_commit_sync_batches_ahead() -> usize {
390 // This is set to be a multiple of default commit_sync_parallel_fetches to allow
391 // fetching ahead, while keeping the total number of inflight fetches
392 // and unprocessed fetched commits limited.
393 32
394 }
395
396 pub(crate) fn default_max_headers_per_bundle() -> usize {
397 150
398 }
399
400 pub(crate) fn default_max_shards_per_bundle() -> usize {
401 150
402 }
403
404 pub(crate) fn default_fast_commit_sync_batch_size() -> u32 {
405 if cfg!(msim) {
406 // Exercise fast commit sync.
407 5
408 } else {
409 // With ~10KB per commit and 4MB max message size, 1000 commits (~10MB) requires
410 // chunking. The server will chunk commits across multiple response messages.
411 1000
412 }
413 }
414
415 pub(crate) fn default_commit_sync_gap_threshold() -> u32 {
416 if cfg!(msim) {
417 // Use smaller threshold for testing.
418 10
419 } else {
420 // When gap > 1000, FastCommitSyncer is more efficient.
421 // When gap <= 1000, CommitSyncer handles incremental sync.
422 1000
423 }
424 }
425
426 pub(crate) fn default_enable_fast_commit_syncer() -> bool {
427 // Enabled by default. Operators can disable it locally if bugs are discovered,
428 // without waiting for a protocol upgrade.
429 true
430 }
431
432 pub(crate) fn default_enable_starfish_speed_adaptive_acknowledgments() -> bool {
433 true
434 }
435
436 pub(crate) fn default_enable_peer_responsiveness_ranking() -> bool {
437 true
438 }
439}
440
441impl Default for Parameters {
442 fn default() -> Self {
443 Self {
444 db_path: PathBuf::default(),
445 leader_timeout: Parameters::default_leader_timeout(),
446 min_block_delay: Parameters::default_min_block_delay(),
447 soft_leader_timeout: Parameters::default_soft_leader_timeout(),
448 block_rate_window: Parameters::default_block_rate_window(),
449 max_headers_per_commit_sync_fetch:
450 Parameters::default_max_headers_per_commit_sync_fetch(),
451 max_transactions_per_commit_sync_fetch:
452 Parameters::default_max_transactions_per_commit_sync_fetch(),
453 max_headers_per_header_sync_fetch:
454 Parameters::default_max_headers_per_header_sync_fetch(),
455 max_transactions_per_transaction_sync_fetch:
456 Parameters::default_max_transactions_per_transaction_sync_fetch(),
457 sync_last_known_own_block_timeout:
458 Parameters::default_sync_last_known_own_block_timeout(),
459 dag_state_cached_rounds: Parameters::default_dag_state_cached_rounds(),
460 peer_round_ahead_margin: Parameters::default_peer_round_ahead_margin(),
461 commit_sync_parallel_fetches: Parameters::default_commit_sync_parallel_fetches(),
462 commit_sync_batch_size: Parameters::default_commit_sync_batch_size(),
463 commit_sync_batches_ahead: Parameters::default_commit_sync_batches_ahead(),
464 commit_recovery_batch_size: Parameters::default_commit_recovery_batch_size(),
465 max_headers_per_bundle: Parameters::default_max_headers_per_bundle(),
466 max_shards_per_bundle: Parameters::default_max_shards_per_bundle(),
467 tonic: TonicParameters::default(),
468 fast_commit_sync_batch_size: Parameters::default_fast_commit_sync_batch_size(),
469 commit_sync_gap_threshold: Parameters::default_commit_sync_gap_threshold(),
470 enable_fast_commit_syncer: Parameters::default_enable_fast_commit_syncer(),
471 enable_starfish_speed_adaptive_acknowledgments:
472 Parameters::default_enable_starfish_speed_adaptive_acknowledgments(),
473 enable_peer_responsiveness_ranking:
474 Parameters::default_enable_peer_responsiveness_ranking(),
475 dag_visualizer_port: None,
476 }
477 }
478}
479
480#[derive(Clone, Debug, Deserialize, Serialize)]
481pub struct TonicParameters {
482 /// Keepalive interval and timeouts for both client and server.
483 ///
484 /// If unspecified, this will default to 5s.
485 #[serde(default = "TonicParameters::default_keepalive_interval")]
486 pub keepalive_interval: Duration,
487
488 /// Size of various per-connection buffers.
489 ///
490 /// If unspecified, this will default to 32MiB.
491 #[serde(default = "TonicParameters::default_connection_buffer_size")]
492 pub connection_buffer_size: usize,
493
494 /// Messages over this size threshold will increment a counter.
495 ///
496 /// If unspecified, this will default to 16MiB.
497 #[serde(default = "TonicParameters::default_excessive_message_size")]
498 pub excessive_message_size: usize,
499
500 /// Hard message size limit for both requests and responses.
501 /// This value is higher than strictly necessary, to allow overheads.
502 /// Message size targets and soft limits are computed based on this value.
503 ///
504 /// If unspecified, this will default to 1GiB.
505 #[serde(default = "TonicParameters::default_message_size_limit")]
506 pub message_size_limit: usize,
507
508 /// Maximum number of concurrent HTTP/2 streams a peer may open on a single
509 /// connection. Bounds per-connection request fan-out.
510 ///
511 /// `0` (the default) disables the limit, leaving the transport default.
512 #[serde(default)]
513 pub max_concurrent_streams: u32,
514
515 /// Server-side fallback deadline for requests that omit a `grpc-timeout`
516 /// header. The long-lived block-subscription stream is always exempt.
517 ///
518 /// A zero duration (the default) disables the fallback deadline.
519 #[serde(default)]
520 pub request_timeout: Duration,
521
522 /// Hard size limit for inbound (decoded) requests. Consensus requests are
523 /// small (ref lists); large payloads belong to responses, bounded by
524 /// `message_size_limit`. A smaller inbound bound shrinks the memory a
525 /// single in-flight request can pin before its handler runs.
526 ///
527 /// `0` (the default) falls back to `message_size_limit`.
528 #[serde(default)]
529 pub max_inbound_message_size: usize,
530
531 /// Per-peer, per-RPC admission caps for the inbound consensus server.
532 #[serde(default)]
533 pub admission: AdmissionParameters,
534}
535
536impl TonicParameters {
537 fn default_keepalive_interval() -> Duration {
538 Duration::from_secs(5)
539 }
540
541 fn default_connection_buffer_size() -> usize {
542 32 << 20
543 }
544
545 fn default_excessive_message_size() -> usize {
546 16 << 20
547 }
548
549 fn default_message_size_limit() -> usize {
550 64 << 20
551 }
552
553 /// Fills the inbound resource bounds that are still at their inert
554 /// defaults with the protective preset (sized for ~100-validator
555 /// committees). Bounds an operator configured explicitly are kept, as are
556 /// the transport settings the preset does not cover (keepalive, buffers,
557 /// `message_size_limit`). A bound explicitly configured to its inert value
558 /// still receives the preset; running without a bound requires disabling
559 /// the preset itself (`CONSENSUS_GRPC_PROTECTIVE_LIMITS=0`).
560 pub fn apply_protective(&mut self) {
561 if self.max_concurrent_streams == 0 {
562 self.max_concurrent_streams = 64;
563 }
564 if self.request_timeout.is_zero() {
565 self.request_timeout = Duration::from_secs(120);
566 }
567 if self.max_inbound_message_size == 0 {
568 self.max_inbound_message_size = 1 << 20;
569 }
570 if self.admission.is_inert() {
571 self.admission = AdmissionParameters::protective();
572 }
573 }
574
575 /// The inert defaults with the protective bounds applied.
576 pub fn protective() -> Self {
577 let mut params = Self::default();
578 params.apply_protective();
579 params
580 }
581}
582
583impl Default for TonicParameters {
584 fn default() -> Self {
585 Self {
586 keepalive_interval: TonicParameters::default_keepalive_interval(),
587 connection_buffer_size: TonicParameters::default_connection_buffer_size(),
588 excessive_message_size: TonicParameters::default_excessive_message_size(),
589 message_size_limit: TonicParameters::default_message_size_limit(),
590 max_concurrent_streams: 0,
591 request_timeout: Duration::ZERO,
592 max_inbound_message_size: 0,
593 admission: AdmissionParameters::default(),
594 }
595 }
596}
597
598/// Per-peer, per-RPC concurrency caps for the inbound consensus gRPC server.
599///
600/// Each cap bounds how many concurrent requests of one RPC group a single
601/// committee peer (keyed on its authenticated authority index) may have in
602/// flight; a peer cannot consume another peer's budget. These are local,
603/// non-protocol parameters — heterogeneous values across authorities are safe,
604/// so they can be rolled out and tuned per node.
605///
606/// `0` (the default for every cap) disables admission for that group. At node
607/// start the protective preset fills the caps when all of them are left at
608/// `0`; a caps block with any explicitly configured value is kept as-is, and
609/// `CONSENSUS_GRPC_PROTECTIVE_LIMITS=0` disables the preset entirely. Preset
610/// values, sized for ~100-validator committees and the local synchronizer
611/// fan-out toward one server: subscriptions 2, header fetches 32, transaction
612/// fetches 16, commit fetches `commit_sync_parallel_fetches` (8).
613#[derive(Clone, Debug, Default, Deserialize, Serialize)]
614pub struct AdmissionParameters {
615 /// Max concurrent block-subscription streams per peer.
616 #[serde(default)]
617 pub max_subscriptions_per_peer: u32,
618
619 /// Max concurrent header fetches per peer
620 /// (`fetch_block_headers` + `fetch_latest_block_headers`).
621 #[serde(default)]
622 pub max_header_fetches_per_peer: u32,
623
624 /// Max concurrent transaction fetches per peer (`fetch_transactions`).
625 #[serde(default)]
626 pub max_transaction_fetches_per_peer: u32,
627
628 /// Max concurrent commit fetches per peer
629 /// (`fetch_commits` + `fetch_commits_and_transactions`).
630 #[serde(default)]
631 pub max_commit_fetches_per_peer: u32,
632}
633
634impl AdmissionParameters {
635 /// Preset sized for ~100-validator committees and the local synchronizer
636 /// fan-out toward one server.
637 pub fn protective() -> Self {
638 Self {
639 max_subscriptions_per_peer: 2,
640 max_header_fetches_per_peer: 32,
641 max_transaction_fetches_per_peer: 16,
642 max_commit_fetches_per_peer: Parameters::default_commit_sync_parallel_fetches() as u32,
643 }
644 }
645
646 /// True when every cap is `0`, i.e. admission control is disabled.
647 pub fn is_inert(&self) -> bool {
648 self.max_subscriptions_per_peer == 0
649 && self.max_header_fetches_per_peer == 0
650 && self.max_transaction_fetches_per_peer == 0
651 && self.max_commit_fetches_per_peer == 0
652 }
653}