litep2p/protocol/libp2p/kademlia/
config.rs

1// Copyright 2023 litep2p developers
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
21use crate::{
22    codec::ProtocolCodec,
23    protocol::libp2p::kademlia::{
24        handle::{
25            IncomingRecordValidationMode, KademliaCommand, KademliaEvent, KademliaHandle,
26            RoutingTableUpdateMode,
27        },
28        store::MemoryStoreConfig,
29    },
30    types::protocol::ProtocolName,
31    PeerId, DEFAULT_CHANNEL_SIZE,
32};
33
34use multiaddr::Multiaddr;
35use tokio::sync::mpsc::{channel, Receiver, Sender};
36
37use std::{
38    collections::HashMap,
39    sync::{atomic::AtomicUsize, Arc},
40    time::Duration,
41};
42
43/// Default TTL for the records.
44const DEFAULT_TTL: Duration = Duration::from_secs(36 * 60 * 60);
45
46/// Default max number of records.
47pub(super) const DEFAULT_MAX_RECORDS: usize = 1024;
48
49/// Default max record size.
50pub(super) const DEFAULT_MAX_RECORD_SIZE_BYTES: usize = 65 * 1024;
51
52/// Default max provider keys.
53pub(super) const DEFAULT_MAX_PROVIDER_KEYS: usize = 1024;
54
55/// Default max provider addresses.
56pub(super) const DEFAULT_MAX_PROVIDER_ADDRESSES: usize = 30;
57
58/// Default max providers per key.
59pub(super) const DEFAULT_MAX_PROVIDERS_PER_KEY: usize = 20;
60
61/// Default provider republish interval.
62pub(super) const DEFAULT_PROVIDER_REFRESH_INTERVAL: Duration = Duration::from_secs(22 * 60 * 60);
63
64/// Default provider record TTL.
65pub(super) const DEFAULT_PROVIDER_TTL: Duration = Duration::from_secs(48 * 60 * 60);
66
67/// Protocol name.
68const PROTOCOL_NAME: &str = "/ipfs/kad/1.0.0";
69
70/// Kademlia replication factor.
71const REPLICATION_FACTOR: usize = 20usize;
72
73/// Kademlia maximum message size. Should fit 64 KiB value + 4 KiB key.
74const DEFAULT_MAX_MESSAGE_SIZE: usize = 70 * 1024;
75
76/// Kademlia configuration.
77#[derive(Debug)]
78pub struct Config {
79    // Protocol name.
80    // pub(crate) protocol: ProtocolName,
81    /// Protocol names.
82    pub(crate) protocol_names: Vec<ProtocolName>,
83
84    /// Protocol codec.
85    pub(crate) codec: ProtocolCodec,
86
87    /// Replication factor.
88    pub(super) replication_factor: usize,
89
90    /// Known peers.
91    pub(super) known_peers: HashMap<PeerId, Vec<Multiaddr>>,
92
93    /// Routing table update mode.
94    pub(super) update_mode: RoutingTableUpdateMode,
95
96    /// Incoming records validation mode.
97    pub(super) validation_mode: IncomingRecordValidationMode,
98
99    /// Default record TTL.
100    pub(super) record_ttl: Duration,
101
102    /// Provider record TTL.
103    pub(super) memory_store_config: MemoryStoreConfig,
104
105    /// TX channel for sending events to `KademliaHandle`.
106    pub(super) event_tx: Sender<KademliaEvent>,
107
108    /// RX channel for receiving commands from `KademliaHandle`.
109    pub(super) cmd_rx: Receiver<KademliaCommand>,
110
111    /// Next query ID counter shared with the handle.
112    pub(super) next_query_id: Arc<AtomicUsize>,
113}
114
115impl Config {
116    fn new(
117        replication_factor: usize,
118        known_peers: HashMap<PeerId, Vec<Multiaddr>>,
119        mut protocol_names: Vec<ProtocolName>,
120        update_mode: RoutingTableUpdateMode,
121        validation_mode: IncomingRecordValidationMode,
122        record_ttl: Duration,
123        memory_store_config: MemoryStoreConfig,
124        max_message_size: usize,
125    ) -> (Self, KademliaHandle) {
126        let (cmd_tx, cmd_rx) = channel(DEFAULT_CHANNEL_SIZE);
127        let (event_tx, event_rx) = channel(DEFAULT_CHANNEL_SIZE);
128        let next_query_id = Arc::new(AtomicUsize::new(0usize));
129
130        // if no protocol names were provided, use the default protocol
131        if protocol_names.is_empty() {
132            protocol_names.push(ProtocolName::from(PROTOCOL_NAME));
133        }
134
135        (
136            Config {
137                protocol_names,
138                update_mode,
139                validation_mode,
140                record_ttl,
141                memory_store_config,
142                codec: ProtocolCodec::UnsignedVarint(Some(max_message_size)),
143                replication_factor,
144                known_peers,
145                cmd_rx,
146                event_tx,
147                next_query_id: next_query_id.clone(),
148            },
149            KademliaHandle::new(cmd_tx, event_rx, next_query_id),
150        )
151    }
152
153    /// Build default Kademlia configuration.
154    pub fn default() -> (Self, KademliaHandle) {
155        Self::new(
156            REPLICATION_FACTOR,
157            HashMap::new(),
158            Vec::new(),
159            RoutingTableUpdateMode::Automatic,
160            IncomingRecordValidationMode::Automatic,
161            DEFAULT_TTL,
162            Default::default(),
163            DEFAULT_MAX_MESSAGE_SIZE,
164        )
165    }
166}
167
168/// Configuration builder for Kademlia.
169#[derive(Debug)]
170pub struct ConfigBuilder {
171    /// Replication factor.
172    pub(super) replication_factor: usize,
173
174    /// Routing table update mode.
175    pub(super) update_mode: RoutingTableUpdateMode,
176
177    /// Incoming records validation mode.
178    pub(super) validation_mode: IncomingRecordValidationMode,
179
180    /// Known peers.
181    pub(super) known_peers: HashMap<PeerId, Vec<Multiaddr>>,
182
183    /// Protocol names.
184    pub(super) protocol_names: Vec<ProtocolName>,
185
186    /// Default TTL for the records.
187    pub(super) record_ttl: Duration,
188
189    /// Memory store configuration.
190    pub(super) memory_store_config: MemoryStoreConfig,
191
192    /// Maximum message size.
193    pub(crate) max_message_size: usize,
194}
195
196impl Default for ConfigBuilder {
197    fn default() -> Self {
198        Self::new()
199    }
200}
201
202impl ConfigBuilder {
203    /// Create new [`ConfigBuilder`].
204    pub fn new() -> Self {
205        Self {
206            replication_factor: REPLICATION_FACTOR,
207            known_peers: HashMap::new(),
208            protocol_names: Vec::new(),
209            update_mode: RoutingTableUpdateMode::Automatic,
210            validation_mode: IncomingRecordValidationMode::Automatic,
211            record_ttl: DEFAULT_TTL,
212            memory_store_config: Default::default(),
213            max_message_size: DEFAULT_MAX_MESSAGE_SIZE,
214        }
215    }
216
217    /// Set replication factor.
218    pub fn with_replication_factor(mut self, replication_factor: usize) -> Self {
219        self.replication_factor = replication_factor;
220        self
221    }
222
223    /// Seed Kademlia with one or more known peers.
224    pub fn with_known_peers(mut self, peers: HashMap<PeerId, Vec<Multiaddr>>) -> Self {
225        self.known_peers = peers;
226        self
227    }
228
229    /// Set routing table update mode.
230    pub fn with_routing_table_update_mode(mut self, mode: RoutingTableUpdateMode) -> Self {
231        self.update_mode = mode;
232        self
233    }
234
235    /// Set incoming records validation mode.
236    pub fn with_incoming_records_validation_mode(
237        mut self,
238        mode: IncomingRecordValidationMode,
239    ) -> Self {
240        self.validation_mode = mode;
241        self
242    }
243
244    /// Set Kademlia protocol names, overriding the default protocol name.
245    ///
246    /// The order of the protocol names signifies preference so if, for example, there are two
247    /// protocols:
248    ///  * `/kad/2.0.0`
249    ///  * `/kad/1.0.0`
250    ///
251    /// Where `/kad/2.0.0` is the preferred version, then that should be in `protocol_names` before
252    /// `/kad/1.0.0`.
253    pub fn with_protocol_names(mut self, protocol_names: Vec<ProtocolName>) -> Self {
254        self.protocol_names = protocol_names;
255        self
256    }
257
258    /// Set default TTL for the records.
259    ///
260    /// If unspecified, the default TTL is 36 hours.
261    pub fn with_record_ttl(mut self, record_ttl: Duration) -> Self {
262        self.record_ttl = record_ttl;
263        self
264    }
265
266    /// Set maximum number of records in the memory store.
267    ///
268    /// If unspecified, the default maximum number of records is 1024.
269    pub fn with_max_records(mut self, max_records: usize) -> Self {
270        self.memory_store_config.max_records = max_records;
271        self
272    }
273
274    /// Set maximum record size in bytes.
275    ///
276    /// If unspecified, the default maximum record size is 65 KiB.
277    pub fn with_max_record_size(mut self, max_record_size_bytes: usize) -> Self {
278        self.memory_store_config.max_record_size_bytes = max_record_size_bytes;
279        self
280    }
281
282    /// Set maximum number of provider keys in the memory store.
283    ///
284    /// If unspecified, the default maximum number of provider keys is 1024.
285    pub fn with_max_provider_keys(mut self, max_provider_keys: usize) -> Self {
286        self.memory_store_config.max_provider_keys = max_provider_keys;
287        self
288    }
289
290    /// Set maximum number of provider addresses per provider in the memory store.
291    ///
292    /// If unspecified, the default maximum number of provider addresses is 30.
293    pub fn with_max_provider_addresses(mut self, max_provider_addresses: usize) -> Self {
294        self.memory_store_config.max_provider_addresses = max_provider_addresses;
295        self
296    }
297
298    /// Set maximum number of providers per key in the memory store.
299    ///
300    /// If unspecified, the default maximum number of providers per key is 20.
301    pub fn with_max_providers_per_key(mut self, max_providers_per_key: usize) -> Self {
302        self.memory_store_config.max_providers_per_key = max_providers_per_key;
303        self
304    }
305
306    /// Set TTL for the provider records. Recommended value is 2 * (refresh interval) + 10%.
307    ///
308    /// If unspecified, the default TTL is 48 hours.
309    pub fn with_provider_record_ttl(mut self, provider_record_ttl: Duration) -> Self {
310        self.memory_store_config.provider_ttl = provider_record_ttl;
311        self
312    }
313
314    /// Set the refresh (republish) interval for provider records.
315    ///
316    /// If unspecified, the default interval is 22 hours.
317    pub fn with_provider_refresh_interval(mut self, provider_refresh_interval: Duration) -> Self {
318        self.memory_store_config.provider_refresh_interval = provider_refresh_interval;
319        self
320    }
321
322    /// Set the maximum Kademlia message size.
323    ///
324    /// Should fit `MemoryStore` max record size. If unspecified, the default maximum message size
325    /// is 70 KiB.
326    pub fn with_max_message_size(mut self, max_message_size: usize) -> Self {
327        self.max_message_size = max_message_size;
328        self
329    }
330
331    /// Build Kademlia [`Config`].
332    pub fn build(self) -> (Config, KademliaHandle) {
333        Config::new(
334            self.replication_factor,
335            self.known_peers,
336            self.protocol_names,
337            self.update_mode,
338            self.validation_mode,
339            self.record_ttl,
340            self.memory_store_config,
341            self.max_message_size,
342        )
343    }
344}