use crate::{ kbucket::MAX_NODES_PER_BUCKET, Enr, Executor, PermitBanList, RateLimiter, RateLimiterBuilder, }; ///! A set of configuration parameters to tune the discovery protocol. use std::time::Duration; /// Configuration parameters that define the performance of the gossipsub network. #[derive(Clone)] pub struct Discv5Config { /// Whether to enable the incoming packet filter. Default: false. pub enable_packet_filter: bool, /// The request timeout for each UDP request. Default: 2 seconds. pub request_timeout: Duration, /// The interval over which votes are remembered when determining our external IP. A lower /// interval will respond faster to IP changes. Default is 30 seconds. pub vote_duration: Duration, /// The timeout after which a `QueryPeer` in an ongoing query is marked unresponsive. /// Unresponsive peers don't count towards the parallelism limits for a query. /// Hence, we may potentially end up making more requests to good peers. Default: 2 seconds. pub query_peer_timeout: Duration, /// The timeout for an entire query. Any peers discovered for this query are returned. Default 60 seconds. pub query_timeout: Duration, /// The number of retries for each UDP request. Default: 1. pub request_retries: u8, /// The session timeout for each node. Default: 1 day. pub session_timeout: Duration, /// The maximum number of established sessions to maintain. Default: 1000. pub session_cache_capacity: usize, /// Updates the local ENR IP and port based on PONG responses from peers. Default: true. pub enr_update: bool, /// The maximum number of nodes we return to a find nodes request. The default is 16. pub max_nodes_response: usize, /// The minimum number of peer's who agree on an external IP port before updating the /// local ENR. Default: 10. pub enr_peer_update_min: usize, /// The number of peers to request in parallel in a single query. Default: 3. pub query_parallelism: usize, /// Limits the number of IP addresses from the same /// /24 subnet in the kbuckets table. This is to mitigate eclipse attacks. Default: false. pub ip_limit: bool, /// Sets a maximum limit to the number of incoming nodes (nodes that have dialed us) to exist per-bucket. This cannot be larger /// than the bucket size (16). By default this is disabled (set to the maximum bucket size, 16). pub incoming_bucket_limit: usize, /// A filter used to decide whether to insert nodes into our local routing table. Nodes can be /// excluded if they do not pass this filter. The default is to accept all nodes. pub table_filter: fn(&Enr) -> bool, /// The time between pings to ensure connectivity amongst connected nodes. Default: 300 /// seconds. pub ping_interval: Duration, /// Reports all discovered ENR's when traversing the DHT to the event stream. Default true. pub report_discovered_peers: bool, /// A set of configuration parameters for setting inbound request rate limits. See /// [`RateLimiterBuilder`] for options. This is only functional if the packet filter is /// enabled via the `enable_packet_filter` option. See the `Default` implementation for /// default values. If set to None, inbound requests are not filtered. pub filter_rate_limiter: Option, /// The maximum number of node-ids allowed per IP address before the IP address gets banned. /// Having this set to None, disables this feature. Default value is 10. This is only /// applicable if the `enable_packet_filter` option is set. pub filter_max_nodes_per_ip: Option, /// The maximum number of nodes that can be banned by a single IP before that IP gets banned. /// The default is 5. This is only /// applicable if the `enable_packet_filter` option is set. pub filter_max_bans_per_ip: Option, /// A set of lists that permit or ban IP's or NodeIds from the server. See /// `crate::PermitBanList`. pub permit_ban_list: PermitBanList, /// Set the default duration for which nodes are banned for. This timeouts are checked every 5 minutes, /// so the precision will be to the nearest 5 minutes. If set to `None`, bans from the filter /// will last indefinitely. Default is 1 hour. pub ban_duration: Option, /// A custom executor which can spawn the discv5 tasks. This must be a tokio runtime, with /// timing support. By default, the executor that created the discv5 struct will be used. pub executor: Option>, } impl Default for Discv5Config { fn default() -> Self { // This is only applicable if enable_packet_filter is set. let filter_rate_limiter = Some( RateLimiterBuilder::new() .total_n_every(10, Duration::from_secs(1)) // Allow bursts, average 10 per second .node_n_every(8, Duration::from_secs(1)) // Allow bursts, average 8 per second .ip_n_every(9, Duration::from_secs(1)) // Allow bursts, average 9 per second .build() .expect("The total rate limit has been specified"), ); Self { enable_packet_filter: false, request_timeout: Duration::from_secs(1), vote_duration: Duration::from_secs(30), query_peer_timeout: Duration::from_secs(2), query_timeout: Duration::from_secs(60), request_retries: 1, session_timeout: Duration::from_secs(86400), session_cache_capacity: 1000, enr_update: true, max_nodes_response: 16, enr_peer_update_min: 10, query_parallelism: 3, ip_limit: false, incoming_bucket_limit: MAX_NODES_PER_BUCKET, table_filter: |_| true, ping_interval: Duration::from_secs(300), report_discovered_peers: true, filter_rate_limiter, filter_max_nodes_per_ip: Some(10), filter_max_bans_per_ip: Some(5), permit_ban_list: PermitBanList::default(), ban_duration: Some(Duration::from_secs(3600)), // 1 hour executor: None, } } } #[derive(Debug, Default)] pub struct Discv5ConfigBuilder { config: Discv5Config, } impl Discv5ConfigBuilder { // set default values pub fn new() -> Self { Discv5ConfigBuilder::default() } /// Whether to enable the incoming packet filter. pub fn enable_packet_filter(&mut self) -> &mut Self { self.config.enable_packet_filter = true; self } /// The request timeout for each UDP request. pub fn request_timeout(&mut self, timeout: Duration) -> &mut Self { self.config.request_timeout = timeout; self } /// The interval over which votes are remembered when determining our external IP. A lower /// interval will respond faster to IP changes. Default is 30 seconds. pub fn vote_duration(&mut self, vote_duration: Duration) -> &mut Self { self.config.vote_duration = vote_duration; self } /// The timeout after which a `QueryPeer` in an ongoing query is marked unresponsive. /// Unresponsive peers don't count towards the parallelism limits for a query. /// Hence, we may potentially end up making more requests to good peers. pub fn query_peer_timeout(&mut self, timeout: Duration) -> &mut Self { self.config.query_peer_timeout = timeout; self } /// The timeout for an entire query. Any peers discovered before this timeout are returned. pub fn query_timeout(&mut self, timeout: Duration) -> &mut Self { self.config.query_timeout = timeout; self } /// The number of retries for each UDP request. pub fn request_retries(&mut self, retries: u8) -> &mut Self { self.config.request_retries = retries; self } /// The session timeout for each node. pub fn session_timeout(&mut self, timeout: Duration) -> &mut Self { self.config.session_timeout = timeout; self } /// The maximum number of established sessions to maintain. pub fn session_cache_capacity(&mut self, capacity: usize) -> &mut Self { self.config.session_cache_capacity = capacity; self } /// Disables the auto-update of the local ENR IP and port based on PONG responses from peers. pub fn disable_enr_update(&mut self) -> &mut Self { self.config.enr_update = false; self } /// The maximum number of nodes we response to a find nodes request. pub fn max_nodes_response(&mut self, max: usize) -> &mut Self { self.config.max_nodes_response = max; self } /// The minimum number of peer's who agree on an external IP port before updating the /// local ENR. pub fn enr_peer_update_min(&mut self, min: usize) -> &mut Self { if min < 2 { panic!("Setting enr_peer_update_min to a value less than 2 will cause issues with discovery with peers behind NAT"); } self.config.enr_peer_update_min = min; self } /// The number of peers to request in parallel in a single query. pub fn query_parallelism(&mut self, parallelism: usize) -> &mut Self { self.config.query_parallelism = parallelism; self } /// Limits the number of IP addresses from the same /// /24 subnet in the kbuckets table. This is to mitigate eclipse attacks. pub fn ip_limit(&mut self) -> &mut Self { self.config.ip_limit = true; self } /// Sets a maximum limit to the number of incoming nodes (nodes that have dialed us) to exist per-bucket. This cannot be larger /// than the bucket size (16). By default, half of every bucket (8 positions) is the largest number of nodes that we accept that dial us. pub fn incoming_bucket_limit(&mut self, limit: usize) -> &mut Self { self.config.incoming_bucket_limit = limit; self } /// A filter used to decide whether to insert nodes into our local routing table. Nodes can be /// excluded if they do not pass this filter. pub fn table_filter(&mut self, filter: fn(&Enr) -> bool) -> &mut Self { self.config.table_filter = filter; self } /// The time between pings to ensure connectivity amongst connected nodes. pub fn ping_interval(&mut self, interval: Duration) -> &mut Self { self.config.ping_interval = interval; self } /// Disables reporting of discovered peers through the event stream. pub fn disable_report_discovered_peers(&mut self) -> &mut Self { self.config.report_discovered_peers = false; self } /// A rate limiter for limiting inbound requests. pub fn filter_rate_limiter(&mut self, rate_limiter: Option) -> &mut Self { self.config.filter_rate_limiter = rate_limiter; self } /// If the filter is enabled, sets the maximum number of nodes per IP before banning /// the IP. pub fn filter_max_nodes_per_ip(&mut self, max_nodes_per_ip: Option) -> &mut Self { self.config.filter_max_nodes_per_ip = max_nodes_per_ip; self } /// The maximum number of times nodes from a single IP can be banned, before the IP itself /// gets banned. pub fn filter_max_bans_per_ip(&mut self, max_bans_per_ip: Option) -> &mut Self { self.config.filter_max_bans_per_ip = max_bans_per_ip; self } /// A set of lists that permit or ban IP's or NodeIds from the server. See /// `crate::PermitBanList`. pub fn permit_ban_list(&mut self, list: PermitBanList) -> &mut Self { self.config.permit_ban_list = list; self } /// Set the default duration for which nodes are banned for. This timeouts are checked every 5 minutes, /// so the precision will be to the nearest 5 minutes. If set to `None`, bans from the filter /// will last indefinitely. Default is 1 hour. pub fn ban_duration(&mut self, ban_duration: Option) -> &mut Self { self.config.ban_duration = ban_duration; self } /// A custom executor which can spawn the discv5 tasks. This must be a tokio runtime, with /// timing support. pub fn executor(&mut self, executor: Box) -> &mut Self { self.config.executor = Some(executor); self } pub fn build(&mut self) -> Discv5Config { // If an executor is not provided, assume a current tokio runtime is running. if self.config.executor.is_none() { self.config.executor = Some(Box::new(crate::executor::TokioExecutor::default())); }; assert!(self.config.incoming_bucket_limit <= MAX_NODES_PER_BUCKET); self.config.clone() } } impl std::fmt::Debug for Discv5Config { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("Discv5Config"); let _ = builder.field("filter_enabled", &self.enable_packet_filter); let _ = builder.field("request_timeout", &self.request_timeout); let _ = builder.field("vote_duration", &self.vote_duration); let _ = builder.field("query_timeout", &self.query_timeout); let _ = builder.field("query_peer_timeout", &self.query_peer_timeout); let _ = builder.field("request_retries", &self.request_retries); let _ = builder.field("session_timeout", &self.session_timeout); let _ = builder.field("session_cache_capacity", &self.session_cache_capacity); let _ = builder.field("enr_update", &self.enr_update); let _ = builder.field("query_parallelism", &self.query_parallelism); let _ = builder.field("report_discovered_peers", &self.report_discovered_peers); let _ = builder.field("ip_limit", &self.ip_limit); let _ = builder.field("filter_max_nodes_per_ip", &self.filter_max_nodes_per_ip); let _ = builder.field("filter_max_bans_per_ip", &self.filter_max_bans_per_ip); let _ = builder.field("ip_limit", &self.ip_limit); let _ = builder.field("incoming_bucket_limit", &self.incoming_bucket_limit); let _ = builder.field("ping_interval", &self.ping_interval); let _ = builder.field("ban_duration", &self.ban_duration); builder.finish() } }