1use alloy_primitives::bytes::Bytes;
7use alloy_rlp::Encodable;
8use reth_net_banlist::BanList;
9use reth_net_nat::{NatResolver, ResolveNatInterval};
10use reth_network_peers::NodeRecord;
11use std::{
12 collections::{HashMap, HashSet},
13 net::IpAddr,
14 time::Duration,
15};
16
17#[derive(Clone, Debug)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub struct Discv4Config {
21 pub udp_egress_message_buffer: usize,
23 pub udp_ingress_message_buffer: usize,
25 pub max_find_node_failures: u8,
27 pub ping_interval: Duration,
30 pub ping_expiration: Duration,
32 pub lookup_interval: Duration,
34 pub request_timeout: Duration,
36 pub enr_expiration: Duration,
38 pub neighbours_expiration: Duration,
40 #[cfg_attr(feature = "serde", serde(skip))]
42 pub ban_list: BanList,
43 pub bootstrap_nodes: HashSet<NodeRecord>,
45 pub enable_dht_random_walk: bool,
49 pub enable_lookup: bool,
51 pub enable_eip868: bool,
53 pub enforce_eip868_neighbours: bool,
60 pub enforce_expiration_timestamps: bool,
62 pub additional_eip868_rlp_pairs: HashMap<Vec<u8>, Bytes>,
64 pub external_ip_resolver: Option<NatResolver>,
66 pub secondary_advertised_ip: Option<IpAddr>,
70 pub resolve_external_ip_interval: Option<Duration>,
73 pub bond_expiration: Duration,
75}
76
77impl Discv4Config {
78 pub fn builder() -> Discv4ConfigBuilder {
80 Default::default()
81 }
82
83 pub fn add_eip868_pair(&mut self, key: impl Into<Vec<u8>>, value: impl Encodable) -> &mut Self {
85 self.add_eip868_rlp_pair(key, Bytes::from(alloy_rlp::encode(&value)))
86 }
87
88 pub fn add_eip868_rlp_pair(&mut self, key: impl Into<Vec<u8>>, rlp: Bytes) -> &mut Self {
90 self.additional_eip868_rlp_pairs.insert(key.into(), rlp);
91 self
92 }
93
94 pub fn extend_eip868_rlp_pairs(
96 &mut self,
97 pairs: impl IntoIterator<Item = (impl Into<Vec<u8>>, Bytes)>,
98 ) -> &mut Self {
99 for (k, v) in pairs {
100 self.add_eip868_rlp_pair(k, v);
101 }
102 self
103 }
104
105 pub fn resolve_external_ip_interval(&self) -> Option<ResolveNatInterval> {
108 let resolver = self.external_ip_resolver.clone()?;
109 let interval = self.resolve_external_ip_interval?;
110 Some(ResolveNatInterval::interval_at(resolver, tokio::time::Instant::now(), interval))
111 }
112}
113
114impl Default for Discv4Config {
115 fn default() -> Self {
116 Self {
117 udp_egress_message_buffer: 1024,
121 udp_ingress_message_buffer: 1024,
123 max_find_node_failures: 5,
124 ping_interval: Duration::from_secs(10),
125 ping_expiration: Duration::from_secs(20),
127 bond_expiration: Duration::from_secs(60 * 60),
128 enr_expiration: Duration::from_secs(20),
129 neighbours_expiration: Duration::from_secs(20),
130 request_timeout: Duration::from_secs(20),
131
132 lookup_interval: Duration::from_secs(20),
133 ban_list: Default::default(),
134 bootstrap_nodes: Default::default(),
135 enable_dht_random_walk: true,
136 enable_lookup: true,
137 enable_eip868: true,
138 enforce_eip868_neighbours: false,
139 enforce_expiration_timestamps: true,
140 additional_eip868_rlp_pairs: Default::default(),
141 external_ip_resolver: Some(Default::default()),
142 secondary_advertised_ip: None,
143 resolve_external_ip_interval: Some(Duration::from_secs(60 * 5)),
145 }
146 }
147}
148
149#[derive(Clone, Debug, Default)]
151#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
152pub struct Discv4ConfigBuilder {
153 config: Discv4Config,
154}
155
156impl Discv4ConfigBuilder {
157 pub const fn udp_ingress_message_buffer(
159 &mut self,
160 udp_ingress_message_buffer: usize,
161 ) -> &mut Self {
162 self.config.udp_ingress_message_buffer = udp_ingress_message_buffer;
163 self
164 }
165
166 pub const fn udp_egress_message_buffer(
168 &mut self,
169 udp_egress_message_buffer: usize,
170 ) -> &mut Self {
171 self.config.udp_egress_message_buffer = udp_egress_message_buffer;
172 self
173 }
174
175 pub const fn max_find_node_failures(&mut self, max_find_node_failures: u8) -> &mut Self {
177 self.config.max_find_node_failures = max_find_node_failures;
178 self
179 }
180
181 pub const fn ping_interval(&mut self, interval: Duration) -> &mut Self {
183 self.config.ping_interval = interval;
184 self
185 }
186
187 pub const fn request_timeout(&mut self, duration: Duration) -> &mut Self {
189 self.config.request_timeout = duration;
190 self
191 }
192
193 pub const fn ping_expiration(&mut self, duration: Duration) -> &mut Self {
195 self.config.ping_expiration = duration;
196 self
197 }
198
199 pub const fn enr_request_expiration(&mut self, duration: Duration) -> &mut Self {
201 self.config.enr_expiration = duration;
202 self
203 }
204
205 pub const fn lookup_neighbours_expiration(&mut self, duration: Duration) -> &mut Self {
207 self.config.neighbours_expiration = duration;
208 self
209 }
210
211 pub const fn bond_expiration(&mut self, duration: Duration) -> &mut Self {
213 self.config.bond_expiration = duration;
214 self
215 }
216
217 pub const fn enable_dht_random_walk(&mut self, enable_dht_random_walk: bool) -> &mut Self {
219 self.config.enable_dht_random_walk = enable_dht_random_walk;
220 self
221 }
222
223 pub const fn enable_lookup(&mut self, enable_lookup: bool) -> &mut Self {
225 self.config.enable_lookup = enable_lookup;
226 self
227 }
228
229 pub const fn enable_eip868(&mut self, enable_eip868: bool) -> &mut Self {
231 self.config.enable_eip868 = enable_eip868;
232 self
233 }
234
235 pub const fn enforce_eip868_neighbours(
238 &mut self,
239 enforce_eip868_neighbours: bool,
240 ) -> &mut Self {
241 self.config.enforce_eip868_neighbours = enforce_eip868_neighbours;
242 self
243 }
244
245 pub const fn enforce_expiration_timestamps(
247 &mut self,
248 enforce_expiration_timestamps: bool,
249 ) -> &mut Self {
250 self.config.enforce_expiration_timestamps = enforce_expiration_timestamps;
251 self
252 }
253
254 pub fn add_eip868_pair(&mut self, key: impl Into<Vec<u8>>, value: impl Encodable) -> &mut Self {
256 self.add_eip868_rlp_pair(key, Bytes::from(alloy_rlp::encode(&value)))
257 }
258
259 pub fn add_eip868_rlp_pair(&mut self, key: impl Into<Vec<u8>>, rlp: Bytes) -> &mut Self {
261 self.config.additional_eip868_rlp_pairs.insert(key.into(), rlp);
262 self
263 }
264
265 pub fn extend_eip868_rlp_pairs(
267 &mut self,
268 pairs: impl IntoIterator<Item = (impl Into<Vec<u8>>, Bytes)>,
269 ) -> &mut Self {
270 for (k, v) in pairs {
271 self.add_eip868_rlp_pair(k, v);
272 }
273 self
274 }
275
276 pub fn ban_list(&mut self, ban_list: BanList) -> &mut Self {
279 self.config.ban_list = ban_list;
280 self
281 }
282
283 pub const fn lookup_interval(&mut self, lookup_interval: Duration) -> &mut Self {
285 self.config.lookup_interval = lookup_interval;
286 self
287 }
288
289 pub fn add_boot_node(&mut self, node: NodeRecord) -> &mut Self {
291 self.config.bootstrap_nodes.insert(node);
292 self
293 }
294
295 pub fn add_boot_nodes(&mut self, nodes: impl IntoIterator<Item = NodeRecord>) -> &mut Self {
297 self.config.bootstrap_nodes.extend(nodes);
298 self
299 }
300
301 pub fn external_ip_resolver(&mut self, external_ip_resolver: Option<NatResolver>) -> &mut Self {
303 self.config.external_ip_resolver = external_ip_resolver;
304 self
305 }
306
307 pub const fn secondary_advertised_ip(&mut self, ip: IpAddr) -> &mut Self {
309 self.config.secondary_advertised_ip = Some(ip);
310 self
311 }
312
313 pub const fn resolve_external_ip_interval(
315 &mut self,
316 resolve_external_ip_interval: Option<Duration>,
317 ) -> &mut Self {
318 self.config.resolve_external_ip_interval = resolve_external_ip_interval;
319 self
320 }
321
322 pub fn build(&self) -> Discv4Config {
324 self.config.clone()
325 }
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331
332 #[test]
333 fn test_config_builder() {
334 let mut builder = Discv4Config::builder();
335 let _ = builder
336 .enable_lookup(true)
337 .enable_dht_random_walk(true)
338 .add_boot_nodes(HashSet::new())
339 .lookup_interval(Duration::from_secs(3))
340 .enable_lookup(true)
341 .build();
342 }
343
344 #[tokio::test]
345 async fn test_resolve_external_ip_interval_uses_interval_at() {
346 use reth_net_nat::NatResolver;
347 use std::net::{IpAddr, Ipv4Addr};
348
349 let ip_addr = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1));
350
351 let mut builder = Discv4Config::builder();
353 builder.external_ip_resolver(Some(NatResolver::ExternalIp(ip_addr)));
354 builder.resolve_external_ip_interval(Some(Duration::from_secs(60 * 5)));
355 let config = builder.build();
356
357 let mut interval = config.resolve_external_ip_interval().expect("should have interval");
359
360 let ip = interval.tick().await;
362 assert_eq!(ip, Some(ip_addr));
363 }
364}