reth_network_types/peers/
config.rsuse std::{
collections::HashSet,
io::{self, ErrorKind},
path::Path,
time::Duration,
};
use reth_net_banlist::BanList;
use reth_network_peers::{NodeRecord, TrustedPeer};
use tracing::info;
use crate::{BackoffKind, ReputationChangeWeights};
pub const DEFAULT_MAX_COUNT_PEERS_OUTBOUND: u32 = 100;
pub const DEFAULT_MAX_COUNT_PEERS_INBOUND: u32 = 30;
pub const DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS: usize = 15;
pub const INBOUND_IP_THROTTLE_DURATION: Duration = Duration::from_secs(30);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PeerBackoffDurations {
#[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
pub low: Duration,
#[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
pub medium: Duration,
#[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
pub high: Duration,
#[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
pub max: Duration,
}
impl PeerBackoffDurations {
pub const fn backoff(&self, kind: BackoffKind) -> Duration {
match kind {
BackoffKind::Low => self.low,
BackoffKind::Medium => self.medium,
BackoffKind::High => self.high,
}
}
pub fn backoff_until(&self, kind: BackoffKind, backoff_counter: u8) -> std::time::Instant {
let backoff_time = self.backoff(kind);
let backoff_time = backoff_time + backoff_time * backoff_counter as u32;
let now = std::time::Instant::now();
now + backoff_time.min(self.max)
}
#[cfg(any(test, feature = "test-utils"))]
pub const fn test() -> Self {
Self {
low: Duration::from_millis(200),
medium: Duration::from_millis(200),
high: Duration::from_millis(200),
max: Duration::from_millis(200),
}
}
}
impl Default for PeerBackoffDurations {
fn default() -> Self {
Self {
low: Duration::from_secs(30),
medium: Duration::from_secs(60 * 3),
high: Duration::from_secs(60 * 15),
max: Duration::from_secs(60 * 60),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(default))]
pub struct ConnectionsConfig {
pub max_outbound: usize,
pub max_inbound: usize,
#[cfg_attr(feature = "serde", serde(default))]
pub max_concurrent_outbound_dials: usize,
}
impl Default for ConnectionsConfig {
fn default() -> Self {
Self {
max_outbound: DEFAULT_MAX_COUNT_PEERS_OUTBOUND as usize,
max_inbound: DEFAULT_MAX_COUNT_PEERS_INBOUND as usize,
max_concurrent_outbound_dials: DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct PeersConfig {
#[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
pub refill_slots_interval: Duration,
pub trusted_nodes: Vec<TrustedPeer>,
#[cfg_attr(feature = "serde", serde(alias = "connect_trusted_nodes_only"))]
pub trusted_nodes_only: bool,
pub max_backoff_count: u8,
#[cfg_attr(feature = "serde", serde(skip))]
pub basic_nodes: HashSet<NodeRecord>,
#[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
pub ban_duration: Duration,
#[cfg_attr(feature = "serde", serde(skip))]
pub ban_list: BanList,
pub connection_info: ConnectionsConfig,
pub reputation_weights: ReputationChangeWeights,
pub backoff_durations: PeerBackoffDurations,
#[cfg_attr(feature = "serde", serde(default, with = "humantime_serde"))]
pub incoming_ip_throttle_duration: Duration,
}
impl Default for PeersConfig {
fn default() -> Self {
Self {
refill_slots_interval: Duration::from_millis(5_000),
connection_info: Default::default(),
reputation_weights: Default::default(),
ban_list: Default::default(),
ban_duration: Duration::from_secs(60 * 60 * 12),
backoff_durations: Default::default(),
trusted_nodes: Default::default(),
trusted_nodes_only: false,
basic_nodes: Default::default(),
max_backoff_count: 5,
incoming_ip_throttle_duration: INBOUND_IP_THROTTLE_DURATION,
}
}
}
impl PeersConfig {
pub fn with_ban_list(mut self, ban_list: BanList) -> Self {
self.ban_list = ban_list;
self
}
pub const fn with_ban_duration(mut self, ban_duration: Duration) -> Self {
self.ban_duration = ban_duration;
self
}
pub const fn with_max_outbound(mut self, max_outbound: usize) -> Self {
self.connection_info.max_outbound = max_outbound;
self
}
pub const fn with_max_inbound_opt(mut self, max_inbound: Option<usize>) -> Self {
if let Some(max_inbound) = max_inbound {
self.connection_info.max_inbound = max_inbound;
}
self
}
pub const fn with_max_outbound_opt(mut self, max_outbound: Option<usize>) -> Self {
if let Some(max_outbound) = max_outbound {
self.connection_info.max_outbound = max_outbound;
}
self
}
pub const fn with_max_inbound(mut self, max_inbound: usize) -> Self {
self.connection_info.max_inbound = max_inbound;
self
}
pub const fn with_max_concurrent_dials(mut self, max_concurrent_outbound_dials: usize) -> Self {
self.connection_info.max_concurrent_outbound_dials = max_concurrent_outbound_dials;
self
}
pub fn with_trusted_nodes(mut self, nodes: Vec<TrustedPeer>) -> Self {
self.trusted_nodes = nodes;
self
}
pub const fn with_trusted_nodes_only(mut self, trusted_only: bool) -> Self {
self.trusted_nodes_only = trusted_only;
self
}
pub fn with_basic_nodes(mut self, nodes: HashSet<NodeRecord>) -> Self {
self.basic_nodes = nodes;
self
}
pub const fn with_max_backoff_count(mut self, max_backoff_count: u8) -> Self {
self.max_backoff_count = max_backoff_count;
self
}
pub const fn with_reputation_weights(
mut self,
reputation_weights: ReputationChangeWeights,
) -> Self {
self.reputation_weights = reputation_weights;
self
}
pub const fn with_backoff_durations(mut self, backoff_durations: PeerBackoffDurations) -> Self {
self.backoff_durations = backoff_durations;
self
}
pub const fn max_peers(&self) -> usize {
self.connection_info.max_outbound + self.connection_info.max_inbound
}
pub fn with_basic_nodes_from_file(
self,
optional_file: Option<impl AsRef<Path>>,
) -> Result<Self, io::Error> {
let Some(file_path) = optional_file else { return Ok(self) };
let reader = match std::fs::File::open(file_path.as_ref()) {
Ok(file) => io::BufReader::new(file),
Err(e) if e.kind() == ErrorKind::NotFound => return Ok(self),
Err(e) => Err(e)?,
};
info!(target: "net::peers", file = %file_path.as_ref().display(), "Loading saved peers");
let nodes: HashSet<NodeRecord> = serde_json::from_reader(reader)?;
Ok(self.with_basic_nodes(nodes))
}
#[cfg(any(test, feature = "test-utils"))]
pub fn test() -> Self {
Self {
refill_slots_interval: Duration::from_millis(100),
backoff_durations: PeerBackoffDurations::test(),
ban_duration: Duration::from_millis(200),
..Default::default()
}
}
}