p2p/network/kad/
p2p_network_kad_protocol.rs

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        // assert!(from_bytes(&[0; 32]).is_ok());
289
290        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        // /ip4/182.51.100.1/tcp/10
309        assert!(from_bytes(&[4, 198, 51, 100, 1, 6, 0, 10]).is_ok());
310        // /dns4/google.com/tcp/443
311        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}