reth_network_types/peers/
config.rs1use std::{collections::HashSet, time::Duration};
4
5use reth_net_banlist::{BanList, IpFilter};
6use reth_network_peers::{NodeRecord, TrustedPeer};
7
8use crate::{peers::PersistedPeerInfo, BackoffKind, ReputationChangeWeights};
9
10pub const DEFAULT_MAX_COUNT_PEERS_OUTBOUND: u32 = 100;
12
13pub const DEFAULT_MAX_COUNT_PEERS_INBOUND: u32 = 30;
15
16pub const DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS: usize = 30;
20
21pub const INBOUND_IP_THROTTLE_DURATION: Duration = Duration::from_secs(30);
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29pub struct PeerBackoffDurations {
30 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
33 pub low: Duration,
34 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
37 pub medium: Duration,
38 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
40 pub high: Duration,
41 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
43 pub max: Duration,
44}
45
46impl PeerBackoffDurations {
47 pub const fn backoff(&self, kind: BackoffKind) -> Duration {
49 match kind {
50 BackoffKind::Low => self.low,
51 BackoffKind::Medium => self.medium,
52 BackoffKind::High => self.high,
53 }
54 }
55
56 pub fn backoff_until(&self, kind: BackoffKind, backoff_counter: u8) -> std::time::Instant {
60 let backoff_time = self.backoff(kind);
61 let backoff_time = backoff_time + backoff_time * backoff_counter as u32;
62 let now = std::time::Instant::now();
63 now + backoff_time.min(self.max)
64 }
65
66 #[cfg(any(test, feature = "test-utils"))]
68 pub const fn test() -> Self {
69 Self {
70 low: Duration::from_millis(200),
71 medium: Duration::from_millis(200),
72 high: Duration::from_millis(200),
73 max: Duration::from_millis(200),
74 }
75 }
76}
77
78impl Default for PeerBackoffDurations {
79 fn default() -> Self {
80 Self {
81 low: Duration::from_secs(30),
82 medium: Duration::from_secs(60 * 3),
84 high: Duration::from_secs(60 * 15),
86 max: Duration::from_secs(60 * 60),
88 }
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
94#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(default))]
95pub struct ConnectionsConfig {
96 pub max_outbound: usize,
98 pub max_inbound: usize,
100 #[cfg_attr(feature = "serde", serde(default))]
102 pub max_concurrent_outbound_dials: usize,
103}
104
105impl Default for ConnectionsConfig {
106 fn default() -> Self {
107 Self {
108 max_outbound: DEFAULT_MAX_COUNT_PEERS_OUTBOUND as usize,
109 max_inbound: DEFAULT_MAX_COUNT_PEERS_INBOUND as usize,
110 max_concurrent_outbound_dials: DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS,
111 }
112 }
113}
114
115pub const DEFAULT_PEER_ROTATION_INTERVAL: Duration = Duration::from_mins(5);
120
121pub const PEER_ROTATION_MIN_UPTIME: Duration = Duration::from_mins(10);
123
124#[derive(Debug, Clone, PartialEq, Eq)]
126#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
127#[cfg_attr(feature = "serde", serde(default))]
128pub struct PeersConfig {
129 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
131 pub refill_slots_interval: Duration,
132 pub trusted_nodes: Vec<TrustedPeer>,
134 #[cfg_attr(feature = "serde", serde(alias = "connect_trusted_nodes_only"))]
136 pub trusted_nodes_only: bool,
137 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
139 pub trusted_nodes_resolution_interval: Duration,
140 pub max_backoff_count: u8,
150 #[cfg_attr(feature = "serde", serde(skip))]
152 pub basic_nodes: HashSet<NodeRecord>,
153 #[cfg_attr(feature = "serde", serde(skip))]
155 pub persisted_peers: Vec<PersistedPeerInfo>,
156 #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))]
158 pub ban_duration: Duration,
159 #[cfg_attr(feature = "serde", serde(skip))]
161 pub ban_list: BanList,
162 pub connection_info: ConnectionsConfig,
164 pub reputation_weights: ReputationChangeWeights,
166 pub backoff_durations: PeerBackoffDurations,
170 #[cfg_attr(feature = "serde", serde(default, with = "humantime_serde"))]
174 pub incoming_ip_throttle_duration: Duration,
175 #[cfg_attr(feature = "serde", serde(skip))]
180 pub ip_filter: IpFilter,
181 pub enforce_enr_fork_id: bool,
186 #[cfg_attr(feature = "serde", serde(default, with = "humantime_serde"))]
189 pub peer_rotation_interval: Option<Duration>,
190}
191
192impl Default for PeersConfig {
193 fn default() -> Self {
194 Self {
195 refill_slots_interval: Duration::from_millis(5_000),
196 connection_info: Default::default(),
197 reputation_weights: Default::default(),
198 ban_list: Default::default(),
199 ban_duration: Duration::from_secs(60 * 60 * 12),
201 backoff_durations: Default::default(),
202 trusted_nodes: Default::default(),
203 trusted_nodes_only: false,
204 trusted_nodes_resolution_interval: Duration::from_secs(60 * 60),
205 basic_nodes: Default::default(),
206 persisted_peers: Default::default(),
207 max_backoff_count: 5,
208 incoming_ip_throttle_duration: INBOUND_IP_THROTTLE_DURATION,
209 ip_filter: IpFilter::default(),
210 enforce_enr_fork_id: false,
211 peer_rotation_interval: Some(DEFAULT_PEER_ROTATION_INTERVAL),
212 }
213 }
214}
215
216impl PeersConfig {
217 pub fn with_ban_list(mut self, ban_list: BanList) -> Self {
219 self.ban_list = ban_list;
220 self
221 }
222
223 pub const fn with_ban_duration(mut self, ban_duration: Duration) -> Self {
225 self.ban_duration = ban_duration;
226 self
227 }
228
229 pub const fn with_refill_slots_interval(mut self, interval: Duration) -> Self {
231 self.refill_slots_interval = interval;
232 self
233 }
234
235 pub const fn with_max_outbound(mut self, max_outbound: usize) -> Self {
237 self.connection_info.max_outbound = max_outbound;
238 self
239 }
240
241 pub const fn with_max_inbound_opt(mut self, max_inbound: Option<usize>) -> Self {
243 if let Some(max_inbound) = max_inbound {
244 self.connection_info.max_inbound = max_inbound;
245 }
246 self
247 }
248
249 pub const fn with_max_outbound_opt(mut self, max_outbound: Option<usize>) -> Self {
251 if let Some(max_outbound) = max_outbound {
252 self.connection_info.max_outbound = max_outbound;
253 }
254 self
255 }
256
257 pub const fn with_max_inbound(mut self, max_inbound: usize) -> Self {
259 self.connection_info.max_inbound = max_inbound;
260 self
261 }
262
263 pub const fn with_max_concurrent_dials(mut self, max_concurrent_outbound_dials: usize) -> Self {
265 self.connection_info.max_concurrent_outbound_dials = max_concurrent_outbound_dials;
266 self
267 }
268
269 pub fn with_trusted_nodes(mut self, nodes: Vec<TrustedPeer>) -> Self {
271 self.trusted_nodes = nodes;
272 self
273 }
274
275 pub const fn with_trusted_nodes_only(mut self, trusted_only: bool) -> Self {
277 self.trusted_nodes_only = trusted_only;
278 self
279 }
280
281 pub fn with_basic_nodes(mut self, nodes: HashSet<NodeRecord>) -> Self {
283 self.basic_nodes = nodes;
284 self
285 }
286
287 pub const fn with_max_backoff_count(mut self, max_backoff_count: u8) -> Self {
289 self.max_backoff_count = max_backoff_count;
290 self
291 }
292
293 pub const fn with_reputation_weights(
295 mut self,
296 reputation_weights: ReputationChangeWeights,
297 ) -> Self {
298 self.reputation_weights = reputation_weights;
299 self
300 }
301
302 pub const fn with_backoff_durations(mut self, backoff_durations: PeerBackoffDurations) -> Self {
304 self.backoff_durations = backoff_durations;
305 self
306 }
307
308 pub const fn max_peers(&self) -> usize {
310 self.connection_info.max_outbound + self.connection_info.max_inbound
311 }
312
313 #[cfg(feature = "serde")]
320 pub fn with_basic_nodes_from_file(
321 mut self,
322 optional_file: Option<impl AsRef<std::path::Path>>,
323 ) -> Result<Self, std::io::Error> {
324 let Some(file_path) = optional_file else { return Ok(self) };
325 let raw = match std::fs::read_to_string(file_path.as_ref()) {
326 Ok(contents) => contents,
327 Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(self),
328 Err(e) => return Err(e),
329 };
330
331 tracing::info!(target: "net::peers", file = %file_path.as_ref().display(), "Loading saved peers");
332
333 let peers: Vec<PersistedPeerInfo> = serde_json::from_str(&raw)
335 .or_else(|_| {
336 let nodes: HashSet<NodeRecord> = serde_json::from_str(&raw)?;
337 Ok::<_, serde_json::Error>(
338 nodes.into_iter().map(PersistedPeerInfo::from_node_record).collect(),
339 )
340 })
341 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
342
343 tracing::info!(target: "net::peers", count = peers.len(), "Loaded persisted peers");
344 self.persisted_peers = peers;
345 Ok(self)
346 }
347
348 pub fn with_ip_filter(mut self, ip_filter: IpFilter) -> Self {
350 self.ip_filter = ip_filter;
351 self
352 }
353
354 pub const fn with_enforce_enr_fork_id(mut self, enforce: bool) -> Self {
357 self.enforce_enr_fork_id = enforce;
358 self
359 }
360
361 pub const fn with_peer_rotation_interval(mut self, interval: Option<Duration>) -> Self {
364 self.peer_rotation_interval = interval;
365 self
366 }
367
368 #[cfg(any(test, feature = "test-utils"))]
370 pub fn test() -> Self {
371 Self {
372 refill_slots_interval: Duration::from_millis(100),
373 backoff_durations: PeerBackoffDurations::test(),
374 ban_duration: Duration::from_millis(200),
375 peer_rotation_interval: None,
376 ..Default::default()
377 }
378 }
379}