1#![cfg(feature = "full")]
5
6use crate::alias;
7
8use libp2p::{multiaddr::Protocol, Multiaddr, PeerId};
9use serde::Deserialize;
10
11use std::{borrow::Cow, collections::HashSet};
12
13const DEFAULT_BIND_MULTIADDR: &str = "/ip4/0.0.0.0/tcp/15600";
14
15pub const DEFAULT_RECONNECT_INTERVAL_SECS: u64 = 30;
16const MIN_RECONNECT_INTERVAL_SECS: u64 = 1;
17
18pub const DEFAULT_MAX_UNKOWN_PEERS: usize = 4;
19
20#[derive(Debug, thiserror::Error)]
22pub enum Error {
23 #[error("Multiaddr is underspecified.")]
25 MultiaddrUnderspecified,
26
27 #[error("Multiaddr is overspecified.")]
29 MultiaddrOverspecified,
30
31 #[error("Invalid Multiaddr protocol at {}.", .0)]
33 InvalidProtocol(usize),
34
35 #[error("Invalid address protocol.")]
37 InvalidAddressProtocol,
38
39 #[error("Invalid port protocol.")]
41 InvalidPortProtocol,
42
43 #[error("Static peer {} already added.", alias!(.0))]
45 DuplicateStaticPeer(PeerId),
46
47 #[error("Domain name '{}' couldn't be resolved to an IP address", .0)]
49 UnresolvableDomain(String),
50
51 #[error("Parsing of '{}' to a Multiaddr failed.", 0)]
53 ParsingFailed(String),
54
55 #[error("Invalid P2p Multiaddr. Did you forget to add '.../p2p/12D3Koo...'?")]
57 MissingP2pProtocol,
58}
59
60#[derive(Clone)]
62pub struct NetworkConfig {
63 pub(crate) bind_multiaddr: Multiaddr,
64 pub(crate) reconnect_interval_secs: u64,
65 pub(crate) max_unknown_peers: usize,
66 pub(crate) static_peers: HashSet<Peer>,
67}
68
69impl NetworkConfig {
70 pub fn new() -> Self {
72 Self::default()
73 }
74
75 pub fn build() -> NetworkConfigBuilder {
77 NetworkConfigBuilder::new()
78 }
79
80 #[cfg(test)]
82 pub fn build_in_memory() -> InMemoryNetworkConfigBuilder {
83 InMemoryNetworkConfigBuilder::new()
84 }
85
86 pub fn replace_addr(&mut self, mut addr: Protocol) -> Result<(), Error> {
90 if !matches!(addr, Protocol::Ip4(_) | Protocol::Ip6(_) | Protocol::Dns(_)) {
91 return Err(Error::InvalidAddressProtocol);
92 }
93
94 if let Protocol::Dns(dns) = addr {
95 addr = resolve_dns_multiaddr(dns)?;
96 }
97
98 let port = self.bind_multiaddr.pop().unwrap();
101
102 let _ = self.bind_multiaddr.pop().unwrap();
103
104 self.bind_multiaddr.push(addr);
105 self.bind_multiaddr.push(port);
106
107 Ok(())
108 }
109
110 pub fn replace_port(&mut self, port: Protocol) -> Result<(), Error> {
114 if !matches!(port, Protocol::Tcp(_)) {
115 return Err(Error::InvalidPortProtocol);
116 }
117
118 self.bind_multiaddr.pop();
119 self.bind_multiaddr.push(port);
120
121 Ok(())
122 }
123
124 pub fn add_static_peer(
126 &mut self,
127 peer_id: PeerId,
128 multiaddr: Multiaddr,
129 alias: Option<String>,
130 ) -> Result<(), Error> {
131 if !self.static_peers.insert(Peer {
132 peer_id,
133 multiaddr,
134 alias,
135 }) {
136 return Err(Error::DuplicateStaticPeer(peer_id));
137 }
138
139 Ok(())
140 }
141
142 pub fn bind_multiaddr(&self) -> &Multiaddr {
144 &self.bind_multiaddr
145 }
146
147 pub fn reconnect_interval_secs(&self) -> u64 {
149 self.reconnect_interval_secs
150 }
151
152 pub fn max_unknown_peers(&self) -> usize {
154 self.max_unknown_peers
155 }
156
157 pub fn static_peers(&self) -> &HashSet<Peer> {
159 &self.static_peers
160 }
161}
162
163fn resolve_dns_multiaddr(dns: Cow<'_, str>) -> Result<Protocol, Error> {
164 use std::net::{IpAddr, ToSocketAddrs};
165
166 match dns
167 .to_socket_addrs()
168 .map_err(|_| Error::UnresolvableDomain(dns.to_string()))?
169 .next()
170 .ok_or_else(|| Error::UnresolvableDomain(dns.to_string()))?
171 .ip()
172 {
173 IpAddr::V4(ip4) => return Ok(Protocol::Ip4(ip4)),
174 IpAddr::V6(ip6) => return Ok(Protocol::Ip6(ip6)),
175 }
176}
177
178impl Default for NetworkConfig {
179 fn default() -> Self {
180 Self {
181 bind_multiaddr: DEFAULT_BIND_MULTIADDR.parse().unwrap(),
184 reconnect_interval_secs: DEFAULT_RECONNECT_INTERVAL_SECS,
185 max_unknown_peers: DEFAULT_MAX_UNKOWN_PEERS,
186 static_peers: Default::default(),
187 }
188 }
189}
190
191#[derive(Default, Deserialize)]
193pub struct NetworkConfigBuilder {
194 #[serde(rename = "bind_address")]
195 bind_multiaddr: Option<Multiaddr>,
196 reconnect_interval_secs: Option<u64>,
197 max_unknown_peers: Option<usize>,
198 peering: PeeringConfigBuilder,
199}
200
201impl NetworkConfigBuilder {
202 pub fn new() -> Self {
204 Self::default()
205 }
206
207 pub fn with_bind_multiaddr(mut self, mut multiaddr: Multiaddr) -> Result<Self, Error> {
209 let mut valid = false;
210 let mut is_dns = false;
211
212 for (i, p) in multiaddr.iter().enumerate() {
213 match i {
214 0 => {
215 if !matches!(p, Protocol::Ip4(_) | Protocol::Ip6(_) | Protocol::Dns(_)) {
216 return Err(Error::InvalidProtocol(0));
217 }
218
219 if matches!(p, Protocol::Dns(_)) {
220 is_dns = true;
221 }
222 }
223 1 => {
224 if !matches!(p, Protocol::Tcp(_)) {
225 return Err(Error::InvalidProtocol(1));
226 }
227 valid = true;
228 }
229 _ => return Err(Error::MultiaddrOverspecified),
230 }
231 }
232 if !valid {
233 return Err(Error::MultiaddrUnderspecified);
234 }
235
236 if is_dns {
237 let port = multiaddr.pop().unwrap();
238 let port = if let Protocol::Tcp(port) = port {
239 port
240 } else {
241 unreachable!("already checked");
242 };
243 let ip = if let Protocol::Dns(dns) = multiaddr.pop().unwrap() {
246 let socket_dns = {
247 let mut socket_addr = String::with_capacity(16);
248 socket_addr.push_str(&dns);
249 socket_addr.push(':');
250 socket_addr.push_str(&port.to_string());
251 socket_addr
252 };
253
254 resolve_dns_multiaddr(socket_dns.into())?
255 } else {
256 unreachable!("already checked");
257 };
258
259 multiaddr.push(ip);
260 multiaddr.push(Protocol::Tcp(port));
261 }
262
263 self.bind_multiaddr.replace(multiaddr);
264 Ok(self)
265 }
266
267 pub fn with_reconnect_interval_secs(mut self, secs: u64) -> Self {
271 let secs = secs.max(MIN_RECONNECT_INTERVAL_SECS);
272 self.reconnect_interval_secs.replace(secs);
273 self
274 }
275
276 pub fn with_max_unknown_peers(mut self, n: usize) -> Self {
278 self.max_unknown_peers.replace(n);
279 self
280 }
281
282 pub fn finish(self) -> Result<NetworkConfig, Error> {
284 Ok(NetworkConfig {
285 bind_multiaddr: self
286 .bind_multiaddr
287 .unwrap_or_else(|| DEFAULT_BIND_MULTIADDR.parse().unwrap()),
290 reconnect_interval_secs: self.reconnect_interval_secs.unwrap_or(DEFAULT_RECONNECT_INTERVAL_SECS),
291 max_unknown_peers: self.max_unknown_peers.unwrap_or(DEFAULT_MAX_UNKOWN_PEERS),
292 static_peers: self.peering.finish()?.peers,
293 })
294 }
295}
296
297#[cfg(test)]
299#[derive(Default)]
300pub struct InMemoryNetworkConfigBuilder {
301 bind_multiaddr: Option<Multiaddr>,
302}
303
304#[cfg(test)]
305impl InMemoryNetworkConfigBuilder {
306 pub fn new() -> Self {
308 Self::default()
309 }
310
311 pub fn with_bind_multiaddr(mut self, multiaddr: Multiaddr) -> Self {
313 for (i, p) in multiaddr.iter().enumerate() {
314 match i {
315 0 => {
316 if !matches!(p, Protocol::Memory(_)) {
317 panic!("Invalid Multiaddr")
318 }
319 }
320 _ => panic!("Invalid Multiaddr"),
321 }
322 }
323 self.bind_multiaddr.replace(multiaddr);
324 self
325 }
326
327 pub fn finish(self) -> NetworkConfig {
329 const DEFAULT_BIND_MULTIADDR_MEM: &str = "/memory/0";
330
331 NetworkConfig {
332 bind_multiaddr: self
333 .bind_multiaddr
334 .unwrap_or_else(|| DEFAULT_BIND_MULTIADDR_MEM.parse().unwrap()),
335 reconnect_interval_secs: DEFAULT_RECONNECT_INTERVAL_SECS,
336 max_unknown_peers: DEFAULT_MAX_UNKOWN_PEERS,
337 static_peers: Default::default(),
338 }
339 }
340}
341
342#[derive(Clone)]
343pub struct PeeringConfig {
344 pub peers: HashSet<Peer>,
345}
346
347#[derive(Clone)]
348pub struct Peer {
349 pub peer_id: PeerId,
350 pub multiaddr: Multiaddr,
351 pub alias: Option<String>,
352}
353
354impl Eq for Peer {}
355impl PartialEq for Peer {
356 fn eq(&self, other: &Self) -> bool {
357 self.peer_id.eq(&other.peer_id)
358 }
359}
360impl std::hash::Hash for Peer {
361 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
362 self.peer_id.hash(state)
363 }
364}
365
366#[derive(Default, Deserialize)]
367pub struct PeeringConfigBuilder {
368 pub peers: Option<Vec<PeerBuilder>>,
369}
370
371impl PeeringConfigBuilder {
372 pub fn finish(self) -> Result<PeeringConfig, Error> {
373 let peers = match self.peers {
374 None => Default::default(),
375 Some(peer_builders) => {
376 let mut peers = HashSet::with_capacity(peer_builders.len());
379
380 for builder in peer_builders {
381 let (multiaddr, peer_id) = split_multiaddr(&builder.multiaddr)?;
382 if !peers.insert(Peer {
383 peer_id,
384 multiaddr,
385 alias: builder.alias,
386 }) {
387 return Err(Error::DuplicateStaticPeer(peer_id));
388 }
389 }
390
391 peers
392 }
393 };
394
395 Ok(PeeringConfig { peers })
396 }
397}
398
399fn split_multiaddr(multiaddr: &str) -> Result<(Multiaddr, PeerId), Error> {
400 let mut multiaddr: Multiaddr = multiaddr
401 .parse()
402 .map_err(|_| Error::ParsingFailed(multiaddr.to_string()))?;
403
404 if let Protocol::P2p(multihash) = multiaddr.pop().ok_or(Error::MultiaddrUnderspecified)? {
405 Ok((
406 multiaddr,
407 PeerId::from_multihash(multihash).expect("Invalid peer Multiaddr: Make sure your peer's Id is complete."),
408 ))
409 } else {
410 Err(Error::MissingP2pProtocol)
411 }
412}
413
414#[derive(Deserialize)]
415pub struct PeerBuilder {
416 #[serde(rename = "address")]
417 multiaddr: String,
418 alias: Option<String>,
419}
420
421#[cfg(test)]
422mod tests {
423 use super::*;
424
425 #[test]
426 fn create_default_network_config() {
427 let config = NetworkConfig::default();
428
429 assert_eq!(
430 config.bind_multiaddr(),
431 &DEFAULT_BIND_MULTIADDR.parse::<Multiaddr>().unwrap()
432 );
433 }
434
435 #[test]
436 #[should_panic]
437 fn create_with_builder_and_too_short_bind_address() {
438 let _config = NetworkConfig::build()
439 .with_bind_multiaddr("/ip4/127.0.0.1".parse().unwrap())
440 .unwrap()
441 .finish();
442 }
443
444 #[test]
445 #[should_panic]
446 fn create_with_builder_and_too_long_bind_address() {
447 let _config = NetworkConfig::build()
448 .with_bind_multiaddr(
449 "/ip4/127.0.0.1/p2p/12D3KooWJWEKvSFbben74C7H4YtKjhPMTDxd7gP7zxWSUEeF27st"
450 .parse()
451 .unwrap(),
452 )
453 .unwrap()
454 .finish();
455 }
456
457 #[test]
458 fn create_with_builder_and_valid_ip_bind_address() {
459 let _config = NetworkConfig::build()
460 .with_bind_multiaddr("/ip4/127.0.0.1/tcp/1337".parse().unwrap())
461 .unwrap()
462 .finish();
463 }
464
465 #[test]
466 fn create_with_builder_and_valid_dns_bind_address() {
467 let _config = NetworkConfig::build()
468 .with_bind_multiaddr("/dns/localhost/tcp/1337".parse().unwrap())
469 .unwrap()
470 .finish();
471 }
472
473 #[test]
474 #[should_panic]
475 fn create_with_mem_builder_and_non_mem_multiaddr() {
476 let _config = NetworkConfig::build_in_memory()
477 .with_bind_multiaddr("/ip4/127.0.0.1/tcp/1337".parse().unwrap())
478 .finish();
479 }
480
481 #[test]
482 fn create_with_mem_builder_and_valid_mem_multiaddr() {
483 let _config = NetworkConfig::build_in_memory()
484 .with_bind_multiaddr("/memory/1337".parse().unwrap())
485 .finish();
486 }
487}