libp2p_kad/
record_priv.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21//! Records and record storage abstraction of the libp2p Kademlia DHT.
22
23pub mod store;
24
25use bytes::Bytes;
26use instant::Instant;
27use libp2p_core::{multihash::Multihash, Multiaddr};
28use libp2p_identity::PeerId;
29#[cfg(feature = "serde")]
30use serde::{Deserialize, Serialize};
31use std::borrow::Borrow;
32use std::hash::{Hash, Hasher};
33
34/// The (opaque) key of a record.
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36#[derive(Clone, Debug, PartialEq, Eq, Hash)]
37pub struct Key(Bytes);
38
39impl Key {
40    /// Creates a new key from the bytes of the input.
41    pub fn new<K: AsRef<[u8]>>(key: &K) -> Self {
42        Key(Bytes::copy_from_slice(key.as_ref()))
43    }
44
45    /// Copies the bytes of the key into a new vector.
46    pub fn to_vec(&self) -> Vec<u8> {
47        Vec::from(&self.0[..])
48    }
49}
50
51impl Borrow<[u8]> for Key {
52    fn borrow(&self) -> &[u8] {
53        &self.0[..]
54    }
55}
56
57impl AsRef<[u8]> for Key {
58    fn as_ref(&self) -> &[u8] {
59        &self.0[..]
60    }
61}
62
63impl From<Vec<u8>> for Key {
64    fn from(v: Vec<u8>) -> Key {
65        Key(Bytes::from(v))
66    }
67}
68
69impl<const S: usize> From<Multihash<S>> for Key {
70    fn from(m: Multihash<S>) -> Key {
71        Key::from(m.to_bytes())
72    }
73}
74
75/// A record stored in the DHT.
76#[derive(Clone, Debug, Eq, PartialEq)]
77pub struct Record {
78    /// Key of the record.
79    pub key: Key,
80    /// Value of the record.
81    pub value: Vec<u8>,
82    /// The (original) publisher of the record.
83    pub publisher: Option<PeerId>,
84    /// The expiration time as measured by a local, monotonic clock.
85    pub expires: Option<Instant>,
86}
87
88impl Record {
89    /// Creates a new record for insertion into the DHT.
90    pub fn new<K>(key: K, value: Vec<u8>) -> Self
91    where
92        K: Into<Key>,
93    {
94        Record {
95            key: key.into(),
96            value,
97            publisher: None,
98            expires: None,
99        }
100    }
101
102    /// Checks whether the record is expired w.r.t. the given `Instant`.
103    pub fn is_expired(&self, now: Instant) -> bool {
104        self.expires.map_or(false, |t| now >= t)
105    }
106}
107
108/// A record stored in the DHT whose value is the ID of a peer
109/// who can provide the value on-demand.
110///
111/// Note: Two [`ProviderRecord`]s as well as their corresponding hashes are
112/// equal iff their `key` and `provider` fields are equal. See the [`Hash`] and
113/// [`PartialEq`] implementations.
114#[derive(Clone, Debug)]
115pub struct ProviderRecord {
116    /// The key whose value is provided by the provider.
117    pub key: Key,
118    /// The provider of the value for the key.
119    pub provider: PeerId,
120    /// The expiration time as measured by a local, monotonic clock.
121    pub expires: Option<Instant>,
122    /// The known addresses that the provider may be listening on.
123    pub addresses: Vec<Multiaddr>,
124}
125
126impl Hash for ProviderRecord {
127    fn hash<H: Hasher>(&self, state: &mut H) {
128        self.key.hash(state);
129        self.provider.hash(state);
130    }
131}
132
133impl PartialEq for ProviderRecord {
134    fn eq(&self, other: &Self) -> bool {
135        self.key == other.key && self.provider == other.provider
136    }
137}
138
139impl Eq for ProviderRecord {}
140
141impl ProviderRecord {
142    /// Creates a new provider record for insertion into a `RecordStore`.
143    pub fn new<K>(key: K, provider: PeerId, addresses: Vec<Multiaddr>) -> Self
144    where
145        K: Into<Key>,
146    {
147        ProviderRecord {
148            key: key.into(),
149            provider,
150            expires: None,
151            addresses,
152        }
153    }
154
155    /// Checks whether the provider record is expired w.r.t. the given `Instant`.
156    pub fn is_expired(&self, now: Instant) -> bool {
157        self.expires.map_or(false, |t| now >= t)
158    }
159}
160
161#[cfg(test)]
162mod tests {
163    use super::*;
164    use crate::SHA_256_MH;
165    use quickcheck::*;
166    use std::time::Duration;
167
168    impl Arbitrary for Key {
169        fn arbitrary(g: &mut Gen) -> Key {
170            let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g));
171            Key::from(Multihash::<64>::wrap(SHA_256_MH, &hash).unwrap())
172        }
173    }
174
175    impl Arbitrary for Record {
176        fn arbitrary(g: &mut Gen) -> Record {
177            Record {
178                key: Key::arbitrary(g),
179                value: Vec::arbitrary(g),
180                publisher: if bool::arbitrary(g) {
181                    Some(PeerId::random())
182                } else {
183                    None
184                },
185                expires: if bool::arbitrary(g) {
186                    Some(Instant::now() + Duration::from_secs(g.gen_range(0..60)))
187                } else {
188                    None
189                },
190            }
191        }
192    }
193
194    impl Arbitrary for ProviderRecord {
195        fn arbitrary(g: &mut Gen) -> ProviderRecord {
196            ProviderRecord {
197                key: Key::arbitrary(g),
198                provider: PeerId::random(),
199                expires: if bool::arbitrary(g) {
200                    Some(Instant::now() + Duration::from_secs(g.gen_range(0..60)))
201                } else {
202                    None
203                },
204                addresses: vec![],
205            }
206        }
207    }
208}