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