reth_network_types/peers/
config.rs1use std::{
4 collections::HashSet,
5 io::{self, ErrorKind},
6 path::Path,
7 time::Duration,
8};
9
10use reth_net_banlist::{BanList, IpFilter};
11use reth_network_peers::{NodeRecord, TrustedPeer};
12use tracing::info;
13
14use crate::{peers::PersistedPeerInfo, BackoffKind, ReputationChangeWeights};
15
16pub const DEFAULT_MAX_COUNT_PEERS_OUTBOUND: u32 = 100;
18
19pub const DEFAULT_MAX_COUNT_PEERS_INBOUND: u32 = 30;
21
22pub const DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS: usize = 30;
26
27pub const INBOUND_IP_THROTTLE_DURATION: Duration = Duration::from_secs(30);
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35pub struct PeerBackoffDurations {
36 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
39 pub low: Duration,
40 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
43 pub medium: Duration,
44 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
46 pub high: Duration,
47 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
49 pub max: Duration,
50}
51
52impl PeerBackoffDurations {
53 pub const fn backoff(&self, kind: BackoffKind) -> Duration {
55 match kind {
56 BackoffKind::Low => self.low,
57 BackoffKind::Medium => self.medium,
58 BackoffKind::High => self.high,
59 }
60 }
61
62 pub fn backoff_until(&self, kind: BackoffKind, backoff_counter: u8) -> std::time::Instant {
66 let backoff_time = self.backoff(kind);
67 let backoff_time = backoff_time + backoff_time * backoff_counter as u32;
68 let now = std::time::Instant::now();
69 now + backoff_time.min(self.max)
70 }
71
72 #[cfg(any(test, feature = "test-utils"))]
74 pub const fn test() -> Self {
75 Self {
76 low: Duration::from_millis(200),
77 medium: Duration::from_millis(200),
78 high: Duration::from_millis(200),
79 max: Duration::from_millis(200),
80 }
81 }
82}
83
84impl Default for PeerBackoffDurations {
85 fn default() -> Self {
86 Self {
87 low: Duration::from_secs(30),
88 medium: Duration::from_secs(60 * 3),
90 high: Duration::from_secs(60 * 15),
92 max: Duration::from_secs(60 * 60),
94 }
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, Eq)]
100#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(default))]
101pub struct ConnectionsConfig {
102 pub max_outbound: usize,
104 pub max_inbound: usize,
106 #[cfg_attr(feature = "serde", serde(default))]
108 pub max_concurrent_outbound_dials: usize,
109}
110
111impl Default for ConnectionsConfig {
112 fn default() -> Self {
113 Self {
114 max_outbound: DEFAULT_MAX_COUNT_PEERS_OUTBOUND as usize,
115 max_inbound: DEFAULT_MAX_COUNT_PEERS_INBOUND as usize,
116 max_concurrent_outbound_dials: DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS,
117 }
118 }
119}
120
121#[derive(Debug, Clone, PartialEq, Eq)]
123#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
124#[cfg_attr(feature = "serde", serde(default))]
125pub struct PeersConfig {
126 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
128 pub refill_slots_interval: Duration,
129 pub trusted_nodes: Vec<TrustedPeer>,
131 #[cfg_attr(feature = "serde", serde(alias = "connect_trusted_nodes_only"))]
133 pub trusted_nodes_only: bool,
134 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
136 pub trusted_nodes_resolution_interval: Duration,
137 pub max_backoff_count: u8,
147 #[cfg_attr(feature = "serde", serde(skip))]
149 pub basic_nodes: HashSet<NodeRecord>,
150 #[cfg_attr(feature = "serde", serde(skip))]
152 pub persisted_peers: Vec<PersistedPeerInfo>,
153 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
155 pub ban_duration: Duration,
156 #[cfg_attr(feature = "serde", serde(skip))]
158 pub ban_list: BanList,
159 pub connection_info: ConnectionsConfig,
161 pub reputation_weights: ReputationChangeWeights,
163 pub backoff_durations: PeerBackoffDurations,
167 #[cfg_attr(feature = "serde", serde(default, with = "humantime_serde"))]
171 pub incoming_ip_throttle_duration: Duration,
172 #[cfg_attr(feature = "serde", serde(skip))]
177 pub ip_filter: IpFilter,
178 pub enforce_enr_fork_id: bool,
183}
184
185impl Default for PeersConfig {
186 fn default() -> Self {
187 Self {
188 refill_slots_interval: Duration::from_millis(5_000),
189 connection_info: Default::default(),
190 reputation_weights: Default::default(),
191 ban_list: Default::default(),
192 ban_duration: Duration::from_secs(60 * 60 * 12),
194 backoff_durations: Default::default(),
195 trusted_nodes: Default::default(),
196 trusted_nodes_only: false,
197 trusted_nodes_resolution_interval: Duration::from_secs(60 * 60),
198 basic_nodes: Default::default(),
199 persisted_peers: Default::default(),
200 max_backoff_count: 5,
201 incoming_ip_throttle_duration: INBOUND_IP_THROTTLE_DURATION,
202 ip_filter: IpFilter::default(),
203 enforce_enr_fork_id: false,
204 }
205 }
206}
207
208impl PeersConfig {
209 pub fn with_ban_list(mut self, ban_list: BanList) -> Self {
211 self.ban_list = ban_list;
212 self
213 }
214
215 pub const fn with_ban_duration(mut self, ban_duration: Duration) -> Self {
217 self.ban_duration = ban_duration;
218 self
219 }
220
221 pub const fn with_refill_slots_interval(mut self, interval: Duration) -> Self {
223 self.refill_slots_interval = interval;
224 self
225 }
226
227 pub const fn with_max_outbound(mut self, max_outbound: usize) -> Self {
229 self.connection_info.max_outbound = max_outbound;
230 self
231 }
232
233 pub const fn with_max_inbound_opt(mut self, max_inbound: Option<usize>) -> Self {
235 if let Some(max_inbound) = max_inbound {
236 self.connection_info.max_inbound = max_inbound;
237 }
238 self
239 }
240
241 pub const fn with_max_outbound_opt(mut self, max_outbound: Option<usize>) -> Self {
243 if let Some(max_outbound) = max_outbound {
244 self.connection_info.max_outbound = max_outbound;
245 }
246 self
247 }
248
249 pub const fn with_max_inbound(mut self, max_inbound: usize) -> Self {
251 self.connection_info.max_inbound = max_inbound;
252 self
253 }
254
255 pub const fn with_max_concurrent_dials(mut self, max_concurrent_outbound_dials: usize) -> Self {
257 self.connection_info.max_concurrent_outbound_dials = max_concurrent_outbound_dials;
258 self
259 }
260
261 pub fn with_trusted_nodes(mut self, nodes: Vec<TrustedPeer>) -> Self {
263 self.trusted_nodes = nodes;
264 self
265 }
266
267 pub const fn with_trusted_nodes_only(mut self, trusted_only: bool) -> Self {
269 self.trusted_nodes_only = trusted_only;
270 self
271 }
272
273 pub fn with_basic_nodes(mut self, nodes: HashSet<NodeRecord>) -> Self {
275 self.basic_nodes = nodes;
276 self
277 }
278
279 pub const fn with_max_backoff_count(mut self, max_backoff_count: u8) -> Self {
281 self.max_backoff_count = max_backoff_count;
282 self
283 }
284
285 pub const fn with_reputation_weights(
287 mut self,
288 reputation_weights: ReputationChangeWeights,
289 ) -> Self {
290 self.reputation_weights = reputation_weights;
291 self
292 }
293
294 pub const fn with_backoff_durations(mut self, backoff_durations: PeerBackoffDurations) -> Self {
296 self.backoff_durations = backoff_durations;
297 self
298 }
299
300 pub const fn max_peers(&self) -> usize {
302 self.connection_info.max_outbound + self.connection_info.max_inbound
303 }
304
305 #[cfg(feature = "serde")]
312 pub fn with_basic_nodes_from_file(
313 mut self,
314 optional_file: Option<impl AsRef<Path>>,
315 ) -> Result<Self, io::Error> {
316 let Some(file_path) = optional_file else { return Ok(self) };
317 let raw = match std::fs::read_to_string(file_path.as_ref()) {
318 Ok(contents) => contents,
319 Err(e) if e.kind() == ErrorKind::NotFound => return Ok(self),
320 Err(e) => return Err(e),
321 };
322
323 info!(target: "net::peers", file = %file_path.as_ref().display(), "Loading saved peers");
324
325 let peers: Vec<PersistedPeerInfo> = serde_json::from_str(&raw)
327 .or_else(|_| {
328 let nodes: HashSet<NodeRecord> = serde_json::from_str(&raw)?;
329 Ok::<_, serde_json::Error>(
330 nodes.into_iter().map(PersistedPeerInfo::from_node_record).collect(),
331 )
332 })
333 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
334
335 info!(target: "net::peers", count = peers.len(), "Loaded persisted peers");
336 self.persisted_peers = peers;
337 Ok(self)
338 }
339
340 pub fn with_ip_filter(mut self, ip_filter: IpFilter) -> Self {
342 self.ip_filter = ip_filter;
343 self
344 }
345
346 pub const fn with_enforce_enr_fork_id(mut self, enforce: bool) -> Self {
349 self.enforce_enr_fork_id = enforce;
350 self
351 }
352
353 #[cfg(any(test, feature = "test-utils"))]
355 pub fn test() -> Self {
356 Self {
357 refill_slots_interval: Duration::from_millis(100),
358 backoff_durations: PeerBackoffDurations::test(),
359 ban_duration: Duration::from_millis(200),
360 ..Default::default()
361 }
362 }
363}