kaspa_p2p_lib/convert/
net_address.rs

1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2
3use super::error::ConversionError;
4use crate::pb as protowire;
5
6use itertools::Itertools;
7use kaspa_utils::networking::{IpAddress, NetAddress};
8
9// ----------------------------------------------------------------------------
10// consensus_core to protowire
11// ----------------------------------------------------------------------------
12
13impl From<(IpAddress, u16)> for protowire::NetAddress {
14    fn from((ip, port): (IpAddress, u16)) -> Self {
15        Self {
16            timestamp: 0, // This field is not used anymore
17            ip: match ip.0 {
18                // We follow the IP encoding of golang's net.IP type
19                IpAddr::V4(ip) => ip.octets().to_vec(),
20                IpAddr::V6(ip) => ip.octets().to_vec(),
21            },
22            port: port as u32,
23        }
24    }
25}
26
27impl From<NetAddress> for protowire::NetAddress {
28    fn from(item: NetAddress) -> Self {
29        (item.ip, item.port).into()
30    }
31}
32
33// ----------------------------------------------------------------------------
34// protowire to consensus_core
35// ----------------------------------------------------------------------------
36
37impl TryFrom<protowire::NetAddress> for (IpAddress, u16) {
38    type Error = ConversionError;
39
40    fn try_from(addr: protowire::NetAddress) -> Result<Self, Self::Error> {
41        // We follow the IP encoding of golang's net.IP type
42        let ip: IpAddress = match addr.ip.len() {
43            4 => Ok(Ipv4Addr::new(addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]).into()),
44            16 => {
45                let octets = addr
46                    .ip
47                    .chunks(size_of::<u16>())
48                    .map(|chunk| u16::from_be_bytes(chunk.try_into().expect("We already checked the number of bytes")))
49                    .collect_vec();
50                let ipv6 = Ipv6Addr::from(<[u16; 8]>::try_from(octets).unwrap());
51                Ok(ipv6.into())
52            }
53            len => Err(ConversionError::IllegalIPLength(len)),
54        }?;
55        Ok((ip, addr.port.try_into()?))
56    }
57}
58
59impl TryFrom<protowire::NetAddress> for NetAddress {
60    type Error = ConversionError;
61
62    fn try_from(item: protowire::NetAddress) -> Result<Self, Self::Error> {
63        let (ip, port) = item.try_into()?;
64        Ok(NetAddress::new(ip, port))
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use kaspa_utils::networking::IpAddress;
71
72    use crate::pb;
73    use std::{
74        net::{Ipv4Addr, Ipv6Addr},
75        str::FromStr,
76    };
77
78    #[test]
79    fn test_netaddress() {
80        let net_addr_ipv4 = pb::NetAddress { timestamp: 0, ip: hex::decode("6a0a8af0").unwrap(), port: 123 };
81        let ipv4 = Ipv4Addr::from_str("106.10.138.240").unwrap().into();
82        assert_eq!(<(IpAddress, u16)>::try_from(net_addr_ipv4.clone()).unwrap(), (ipv4, 123u16));
83        assert_eq!(pb::NetAddress::from((ipv4, 123u16)), net_addr_ipv4);
84
85        let net_addr_ipv6 = pb::NetAddress { timestamp: 0, ip: hex::decode("20010db885a3000000008a2e03707334").unwrap(), port: 456 };
86        let ipv6 = Ipv6Addr::from_str("2001:0db8:85a3:0000:0000:8a2e:0370:7334").unwrap().into();
87        assert_eq!(<(IpAddress, u16)>::try_from(net_addr_ipv6.clone()).unwrap(), (ipv6, 456u16));
88        assert_eq!(pb::NetAddress::from((ipv6, 456u16)), net_addr_ipv6);
89    }
90}