From e8a9a89e25158c3823004d54a803ae6efec08921 Mon Sep 17 00:00:00 2001 From: Erick Cestari Date: Sat, 17 May 2025 20:00:34 -0300 Subject: [PATCH] feat(p2p): add `AddrV2` <> `IpAddr` conversions --- bitcoin/src/p2p/address.rs | 172 ++++++++++++++++++++++++++++++++++--- 1 file changed, 159 insertions(+), 13 deletions(-) diff --git a/bitcoin/src/p2p/address.rs b/bitcoin/src/p2p/address.rs index 576b257b2..65603bae1 100644 --- a/bitcoin/src/p2p/address.rs +++ b/bitcoin/src/p2p/address.rs @@ -6,7 +6,7 @@ //! network addresses in Bitcoin messages. use core::{fmt, iter}; -use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; use io::{BufRead, Read, Write}; @@ -140,7 +140,7 @@ pub enum AddrV2 { /// Error types for [`AddrV2`] to [`SocketAddr`] conversion. #[derive(Debug, PartialEq, Eq)] -pub enum AddrV2ConversionError { +pub enum AddrV2ToSocketAddrError { /// A [`AddrV2::TorV3`] address cannot be converted to a [`SocketAddr`]. TorV3NotSupported, /// A [`AddrV2::I2p`] address cannot be converted to a [`SocketAddr`]. @@ -152,7 +152,7 @@ pub enum AddrV2ConversionError { UnknownNotSupported, } -impl fmt::Display for AddrV2ConversionError { +impl fmt::Display for AddrV2ToSocketAddrError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::TorV3NotSupported => write!(f, "TorV3 addresses cannot be converted to SocketAddr"), @@ -163,7 +163,7 @@ impl fmt::Display for AddrV2ConversionError { } } -impl std::error::Error for AddrV2ConversionError {} +impl std::error::Error for AddrV2ToSocketAddrError {} impl From for AddrV2 { fn from(addr: SocketAddr) -> Self { @@ -184,20 +184,82 @@ impl From for AddrV2 { } impl TryFrom for SocketAddr { - type Error = AddrV2ConversionError; + type Error = AddrV2ToSocketAddrError; fn try_from(addr: AddrV2) -> Result { match addr { AddrV2::Ipv4(ip) => Ok(SocketAddr::V4(SocketAddrV4::new(ip, 0))), AddrV2::Ipv6(ip) => Ok(SocketAddr::V6(SocketAddrV6::new(ip, 0, 0, 0))), - AddrV2::Cjdns(_) => Err(AddrV2ConversionError::CjdnsNotRecommended), - AddrV2::TorV3(_) => Err(AddrV2ConversionError::TorV3NotSupported), - AddrV2::I2p(_) => Err(AddrV2ConversionError::I2pNotSupported), - AddrV2::Unknown(_, _) => Err(AddrV2ConversionError::UnknownNotSupported), + AddrV2::Cjdns(_) => Err(AddrV2ToSocketAddrError::CjdnsNotRecommended), + AddrV2::TorV3(_) => Err(AddrV2ToSocketAddrError::TorV3NotSupported), + AddrV2::I2p(_) => Err(AddrV2ToSocketAddrError::I2pNotSupported), + AddrV2::Unknown(_, _) => Err(AddrV2ToSocketAddrError::UnknownNotSupported), } } } +impl TryFrom for IpAddr { + type Error = AddrV2ToIpAddrError; + + fn try_from(addr: AddrV2) -> Result { + match addr { + AddrV2::Ipv4(ip) => Ok(IpAddr::V4(ip)), + AddrV2::Ipv6(ip) => Ok(IpAddr::V6(ip)), + AddrV2::Cjdns(_) => Err(AddrV2ToIpAddrError::Cjdns), + AddrV2::TorV3(_) => Err(AddrV2ToIpAddrError::TorV3), + AddrV2::I2p(_) => Err(AddrV2ToIpAddrError::I2p), + AddrV2::Unknown(_, _) => Err(AddrV2ToIpAddrError::Unknown), + } + } +} + +impl TryFrom for Ipv4Addr { + type Error = AddrV2ToIpv4AddrError; + + fn try_from(addr: AddrV2) -> Result { + match addr { + AddrV2::Ipv4(ip) => Ok(ip), + AddrV2::Ipv6(_) => Err(AddrV2ToIpv4AddrError::Ipv6), + AddrV2::Cjdns(_) => Err(AddrV2ToIpv4AddrError::Cjdns), + AddrV2::TorV3(_) => Err(AddrV2ToIpv4AddrError::TorV3), + AddrV2::I2p(_) => Err(AddrV2ToIpv4AddrError::I2p), + AddrV2::Unknown(_, _) => Err(AddrV2ToIpv4AddrError::Unknown), + } + } +} + +impl TryFrom for Ipv6Addr { + type Error = AddrV2ToIpv6AddrError; + + fn try_from(addr: AddrV2) -> Result { + match addr { + AddrV2::Ipv6(ip) => Ok(ip), + AddrV2::Cjdns(_) => Err(AddrV2ToIpv6AddrError::Cjdns), + AddrV2::Ipv4(_) => Err(AddrV2ToIpv6AddrError::Ipv4), + AddrV2::TorV3(_) => Err(AddrV2ToIpv6AddrError::TorV3), + AddrV2::I2p(_) => Err(AddrV2ToIpv6AddrError::I2p), + AddrV2::Unknown(_, _) => Err(AddrV2ToIpv6AddrError::Unknown), + } + } +} + +impl From for AddrV2 { + fn from(addr: IpAddr) -> Self { + match addr { + IpAddr::V4(ip) => AddrV2::Ipv4(ip), + IpAddr::V6(ip) => AddrV2::Ipv6(ip), + } + } +} + +impl From for AddrV2 { + fn from(addr: Ipv4Addr) -> Self { AddrV2::Ipv4(addr) } +} + +impl From for AddrV2 { + fn from(addr: Ipv6Addr) -> Self { AddrV2::Ipv6(addr) } +} + impl Encodable for AddrV2 { fn consensus_encode(&self, w: &mut W) -> Result { fn encode_addr( @@ -348,6 +410,90 @@ impl ToSocketAddrs for AddrV2Message { } } +/// Error types for [`AddrV2`] to [`IpAddr`] conversion. +#[derive(Debug, PartialEq, Eq)] +pub enum AddrV2ToIpAddrError { + /// A [`AddrV2::TorV3`] address cannot be converted to a [`IpAddr`]. + TorV3, + /// A [`AddrV2::I2p`] address cannot be converted to a [`IpAddr`]. + I2p, + /// A [`AddrV2::Cjdns`] address cannot be converted to a [`IpAddr`], + Cjdns, + /// A [`AddrV2::Unknown`] address cannot be converted to a [`IpAddr`]. + Unknown, +} + +impl fmt::Display for AddrV2ToIpAddrError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::TorV3 => write!(f, "TorV3 addresses cannot be converted to IpAddr"), + Self::I2p => write!(f, "I2P addresses cannot be converted to IpAddr"), + Self::Cjdns => write!(f, "Cjdns addresses cannot be converted to IpAddr"), + Self::Unknown => write!(f, "Unknown address type cannot be converted to IpAddr"), + } + } +} + +impl std::error::Error for AddrV2ToIpAddrError {} + +/// Error types for [`AddrV2`] to [`Ipv4Addr`] conversion. +#[derive(Debug, PartialEq, Eq)] +pub enum AddrV2ToIpv4AddrError { + /// A [`AddrV2::Ipv6`] address cannot be converted to a [`Ipv4Addr`]. + Ipv6, + /// A [`AddrV2::TorV3`] address cannot be converted to a [`Ipv4Addr`]. + TorV3, + /// A [`AddrV2::I2p`] address cannot be converted to a [`Ipv4Addr`]. + I2p, + /// A [`AddrV2::Cjdns`] address cannot be converted to a [`Ipv4Addr`], + Cjdns, + /// A [`AddrV2::Unknown`] address cannot be converted to a [`Ipv4Addr`]. + Unknown, +} + +impl fmt::Display for AddrV2ToIpv4AddrError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Ipv6 => write!(f, "Ipv6 addresses cannot be converted to Ipv4Addr"), + Self::TorV3 => write!(f, "TorV3 addresses cannot be converted to Ipv4Addr"), + Self::I2p => write!(f, "I2P addresses cannot be converted to Ipv4Addr"), + Self::Cjdns => write!(f, "Cjdns addresses cannot be converted to Ipv4Addr"), + Self::Unknown => write!(f, "Unknown address type cannot be converted to Ipv4Addr"), + } + } +} + +impl std::error::Error for AddrV2ToIpv4AddrError {} + +/// Error types for [`AddrV2`] to [`Ipv6Addr`] conversion. +#[derive(Debug, PartialEq, Eq)] +pub enum AddrV2ToIpv6AddrError { + /// A [`AddrV2::Ipv4`] address cannot be converted to a [`Ipv6Addr`]. + Ipv4, + /// A [`AddrV2::TorV3`] address cannot be converted to a [`Ipv6Addr`]. + TorV3, + /// A [`AddrV2::I2p`] address cannot be converted to a [`Ipv6Addr`]. + I2p, + /// A [`AddrV2::Cjdns`] address cannot be converted to a [`Ipv6Addr`], + Cjdns, + /// A [`AddrV2::Unknown`] address cannot be converted to a [`Ipv6Addr`]. + Unknown, +} + +impl fmt::Display for AddrV2ToIpv6AddrError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Ipv4 => write!(f, "Ipv addresses cannot be converted to Ipv6Addr"), + Self::TorV3 => write!(f, "TorV3 addresses cannot be converted to Ipv6Addr"), + Self::I2p => write!(f, "I2P addresses cannot be converted to Ipv6Addr"), + Self::Cjdns => write!(f, "Cjdns addresses cannot be converted to Ipv6Addr"), + Self::Unknown => write!(f, "Unknown address type cannot be converted to Ipv6Addr"), + } + } +} + +impl std::error::Error for AddrV2ToIpv6AddrError {} + #[cfg(test)] mod test { use std::net::IpAddr; @@ -658,7 +804,7 @@ mod test { let result = SocketAddr::try_from(addr); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ConversionError::CjdnsNotRecommended); + assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::CjdnsNotRecommended); } #[test] @@ -667,7 +813,7 @@ mod test { let result = SocketAddr::try_from(addr); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ConversionError::TorV3NotSupported); + assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::TorV3NotSupported); } #[test] @@ -676,7 +822,7 @@ mod test { let result = SocketAddr::try_from(addr); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ConversionError::I2pNotSupported); + assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::I2pNotSupported); } #[test] @@ -685,6 +831,6 @@ mod test { let result = SocketAddr::try_from(addr); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ConversionError::UnknownNotSupported); + assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::UnknownNotSupported); } }