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 time::Duration,
14};
15
16#[derive(Clone, Debug)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct Discv4Config {
20 pub udp_egress_message_buffer: usize,
22 pub udp_ingress_message_buffer: usize,
24 pub max_find_node_failures: u8,
26 pub ping_interval: Duration,
29 pub ping_expiration: Duration,
31 pub lookup_interval: Duration,
33 pub request_timeout: Duration,
35 pub enr_expiration: Duration,
37 pub neighbours_expiration: Duration,
39 #[cfg_attr(feature = "serde", serde(skip))]
41 pub ban_list: BanList,
42 pub bootstrap_nodes: HashSet<NodeRecord>,
44 pub enable_dht_random_walk: bool,
48 pub enable_lookup: bool,
50 pub enable_eip868: bool,
52 pub enforce_eip868_neighbours: bool,
59 pub enforce_expiration_timestamps: bool,
61 pub additional_eip868_rlp_pairs: HashMap<Vec<u8>, Bytes>,
63 pub external_ip_resolver: Option<NatResolver>,
65 pub resolve_external_ip_interval: Option<Duration>,
68 pub bond_expiration: Duration,
70}
71
72impl Discv4Config {
73 pub fn builder() -> Discv4ConfigBuilder {
75 Default::default()
76 }
77
78 pub fn add_eip868_pair(&mut self, key: impl Into<Vec<u8>>, value: impl Encodable) -> &mut Self {
80 self.add_eip868_rlp_pair(key, Bytes::from(alloy_rlp::encode(&value)))
81 }
82
83 pub fn add_eip868_rlp_pair(&mut self, key: impl Into<Vec<u8>>, rlp: Bytes) -> &mut Self {
85 self.additional_eip868_rlp_pairs.insert(key.into(), rlp);
86 self
87 }
88
89 pub fn extend_eip868_rlp_pairs(
91 &mut self,
92 pairs: impl IntoIterator<Item = (impl Into<Vec<u8>>, Bytes)>,
93 ) -> &mut Self {
94 for (k, v) in pairs {
95 self.add_eip868_rlp_pair(k, v);
96 }
97 self
98 }
99
100 pub fn resolve_external_ip_interval(&self) -> Option<ResolveNatInterval> {
103 let resolver = self.external_ip_resolver.clone()?;
104 let interval = self.resolve_external_ip_interval?;
105 Some(ResolveNatInterval::interval_at(resolver, tokio::time::Instant::now(), interval))
106 }
107}
108
109impl Default for Discv4Config {
110 fn default() -> Self {
111 Self {
112 udp_egress_message_buffer: 1024,
116 udp_ingress_message_buffer: 1024,
118 max_find_node_failures: 5,
119 ping_interval: Duration::from_secs(10),
120 ping_expiration: Duration::from_secs(20),
122 bond_expiration: Duration::from_secs(60 * 60),
123 enr_expiration: Duration::from_secs(20),
124 neighbours_expiration: Duration::from_secs(20),
125 request_timeout: Duration::from_secs(20),
126
127 lookup_interval: Duration::from_secs(20),
128 ban_list: Default::default(),
129 bootstrap_nodes: Default::default(),
130 enable_dht_random_walk: true,
131 enable_lookup: true,
132 enable_eip868: true,
133 enforce_eip868_neighbours: false,
134 enforce_expiration_timestamps: true,
135 additional_eip868_rlp_pairs: Default::default(),
136 external_ip_resolver: Some(Default::default()),
137 resolve_external_ip_interval: Some(Duration::from_secs(60 * 5)),
139 }
140 }
141}
142
143#[derive(Clone, Debug, Default)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146pub struct Discv4ConfigBuilder {
147 config: Discv4Config,
148}
149
150impl Discv4ConfigBuilder {
151 pub const fn udp_ingress_message_buffer(
153 &mut self,
154 udp_ingress_message_buffer: usize,
155 ) -> &mut Self {
156 self.config.udp_ingress_message_buffer = udp_ingress_message_buffer;
157 self
158 }
159
160 pub const fn udp_egress_message_buffer(
162 &mut self,
163 udp_egress_message_buffer: usize,
164 ) -> &mut Self {
165 self.config.udp_egress_message_buffer = udp_egress_message_buffer;
166 self
167 }
168
169 pub const fn max_find_node_failures(&mut self, max_find_node_failures: u8) -> &mut Self {
171 self.config.max_find_node_failures = max_find_node_failures;
172 self
173 }
174
175 pub const fn ping_interval(&mut self, interval: Duration) -> &mut Self {
177 self.config.ping_interval = interval;
178 self
179 }
180
181 pub const fn request_timeout(&mut self, duration: Duration) -> &mut Self {
183 self.config.request_timeout = duration;
184 self
185 }
186
187 pub const fn ping_expiration(&mut self, duration: Duration) -> &mut Self {
189 self.config.ping_expiration = duration;
190 self
191 }
192
193 pub const fn enr_request_expiration(&mut self, duration: Duration) -> &mut Self {
195 self.config.enr_expiration = duration;
196 self
197 }
198
199 pub const fn lookup_neighbours_expiration(&mut self, duration: Duration) -> &mut Self {
201 self.config.neighbours_expiration = duration;
202 self
203 }
204
205 pub const fn bond_expiration(&mut self, duration: Duration) -> &mut Self {
207 self.config.bond_expiration = duration;
208 self
209 }
210
211 pub const fn enable_dht_random_walk(&mut self, enable_dht_random_walk: bool) -> &mut Self {
213 self.config.enable_dht_random_walk = enable_dht_random_walk;
214 self
215 }
216
217 pub const fn enable_lookup(&mut self, enable_lookup: bool) -> &mut Self {
219 self.config.enable_lookup = enable_lookup;
220 self
221 }
222
223 pub const fn enable_eip868(&mut self, enable_eip868: bool) -> &mut Self {
225 self.config.enable_eip868 = enable_eip868;
226 self
227 }
228
229 pub const fn enforce_eip868_neighbours(
232 &mut self,
233 enforce_eip868_neighbours: bool,
234 ) -> &mut Self {
235 self.config.enforce_eip868_neighbours = enforce_eip868_neighbours;
236 self
237 }
238
239 pub const fn enforce_expiration_timestamps(
241 &mut self,
242 enforce_expiration_timestamps: bool,
243 ) -> &mut Self {
244 self.config.enforce_expiration_timestamps = enforce_expiration_timestamps;
245 self
246 }
247
248 pub fn add_eip868_pair(&mut self, key: impl Into<Vec<u8>>, value: impl Encodable) -> &mut Self {
250 self.add_eip868_rlp_pair(key, Bytes::from(alloy_rlp::encode(&value)))
251 }
252
253 pub fn add_eip868_rlp_pair(&mut self, key: impl Into<Vec<u8>>, rlp: Bytes) -> &mut Self {
255 self.config.additional_eip868_rlp_pairs.insert(key.into(), rlp);
256 self
257 }
258
259 pub fn extend_eip868_rlp_pairs(
261 &mut self,
262 pairs: impl IntoIterator<Item = (impl Into<Vec<u8>>, Bytes)>,
263 ) -> &mut Self {
264 for (k, v) in pairs {
265 self.add_eip868_rlp_pair(k, v);
266 }
267 self
268 }
269
270 pub fn ban_list(&mut self, ban_list: BanList) -> &mut Self {
273 self.config.ban_list = ban_list;
274 self
275 }
276
277 pub const fn lookup_interval(&mut self, lookup_interval: Duration) -> &mut Self {
279 self.config.lookup_interval = lookup_interval;
280 self
281 }
282
283 pub fn add_boot_node(&mut self, node: NodeRecord) -> &mut Self {
285 self.config.bootstrap_nodes.insert(node);
286 self
287 }
288
289 pub fn add_boot_nodes(&mut self, nodes: impl IntoIterator<Item = NodeRecord>) -> &mut Self {
291 self.config.bootstrap_nodes.extend(nodes);
292 self
293 }
294
295 pub fn external_ip_resolver(&mut self, external_ip_resolver: Option<NatResolver>) -> &mut Self {
297 self.config.external_ip_resolver = external_ip_resolver;
298 self
299 }
300
301 pub const fn resolve_external_ip_interval(
303 &mut self,
304 resolve_external_ip_interval: Option<Duration>,
305 ) -> &mut Self {
306 self.config.resolve_external_ip_interval = resolve_external_ip_interval;
307 self
308 }
309
310 pub fn build(&self) -> Discv4Config {
312 self.config.clone()
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319
320 #[test]
321 fn test_config_builder() {
322 let mut builder = Discv4Config::builder();
323 let _ = builder
324 .enable_lookup(true)
325 .enable_dht_random_walk(true)
326 .add_boot_nodes(HashSet::new())
327 .lookup_interval(Duration::from_secs(3))
328 .enable_lookup(true)
329 .build();
330 }
331
332 #[tokio::test]
333 async fn test_resolve_external_ip_interval_uses_interval_at() {
334 use reth_net_nat::NatResolver;
335 use std::net::{IpAddr, Ipv4Addr};
336
337 let ip_addr = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1));
338
339 let mut builder = Discv4Config::builder();
341 builder.external_ip_resolver(Some(NatResolver::ExternalIp(ip_addr)));
342 builder.resolve_external_ip_interval(Some(Duration::from_secs(60 * 5)));
343 let config = builder.build();
344
345 let mut interval = config.resolve_external_ip_interval().expect("should have interval");
347
348 let ip = interval.tick().await;
350 assert_eq!(ip, Some(ip_addr));
351 }
352}