1use super::*;
2use crate::Enr;
3use enr::{CombinedPublicKey, NodeId};
4use std::net::SocketAddr;
5
6#[cfg(feature = "libp2p")]
7use libp2p_identity::{KeyType, PublicKey};
8#[cfg(feature = "libp2p")]
9use multiaddr::{Multiaddr, Protocol};
10
11#[derive(Debug, Clone, PartialEq)]
14pub struct NodeContact {
15 public_key: CombinedPublicKey,
17 socket_addr: SocketAddr,
19 enr: Option<Enr>,
21}
22
23#[derive(Debug, Clone)]
24pub struct NonContactable {
25 pub enr: Enr,
26}
27
28impl NodeContact {
29 pub fn new(public_key: CombinedPublicKey, socket_addr: SocketAddr, enr: Option<Enr>) -> Self {
30 NodeContact {
31 public_key,
32 socket_addr,
33 enr,
34 }
35 }
36
37 pub fn node_id(&self) -> NodeId {
38 match self.enr {
39 Some(ref enr) => enr.node_id(),
40 None => self.public_key.clone().into(),
41 }
42 }
43
44 pub fn seq_no(&self) -> Option<u64> {
45 self.enr.as_ref().map(|enr| enr.seq())
46 }
47
48 pub fn public_key(&self) -> CombinedPublicKey {
49 self.public_key.clone()
50 }
51
52 pub fn enr(&self) -> Option<Enr> {
53 self.enr.clone()
54 }
55
56 pub fn socket_addr(&self) -> SocketAddr {
57 self.socket_addr
58 }
59
60 pub fn node_address(&self) -> NodeAddress {
61 NodeAddress {
62 socket_addr: self.socket_addr,
63 node_id: self.node_id(),
64 }
65 }
66
67 pub fn to_address_and_enr(self) -> (NodeAddress, Option<Enr>) {
68 let NodeContact {
69 public_key,
70 socket_addr,
71 enr,
72 } = self;
73 (
74 NodeAddress {
75 node_id: public_key.into(),
76 socket_addr,
77 },
78 enr,
79 )
80 }
81
82 pub fn try_from_enr(enr: Enr, ip_mode: IpMode) -> Result<Self, NonContactable> {
83 let socket_addr = match ip_mode.get_contactable_addr(&enr) {
84 Some(socket_addr) => socket_addr,
85 None => return Err(NonContactable { enr }),
86 };
87
88 Ok(NodeContact {
89 public_key: enr.public_key(),
90 socket_addr,
91 enr: Some(enr),
92 })
93 }
94
95 #[cfg(feature = "libp2p")]
96 pub fn try_from_multiaddr(multiaddr: Multiaddr) -> Result<Self, &'static str> {
97 let mut ip_addr = None;
102 let mut udp_port = None;
103 let mut p2p = None;
104
105 for protocol in multiaddr.into_iter() {
106 match protocol {
107 Protocol::Udp(port) => udp_port = Some(port),
108 Protocol::Ip4(addr) => ip_addr = Some(addr.into()),
109 Protocol::Ip6(addr) => ip_addr = Some(addr.into()),
110 Protocol::P2p(peer_id) => p2p = Some(peer_id),
111 _ => {}
112 }
113 }
114
115 let udp_port = udp_port.ok_or("A UDP port must be specified in the multiaddr")?;
116 let ip_addr = ip_addr.ok_or("An IP address must be specified in the multiaddr")?;
117 let peer_id = p2p.ok_or("The p2p protocol must be specified in the multiaddr")?;
118
119 let public_key: CombinedPublicKey = {
120 let pk = PublicKey::try_decode_protobuf(&peer_id.to_bytes()[2..])
121 .map_err(|_| "Invalid public key")?;
122 match pk.key_type() {
123 KeyType::Secp256k1 => enr::k256::ecdsa::VerifyingKey::from_sec1_bytes(
124 &pk.try_into_secp256k1()
125 .expect("Must be secp256k1")
126 .to_bytes_uncompressed(),
127 )
128 .expect("Libp2p key conversion, always valid")
129 .into(),
130 KeyType::Ed25519 => enr::ed25519_dalek::VerifyingKey::from_bytes(
131 &pk.try_into_ed25519().expect("Must be ed25519").to_bytes(),
132 )
133 .expect("Libp2p key conversion, always valid")
134 .into(),
135 _ => return Err("The key type is not supported"),
136 }
137 };
138
139 Ok(NodeContact {
140 public_key,
141 socket_addr: SocketAddr::new(ip_addr, udp_port),
142 enr: None,
143 })
144 }
145}
146
147#[cfg(test)]
148impl From<Enr> for NodeContact {
149 #[track_caller]
150 fn from(enr: Enr) -> Self {
151 NodeContact::try_from_enr(enr, IpMode::default()).unwrap()
152 }
153}
154
155impl std::fmt::Display for NodeContact {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 write!(f, "Node: {}, addr: {:?}", self.node_id(), self.socket_addr)
158 }
159}
160
161#[derive(PartialEq, Hash, Eq, Clone, Debug)]
163pub struct NodeAddress {
164 pub socket_addr: SocketAddr,
166 pub node_id: NodeId,
168}
169
170impl Ord for NodeAddress {
171 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
172 let ord = self.node_id.raw().cmp(&other.node_id.raw());
173 if ord != std::cmp::Ordering::Equal {
174 return ord;
175 }
176 let ord = self.socket_addr.ip().cmp(&other.socket_addr.ip());
177 if ord != std::cmp::Ordering::Equal {
178 return ord;
179 }
180 self.socket_addr.port().cmp(&other.socket_addr.port())
181 }
182}
183
184impl PartialOrd for NodeAddress {
185 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
186 Some(self.cmp(other))
187 }
188}
189
190impl NodeAddress {
191 pub fn new(socket_addr: SocketAddr, node_id: NodeId) -> Self {
192 Self {
193 socket_addr,
194 node_id,
195 }
196 }
197}
198
199impl std::fmt::Display for NodeAddress {
200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 write!(f, "Node: {}, addr: {:?}", self.node_id, self.socket_addr)
202 }
203}