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#[macro_use]
10extern crate tracing;
11
12/// Errors.
13pub mod error;
14/// Messages types
15pub mod messages;
16/// Helpers for antnode
17pub mod node;
18/// RPC commands to node
19pub mod node_rpc;
20/// Storage types for GraphEntry and Chunk
21pub mod storage;
22/// Network versioning
23pub mod version;
24
25// this includes code generated from .proto files
26#[expect(clippy::unwrap_used, clippy::clone_on_ref_ptr)]
27#[cfg(feature = "rpc")]
28pub mod antnode_proto {
29    tonic::include_proto!("antnode_proto");
30}
31pub use error::Error;
32pub use error::Error as NetworkError;
33
34use self::storage::{ChunkAddress, GraphEntryAddress, PointerAddress, ScratchpadAddress};
35
36/// Re-export of Bytes used throughout the protocol
37pub use bytes::Bytes;
38
39use libp2p::{
40    kad::{KBucketDistance as Distance, KBucketKey as Key, RecordKey},
41    multiaddr::Protocol,
42    Multiaddr, PeerId,
43};
44use serde::{Deserialize, Deserializer, Serialize, Serializer};
45use std::{
46    borrow::Cow,
47    fmt::{self, Debug, Display, Formatter, Write},
48};
49
50/// The maximum number of peers to return in a `GetClosestPeers` response.
51/// This is the group size used in safe network protocol to be responsible for
52/// an item in the network.
53/// The peer should be present among the CLOSE_GROUP_SIZE if we're fetching the close_group(peer)
54/// The size has been set to 5 for improved performance.
55pub const CLOSE_GROUP_SIZE: usize = 5;
56
57/// Returns the UDP port from the provided MultiAddr.
58pub fn get_port_from_multiaddr(multi_addr: &Multiaddr) -> Option<u16> {
59    // assuming the listening addr contains /ip4/127.0.0.1/udp/56215/quic-v1/p2p/<peer_id>
60    for protocol in multi_addr.iter() {
61        if let Protocol::Udp(port) = protocol {
62            return Some(port);
63        }
64    }
65    None
66}
67
68/// This is the address in the network by which proximity/distance
69/// to other items (whether nodes or data chunks) are calculated.
70///
71/// This is the mapping from the XOR name used
72/// by for example self encryption, or the libp2p `PeerId`,
73/// to the key used in the Kademlia DHT.
74/// All our xorname calculations shall be replaced with the `KBucketKey` calculations,
75/// for getting proximity/distance to other items (whether nodes or data).
76#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
77pub enum NetworkAddress {
78    /// The NetworkAddress is representing a PeerId.
79    PeerId(Bytes),
80    /// The NetworkAddress is representing a ChunkAddress.
81    ChunkAddress(ChunkAddress),
82    /// The NetworkAddress is representing a GraphEntryAddress.
83    GraphEntryAddress(GraphEntryAddress),
84    /// The NetworkAddress is representing a ScratchpadAddress.
85    ScratchpadAddress(ScratchpadAddress),
86    /// The NetworkAddress is representing a PointerAddress.
87    PointerAddress(PointerAddress),
88    /// The NetworkAddress is representing a RecordKey.
89    RecordKey(Bytes),
90}
91
92impl NetworkAddress {
93    /// Return a `NetworkAddress` representation of the `ChunkAddress`.
94    pub fn from_chunk_address(chunk_address: ChunkAddress) -> Self {
95        NetworkAddress::ChunkAddress(chunk_address)
96    }
97
98    /// Return a `NetworkAddress` representation of the `GraphEntryAddress`.
99    pub fn from_graph_entry_address(graph_entry_address: GraphEntryAddress) -> Self {
100        NetworkAddress::GraphEntryAddress(graph_entry_address)
101    }
102
103    /// Return a `NetworkAddress` representation of the `GraphEntryAddress`.
104    pub fn from_scratchpad_address(address: ScratchpadAddress) -> Self {
105        NetworkAddress::ScratchpadAddress(address)
106    }
107
108    /// Return a `NetworkAddress` representation of the `PeerId` by encapsulating its bytes.
109    pub fn from_peer(peer_id: PeerId) -> Self {
110        NetworkAddress::PeerId(Bytes::from(peer_id.to_bytes()))
111    }
112
113    /// Return a `NetworkAddress` representation of the `RecordKey` by encapsulating its bytes.
114    pub fn from_record_key(record_key: &RecordKey) -> Self {
115        NetworkAddress::RecordKey(Bytes::copy_from_slice(record_key.as_ref()))
116    }
117
118    /// Return a `NetworkAddress` representation of the `PointerAddress`.
119    pub fn from_pointer_address(pointer_address: PointerAddress) -> Self {
120        NetworkAddress::PointerAddress(pointer_address)
121    }
122
123    /// Return the encapsulated bytes of this `NetworkAddress`.
124    pub fn as_bytes(&self) -> Vec<u8> {
125        match self {
126            NetworkAddress::PeerId(bytes) | NetworkAddress::RecordKey(bytes) => bytes.to_vec(),
127            NetworkAddress::ChunkAddress(chunk_address) => chunk_address.xorname().to_vec(),
128            NetworkAddress::GraphEntryAddress(graph_entry_address) => {
129                graph_entry_address.xorname().to_vec()
130            }
131            NetworkAddress::ScratchpadAddress(addr) => addr.xorname().to_vec(),
132            NetworkAddress::PointerAddress(pointer_address) => pointer_address.xorname().to_vec(),
133        }
134    }
135
136    /// Try to return the represented `PeerId`.
137    pub fn as_peer_id(&self) -> Option<PeerId> {
138        if let NetworkAddress::PeerId(bytes) = self {
139            if let Ok(peer_id) = PeerId::from_bytes(bytes) {
140                return Some(peer_id);
141            }
142        }
143        None
144    }
145
146    /// Try to return the represented `RecordKey`.
147    pub fn as_record_key(&self) -> Option<RecordKey> {
148        match self {
149            NetworkAddress::RecordKey(bytes) => Some(RecordKey::new(bytes)),
150            _ => None,
151        }
152    }
153
154    /// Return the convertable `RecordKey`.
155    pub fn to_record_key(&self) -> RecordKey {
156        match self {
157            NetworkAddress::RecordKey(bytes) => RecordKey::new(bytes),
158            NetworkAddress::ChunkAddress(chunk_address) => RecordKey::new(chunk_address.xorname()),
159            NetworkAddress::GraphEntryAddress(graph_entry_address) => {
160                RecordKey::new(&graph_entry_address.xorname())
161            }
162            NetworkAddress::PointerAddress(pointer_address) => {
163                RecordKey::new(&pointer_address.xorname())
164            }
165            NetworkAddress::ScratchpadAddress(addr) => RecordKey::new(&addr.xorname()),
166            NetworkAddress::PeerId(bytes) => RecordKey::new(bytes),
167        }
168    }
169
170    /// Return the `KBucketKey` representation of this `NetworkAddress`.
171    ///
172    /// The `KBucketKey` is used for calculating proximity/distance to other items (whether nodes or data).
173    /// Important to note is that it will always SHA256 hash any bytes it receives.
174    /// Therefore, the canonical use of distance/proximity calculations in the network
175    /// is via the `KBucketKey`, or the convenience methods of `NetworkAddress`.
176    pub fn as_kbucket_key(&self) -> Key<Vec<u8>> {
177        Key::new(self.as_bytes())
178    }
179
180    /// Compute the distance of the keys according to the XOR metric.
181    pub fn distance(&self, other: &NetworkAddress) -> Distance {
182        self.as_kbucket_key().distance(&other.as_kbucket_key())
183    }
184}
185
186impl Debug for NetworkAddress {
187    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
188        let name_str = match self {
189            NetworkAddress::PeerId(_) => {
190                if let Some(peer_id) = self.as_peer_id() {
191                    format!("NetworkAddress::PeerId({peer_id} - ")
192                } else {
193                    "NetworkAddress::PeerId(".to_string()
194                }
195            }
196            NetworkAddress::ChunkAddress(chunk_address) => {
197                format!(
198                    "NetworkAddress::ChunkAddress({} - ",
199                    &chunk_address.to_hex()
200                )
201            }
202            NetworkAddress::GraphEntryAddress(graph_entry_address) => {
203                format!(
204                    "NetworkAddress::GraphEntryAddress({} - ",
205                    &graph_entry_address.to_hex()
206                )
207            }
208            NetworkAddress::ScratchpadAddress(scratchpad_address) => {
209                format!(
210                    "NetworkAddress::ScratchpadAddress({} - ",
211                    &scratchpad_address.to_hex()
212                )
213            }
214            NetworkAddress::PointerAddress(pointer_address) => {
215                format!(
216                    "NetworkAddress::PointerAddress({} - ",
217                    &pointer_address.to_hex()
218                )
219            }
220            NetworkAddress::RecordKey(bytes) => {
221                format!("NetworkAddress::RecordKey({:?} - ", hex::encode(bytes))
222            }
223        };
224
225        write!(
226            f,
227            "{name_str}{:?})",
228            PrettyPrintKBucketKey(self.as_kbucket_key())
229        )
230    }
231}
232
233impl Display for NetworkAddress {
234    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
235        match self {
236            NetworkAddress::PeerId(id) => {
237                write!(f, "NetworkAddress::PeerId({})", hex::encode(id))
238            }
239            NetworkAddress::ChunkAddress(addr) => {
240                write!(f, "NetworkAddress::ChunkAddress({addr})")
241            }
242            NetworkAddress::GraphEntryAddress(addr) => {
243                write!(f, "NetworkAddress::GraphEntryAddress({addr})")
244            }
245            NetworkAddress::ScratchpadAddress(addr) => {
246                write!(f, "NetworkAddress::ScratchpadAddress({addr})")
247            }
248            NetworkAddress::RecordKey(key) => {
249                write!(f, "NetworkAddress::RecordKey({})", hex::encode(key))
250            }
251            NetworkAddress::PointerAddress(addr) => {
252                write!(f, "NetworkAddress::PointerAddress({addr})")
253            }
254        }
255    }
256}
257
258/// Pretty print a `kad::KBucketKey` as a hex string.
259#[derive(Clone)]
260pub struct PrettyPrintKBucketKey(pub Key<Vec<u8>>);
261
262impl std::fmt::Display for PrettyPrintKBucketKey {
263    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264        for byte in self.0.hashed_bytes() {
265            f.write_fmt(format_args!("{byte:02x}"))?;
266        }
267        Ok(())
268    }
269}
270
271impl std::fmt::Debug for PrettyPrintKBucketKey {
272    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273        write!(f, "{self}")
274    }
275}
276
277/// Provides a hex representation of a `kad::RecordKey`.
278///
279/// This internally stores the RecordKey as a `Cow` type. Use `PrettyPrintRecordKey::from(&RecordKey)` to create a
280/// borrowed version for printing/logging.
281/// To use in error messages, to pass to other functions, call `PrettyPrintRecordKey::from(&RecordKey).into_owned()` to
282///  obtain a cloned, non-referenced `RecordKey`.
283#[derive(Clone, Hash, Eq, PartialEq)]
284pub struct PrettyPrintRecordKey<'a> {
285    key: Cow<'a, RecordKey>,
286}
287
288impl Serialize for PrettyPrintRecordKey<'_> {
289    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
290    where
291        S: Serializer,
292    {
293        let record_key_bytes = match &self.key {
294            Cow::Borrowed(borrowed_key) => borrowed_key.as_ref(),
295            Cow::Owned(owned_key) => owned_key.as_ref(),
296        };
297        record_key_bytes.serialize(serializer)
298    }
299}
300
301// Implementing Deserialize for PrettyPrintRecordKey
302impl<'de> Deserialize<'de> for PrettyPrintRecordKey<'static> {
303    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
304    where
305        D: Deserializer<'de>,
306    {
307        // Deserialize to bytes first
308        let bytes = Vec::<u8>::deserialize(deserializer)?;
309        // Then use the bytes to create a RecordKey and wrap it in PrettyPrintRecordKey
310        Ok(PrettyPrintRecordKey {
311            key: Cow::Owned(RecordKey::new(&bytes)),
312        })
313    }
314}
315/// This is the only interface to create a PrettyPrintRecordKey.
316/// `.into_owned()` must be called explicitly if you want a Owned version to be used for errors/args.
317impl<'a> From<&'a RecordKey> for PrettyPrintRecordKey<'a> {
318    fn from(key: &'a RecordKey) -> Self {
319        PrettyPrintRecordKey {
320            key: Cow::Borrowed(key),
321        }
322    }
323}
324
325impl PrettyPrintRecordKey<'_> {
326    /// Creates a owned version that can be then used to pass as error values.
327    /// Do not call this if you just want to print/log `PrettyPrintRecordKey`
328    pub fn into_owned(self) -> PrettyPrintRecordKey<'static> {
329        let cloned_key = match self.key {
330            Cow::Borrowed(key) => Cow::Owned(key.clone()),
331            Cow::Owned(key) => Cow::Owned(key),
332        };
333
334        PrettyPrintRecordKey { key: cloned_key }
335    }
336
337    pub fn no_kbucket_log(self) -> String {
338        let mut content = String::from("");
339        let record_key_bytes = match &self.key {
340            Cow::Borrowed(borrowed_key) => borrowed_key.as_ref(),
341            Cow::Owned(owned_key) => owned_key.as_ref(),
342        };
343        for byte in record_key_bytes {
344            let _ = content.write_fmt(format_args!("{byte:02x}"));
345        }
346        content
347    }
348}
349
350impl std::fmt::Display for PrettyPrintRecordKey<'_> {
351    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352        let record_key_bytes = match &self.key {
353            Cow::Borrowed(borrowed_key) => borrowed_key.as_ref(),
354            Cow::Owned(owned_key) => owned_key.as_ref(),
355        };
356        // print the first 6 chars
357        for byte in record_key_bytes.iter().take(3) {
358            f.write_fmt(format_args!("{byte:02x}"))?;
359        }
360
361        write!(
362            f,
363            "({:?})",
364            PrettyPrintKBucketKey(NetworkAddress::from_record_key(&self.key).as_kbucket_key())
365        )
366    }
367}
368
369impl std::fmt::Debug for PrettyPrintRecordKey<'_> {
370    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
371        // same as display
372        write!(f, "{self}")
373    }
374}
375
376#[cfg(test)]
377mod tests {
378    use crate::storage::GraphEntryAddress;
379    use crate::NetworkAddress;
380
381    #[test]
382    fn verify_graph_entry_addr_is_actionable() {
383        let pk = bls::SecretKey::random().public_key();
384        let graph_entry_addr = GraphEntryAddress::new(pk);
385        let net_addr = NetworkAddress::from_graph_entry_address(graph_entry_addr);
386
387        let graph_entry_addr_hex = &graph_entry_addr.to_hex();
388        let net_addr_fmt = format!("{net_addr}");
389        let net_addr_dbg = format!("{net_addr:?}");
390
391        assert!(net_addr_fmt.contains(graph_entry_addr_hex));
392        assert!(net_addr_dbg.contains(graph_entry_addr_hex));
393    }
394}