use super::Location;
use crate::transport::TransportPublicKey;
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
use std::{fmt::Display, hash::Hash};
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Debug)]
pub enum PeerAddr {
Unknown,
Known(SocketAddr),
}
impl PeerAddr {
pub fn as_known(&self) -> Option<&SocketAddr> {
match self {
PeerAddr::Known(addr) => Some(addr),
PeerAddr::Unknown => None,
}
}
pub fn is_known(&self) -> bool {
matches!(self, PeerAddr::Known(_))
}
pub fn is_unknown(&self) -> bool {
matches!(self, PeerAddr::Unknown)
}
}
impl From<SocketAddr> for PeerAddr {
fn from(addr: SocketAddr) -> Self {
PeerAddr::Known(addr)
}
}
impl std::fmt::Display for PeerAddr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PeerAddr::Unknown => write!(f, "<unknown>"),
PeerAddr::Known(addr) => write!(f, "{}", addr),
}
}
}
impl PartialOrd for PeerAddr {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PeerAddr {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(PeerAddr::Unknown, PeerAddr::Unknown) => std::cmp::Ordering::Equal,
(PeerAddr::Unknown, PeerAddr::Known(_)) => std::cmp::Ordering::Less,
(PeerAddr::Known(_), PeerAddr::Unknown) => std::cmp::Ordering::Greater,
(PeerAddr::Known(a), PeerAddr::Known(b)) => a.cmp(b),
}
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
pub struct PeerKeyLocation {
pub pub_key: TransportPublicKey,
pub peer_addr: PeerAddr,
}
impl PeerKeyLocation {
pub fn new(pub_key: TransportPublicKey, addr: SocketAddr) -> Self {
PeerKeyLocation {
pub_key,
peer_addr: PeerAddr::Known(addr),
}
}
pub fn with_unknown_addr(pub_key: TransportPublicKey) -> Self {
PeerKeyLocation {
pub_key,
peer_addr: PeerAddr::Unknown,
}
}
#[inline]
pub fn pub_key(&self) -> &TransportPublicKey {
&self.pub_key
}
#[inline]
pub fn socket_addr(&self) -> Option<SocketAddr> {
match &self.peer_addr {
PeerAddr::Known(addr) => Some(*addr),
PeerAddr::Unknown => None,
}
}
#[inline]
pub fn location(&self) -> Option<Location> {
self.socket_addr().map(|addr| Location::from_address(&addr))
}
pub fn set_addr(&mut self, addr: SocketAddr) {
self.peer_addr = PeerAddr::Known(addr);
}
#[cfg(test)]
pub fn random() -> Self {
use crate::config::GlobalRng;
use crate::transport::{TransportKeypair, TransportPublicKey};
use std::cell::RefCell;
thread_local! {
static CACHED_KEY: RefCell<Option<TransportPublicKey>> = const { RefCell::new(None) };
}
let mut addr_bytes = [0u8; 4];
GlobalRng::fill_bytes(&mut addr_bytes[..]);
let port: u16 = GlobalRng::random_range(1024u16..65535u16);
let addr = SocketAddr::from((addr_bytes, port));
let pub_key = CACHED_KEY.with(|cached| {
let mut cached = cached.borrow_mut();
match &*cached {
Some(k) => k.clone(),
None => {
let key = TransportKeypair::new().public().clone();
cached.replace(key.clone());
key
}
}
});
PeerKeyLocation {
pub_key,
peer_addr: PeerAddr::Known(addr),
}
}
}
impl Ord for PeerKeyLocation {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (&self.peer_addr, &other.peer_addr) {
(PeerAddr::Known(a), PeerAddr::Known(b)) => a.cmp(b),
(PeerAddr::Known(_), PeerAddr::Unknown) => std::cmp::Ordering::Less,
(PeerAddr::Unknown, PeerAddr::Known(_)) => std::cmp::Ordering::Greater,
(PeerAddr::Unknown, PeerAddr::Unknown) => std::cmp::Ordering::Equal,
}
}
}
impl PartialOrd for PeerKeyLocation {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::fmt::Debug for PeerKeyLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Self as Display>::fmt(self, f)
}
}
impl Display for PeerKeyLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.location() {
Some(loc) => write!(f, "{:?}@{} (@ {loc})", self.pub_key, self.peer_addr),
None => write!(f, "{:?}@{}", self.pub_key, self.peer_addr),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnknownAddressError {
pub pub_key: TransportPublicKey,
}
impl std::fmt::Display for UnknownAddressError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"cannot convert PeerKeyLocation with unknown address to KnownPeerKeyLocation (pub_key: {:?})",
self.pub_key
)
}
}
impl std::error::Error for UnknownAddressError {}
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
pub struct KnownPeerKeyLocation {
pub_key: TransportPublicKey,
addr: SocketAddr,
}
impl KnownPeerKeyLocation {
pub fn new(pub_key: TransportPublicKey, addr: SocketAddr) -> Self {
KnownPeerKeyLocation { pub_key, addr }
}
#[inline]
pub fn pub_key(&self) -> &TransportPublicKey {
&self.pub_key
}
#[inline]
pub fn socket_addr(&self) -> SocketAddr {
self.addr
}
#[inline]
pub fn location(&self) -> Location {
Location::from_address(&self.addr)
}
#[inline]
pub fn into_peer_key_location(self) -> PeerKeyLocation {
PeerKeyLocation::from(self)
}
#[inline]
pub fn as_peer_key_location(&self) -> PeerKeyLocation {
PeerKeyLocation {
pub_key: self.pub_key.clone(),
peer_addr: PeerAddr::Known(self.addr),
}
}
}
impl TryFrom<PeerKeyLocation> for KnownPeerKeyLocation {
type Error = UnknownAddressError;
fn try_from(pkl: PeerKeyLocation) -> Result<Self, Self::Error> {
match pkl.peer_addr {
PeerAddr::Known(addr) => Ok(KnownPeerKeyLocation {
pub_key: pkl.pub_key,
addr,
}),
PeerAddr::Unknown => Err(UnknownAddressError {
pub_key: pkl.pub_key,
}),
}
}
}
impl TryFrom<&PeerKeyLocation> for KnownPeerKeyLocation {
type Error = UnknownAddressError;
fn try_from(pkl: &PeerKeyLocation) -> Result<Self, Self::Error> {
match &pkl.peer_addr {
PeerAddr::Known(addr) => Ok(KnownPeerKeyLocation {
pub_key: pkl.pub_key.clone(),
addr: *addr,
}),
PeerAddr::Unknown => Err(UnknownAddressError {
pub_key: pkl.pub_key.clone(),
}),
}
}
}
impl From<KnownPeerKeyLocation> for PeerKeyLocation {
fn from(known: KnownPeerKeyLocation) -> Self {
PeerKeyLocation {
pub_key: known.pub_key,
peer_addr: PeerAddr::Known(known.addr),
}
}
}
impl From<&KnownPeerKeyLocation> for PeerKeyLocation {
fn from(known: &KnownPeerKeyLocation) -> Self {
PeerKeyLocation {
pub_key: known.pub_key.clone(),
peer_addr: PeerAddr::Known(known.addr),
}
}
}
impl Ord for KnownPeerKeyLocation {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.addr
.cmp(&other.addr)
.then_with(|| self.pub_key.cmp(&other.pub_key))
}
}
impl PartialOrd for KnownPeerKeyLocation {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::fmt::Debug for KnownPeerKeyLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Self as Display>::fmt(self, f)
}
}
impl Display for KnownPeerKeyLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let loc = self.location();
write!(f, "{:?}@{} (@ {loc})", self.pub_key, self.addr)
}
}
impl KnownPeerKeyLocation {
pub fn random() -> Self {
use crate::config::GlobalRng;
use crate::transport::TransportKeypair;
use std::cell::RefCell;
thread_local! {
static CACHED_KEY: RefCell<Option<crate::transport::TransportPublicKey>> = const { RefCell::new(None) };
}
let mut addr_bytes = [0u8; 4];
GlobalRng::fill_bytes(&mut addr_bytes[..]);
let port: u16 = GlobalRng::random_range(1024u16..65535u16);
let pub_key = CACHED_KEY.with(|cached| {
let mut cached = cached.borrow_mut();
match &*cached {
Some(k) => k.clone(),
None => {
let key = TransportKeypair::new().public().clone();
cached.replace(key.clone());
key
}
}
});
KnownPeerKeyLocation {
pub_key,
addr: (addr_bytes, port).into(),
}
}
#[cfg(test)]
pub fn to_bytes(&self) -> Vec<u8> {
bincode::serialize(self).unwrap()
}
}
#[cfg(test)]
thread_local! {
static CACHED_PUB_KEY: std::cell::RefCell<Option<crate::transport::TransportPublicKey>> = const { std::cell::RefCell::new(None) };
}
#[cfg(test)]
impl<'a> arbitrary::Arbitrary<'a> for PeerKeyLocation {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
use crate::transport::TransportKeypair;
let addr: SocketAddr = u.arbitrary()?;
let pub_key = CACHED_PUB_KEY.with(|cached| {
let mut cached = cached.borrow_mut();
match &*cached {
Some(k) => k.clone(),
None => {
let key = TransportKeypair::new().public().clone();
cached.replace(key.clone());
key
}
}
});
Ok(PeerKeyLocation {
pub_key,
peer_addr: PeerAddr::Known(addr),
})
}
}
#[cfg(test)]
impl<'a> arbitrary::Arbitrary<'a> for KnownPeerKeyLocation {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
use crate::transport::TransportKeypair;
let addr: SocketAddr = u.arbitrary()?;
let pub_key = CACHED_PUB_KEY.with(|cached| {
let mut cached = cached.borrow_mut();
match &*cached {
Some(k) => k.clone(),
None => {
let key = TransportKeypair::new().public().clone();
cached.replace(key.clone());
key
}
}
});
Ok(KnownPeerKeyLocation { pub_key, addr })
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::transport::TransportKeypair;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
fn make_pub_key() -> TransportPublicKey {
TransportKeypair::new().public().clone()
}
#[test]
fn test_peer_addr_unknown() {
let addr = PeerAddr::Unknown;
assert!(addr.is_unknown());
assert!(!addr.is_known());
assert!(addr.as_known().is_none());
}
#[test]
fn test_peer_addr_known() {
let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
let addr = PeerAddr::Known(socket);
assert!(addr.is_known());
assert!(!addr.is_unknown());
assert_eq!(addr.as_known(), Some(&socket));
}
#[test]
fn test_peer_addr_from_socket_addr() {
let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 5000);
let addr: PeerAddr = socket.into();
assert!(addr.is_known());
assert_eq!(addr.as_known(), Some(&socket));
}
#[test]
fn test_peer_addr_display() {
let unknown = PeerAddr::Unknown;
assert_eq!(format!("{}", unknown), "<unknown>");
let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 9000);
let known = PeerAddr::Known(socket);
assert_eq!(format!("{}", known), "127.0.0.1:9000");
}
#[test]
fn test_peer_addr_equality() {
let socket1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 1000);
let socket2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 1000);
let socket3 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(5, 6, 7, 8)), 2000);
assert_eq!(PeerAddr::Known(socket1), PeerAddr::Known(socket2));
assert_ne!(PeerAddr::Known(socket1), PeerAddr::Known(socket3));
assert_eq!(PeerAddr::Unknown, PeerAddr::Unknown);
assert_ne!(PeerAddr::Unknown, PeerAddr::Known(socket1));
}
#[test]
fn test_peer_key_location_new() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 8000);
let pkl = PeerKeyLocation::new(pub_key.clone(), addr);
assert_eq!(pkl.pub_key(), &pub_key);
assert_eq!(pkl.socket_addr(), Some(addr));
assert!(pkl.location().is_some());
}
#[test]
fn test_peer_key_location_with_unknown_addr() {
let pub_key = make_pub_key();
let pkl = PeerKeyLocation::with_unknown_addr(pub_key.clone());
assert_eq!(pkl.pub_key(), &pub_key);
assert!(pkl.socket_addr().is_none());
assert!(pkl.location().is_none());
}
#[test]
fn test_peer_key_location_set_addr() {
let pub_key = make_pub_key();
let mut pkl = PeerKeyLocation::with_unknown_addr(pub_key.clone());
assert!(pkl.socket_addr().is_none());
assert!(pkl.location().is_none());
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 50)), 12345);
pkl.set_addr(addr);
assert_eq!(pkl.socket_addr(), Some(addr));
assert!(pkl.location().is_some());
}
#[test]
fn test_peer_key_location_location_computation() {
let pub_key = make_pub_key();
let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 1, 1)), 5000);
let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 2, 1)), 5000);
let pkl1 = PeerKeyLocation::new(pub_key.clone(), addr1);
let pkl2 = PeerKeyLocation::new(pub_key.clone(), addr2);
let loc1 = pkl1.location().unwrap();
let loc2 = pkl2.location().unwrap();
assert_ne!(loc1, loc2);
}
#[test]
fn test_peer_key_location_ordering_both_known() {
let pub_key = make_pub_key();
let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 5000);
let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)), 5000);
let pkl1 = PeerKeyLocation::new(pub_key.clone(), addr1);
let pkl2 = PeerKeyLocation::new(pub_key.clone(), addr2);
assert!(pkl1 < pkl2);
assert!(pkl2 > pkl1);
}
#[test]
fn test_peer_key_location_ordering_unknown_last() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
let known = PeerKeyLocation::new(pub_key.clone(), addr);
let unknown = PeerKeyLocation::with_unknown_addr(pub_key.clone());
assert!(known < unknown);
assert!(unknown > known);
}
#[test]
fn test_peer_key_location_ordering_both_unknown() {
let pub_key1 = make_pub_key();
let pub_key2 = make_pub_key();
let unknown1 = PeerKeyLocation::with_unknown_addr(pub_key1);
let unknown2 = PeerKeyLocation::with_unknown_addr(pub_key2);
assert_eq!(unknown1.cmp(&unknown2), std::cmp::Ordering::Equal);
}
#[test]
fn test_peer_key_location_sorting() {
let pub_key = make_pub_key();
let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 3)), 5000);
let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 5000);
let addr3 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)), 5000);
let mut peers = [
PeerKeyLocation::with_unknown_addr(pub_key.clone()),
PeerKeyLocation::new(pub_key.clone(), addr1),
PeerKeyLocation::new(pub_key.clone(), addr2),
PeerKeyLocation::with_unknown_addr(pub_key.clone()),
PeerKeyLocation::new(pub_key.clone(), addr3),
];
peers.sort();
assert_eq!(peers[0].socket_addr(), Some(addr2)); assert_eq!(peers[1].socket_addr(), Some(addr3)); assert_eq!(peers[2].socket_addr(), Some(addr1)); assert!(peers[3].socket_addr().is_none()); assert!(peers[4].socket_addr().is_none()); }
#[test]
fn test_peer_key_location_display_with_known_addr() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 9000);
let pkl = PeerKeyLocation::new(pub_key, addr);
let display = format!("{}", pkl);
assert!(display.contains("127.0.0.1:9000"));
assert!(display.contains("@")); }
#[test]
fn test_peer_key_location_display_with_unknown_addr() {
let pub_key = make_pub_key();
let pkl = PeerKeyLocation::with_unknown_addr(pub_key);
let display = format!("{}", pkl);
assert!(display.contains("<unknown>"));
}
#[test]
fn test_peer_key_location_equality() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
let pkl1 = PeerKeyLocation::new(pub_key.clone(), addr);
let pkl2 = PeerKeyLocation::new(pub_key.clone(), addr);
assert_eq!(pkl1, pkl2);
}
#[test]
fn test_peer_key_location_clone() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 20, 30, 40)), 5555);
let pkl = PeerKeyLocation::new(pub_key, addr);
let cloned = pkl.clone();
assert_eq!(pkl, cloned);
assert_eq!(pkl.socket_addr(), cloned.socket_addr());
}
#[test]
fn test_peer_key_location_random() {
let pkl1 = PeerKeyLocation::random();
let pkl2 = PeerKeyLocation::random();
assert!(pkl1.socket_addr().is_some());
assert!(pkl2.socket_addr().is_some());
assert_ne!(pkl1.socket_addr(), pkl2.socket_addr());
}
#[test]
fn test_peer_key_location_with_ipv6() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(
IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)),
8080,
);
let pkl = PeerKeyLocation::new(pub_key, addr);
assert_eq!(pkl.socket_addr(), Some(addr));
assert!(pkl.location().is_some());
}
#[test]
fn test_known_peer_key_location_new() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 8000);
let kpkl = KnownPeerKeyLocation::new(pub_key.clone(), addr);
assert_eq!(kpkl.pub_key(), &pub_key);
assert_eq!(kpkl.socket_addr(), addr); assert_eq!(kpkl.location(), Location::from_address(&addr));
}
#[test]
fn test_known_peer_key_location_try_from_known() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 5000);
let pkl = PeerKeyLocation::new(pub_key.clone(), addr);
let kpkl = KnownPeerKeyLocation::try_from(pkl).expect("should succeed for known address");
assert_eq!(kpkl.pub_key(), &pub_key);
assert_eq!(kpkl.socket_addr(), addr);
}
#[test]
fn test_known_peer_key_location_try_from_unknown_fails() {
let pub_key = make_pub_key();
let pkl = PeerKeyLocation::with_unknown_addr(pub_key.clone());
let result = KnownPeerKeyLocation::try_from(pkl);
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.pub_key, pub_key);
}
#[test]
fn test_known_peer_key_location_try_from_ref() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)), 6000);
let pkl = PeerKeyLocation::new(pub_key.clone(), addr);
let kpkl = KnownPeerKeyLocation::try_from(&pkl).expect("should succeed for known address");
assert_eq!(kpkl.pub_key(), &pub_key);
assert_eq!(kpkl.socket_addr(), addr);
assert_eq!(pkl.socket_addr(), Some(addr));
}
#[test]
fn test_known_peer_key_location_into_peer_key_location() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 50)), 12345);
let kpkl = KnownPeerKeyLocation::new(pub_key.clone(), addr);
let pkl: PeerKeyLocation = kpkl.into_peer_key_location();
assert_eq!(pkl.pub_key(), &pub_key);
assert_eq!(pkl.socket_addr(), Some(addr));
assert!(pkl.peer_addr.is_known());
}
#[test]
fn test_known_peer_key_location_as_peer_key_location() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 0, 1)), 7777);
let kpkl = KnownPeerKeyLocation::new(pub_key.clone(), addr);
let pkl = kpkl.as_peer_key_location();
assert_eq!(pkl.pub_key(), &pub_key);
assert_eq!(pkl.socket_addr(), Some(addr));
assert_eq!(kpkl.socket_addr(), addr);
}
#[test]
fn test_known_peer_key_location_from_impl() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 20, 30, 40)), 8888);
let kpkl = KnownPeerKeyLocation::new(pub_key.clone(), addr);
let pkl = PeerKeyLocation::from(kpkl);
assert_eq!(pkl.pub_key(), &pub_key);
assert_eq!(pkl.socket_addr(), Some(addr));
}
#[test]
fn test_known_peer_key_location_from_ref_impl() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1)), 9999);
let kpkl = KnownPeerKeyLocation::new(pub_key.clone(), addr);
let pkl = PeerKeyLocation::from(&kpkl);
assert_eq!(pkl.pub_key(), &pub_key);
assert_eq!(pkl.socket_addr(), Some(addr));
assert_eq!(kpkl.socket_addr(), addr);
}
#[test]
fn test_known_peer_key_location_ordering() {
let pub_key = make_pub_key();
let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 5000);
let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)), 5000);
let kpkl1 = KnownPeerKeyLocation::new(pub_key.clone(), addr1);
let kpkl2 = KnownPeerKeyLocation::new(pub_key.clone(), addr2);
assert!(kpkl1 < kpkl2);
assert!(kpkl2 > kpkl1);
}
#[test]
fn test_known_peer_key_location_equality() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
let kpkl1 = KnownPeerKeyLocation::new(pub_key.clone(), addr);
let kpkl2 = KnownPeerKeyLocation::new(pub_key.clone(), addr);
assert_eq!(kpkl1, kpkl2);
}
#[test]
fn test_known_peer_key_location_display() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 9000);
let kpkl = KnownPeerKeyLocation::new(pub_key, addr);
let display = format!("{}", kpkl);
assert!(display.contains("127.0.0.1:9000"));
assert!(display.contains("@")); }
#[test]
fn test_known_peer_key_location_clone() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 20, 30, 40)), 5555);
let kpkl = KnownPeerKeyLocation::new(pub_key, addr);
let cloned = kpkl.clone();
assert_eq!(kpkl, cloned);
assert_eq!(kpkl.socket_addr(), cloned.socket_addr());
}
#[test]
fn test_unknown_address_error_display() {
let pub_key = make_pub_key();
let err = UnknownAddressError {
pub_key: pub_key.clone(),
};
let display = format!("{}", err);
assert!(display.contains("cannot convert PeerKeyLocation with unknown address"));
}
#[test]
fn test_roundtrip_known_to_peer_to_known() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 100, 1)), 12000);
let kpkl_original = KnownPeerKeyLocation::new(pub_key.clone(), addr);
let pkl = PeerKeyLocation::from(&kpkl_original);
let kpkl_roundtrip =
KnownPeerKeyLocation::try_from(pkl).expect("roundtrip should preserve known state");
assert_eq!(kpkl_original.pub_key(), kpkl_roundtrip.pub_key());
assert_eq!(kpkl_original.socket_addr(), kpkl_roundtrip.socket_addr());
}
#[test]
fn test_known_peer_key_location_with_ipv6() {
let pub_key = make_pub_key();
let addr = SocketAddr::new(
IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)),
8080,
);
let kpkl = KnownPeerKeyLocation::new(pub_key, addr);
assert_eq!(kpkl.socket_addr(), addr);
let loc = kpkl.location();
assert!(loc.as_f64() >= 0.0 && loc.as_f64() <= 1.0);
}
}