1use std::borrow::Cow;
2
3use libp2p_identity::DecodingError;
4use malloc_size_of_derive::MallocSizeOf;
5use multiaddr::Multiaddr;
6use serde::{Deserialize, Serialize};
7
8use super::{P2pNetworkKadEntry, P2pNetworkKadEntryTryFromError, P2pNetworkKadKeyError};
9use crate::{mod_Message::MessageType, P2pNetworkServiceError, PeerId};
10
11#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Serialize, Deserialize)]
12pub enum ConnectionType {
13 NotConnected,
14 Connected,
15 CanConnect,
16 CannotConnect,
17}
18
19impl From<super::mod_Message::ConnectionType> for ConnectionType {
20 fn from(value: super::mod_Message::ConnectionType) -> Self {
21 match value {
22 super::mod_Message::ConnectionType::NOT_CONNECTED => ConnectionType::NotConnected,
23 super::mod_Message::ConnectionType::CONNECTED => ConnectionType::Connected,
24 super::mod_Message::ConnectionType::CAN_CONNECT => ConnectionType::CanConnect,
25 super::mod_Message::ConnectionType::CANNOT_CONNECT => ConnectionType::CannotConnect,
26 }
27 }
28}
29
30impl From<ConnectionType> for super::mod_Message::ConnectionType {
31 fn from(value: ConnectionType) -> Self {
32 match value {
33 ConnectionType::NotConnected => super::mod_Message::ConnectionType::NOT_CONNECTED,
34 ConnectionType::Connected => super::mod_Message::ConnectionType::CONNECTED,
35 ConnectionType::CanConnect => super::mod_Message::ConnectionType::CAN_CONNECT,
36 ConnectionType::CannotConnect => super::mod_Message::ConnectionType::CANNOT_CONNECT,
37 }
38 }
39}
40
41#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, MallocSizeOf)]
42pub struct CID(pub Vec<u8>);
43
44#[cfg(test)]
45impl CID {
46 pub fn to_libp2p_string(&self) -> String {
47 libp2p_identity::PeerId::from_bytes(&self.0)
48 .expect("Invalid bytes")
49 .to_string()
50 }
51}
52
53impl TryFrom<PeerId> for CID {
54 type Error = libp2p_identity::DecodingError;
55
56 fn try_from(value: PeerId) -> Result<Self, Self::Error> {
57 Ok(Self::from(libp2p_identity::PeerId::try_from(value)?))
58 }
59}
60
61impl From<libp2p_identity::PeerId> for CID {
62 fn from(value: libp2p_identity::PeerId) -> Self {
63 Self(value.to_bytes())
64 }
65}
66
67impl std::fmt::Debug for CID {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 f.write_str(&hex::encode(&self.0))
70 }
71}
72
73#[derive(Clone, Debug, Serialize, Deserialize, MallocSizeOf)]
74pub enum P2pNetworkKademliaRpcRequest {
75 FindNode { key: CID },
76}
77
78#[derive(Clone, Debug, Serialize, Deserialize, MallocSizeOf)]
79pub enum P2pNetworkKademliaRpcReply {
80 FindNode {
81 closer_peers: Vec<P2pNetworkKadEntry>,
82 },
83}
84
85impl P2pNetworkKademliaRpcRequest {
86 pub fn find_node(key: PeerId) -> Result<Self, P2pNetworkKadKeyError> {
87 Ok(P2pNetworkKademliaRpcRequest::FindNode {
88 key: key
89 .try_into()
90 .map_err(|_| P2pNetworkKadKeyError::DecodingError)?,
91 })
92 }
93}
94
95#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, thiserror::Error, MallocSizeOf)]
96pub enum P2pNetworkKademliaPeerIdError {
97 #[error("error decoding PeerId from bytes: lenght {0} while expected 32")]
98 Parse(String),
99 #[error(transparent)]
100 Identity(#[from] crate::identity::PeerIdFromLibp2pPeerId),
101}
102
103impl From<libp2p_identity::ParseError> for P2pNetworkKademliaPeerIdError {
104 fn from(value: libp2p_identity::ParseError) -> Self {
105 P2pNetworkKademliaPeerIdError::Parse(value.to_string())
106 }
107}
108
109impl<'a> TryFrom<Cow<'a, [u8]>> for PeerId {
110 type Error = P2pNetworkKademliaPeerIdError;
111
112 fn try_from(value: Cow<'a, [u8]>) -> Result<Self, Self::Error> {
113 peer_id_try_from_bytes(value)
114 }
115}
116
117pub(super) fn peer_id_try_from_bytes(
118 bytes: Cow<'_, [u8]>,
119) -> Result<PeerId, P2pNetworkKademliaPeerIdError> {
120 Ok((libp2p_identity::PeerId::from_bytes(bytes.as_ref())?).try_into()?)
121}
122
123impl TryFrom<&PeerId> for Cow<'_, [u8]> {
124 type Error = DecodingError;
125
126 fn try_from(value: &PeerId) -> Result<Self, Self::Error> {
127 Ok(libp2p_identity::PeerId::try_from(*value)?.to_bytes().into())
128 }
129}
130
131#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
132pub enum P2pNetworkKademliaRpcPeerTryFromError {
133 #[error(transparent)]
134 PeerId(#[from] P2pNetworkKademliaPeerIdError),
135 #[error(transparent)]
136 Multiaddr(#[from] P2pNetworkKademliaMultiaddrError),
137}
138
139#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, thiserror::Error, MallocSizeOf)]
140#[error("error decoding Multiaddr from bytes: {0}")]
141pub struct P2pNetworkKademliaMultiaddrError(String);
142
143pub(super) fn multiaddr_try_from_bytes(
144 bytes: Cow<'_, [u8]>,
145) -> Result<Multiaddr, P2pNetworkKademliaMultiaddrError> {
146 Ok(bytes.into_owned().try_into()?)
147}
148
149impl From<multiaddr::Error> for P2pNetworkKademliaMultiaddrError {
150 fn from(value: multiaddr::Error) -> Self {
151 P2pNetworkKademliaMultiaddrError(value.to_string())
152 }
153}
154
155#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, thiserror::Error, MallocSizeOf)]
156pub enum P2pNetworkKademliaRpcFromMessageError {
157 #[error(transparent)]
158 PeerId(#[from] P2pNetworkKademliaPeerIdError),
159 #[error(transparent)]
160 Peer(#[from] P2pNetworkKadEntryTryFromError),
161 #[error("unsupported RPC kind: {0}")]
162 Unsupported(String),
163}
164
165impl<'a> TryFrom<super::Message<'a>> for P2pNetworkKademliaRpcRequest {
166 type Error = P2pNetworkKademliaRpcFromMessageError;
167
168 fn try_from(value: super::Message<'a>) -> Result<Self, Self::Error> {
169 match value.type_pb {
170 MessageType::FIND_NODE => {
171 let key = libp2p_identity::PeerId::from_bytes(&value.key)
172 .map_err(P2pNetworkKademliaPeerIdError::from)?;
173
174 Ok(P2pNetworkKademliaRpcRequest::FindNode {
175 key: CID::from(key),
176 })
177 }
178 _ => Err(P2pNetworkKademliaRpcFromMessageError::Unsupported(format!(
179 "{:?}",
180 value.type_pb
181 ))),
182 }
183 }
184}
185
186impl<'a> TryFrom<super::Message<'a>> for P2pNetworkKademliaRpcReply {
187 type Error = P2pNetworkKademliaRpcFromMessageError;
188
189 fn try_from(value: super::Message<'a>) -> Result<Self, Self::Error> {
190 match value.type_pb {
191 MessageType::FIND_NODE => {
192 let closer_peers = value
193 .closerPeers
194 .into_iter()
195 .map(TryFrom::try_from)
196 .collect::<Result<_, _>>()?;
197 Ok(P2pNetworkKademliaRpcReply::FindNode { closer_peers })
198 }
199 _ => Err(P2pNetworkKademliaRpcFromMessageError::Unsupported(format!(
200 "{:?}",
201 value.type_pb
202 ))),
203 }
204 }
205}
206
207impl<'a> From<&'a P2pNetworkKademliaRpcRequest> for super::Message<'a> {
208 fn from(value: &'a P2pNetworkKademliaRpcRequest) -> Self {
209 match value {
210 P2pNetworkKademliaRpcRequest::FindNode { key } => super::Message {
211 type_pb: MessageType::FIND_NODE,
212 clusterLevelRaw: 10,
213 key: key.clone().0.into(),
214 ..Default::default()
215 },
216 }
217 }
218}
219
220impl<'a> TryFrom<&'a P2pNetworkKademliaRpcReply> for super::Message<'a> {
221 type Error = DecodingError;
222
223 fn try_from(value: &'a P2pNetworkKademliaRpcReply) -> Result<Self, Self::Error> {
224 match value {
225 P2pNetworkKademliaRpcReply::FindNode { closer_peers } => {
226 let mut _closer_peers = Vec::new();
227
228 for peer in closer_peers.iter() {
229 _closer_peers.push(peer.try_into()?)
230 }
231
232 Ok(super::Message {
233 type_pb: MessageType::FIND_NODE,
234 clusterLevelRaw: 10,
235 closerPeers: _closer_peers,
236 ..Default::default()
237 })
238 }
239 }
240 }
241}
242
243#[derive(Debug, thiserror::Error)]
244pub enum SocketAddrTryFromMultiaddrError {
245 #[error("no protocol with host")]
246 NoHost,
247 #[error("{0} is not supported as host")]
248 UnsupportedHost(String),
249 #[error("no protocol for port")]
250 NoPort,
251 #[error("{0} is not supported as a port")]
252 UnsupportedPort(String),
253 #[error("extra protocol {0}")]
254 ExtraProtocol(String),
255 #[error("{0}")]
256 Service(#[from] P2pNetworkServiceError),
257}
258
259#[cfg(test)]
260pub mod tests {
261 use multiaddr::Multiaddr;
262 use quick_protobuf::BytesReader;
263
264 use crate::{
265 identity::SecretKey, kad::p2p_network_kad_protocol::multiaddr_try_from_bytes,
266 P2pNetworkKademliaRpcRequest, PeerId,
267 };
268
269 use super::{peer_id_try_from_bytes, CID};
270
271 #[test]
272 fn cid_generation() {
273 let random_peer_id = SecretKey::rand().public_key().peer_id();
274 let libp2p_peer_id =
275 libp2p_identity::PeerId::try_from(random_peer_id).expect("PeerId conversion failed");
276
277 let cid0 = CID::try_from(random_peer_id).expect("Error generating CID");
278 let cid1 = CID::from(libp2p_peer_id);
279
280 assert_eq!(cid0, cid1);
281 }
282
283 #[test]
284 fn peer_id_from_wire() {
285 let from_bytes = |bytes: &[u8]| peer_id_try_from_bytes(bytes.into());
286
287 assert!(from_bytes(&[]).is_err());
288 let peer_id = "2bEgBrPTzL8wov2D4Kz34WVLCxR4uCarsBmHYXWKQA5wvBQzd9H"
291 .parse::<PeerId>()
292 .expect("Error parsing peer id");
293 assert_eq!(
294 from_bytes(
295 &libp2p_identity::PeerId::try_from(peer_id)
296 .expect("Error converting to PeerId")
297 .to_bytes()
298 )
299 .expect("Error generating from bytes"),
300 peer_id
301 );
302 }
303
304 #[test]
305 fn multiaddr_from_wire() {
306 let from_bytes = |bytes: &[u8]| multiaddr_try_from_bytes(bytes.into());
307
308 assert!(from_bytes(&[4, 198, 51, 100, 1, 6, 0, 10]).is_ok());
310 assert!(
312 from_bytes(&[54, 10, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 6, 1, 187])
313 .is_ok()
314 );
315
316 for multiaddr in [
317 "/ip4/198.51.100.1/tcp/80",
318 "/dns4/ams-2.bootstrap.libp2p.io/tcp/443",
319 ] {
320 let multiaddr = multiaddr.parse::<Multiaddr>().expect("Failed to parse");
321 assert_eq!(
322 from_bytes(&multiaddr.to_vec()).expect("Error converting from bytes"),
323 multiaddr
324 );
325 }
326 }
327
328 #[test]
329 fn find_nodes_from_wire() {
330 let input = "2c0804500a1226002408011220bcbfc53faa51a1410b7599c1e4411d5ac45ed5a1ffdc4673c1a6e2b9e9125c4d";
331
332 let bytes = hex::decode(input).expect("Error decoding");
333 let protobuf_message = BytesReader::from_bytes(&bytes)
334 .read_message::<super::super::Message>(&bytes)
335 .expect("should be able to decode");
336
337 let message = super::P2pNetworkKademliaRpcRequest::try_from(protobuf_message)
338 .expect("should be able to convert");
339
340 let P2pNetworkKademliaRpcRequest::FindNode { key } = message;
341 assert_eq!(
342 &key.to_libp2p_string(),
343 "12D3KooWNXARF5S7qTRZZuoTZwSda7XA7fBh4oz1vZadHnaFv1nL"
344 );
345 }
346
347 #[test]
348 fn find_nodes_from_wire_len() {
349 let input = "2c0804500a1226002408011220bcbfc53faa51a1410b7599c1e4411d5ac45ed5a1ffdc4673c1a6e2b9e9125c4d";
350
351 let bytes = hex::decode(input).expect("Error decoding");
352 let from_bytes = &mut BytesReader::from_bytes(&bytes);
353 let len = from_bytes.read_varint32(&bytes).expect("Error reading len");
354
355 println!("{} {}", len, from_bytes.len());
356 let protobuf_message = BytesReader::from_bytes(&bytes)
357 .read_message::<super::super::Message>(&bytes)
358 .expect("should be able to decode");
359
360 let message = super::P2pNetworkKademliaRpcRequest::try_from(protobuf_message)
361 .expect("should be able to convert");
362
363 let P2pNetworkKademliaRpcRequest::FindNode { key } = message;
364 assert_eq!(
365 &key.to_libp2p_string(),
366 "12D3KooWNXARF5S7qTRZZuoTZwSda7XA7fBh4oz1vZadHnaFv1nL"
367 );
368 }
369}