libp2p_gossipsub/config.rs
1// Copyright 2020 Sigma Prime Pty Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use std::borrow::Cow;
22use std::time::Duration;
23
24use libp2p_core::PeerId;
25
26use crate::types::{FastMessageId, GossipsubMessage, MessageId, RawGossipsubMessage};
27
28/// The types of message validation that can be employed by gossipsub.
29#[derive(Debug, Clone)]
30pub enum ValidationMode {
31 /// This is the default setting. This requires the message author to be a valid [`PeerId`] and to
32 /// be present as well as the sequence number. All messages must have valid signatures.
33 ///
34 /// NOTE: This setting will reject messages from nodes using
35 /// [`crate::behaviour::MessageAuthenticity::Anonymous`] and all messages that do not have
36 /// signatures.
37 Strict,
38 /// This setting permits messages that have no author, sequence number or signature. If any of
39 /// these fields exist in the message these are validated.
40 Permissive,
41 /// This setting requires the author, sequence number and signature fields of a message to be
42 /// empty. Any message that contains these fields is considered invalid.
43 Anonymous,
44 /// This setting does not check the author, sequence number or signature fields of incoming
45 /// messages. If these fields contain data, they are simply ignored.
46 ///
47 /// NOTE: This setting will consider messages with invalid signatures as valid messages.
48 None,
49}
50
51/// Configuration parameters that define the performance of the gossipsub network.
52#[derive(Clone)]
53pub struct GossipsubConfig {
54 protocol_id_prefix: Cow<'static, str>,
55 history_length: usize,
56 history_gossip: usize,
57 mesh_n: usize,
58 mesh_n_low: usize,
59 mesh_n_high: usize,
60 retain_scores: usize,
61 gossip_lazy: usize,
62 gossip_factor: f64,
63 heartbeat_initial_delay: Duration,
64 heartbeat_interval: Duration,
65 fanout_ttl: Duration,
66 check_explicit_peers_ticks: u64,
67 max_transmit_size: usize,
68 duplicate_cache_time: Duration,
69 validate_messages: bool,
70 validation_mode: ValidationMode,
71 message_id_fn: fn(&GossipsubMessage) -> MessageId,
72 fast_message_id_fn: Option<fn(&RawGossipsubMessage) -> FastMessageId>,
73 allow_self_origin: bool,
74 do_px: bool,
75 prune_peers: usize,
76 prune_backoff: Duration,
77 backoff_slack: u32,
78 flood_publish: bool,
79 graft_flood_threshold: Duration,
80 mesh_outbound_min: usize,
81 opportunistic_graft_ticks: u64,
82 opportunistic_graft_peers: usize,
83 gossip_retransimission: u32,
84 max_messages_per_rpc: Option<usize>,
85 max_ihave_length: usize,
86 max_ihave_messages: usize,
87 iwant_followup_time: Duration,
88 support_floodsub: bool,
89 published_message_ids_cache_time: Duration,
90}
91
92impl GossipsubConfig {
93 // All the getters
94
95 /// The protocol id prefix to negotiate this protocol. The protocol id is of the form
96 /// `/<prefix>/<supported-versions>`. As gossipsub supports version 1.0 and 1.1, there are two
97 /// protocol id's supported.
98 ///
99 /// The default prefix is `meshsub`, giving the supported protocol ids: `/meshsub/1.1.0` and `/meshsub/1.0.0`, negotiated in that order.
100 pub fn protocol_id_prefix(&self) -> &Cow<'static, str> {
101 &self.protocol_id_prefix
102 }
103
104 // Overlay network parameters.
105 /// Number of heartbeats to keep in the `memcache` (default is 5).
106 pub fn history_length(&self) -> usize {
107 self.history_length
108 }
109
110 /// Number of past heartbeats to gossip about (default is 3).
111 pub fn history_gossip(&self) -> usize {
112 self.history_gossip
113 }
114
115 /// Target number of peers for the mesh network (D in the spec, default is 6).
116 pub fn mesh_n(&self) -> usize {
117 self.mesh_n
118 }
119
120 /// Minimum number of peers in mesh network before adding more (D_lo in the spec, default is 5).
121 pub fn mesh_n_low(&self) -> usize {
122 self.mesh_n_low
123 }
124
125 /// Maximum number of peers in mesh network before removing some (D_high in the spec, default
126 /// is 12).
127 pub fn mesh_n_high(&self) -> usize {
128 self.mesh_n_high
129 }
130
131 /// Affects how peers are selected when pruning a mesh due to over subscription.
132 ///
133 /// At least `retain_scores` of the retained peers will be high-scoring, while the remainder are
134 /// chosen randomly (D_score in the spec, default is 4).
135 pub fn retain_scores(&self) -> usize {
136 self.retain_scores
137 }
138
139 /// Minimum number of peers to emit gossip to during a heartbeat (D_lazy in the spec,
140 /// default is 6).
141 pub fn gossip_lazy(&self) -> usize {
142 self.gossip_lazy
143 }
144
145 /// Affects how many peers we will emit gossip to at each heartbeat.
146 ///
147 /// We will send gossip to `gossip_factor * (total number of non-mesh peers)`, or
148 /// `gossip_lazy`, whichever is greater. The default is 0.25.
149 pub fn gossip_factor(&self) -> f64 {
150 self.gossip_factor
151 }
152
153 /// Initial delay in each heartbeat (default is 5 seconds).
154 pub fn heartbeat_initial_delay(&self) -> Duration {
155 self.heartbeat_initial_delay
156 }
157
158 /// Time between each heartbeat (default is 1 second).
159 pub fn heartbeat_interval(&self) -> Duration {
160 self.heartbeat_interval
161 }
162
163 /// Time to live for fanout peers (default is 60 seconds).
164 pub fn fanout_ttl(&self) -> Duration {
165 self.fanout_ttl
166 }
167
168 /// The number of heartbeat ticks until we recheck the connection to explicit peers and
169 /// reconnecting if necessary (default 300).
170 pub fn check_explicit_peers_ticks(&self) -> u64 {
171 self.check_explicit_peers_ticks
172 }
173
174 /// The maximum byte size for each gossipsub RPC (default is 65536 bytes).
175 ///
176 /// This represents the maximum size of the entire protobuf payload. It must be at least
177 /// large enough to support basic control messages. If Peer eXchange is enabled, this
178 /// must be large enough to transmit the desired peer information on pruning. It must be at
179 /// least 100 bytes. Default is 65536 bytes.
180 pub fn max_transmit_size(&self) -> usize {
181 self.max_transmit_size
182 }
183
184 /// Duplicates are prevented by storing message id's of known messages in an LRU time cache.
185 /// This settings sets the time period that messages are stored in the cache. Duplicates can be
186 /// received if duplicate messages are sent at a time greater than this setting apart. The
187 /// default is 1 minute.
188 pub fn duplicate_cache_time(&self) -> Duration {
189 self.duplicate_cache_time
190 }
191
192 /// When set to `true`, prevents automatic forwarding of all received messages. This setting
193 /// allows a user to validate the messages before propagating them to their peers. If set to
194 /// true, the user must manually call [`crate::Gossipsub::report_message_validation_result()`]
195 /// on the behaviour to forward message once validated (default is `false`).
196 /// The default is `false`.
197 pub fn validate_messages(&self) -> bool {
198 self.validate_messages
199 }
200
201 /// Determines the level of validation used when receiving messages. See [`ValidationMode`]
202 /// for the available types. The default is ValidationMode::Strict.
203 pub fn validation_mode(&self) -> &ValidationMode {
204 &self.validation_mode
205 }
206
207 /// A user-defined function allowing the user to specify the message id of a gossipsub message.
208 /// The default value is to concatenate the source peer id with a sequence number. Setting this
209 /// parameter allows the user to address packets arbitrarily. One example is content based
210 /// addressing, where this function may be set to `hash(message)`. This would prevent messages
211 /// of the same content from being duplicated.
212 ///
213 /// The function takes a [`GossipsubMessage`] as input and outputs a String to be interpreted as
214 /// the message id.
215 pub fn message_id(&self, message: &GossipsubMessage) -> MessageId {
216 (self.message_id_fn)(message)
217 }
218
219 /// A user-defined optional function that computes fast ids from raw messages. This can be used
220 /// to avoid possibly expensive transformations from [`RawGossipsubMessage`] to
221 /// [`GossipsubMessage`] for duplicates. Two semantically different messages must always
222 /// have different fast message ids, but it is allowed that two semantically identical messages
223 /// have different fast message ids as long as the message_id_fn produces the same id for them.
224 ///
225 /// The function takes a [`RawGossipsubMessage`] as input and outputs a String to be
226 /// interpreted as the fast message id. Default is None.
227 pub fn fast_message_id(&self, message: &RawGossipsubMessage) -> Option<FastMessageId> {
228 self.fast_message_id_fn
229 .map(|fast_message_id_fn| fast_message_id_fn(message))
230 }
231
232 /// By default, gossipsub will reject messages that are sent to us that have the same message
233 /// source as we have specified locally. Enabling this, allows these messages and prevents
234 /// penalizing the peer that sent us the message. Default is false.
235 pub fn allow_self_origin(&self) -> bool {
236 self.allow_self_origin
237 }
238
239 /// Whether Peer eXchange is enabled; this should be enabled in bootstrappers and other well
240 /// connected/trusted nodes. The default is true.
241 pub fn do_px(&self) -> bool {
242 self.do_px
243 }
244
245 /// Controls the number of peers to include in prune Peer eXchange.
246 /// When we prune a peer that's eligible for PX (has a good score, etc), we will try to
247 /// send them signed peer records for up to `prune_peers` other peers that we
248 /// know of. It is recommended that this value is larger than `mesh_n_high` so that the pruned
249 /// peer can reliably form a full mesh. The default is typically 16 however until signed
250 /// records are spec'd this is disabled and set to 0.
251 pub fn prune_peers(&self) -> usize {
252 self.prune_peers
253 }
254
255 /// Controls the backoff time for pruned peers. This is how long
256 /// a peer must wait before attempting to graft into our mesh again after being pruned.
257 /// When pruning a peer, we send them our value of `prune_backoff` so they know
258 /// the minimum time to wait. Peers running older versions may not send a backoff time,
259 /// so if we receive a prune message without one, we will wait at least `prune_backoff`
260 /// before attempting to re-graft. The default is one minute.
261 pub fn prune_backoff(&self) -> Duration {
262 self.prune_backoff
263 }
264
265 /// Number of heartbeat slots considered as slack for backoffs. This gurantees that we wait
266 /// at least backoff_slack heartbeats after a backoff is over before we try to graft. This
267 /// solves problems occuring through high latencies. In particular if
268 /// `backoff_slack * heartbeat_interval` is longer than any latencies between processing
269 /// prunes on our side and processing prunes on the receiving side this guarantees that we
270 /// get not punished for too early grafting. The default is 1.
271 pub fn backoff_slack(&self) -> u32 {
272 self.backoff_slack
273 }
274
275 /// Whether to do flood publishing or not. If enabled newly created messages will always be
276 /// sent to all peers that are subscribed to the topic and have a good enough score.
277 /// The default is true.
278 pub fn flood_publish(&self) -> bool {
279 self.flood_publish
280 }
281
282 /// If a GRAFT comes before `graft_flood_threshold` has elapsed since the last PRUNE,
283 /// then there is an extra score penalty applied to the peer through P7.
284 pub fn graft_flood_threshold(&self) -> Duration {
285 self.graft_flood_threshold
286 }
287
288 /// Minimum number of outbound peers in the mesh network before adding more (D_out in the spec).
289 /// This value must be smaller or equal than `mesh_n / 2` and smaller than `mesh_n_low`.
290 /// The default is 2.
291 pub fn mesh_outbound_min(&self) -> usize {
292 self.mesh_outbound_min
293 }
294
295 /// Number of heartbeat ticks that specifcy the interval in which opportunistic grafting is
296 /// applied. Every `opportunistic_graft_ticks` we will attempt to select some high-scoring mesh
297 /// peers to replace lower-scoring ones, if the median score of our mesh peers falls below a
298 /// threshold (see https://godoc.org/github.com/libp2p/go-libp2p-pubsub#PeerScoreThresholds).
299 /// The default is 60.
300 pub fn opportunistic_graft_ticks(&self) -> u64 {
301 self.opportunistic_graft_ticks
302 }
303
304 /// Controls how many times we will allow a peer to request the same message id through IWANT
305 /// gossip before we start ignoring them. This is designed to prevent peers from spamming us
306 /// with requests and wasting our resources. The default is 3.
307 pub fn gossip_retransimission(&self) -> u32 {
308 self.gossip_retransimission
309 }
310
311 /// The maximum number of new peers to graft to during opportunistic grafting. The default is 2.
312 pub fn opportunistic_graft_peers(&self) -> usize {
313 self.opportunistic_graft_peers
314 }
315
316 /// The maximum number of messages we will process in a given RPC. If this is unset, there is
317 /// no limit. The default is None.
318 pub fn max_messages_per_rpc(&self) -> Option<usize> {
319 self.max_messages_per_rpc
320 }
321
322 /// The maximum number of messages to include in an IHAVE message.
323 /// Also controls the maximum number of IHAVE ids we will accept and request with IWANT from a
324 /// peer within a heartbeat, to protect from IHAVE floods. You should adjust this value from the
325 /// default if your system is pushing more than 5000 messages in GossipSubHistoryGossip
326 /// heartbeats; with the defaults this is 1666 messages/s. The default is 5000.
327 pub fn max_ihave_length(&self) -> usize {
328 self.max_ihave_length
329 }
330
331 /// GossipSubMaxIHaveMessages is the maximum number of IHAVE messages to accept from a peer
332 /// within a heartbeat.
333 pub fn max_ihave_messages(&self) -> usize {
334 self.max_ihave_messages
335 }
336
337 /// Time to wait for a message requested through IWANT following an IHAVE advertisement.
338 /// If the message is not received within this window, a broken promise is declared and
339 /// the router may apply behavioural penalties. The default is 3 seconds.
340 pub fn iwant_followup_time(&self) -> Duration {
341 self.iwant_followup_time
342 }
343
344 /// Enable support for flooodsub peers. Default false.
345 pub fn support_floodsub(&self) -> bool {
346 self.support_floodsub
347 }
348
349 /// Published message ids time cache duration. The default is 10 seconds.
350 pub fn published_message_ids_cache_time(&self) -> Duration {
351 self.published_message_ids_cache_time
352 }
353}
354
355impl Default for GossipsubConfig {
356 fn default() -> Self {
357 // use ConfigBuilder to also validate defaults
358 GossipsubConfigBuilder::default()
359 .build()
360 .expect("Default config parameters should be valid parameters")
361 }
362}
363
364/// The builder struct for constructing a gossipsub configuration.
365pub struct GossipsubConfigBuilder {
366 config: GossipsubConfig,
367}
368
369impl Default for GossipsubConfigBuilder {
370 fn default() -> Self {
371 GossipsubConfigBuilder {
372 config: GossipsubConfig {
373 protocol_id_prefix: Cow::Borrowed("meshsub"),
374 history_length: 5,
375 history_gossip: 3,
376 mesh_n: 6,
377 mesh_n_low: 5,
378 mesh_n_high: 12,
379 retain_scores: 4,
380 gossip_lazy: 6, // default to mesh_n
381 gossip_factor: 0.25,
382 heartbeat_initial_delay: Duration::from_secs(5),
383 heartbeat_interval: Duration::from_secs(1),
384 fanout_ttl: Duration::from_secs(60),
385 check_explicit_peers_ticks: 300,
386 max_transmit_size: 65536,
387 duplicate_cache_time: Duration::from_secs(60),
388 validate_messages: false,
389 validation_mode: ValidationMode::Strict,
390 message_id_fn: |message| {
391 // default message id is: source + sequence number
392 // NOTE: If either the peer_id or source is not provided, we set to 0;
393 let mut source_string = if let Some(peer_id) = message.source.as_ref() {
394 peer_id.to_base58()
395 } else {
396 PeerId::from_bytes(&[0, 1, 0])
397 .expect("Valid peer id")
398 .to_base58()
399 };
400 source_string
401 .push_str(&message.sequence_number.unwrap_or_default().to_string());
402 MessageId::from(source_string)
403 },
404 fast_message_id_fn: None,
405 allow_self_origin: false,
406 do_px: false,
407 prune_peers: 0, // NOTE: Increasing this currently has little effect until Signed records are implemented.
408 prune_backoff: Duration::from_secs(60),
409 backoff_slack: 1,
410 flood_publish: true,
411 graft_flood_threshold: Duration::from_secs(10),
412 mesh_outbound_min: 2,
413 opportunistic_graft_ticks: 60,
414 opportunistic_graft_peers: 2,
415 gossip_retransimission: 3,
416 max_messages_per_rpc: None,
417 max_ihave_length: 5000,
418 max_ihave_messages: 10,
419 iwant_followup_time: Duration::from_secs(3),
420 support_floodsub: false,
421 published_message_ids_cache_time: Duration::from_secs(10),
422 },
423 }
424 }
425}
426
427impl From<GossipsubConfig> for GossipsubConfigBuilder {
428 fn from(config: GossipsubConfig) -> Self {
429 GossipsubConfigBuilder { config }
430 }
431}
432
433impl GossipsubConfigBuilder {
434 /// The protocol id to negotiate this protocol (default is `/meshsub/1.0.0`).
435 pub fn protocol_id_prefix(&mut self, protocol_id: impl Into<Cow<'static, str>>) -> &mut Self {
436 self.config.protocol_id_prefix = protocol_id.into();
437 self
438 }
439
440 /// Number of heartbeats to keep in the `memcache` (default is 5).
441 pub fn history_length(&mut self, history_length: usize) -> &mut Self {
442 self.config.history_length = history_length;
443 self
444 }
445
446 /// Number of past heartbeats to gossip about (default is 3).
447 pub fn history_gossip(&mut self, history_gossip: usize) -> &mut Self {
448 self.config.history_gossip = history_gossip;
449 self
450 }
451
452 /// Target number of peers for the mesh network (D in the spec, default is 6).
453 pub fn mesh_n(&mut self, mesh_n: usize) -> &mut Self {
454 self.config.mesh_n = mesh_n;
455 self
456 }
457
458 /// Minimum number of peers in mesh network before adding more (D_lo in the spec, default is 4).
459 pub fn mesh_n_low(&mut self, mesh_n_low: usize) -> &mut Self {
460 self.config.mesh_n_low = mesh_n_low;
461 self
462 }
463
464 /// Maximum number of peers in mesh network before removing some (D_high in the spec, default
465 /// is 12).
466 pub fn mesh_n_high(&mut self, mesh_n_high: usize) -> &mut Self {
467 self.config.mesh_n_high = mesh_n_high;
468 self
469 }
470
471 /// Affects how peers are selected when pruning a mesh due to over subscription.
472 ///
473 /// At least [`Self::retain_scores`] of the retained peers will be high-scoring, while the remainder are
474 /// chosen randomly (D_score in the spec, default is 4).
475 pub fn retain_scores(&mut self, retain_scores: usize) -> &mut Self {
476 self.config.retain_scores = retain_scores;
477 self
478 }
479
480 /// Minimum number of peers to emit gossip to during a heartbeat (D_lazy in the spec,
481 /// default is 6).
482 pub fn gossip_lazy(&mut self, gossip_lazy: usize) -> &mut Self {
483 self.config.gossip_lazy = gossip_lazy;
484 self
485 }
486
487 /// Affects how many peers we will emit gossip to at each heartbeat.
488 ///
489 /// We will send gossip to `gossip_factor * (total number of non-mesh peers)`, or
490 /// `gossip_lazy`, whichever is greater. The default is 0.25.
491 pub fn gossip_factor(&mut self, gossip_factor: f64) -> &mut Self {
492 self.config.gossip_factor = gossip_factor;
493 self
494 }
495
496 /// Initial delay in each heartbeat (default is 5 seconds).
497 pub fn heartbeat_initial_delay(&mut self, heartbeat_initial_delay: Duration) -> &mut Self {
498 self.config.heartbeat_initial_delay = heartbeat_initial_delay;
499 self
500 }
501
502 /// Time between each heartbeat (default is 1 second).
503 pub fn heartbeat_interval(&mut self, heartbeat_interval: Duration) -> &mut Self {
504 self.config.heartbeat_interval = heartbeat_interval;
505 self
506 }
507
508 /// The number of heartbeat ticks until we recheck the connection to explicit peers and
509 /// reconnecting if necessary (default 300).
510 pub fn check_explicit_peers_ticks(&mut self, check_explicit_peers_ticks: u64) -> &mut Self {
511 self.config.check_explicit_peers_ticks = check_explicit_peers_ticks;
512 self
513 }
514
515 /// Time to live for fanout peers (default is 60 seconds).
516 pub fn fanout_ttl(&mut self, fanout_ttl: Duration) -> &mut Self {
517 self.config.fanout_ttl = fanout_ttl;
518 self
519 }
520
521 /// The maximum byte size for each gossip (default is 2048 bytes).
522 pub fn max_transmit_size(&mut self, max_transmit_size: usize) -> &mut Self {
523 self.config.max_transmit_size = max_transmit_size;
524 self
525 }
526
527 /// Duplicates are prevented by storing message id's of known messages in an LRU time cache.
528 /// This settings sets the time period that messages are stored in the cache. Duplicates can be
529 /// received if duplicate messages are sent at a time greater than this setting apart. The
530 /// default is 1 minute.
531 pub fn duplicate_cache_time(&mut self, cache_size: Duration) -> &mut Self {
532 self.config.duplicate_cache_time = cache_size;
533 self
534 }
535
536 /// When set, prevents automatic forwarding of all received messages. This setting
537 /// allows a user to validate the messages before propagating them to their peers. If set,
538 /// the user must manually call [`crate::Gossipsub::report_message_validation_result()`] on the
539 /// behaviour to forward a message once validated.
540 pub fn validate_messages(&mut self) -> &mut Self {
541 self.config.validate_messages = true;
542 self
543 }
544
545 /// Determines the level of validation used when receiving messages. See [`ValidationMode`]
546 /// for the available types. The default is ValidationMode::Strict.
547 pub fn validation_mode(&mut self, validation_mode: ValidationMode) -> &mut Self {
548 self.config.validation_mode = validation_mode;
549 self
550 }
551
552 /// A user-defined function allowing the user to specify the message id of a gossipsub message.
553 /// The default value is to concatenate the source peer id with a sequence number. Setting this
554 /// parameter allows the user to address packets arbitrarily. One example is content based
555 /// addressing, where this function may be set to `hash(message)`. This would prevent messages
556 /// of the same content from being duplicated.
557 ///
558 /// The function takes a [`GossipsubMessage`] as input and outputs a String to be
559 /// interpreted as the message id.
560 pub fn message_id_fn(&mut self, id_fn: fn(&GossipsubMessage) -> MessageId) -> &mut Self {
561 self.config.message_id_fn = id_fn;
562 self
563 }
564
565 /// A user-defined optional function that computes fast ids from raw messages. This can be used
566 /// to avoid possibly expensive transformations from [`RawGossipsubMessage`] to
567 /// [`GossipsubMessage`] for duplicates. Two semantically different messages must always
568 /// have different fast message ids, but it is allowed that two semantically identical messages
569 /// have different fast message ids as long as the message_id_fn produces the same id for them.
570 ///
571 /// The function takes a [`RawGossipsubMessage`] as input and outputs a String to be interpreted
572 /// as the fast message id. Default is None.
573 pub fn fast_message_id_fn(
574 &mut self,
575 fast_id_fn: fn(&RawGossipsubMessage) -> FastMessageId,
576 ) -> &mut Self {
577 self.config.fast_message_id_fn = Some(fast_id_fn);
578 self
579 }
580
581 /// Enables Peer eXchange. This should be enabled in bootstrappers and other well
582 /// connected/trusted nodes. The default is true.
583 pub fn do_px(&mut self) -> &mut Self {
584 self.config.do_px = true;
585 self
586 }
587
588 /// Controls the number of peers to include in prune Peer eXchange.
589 ///
590 /// When we prune a peer that's eligible for PX (has a good score, etc), we will try to
591 /// send them signed peer records for up to [`Self::prune_peers] other peers that we
592 /// know of. It is recommended that this value is larger than [`Self::mesh_n_high`] so that the
593 /// pruned peer can reliably form a full mesh. The default is 16.
594 pub fn prune_peers(&mut self, prune_peers: usize) -> &mut Self {
595 self.config.prune_peers = prune_peers;
596 self
597 }
598
599 /// Controls the backoff time for pruned peers. This is how long
600 /// a peer must wait before attempting to graft into our mesh again after being pruned.
601 /// When pruning a peer, we send them our value of [`Self::prune_backoff`] so they know
602 /// the minimum time to wait. Peers running older versions may not send a backoff time,
603 /// so if we receive a prune message without one, we will wait at least [`Self::prune_backoff`]
604 /// before attempting to re-graft. The default is one minute.
605 pub fn prune_backoff(&mut self, prune_backoff: Duration) -> &mut Self {
606 self.config.prune_backoff = prune_backoff;
607 self
608 }
609
610 /// Number of heartbeat slots considered as slack for backoffs. This gurantees that we wait
611 /// at least backoff_slack heartbeats after a backoff is over before we try to graft. This
612 /// solves problems occuring through high latencies. In particular if
613 /// `backoff_slack * heartbeat_interval` is longer than any latencies between processing
614 /// prunes on our side and processing prunes on the receiving side this guarantees that we
615 /// get not punished for too early grafting. The default is 1.
616 pub fn backoff_slack(&mut self, backoff_slack: u32) -> &mut Self {
617 self.config.backoff_slack = backoff_slack;
618 self
619 }
620
621 /// Whether to do flood publishing or not. If enabled newly created messages will always be
622 /// sent to all peers that are subscribed to the topic and have a good enough score.
623 /// The default is true.
624 pub fn flood_publish(&mut self, flood_publish: bool) -> &mut Self {
625 self.config.flood_publish = flood_publish;
626 self
627 }
628
629 /// If a GRAFT comes before `graft_flood_threshold` has elapsed since the last PRUNE,
630 /// then there is an extra score penalty applied to the peer through P7.
631 pub fn graft_flood_threshold(&mut self, graft_flood_threshold: Duration) -> &mut Self {
632 self.config.graft_flood_threshold = graft_flood_threshold;
633 self
634 }
635
636 /// Minimum number of outbound peers in the mesh network before adding more (D_out in the spec).
637 /// This value must be smaller or equal than `mesh_n / 2` and smaller than `mesh_n_low`.
638 /// The default is 2.
639 pub fn mesh_outbound_min(&mut self, mesh_outbound_min: usize) -> &mut Self {
640 self.config.mesh_outbound_min = mesh_outbound_min;
641 self
642 }
643
644 /// Number of heartbeat ticks that specifcy the interval in which opportunistic grafting is
645 /// applied. Every `opportunistic_graft_ticks` we will attempt to select some high-scoring mesh
646 /// peers to replace lower-scoring ones, if the median score of our mesh peers falls below a
647 /// threshold (see https://godoc.org/github.com/libp2p/go-libp2p-pubsub#PeerScoreThresholds).
648 /// The default is 60.
649 pub fn opportunistic_graft_ticks(&mut self, opportunistic_graft_ticks: u64) -> &mut Self {
650 self.config.opportunistic_graft_ticks = opportunistic_graft_ticks;
651 self
652 }
653
654 /// Controls how many times we will allow a peer to request the same message id through IWANT
655 /// gossip before we start ignoring them. This is designed to prevent peers from spamming us
656 /// with requests and wasting our resources.
657 pub fn gossip_retransimission(&mut self, gossip_retransimission: u32) -> &mut Self {
658 self.config.gossip_retransimission = gossip_retransimission;
659 self
660 }
661
662 /// The maximum number of new peers to graft to during opportunistic grafting. The default is 2.
663 pub fn opportunistic_graft_peers(&mut self, opportunistic_graft_peers: usize) -> &mut Self {
664 self.config.opportunistic_graft_peers = opportunistic_graft_peers;
665 self
666 }
667
668 /// The maximum number of messages we will process in a given RPC. If this is unset, there is
669 /// no limit. The default is None.
670 pub fn max_messages_per_rpc(&mut self, max: Option<usize>) -> &mut Self {
671 self.config.max_messages_per_rpc = max;
672 self
673 }
674
675 /// The maximum number of messages to include in an IHAVE message.
676 /// Also controls the maximum number of IHAVE ids we will accept and request with IWANT from a
677 /// peer within a heartbeat, to protect from IHAVE floods. You should adjust this value from the
678 /// default if your system is pushing more than 5000 messages in GossipSubHistoryGossip
679 /// heartbeats; with the defaults this is 1666 messages/s. The default is 5000.
680 pub fn max_ihave_length(&mut self, max_ihave_length: usize) -> &mut Self {
681 self.config.max_ihave_length = max_ihave_length;
682 self
683 }
684
685 /// GossipSubMaxIHaveMessages is the maximum number of IHAVE messages to accept from a peer
686 /// within a heartbeat.
687 pub fn max_ihave_messages(&mut self, max_ihave_messages: usize) -> &mut Self {
688 self.config.max_ihave_messages = max_ihave_messages;
689 self
690 }
691
692 /// By default, gossipsub will reject messages that are sent to us that has the same message
693 /// source as we have specified locally. Enabling this, allows these messages and prevents
694 /// penalizing the peer that sent us the message. Default is false.
695 pub fn allow_self_origin(&mut self, allow_self_origin: bool) -> &mut Self {
696 self.config.allow_self_origin = allow_self_origin;
697 self
698 }
699
700 /// Time to wait for a message requested through IWANT following an IHAVE advertisement.
701 /// If the message is not received within this window, a broken promise is declared and
702 /// the router may apply behavioural penalties. The default is 3 seconds.
703 pub fn iwant_followup_time(&mut self, iwant_followup_time: Duration) -> &mut Self {
704 self.config.iwant_followup_time = iwant_followup_time;
705 self
706 }
707
708 /// Enable support for flooodsub peers.
709 pub fn support_floodsub(&mut self) -> &mut Self {
710 self.config.support_floodsub = true;
711 self
712 }
713
714 /// Published message ids time cache duration. The default is 10 seconds.
715 pub fn published_message_ids_cache_time(
716 &mut self,
717 published_message_ids_cache_time: Duration,
718 ) -> &mut Self {
719 self.config.published_message_ids_cache_time = published_message_ids_cache_time;
720 self
721 }
722
723 /// Constructs a [`GossipsubConfig`] from the given configuration and validates the settings.
724 pub fn build(&self) -> Result<GossipsubConfig, &str> {
725 // check all constraints on config
726
727 if self.config.max_transmit_size < 100 {
728 return Err("The maximum transmission size must be greater than 100 to permit basic control messages");
729 }
730
731 if self.config.history_length < self.config.history_gossip {
732 return Err(
733 "The history_length must be greater than or equal to the history_gossip \
734 length",
735 );
736 }
737
738 if !(self.config.mesh_outbound_min < self.config.mesh_n_low
739 && self.config.mesh_n_low <= self.config.mesh_n
740 && self.config.mesh_n <= self.config.mesh_n_high)
741 {
742 return Err("The following inequality doesn't hold \
743 mesh_outbound_min < mesh_n_low <= mesh_n <= mesh_n_high");
744 }
745
746 if self.config.mesh_outbound_min * 2 > self.config.mesh_n {
747 return Err(
748 "The following inequality doesn't hold mesh_outbound_min <= self.config.mesh_n / 2",
749 );
750 }
751 Ok(self.config.clone())
752 }
753}
754
755impl std::fmt::Debug for GossipsubConfig {
756 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
757 let mut builder = f.debug_struct("GossipsubConfig");
758 let _ = builder.field("protocol_id_prefix", &self.protocol_id_prefix);
759 let _ = builder.field("history_length", &self.history_length);
760 let _ = builder.field("history_gossip", &self.history_gossip);
761 let _ = builder.field("mesh_n", &self.mesh_n);
762 let _ = builder.field("mesh_n_low", &self.mesh_n_low);
763 let _ = builder.field("mesh_n_high", &self.mesh_n_high);
764 let _ = builder.field("retain_scores", &self.retain_scores);
765 let _ = builder.field("gossip_lazy", &self.gossip_lazy);
766 let _ = builder.field("gossip_factor", &self.gossip_factor);
767 let _ = builder.field("heartbeat_initial_delay", &self.heartbeat_initial_delay);
768 let _ = builder.field("heartbeat_interval", &self.heartbeat_interval);
769 let _ = builder.field("fanout_ttl", &self.fanout_ttl);
770 let _ = builder.field("max_transmit_size", &self.max_transmit_size);
771 let _ = builder.field("duplicate_cache_time", &self.duplicate_cache_time);
772 let _ = builder.field("validate_messages", &self.validate_messages);
773 let _ = builder.field("validation_mode", &self.validation_mode);
774 let _ = builder.field("allow_self_origin", &self.allow_self_origin);
775 let _ = builder.field("do_px", &self.do_px);
776 let _ = builder.field("prune_peers", &self.prune_peers);
777 let _ = builder.field("prune_backoff", &self.prune_backoff);
778 let _ = builder.field("backoff_slack", &self.backoff_slack);
779 let _ = builder.field("flood_publish", &self.flood_publish);
780 let _ = builder.field("graft_flood_threshold", &self.graft_flood_threshold);
781 let _ = builder.field("mesh_outbound_min", &self.mesh_outbound_min);
782 let _ = builder.field("opportunistic_graft_ticks", &self.opportunistic_graft_ticks);
783 let _ = builder.field("opportunistic_graft_peers", &self.opportunistic_graft_peers);
784 let _ = builder.field("max_messages_per_rpc", &self.max_messages_per_rpc);
785 let _ = builder.field("max_ihave_length", &self.max_ihave_length);
786 let _ = builder.field("max_ihave_messages", &self.max_ihave_messages);
787 let _ = builder.field("iwant_followup_time", &self.iwant_followup_time);
788 let _ = builder.field("support_floodsub", &self.support_floodsub);
789 let _ = builder.field(
790 "published_message_ids_cache_time",
791 &self.published_message_ids_cache_time,
792 );
793 builder.finish()
794 }
795}
796
797#[cfg(test)]
798mod test {
799 use super::*;
800
801 #[test]
802 fn create_thing() {
803 let builder: GossipsubConfig = GossipsubConfigBuilder::default()
804 .protocol_id_prefix("purple")
805 .build()
806 .unwrap();
807
808 dbg!(builder);
809 }
810}