ant_protocol/
lib.rs

1// Copyright 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9// Allow enum variant names that end with Error as they come from thiserror derives
10#![allow(clippy::enum_variant_names)]
11// Allow the to_* methods on Copy types (used for byte conversions)
12#![allow(clippy::wrong_self_convention)]
13// Allow expect/panic usage temporarily
14#![allow(clippy::expect_used)]
15#![allow(clippy::panic)]
16
17#[macro_use]
18extern crate tracing;
19
20/// Constants
21pub mod constants;
22/// Errors.
23pub mod error;
24/// Messages types
25pub mod messages;
26/// RPC commands to node
27pub mod node_rpc;
28/// `PeerId` serialization helpers
29pub(crate) mod peer_id_serde;
30/// Storage types for GraphEntry and Chunk
31pub mod storage;
32/// Network versioning
33pub mod version;
34
35// this includes code generated from .proto files
36#[expect(clippy::unwrap_used, clippy::clone_on_ref_ptr)]
37#[cfg(feature = "rpc")]
38pub mod antnode_proto {
39    tonic::include_proto!("antnode_proto");
40}
41pub use error::Error;
42pub use error::Error as NetworkError;
43
44use self::storage::{ChunkAddress, GraphEntryAddress, PointerAddress, ScratchpadAddress};
45
46/// Re-export of Bytes used throughout the protocol
47pub use bytes::Bytes;
48
49use libp2p::{
50    Multiaddr, PeerId,
51    kad::{KBucketDistance as Distance, KBucketKey as Key, RecordKey},
52    multiaddr::Protocol,
53};
54use serde::{Deserialize, Deserializer, Serialize, Serializer};
55use std::{
56    borrow::Cow,
57    fmt::{self, Debug, Display, Formatter, Write},
58};
59use xor_name::XorName;
60
61pub use constants::CLOSE_GROUP_SIZE;
62
63/// Returns the UDP port from the provided MultiAddr.
64pub fn get_port_from_multiaddr(multi_addr: &Multiaddr) -> Option<u16> {
65    // assuming the listening addr contains /ip4/127.0.0.1/udp/56215/quic-v1/p2p/<peer_id>
66    for protocol in multi_addr.iter() {
67        if let Protocol::Udp(port) = protocol {
68            return Some(port);
69        }
70    }
71    None
72}
73
74/// This is the address in the network by which proximity/distance
75/// to other items (whether nodes or data chunks) are calculated.
76///
77/// This is the mapping from the XOR name used
78/// by for example self encryption, or the libp2p `PeerId`,
79/// to the key used in the Kademlia DHT.
80/// All our xorname calculations shall be replaced with the `KBucketKey` calculations,
81/// for getting proximity/distance to other items (whether nodes or data).
82#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
83pub enum NetworkAddress {
84    /// The NetworkAddress is representing a PeerId.
85    PeerId(Bytes),
86    /// The NetworkAddress is representing a ChunkAddress.
87    ChunkAddress(ChunkAddress),
88    /// The NetworkAddress is representing a GraphEntryAddress.
89    GraphEntryAddress(GraphEntryAddress),
90    /// The NetworkAddress is representing a ScratchpadAddress.
91    ScratchpadAddress(ScratchpadAddress),
92    /// The NetworkAddress is representing a PointerAddress.
93    PointerAddress(PointerAddress),
94    /// The NetworkAddress is representing a RecordKey.
95    RecordKey(Bytes),
96}
97
98impl NetworkAddress {
99    /// Return the encapsulated bytes of this `NetworkAddress`.
100    pub fn as_bytes(&self) -> Vec<u8> {
101        match self {
102            NetworkAddress::PeerId(bytes) | NetworkAddress::RecordKey(bytes) => bytes.to_vec(),
103            NetworkAddress::ChunkAddress(chunk_address) => chunk_address.xorname().to_vec(),
104            NetworkAddress::GraphEntryAddress(graph_entry_address) => {
105                graph_entry_address.xorname().to_vec()
106            }
107            NetworkAddress::ScratchpadAddress(addr) => addr.xorname().to_vec(),
108            NetworkAddress::PointerAddress(pointer_address) => pointer_address.xorname().to_vec(),
109        }
110    }
111
112    /// Return the XorName represented by this `NetworkAddress`.
113    pub fn xorname(&self) -> Option<XorName> {
114        match self {
115            NetworkAddress::ChunkAddress(chunk_address) => Some(*chunk_address.xorname()),
116            NetworkAddress::GraphEntryAddress(graph_entry_address) => {
117                Some(graph_entry_address.xorname())
118            }
119            NetworkAddress::ScratchpadAddress(scratchpad_address) => {
120                Some(scratchpad_address.xorname())
121            }
122            NetworkAddress::PointerAddress(pointer_address) => Some(pointer_address.xorname()),
123            NetworkAddress::PeerId(_) => None,
124            NetworkAddress::RecordKey(_) => None,
125        }
126    }
127
128    /// Try to return the represented `PeerId`.
129    pub fn as_peer_id(&self) -> Option<PeerId> {
130        if let NetworkAddress::PeerId(bytes) = self
131            && let Ok(peer_id) = PeerId::from_bytes(bytes)
132        {
133            return Some(peer_id);
134        }
135        None
136    }
137
138    /// Return the convertable `RecordKey`.
139    pub fn to_record_key(&self) -> RecordKey {
140        match self {
141            NetworkAddress::RecordKey(bytes) => RecordKey::new(bytes),
142            NetworkAddress::ChunkAddress(chunk_address) => RecordKey::new(chunk_address.xorname()),
143            NetworkAddress::GraphEntryAddress(graph_entry_address) => {
144                RecordKey::new(&graph_entry_address.xorname())
145            }
146            NetworkAddress::PointerAddress(pointer_address) => {
147                RecordKey::new(&pointer_address.xorname())
148            }
149            NetworkAddress::ScratchpadAddress(addr) => RecordKey::new(&addr.xorname()),
150            NetworkAddress::PeerId(bytes) => RecordKey::new(bytes),
151        }
152    }
153
154    /// Return the `KBucketKey` representation of this `NetworkAddress`.
155    ///
156    /// The `KBucketKey` is used for calculating proximity/distance to other items (whether nodes or data).
157    /// Important to note is that it will always SHA256 hash any bytes it receives.
158    /// Therefore, the canonical use of distance/proximity calculations in the network
159    /// is via the `KBucketKey`, or the convenience methods of `NetworkAddress`.
160    pub fn as_kbucket_key(&self) -> Key<Vec<u8>> {
161        Key::new(self.as_bytes())
162    }
163
164    /// Compute the distance of the keys according to the XOR metric.
165    pub fn distance(&self, other: &NetworkAddress) -> Distance {
166        self.as_kbucket_key().distance(&other.as_kbucket_key())
167    }
168}
169
170impl From<XorName> for NetworkAddress {
171    fn from(xorname: XorName) -> Self {
172        NetworkAddress::ChunkAddress(ChunkAddress::new(xorname))
173    }
174}
175
176impl From<ChunkAddress> for NetworkAddress {
177    fn from(chunk_address: ChunkAddress) -> Self {
178        NetworkAddress::ChunkAddress(chunk_address)
179    }
180}
181
182impl From<GraphEntryAddress> for NetworkAddress {
183    fn from(graph_entry_address: GraphEntryAddress) -> Self {
184        NetworkAddress::GraphEntryAddress(graph_entry_address)
185    }
186}
187
188impl From<ScratchpadAddress> for NetworkAddress {
189    fn from(scratchpad_address: ScratchpadAddress) -> Self {
190        NetworkAddress::ScratchpadAddress(scratchpad_address)
191    }
192}
193
194impl From<PointerAddress> for NetworkAddress {
195    fn from(pointer_address: PointerAddress) -> Self {
196        NetworkAddress::PointerAddress(pointer_address)
197    }
198}
199
200impl From<PeerId> for NetworkAddress {
201    fn from(peer_id: PeerId) -> Self {
202        NetworkAddress::PeerId(Bytes::from(peer_id.to_bytes()))
203    }
204}
205
206impl From<&RecordKey> for NetworkAddress {
207    fn from(record_key: &RecordKey) -> Self {
208        NetworkAddress::RecordKey(Bytes::copy_from_slice(record_key.as_ref()))
209    }
210}
211
212impl Debug for NetworkAddress {
213    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
214        let name_str = match self {
215            NetworkAddress::PeerId(_) => {
216                if let Some(peer_id) = self.as_peer_id() {
217                    format!("NetworkAddress::{peer_id:?} - (")
218                } else {
219                    "NetworkAddress::PeerId(".to_string()
220                }
221            }
222            NetworkAddress::ChunkAddress(chunk_address) => {
223                format!(
224                    "NetworkAddress::ChunkAddress({}) - (",
225                    &chunk_address.to_hex()
226                )
227            }
228            NetworkAddress::GraphEntryAddress(graph_entry_address) => {
229                format!(
230                    "NetworkAddress::GraphEntryAddress({}) - (",
231                    &graph_entry_address.to_hex()
232                )
233            }
234            NetworkAddress::ScratchpadAddress(scratchpad_address) => {
235                format!(
236                    "NetworkAddress::ScratchpadAddress({}) - (",
237                    &scratchpad_address.to_hex()
238                )
239            }
240            NetworkAddress::PointerAddress(pointer_address) => {
241                format!(
242                    "NetworkAddress::PointerAddress({}) - (",
243                    &pointer_address.to_hex()
244                )
245            }
246            NetworkAddress::RecordKey(bytes) => {
247                format!("NetworkAddress::RecordKey({:?}) - (", hex::encode(bytes))
248            }
249        };
250
251        write!(
252            f,
253            "{name_str}{:?})",
254            PrettyPrintKBucketKey(self.as_kbucket_key())
255        )
256    }
257}
258
259impl Display for NetworkAddress {
260    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
261        match self {
262            NetworkAddress::PeerId(id) => {
263                write!(f, "NetworkAddress::PeerId({})", hex::encode(id))
264            }
265            NetworkAddress::ChunkAddress(addr) => {
266                write!(f, "NetworkAddress::ChunkAddress({addr})")
267            }
268            NetworkAddress::GraphEntryAddress(addr) => {
269                write!(f, "NetworkAddress::GraphEntryAddress({addr})")
270            }
271            NetworkAddress::ScratchpadAddress(addr) => {
272                write!(f, "NetworkAddress::ScratchpadAddress({addr})")
273            }
274            NetworkAddress::RecordKey(key) => {
275                write!(f, "NetworkAddress::RecordKey({})", hex::encode(key))
276            }
277            NetworkAddress::PointerAddress(addr) => {
278                write!(f, "NetworkAddress::PointerAddress({addr})")
279            }
280        }
281    }
282}
283
284/// Pretty print a `kad::KBucketKey` as a hex string.
285#[derive(Clone)]
286pub struct PrettyPrintKBucketKey(pub Key<Vec<u8>>);
287
288impl std::fmt::Display for PrettyPrintKBucketKey {
289    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290        for byte in self.0.hashed_bytes() {
291            f.write_fmt(format_args!("{byte:02x}"))?;
292        }
293        Ok(())
294    }
295}
296
297impl std::fmt::Debug for PrettyPrintKBucketKey {
298    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
299        write!(f, "{self}")
300    }
301}
302
303/// Provides a hex representation of a `kad::RecordKey`.
304///
305/// This internally stores the RecordKey as a `Cow` type. Use `PrettyPrintRecordKey::from(&RecordKey)` to create a
306/// borrowed version for printing/logging.
307/// To use in error messages, to pass to other functions, call `PrettyPrintRecordKey::from(&RecordKey).into_owned()` to
308///  obtain a cloned, non-referenced `RecordKey`.
309#[derive(Clone, Hash, Eq, PartialEq)]
310pub struct PrettyPrintRecordKey<'a> {
311    key: Cow<'a, RecordKey>,
312}
313
314impl Serialize for PrettyPrintRecordKey<'_> {
315    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
316    where
317        S: Serializer,
318    {
319        let record_key_bytes = match &self.key {
320            Cow::Borrowed(borrowed_key) => borrowed_key.as_ref(),
321            Cow::Owned(owned_key) => owned_key.as_ref(),
322        };
323        record_key_bytes.serialize(serializer)
324    }
325}
326
327// Implementing Deserialize for PrettyPrintRecordKey
328impl<'de> Deserialize<'de> for PrettyPrintRecordKey<'static> {
329    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
330    where
331        D: Deserializer<'de>,
332    {
333        // Deserialize to bytes first
334        let bytes = Vec::<u8>::deserialize(deserializer)?;
335        // Then use the bytes to create a RecordKey and wrap it in PrettyPrintRecordKey
336        Ok(PrettyPrintRecordKey {
337            key: Cow::Owned(RecordKey::new(&bytes)),
338        })
339    }
340}
341/// This is the only interface to create a PrettyPrintRecordKey.
342/// `.into_owned()` must be called explicitly if you want a Owned version to be used for errors/args.
343impl<'a> From<&'a RecordKey> for PrettyPrintRecordKey<'a> {
344    fn from(key: &'a RecordKey) -> Self {
345        PrettyPrintRecordKey {
346            key: Cow::Borrowed(key),
347        }
348    }
349}
350
351impl PrettyPrintRecordKey<'_> {
352    /// Creates a owned version that can be then used to pass as error values.
353    /// Do not call this if you just want to print/log `PrettyPrintRecordKey`
354    pub fn into_owned(self) -> PrettyPrintRecordKey<'static> {
355        let cloned_key = match self.key {
356            Cow::Borrowed(key) => Cow::Owned(key.clone()),
357            Cow::Owned(key) => Cow::Owned(key),
358        };
359
360        PrettyPrintRecordKey { key: cloned_key }
361    }
362
363    pub fn no_kbucket_log(self) -> String {
364        let mut content = String::from("");
365        let record_key_bytes = match &self.key {
366            Cow::Borrowed(borrowed_key) => borrowed_key.as_ref(),
367            Cow::Owned(owned_key) => owned_key.as_ref(),
368        };
369        for byte in record_key_bytes {
370            let _ = content.write_fmt(format_args!("{byte:02x}"));
371        }
372        content
373    }
374}
375
376impl std::fmt::Display for PrettyPrintRecordKey<'_> {
377    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
378        let record_key_bytes = match &self.key {
379            Cow::Borrowed(borrowed_key) => borrowed_key.as_ref(),
380            Cow::Owned(owned_key) => owned_key.as_ref(),
381        };
382        // print the first 6 chars
383        for byte in record_key_bytes.iter().take(3) {
384            f.write_fmt(format_args!("{byte:02x}"))?;
385        }
386
387        write!(
388            f,
389            "({:?})",
390            PrettyPrintKBucketKey(NetworkAddress::from(self.key.as_ref()).as_kbucket_key())
391        )
392    }
393}
394
395impl std::fmt::Debug for PrettyPrintRecordKey<'_> {
396    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
397        // same as display
398        write!(f, "{self}")
399    }
400}
401
402#[cfg(test)]
403mod tests {
404    use crate::{
405        NetworkAddress, PeerId,
406        messages::{Nonce, Query},
407        storage::GraphEntryAddress,
408    };
409    use serde::{Deserialize, Serialize};
410
411    #[test]
412    fn verify_graph_entry_addr_is_actionable() {
413        let pk = bls::SecretKey::random().public_key();
414        let graph_entry_addr = GraphEntryAddress::new(pk);
415        let net_addr = NetworkAddress::from(graph_entry_addr);
416
417        let graph_entry_addr_hex = &graph_entry_addr.to_hex();
418        let net_addr_fmt = format!("{net_addr}");
419
420        assert!(net_addr_fmt.contains(graph_entry_addr_hex));
421    }
422
423    #[derive(Eq, PartialEq, PartialOrd, Clone, Serialize, Deserialize, Debug)]
424    enum QueryExtended {
425        GetStoreQuote {
426            key: NetworkAddress,
427            data_type: u32,
428            data_size: usize,
429            nonce: Option<Nonce>,
430            difficulty: usize,
431        },
432        GetReplicatedRecord {
433            requester: NetworkAddress,
434            key: NetworkAddress,
435        },
436        GetChunkExistenceProof {
437            key: NetworkAddress,
438            nonce: Nonce,
439            difficulty: usize,
440        },
441        CheckNodeInProblem(NetworkAddress),
442        GetClosestPeers {
443            key: NetworkAddress,
444            num_of_peers: Option<usize>,
445            range: Option<[u8; 32]>,
446            sign_result: bool,
447        },
448        GetVersion(NetworkAddress),
449        AdditionalVariant(NetworkAddress), // New variant for extended functionality
450    }
451
452    #[test]
453    fn test_query_serialization_deserialization() {
454        let peer_id = PeerId::random();
455        // Create a sample Query message
456        let original_query = Query::GetStoreQuote {
457            key: NetworkAddress::from(peer_id),
458            data_type: 1,
459            data_size: 100,
460            nonce: Some(0),
461            difficulty: 3,
462        };
463
464        // Serialize to bytes
465        let serialized = bincode::serialize(&original_query).expect("Serialization failed");
466
467        // Deserialize into QueryExtended
468        let deserialized: QueryExtended =
469            bincode::deserialize(&serialized).expect("Deserialization into QueryExtended failed");
470
471        // Verify the deserialized data matches the original
472        match deserialized {
473            QueryExtended::GetStoreQuote {
474                key,
475                data_type,
476                data_size,
477                nonce,
478                difficulty,
479            } => {
480                assert_eq!(key, NetworkAddress::from(peer_id));
481                assert_eq!(data_type, 1);
482                assert_eq!(data_size, 100);
483                assert_eq!(nonce, Some(0));
484                assert_eq!(difficulty, 3);
485            }
486            _ => panic!("Deserialized into wrong variant"),
487        }
488    }
489
490    #[test]
491    fn test_query_extended_serialization() {
492        // Create a sample QueryExtended message with extended new variant
493        let extended_query =
494            QueryExtended::AdditionalVariant(NetworkAddress::from(PeerId::random()));
495
496        // Serialize to bytes
497        let serialized = bincode::serialize(&extended_query).expect("Serialization failed");
498
499        // Attempt to deserialize into original Query (should fail)
500        let result: Result<Query, _> = bincode::deserialize(&serialized);
501        assert!(
502            result.is_err(),
503            "Should fail to deserialize extended enum into original"
504        );
505
506        let peer_id = PeerId::random();
507        // Create a sample QueryExtended message with old variant
508        let extended_query = QueryExtended::GetStoreQuote {
509            key: NetworkAddress::from(peer_id),
510            data_type: 1,
511            data_size: 100,
512            nonce: Some(0),
513            difficulty: 3,
514        };
515
516        // Serialize to bytes
517        let serialized = bincode::serialize(&extended_query).expect("Serialization failed");
518
519        // Deserialize into Query
520        let deserialized: Query =
521            bincode::deserialize(&serialized).expect("Deserialization into Query failed");
522
523        // Verify the deserialized data matches the original
524        match deserialized {
525            Query::GetStoreQuote {
526                key,
527                data_type,
528                data_size,
529                nonce,
530                difficulty,
531            } => {
532                assert_eq!(key, NetworkAddress::from(peer_id));
533                assert_eq!(data_type, 1);
534                assert_eq!(data_size, 100);
535                assert_eq!(nonce, Some(0));
536                assert_eq!(difficulty, 3);
537            }
538            _ => panic!("Deserialized into wrong variant"),
539        }
540    }
541}