litep2p/protocol/libp2p/kademlia/
record.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2// Copyright 2023 litep2p developers
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22use crate::{
23    protocol::libp2p::kademlia::types::{
24        ConnectionType, Distance, KademliaPeer, Key as KademliaKey,
25    },
26    transport::manager::address::{AddressRecord, AddressStore},
27    Multiaddr, PeerId,
28};
29
30use bytes::Bytes;
31use multihash::Multihash;
32
33use std::{borrow::Borrow, time::Instant};
34
35/// The (opaque) key of a record.
36#[derive(Clone, Debug, PartialEq, Eq, Hash)]
37#[cfg_attr(feature = "fuzz", derive(serde::Serialize, serde::Deserialize))]
38pub struct Key(Bytes);
39
40impl Key {
41    /// Creates a new key from the bytes of the input.
42    pub fn new<K: AsRef<[u8]>>(key: &K) -> Self {
43        Key(Bytes::copy_from_slice(key.as_ref()))
44    }
45
46    /// Copies the bytes of the key into a new vector.
47    pub fn to_vec(&self) -> Vec<u8> {
48        Vec::from(&self.0[..])
49    }
50}
51
52impl From<Key> for Vec<u8> {
53    fn from(k: Key) -> Vec<u8> {
54        Vec::from(&k.0[..])
55    }
56}
57
58impl Borrow<[u8]> for Key {
59    fn borrow(&self) -> &[u8] {
60        &self.0[..]
61    }
62}
63
64impl AsRef<[u8]> for Key {
65    fn as_ref(&self) -> &[u8] {
66        &self.0[..]
67    }
68}
69
70impl From<Vec<u8>> for Key {
71    fn from(v: Vec<u8>) -> Key {
72        Key(Bytes::from(v))
73    }
74}
75
76impl From<Multihash> for Key {
77    fn from(m: Multihash) -> Key {
78        Key::from(m.to_bytes())
79    }
80}
81
82/// A record stored in the DHT.
83#[derive(Clone, Debug, Eq, PartialEq, Hash)]
84#[cfg_attr(feature = "fuzz", derive(serde::Serialize, serde::Deserialize))]
85pub struct Record {
86    /// Key of the record.
87    pub key: Key,
88
89    /// Value of the record.
90    pub value: Vec<u8>,
91
92    /// The (original) publisher of the record.
93    pub publisher: Option<PeerId>,
94
95    /// The expiration time as measured by a local, monotonic clock.
96    #[cfg_attr(feature = "fuzz", serde(with = "serde_millis"))]
97    pub expires: Option<Instant>,
98}
99
100impl Record {
101    /// Creates a new record for insertion into the DHT.
102    pub fn new<K>(key: K, value: Vec<u8>) -> Self
103    where
104        K: Into<Key>,
105    {
106        Record {
107            key: key.into(),
108            value,
109            publisher: None,
110            expires: None,
111        }
112    }
113
114    /// Checks whether the record is expired w.r.t. the given `Instant`.
115    pub fn is_expired(&self, now: Instant) -> bool {
116        self.expires.is_some_and(|t| now >= t)
117    }
118}
119
120/// A record received by the given peer.
121#[derive(Debug, Clone, PartialEq, Eq)]
122pub struct PeerRecord {
123    /// The peer from whom the record was received
124    pub peer: PeerId,
125
126    /// The provided record.
127    pub record: Record,
128}
129
130/// A record keeping information about a content provider.
131#[derive(Clone, Debug, Eq, PartialEq, Hash)]
132pub struct ProviderRecord {
133    /// Key of the record.
134    pub key: Key,
135
136    /// Key of the provider, based on its peer ID.
137    pub provider: PeerId,
138
139    /// Cached addresses of the provider.
140    pub addresses: Vec<Multiaddr>,
141
142    /// The expiration time of the record. The provider records must always have the expiration
143    /// time.
144    pub expires: Instant,
145}
146
147impl ProviderRecord {
148    /// The distance from the provider's peer ID to the provided key.
149    pub fn distance(&self) -> Distance {
150        // Note that the record key is raw (opaque bytes). In order to calculate the distance from
151        // the provider's peer ID to this key we must first hash both.
152        KademliaKey::from(self.provider).distance(&KademliaKey::new(self.key.clone()))
153    }
154
155    /// Checks whether the record is expired w.r.t. the given `Instant`.
156    pub fn is_expired(&self, now: Instant) -> bool {
157        now >= self.expires
158    }
159}
160
161/// A user-facing provider type.
162#[derive(Clone, Debug, Eq, PartialEq, Hash)]
163pub struct ContentProvider {
164    // Peer ID of the provider.
165    pub peer: PeerId,
166
167    // Cached addresses of the provider.
168    pub addresses: Vec<Multiaddr>,
169}
170
171impl From<ContentProvider> for KademliaPeer {
172    fn from(provider: ContentProvider) -> Self {
173        let mut address_store = AddressStore::new();
174        for address in provider.addresses.iter() {
175            address_store.insert(AddressRecord::from_raw_multiaddr(address.clone()));
176        }
177
178        Self {
179            key: KademliaKey::from(provider.peer),
180            peer: provider.peer,
181            address_store,
182            connection: ConnectionType::NotConnected,
183        }
184    }
185}