actaeon/bucket.rs
1//! # Bucket
2//!
3//! Leafs of the binary routing tree responsible for storing the
4//! actual nodes in the binary tree. (Nodes are in the leafes, not the
5//! "nodes" of the binary tree.) The nodes are stored sorted by time,
6//! not their keys. Within each bucket nodes share a common property,
7//! they are assumed to be "equally distanced". This might not be
8//! perfect for very large buckets (higher up in the tree) but will
9//! make no difference for buckets deeper in the tree.
10//!
11//! TODO: Create generic Bucket implementation based on std HashMap.
12
13use crate::error::Error;
14use crate::node::{Address, Center, Node};
15
16/// Stores a maximum of "limit" nodes, sorted by age / time. The first
17/// element in the array is the oldest one. This equals a Kademlia
18/// k-Bucket. The bucket will be used in the binary routing tree as
19/// a leaf..
20#[derive(Clone, Debug, Eq, PartialEq)]
21pub struct Bucket {
22    /// Stores the nodes, gets sorted by time, from old to new.
23    nodes: Vec<Node>,
24    /// Maximum length of the nodes array.
25    limit: usize,
26}
27
28impl Bucket {
29    /// Creates a new empty bucket and stores the provided limit. It
30    /// usually has to be declared as mutable, since sorting and
31    /// adding require mutable references. This might get replaced by
32    /// interior mutability in the future. It should be enough to just
33    /// store the nodes in a RefCell, since everything else stays
34    /// constant.
35    pub fn new(limit: usize) -> Self {
36        Bucket {
37            nodes: Vec::new(),
38            limit,
39        }
40    }
41
42    /// Sorts the nodes in the bucket with the existing Ord
43    /// implementation. THe first element in the Vector will be the
44    /// oldest one, the last the oldest.
45    pub fn sort(&mut self) {
46        self.nodes.sort();
47    }
48
49    /// Adds a node to a bucket. If the bucket is full, an error is
50    /// returned. This function does not follow any of the kademlia
51    /// rules and is intended to be used as a first step, before
52    /// specifiying the behavior for full buckets. Currently a
53    /// dedicated error type is used for situations like this:
54    /// Error::Full. Should the node not belong in this bucket, the
55    /// function will also fail.
56    pub fn try_add(&mut self, node: Node) -> Result<(), Error> {
57        if self.len() == self.limit {
58            return Err(Error::Full);
59        } else {
60            self.nodes.push(node);
61            self.dedup();
62            return Ok(());
63        }
64    }
65
66    /// Adds a new node the the existing bucket, in which the center
67    /// is not. It roughly follows the Kademlia update rules:
68    ///
69    /// - If there is still space in the bucket, the node is simply
70    /// appended.
71    ///
72    /// - If there is no space, the oldest node gets replaced, but
73    /// only if it is currently not reachable. This part requires the
74    /// nodes in the table to get checked by a dedicated process. No
75    /// status checks are happening in the table.
76    ///
77    /// This function will not split buckets or create new, should the
78    /// bucket be full the node is simply disregarded.
79    pub fn add(&mut self, node: Node) {
80        if self.len() < self.limit {
81            self.nodes.push(node);
82            self.sort();
83            self.dedup();
84        } else {
85            if let Some(first) = self.nodes.first_mut() {
86                // instead of manually checking the status of the
87                // oldest node it is assumed that it is updated by a
88                // dedicated process.
89                if !first.is_reachable() {
90                    *first = node;
91                }
92                self.sort();
93                self.dedup();
94            }
95        }
96    }
97
98    /// Takes ownership of the Bucket and returns two new once, with
99    /// the nodes distributed between the two based on their distance
100    /// in comparison to the upper limit. The center has to be
101    /// provided to calculate the distance, the "ul" parameter is the
102    /// upper limit of the bucket. When spliting the root bucket the
103    /// upper limit would be 255 and the two new buckets would have
104    /// upper limits of 127 and 255. This function will do no
105    /// validation of size and will return even if one of the buckets
106    /// is empty.
107    pub fn split(self, center: &Center, ul: u8) -> (Self, Self) {
108        let mut near = Bucket::new(self.limit);
109        let mut far = Bucket::new(self.limit);
110
111        for i in self.nodes {
112            let index = (i.address.clone() ^ center.public.clone())[0];
113            if index < (ul / 2) {
114                near.add(i);
115            } else {
116                far.add(i);
117            }
118        }
119
120        (near, far)
121    }
122
123    /// With a provided address it will return a pointer to the node
124    /// matching that address. This is for exact matches, not for
125    /// getting targets. It will only every return one optional node.
126    pub fn find(&self, search: &Address) -> Option<&Node> {
127        let index = self.nodes.iter().position(|e| &e.address == search);
128        match index {
129            Some(i) => self.nodes.get(i),
130            None => None,
131        }
132    }
133
134    /// With a provided address it will return a pointer to the node
135    /// matching that address. This is for exact matches, not for
136    /// getting targets. It will only every return one optional node.
137    pub fn find_mut(&mut self, search: &Address) -> Option<&mut Node> {
138        let index = self.nodes.iter().position(|e| &e.address == search);
139        match index {
140            Some(i) => self.nodes.get_mut(i),
141            None => None,
142        }
143    }
144
145    /// Returns upto "limit" number of nodes. It only return
146    /// references to the nodes, since the nodes in the routing table
147    /// are expected to live the longest.
148    pub fn get(&self, limit: usize) -> Vec<&Node> {
149        let mut targets = Vec::new();
150        for i in &self.nodes {
151            targets.push(i);
152        }
153        targets.sort();
154        targets.truncate(limit);
155        return targets;
156    }
157
158    pub fn remove(&mut self, target: &Address) -> Result<(), Error> {
159        let index = self.nodes.iter().position(|e| &e.address == target);
160        match index {
161            Some(i) => {
162                self.nodes.remove(i);
163                Ok(())
164            }
165            None => Err(Error::Unknown),
166        }
167    }
168
169    /// Simple wrapper around the limit field so that all fields can
170    /// remain private. It gets used by the router capacity query to
171    /// calculate the maximum size of the entire tree.
172    pub fn capacity(&self) -> usize {
173        self.limit
174    }
175
176    /// Since it is possible to add nodes to the tree or a bucket
177    /// multiple times some cleanup might be required. This function
178    /// removes all nodes with duplicate addresses.
179    pub fn dedup(&mut self) {
180        self.sort_by_address();
181        self.nodes.dedup_by(|a, b| a.address == b.address);
182    }
183
184    /// Wrapper around the length of the nodes array.
185    pub fn len(&self) -> usize {
186        self.nodes.len()
187    }
188
189    /// Uses the Ord and Partial Ord implementation Address to sort
190    /// the nodes based on that. This does not represent the distance
191    /// sorting for Kademlia but is just a shortcut for easier
192    /// handling.
193    fn sort_by_address(&mut self) {
194        self.nodes
195            .sort_by(|a, b| a.address.partial_cmp(&b.address).unwrap());
196    }
197}
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202    use crate::node::Address;
203    use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::SecretKey;
204
205    #[test]
206    fn test_leaf_add() {
207        let mut bucket = gen_bucket(20);
208        let node = gen_node("test");
209        let ret = bucket.try_add(node);
210        assert_eq!(ret.is_err(), false);
211    }
212
213    #[test]
214    fn test_leaf_add_error() {
215        let mut leaf = gen_bucket(1);
216        let node = gen_node("test");
217        leaf.try_add(node).unwrap();
218        let node = gen_node("test2");
219        let ret = leaf.try_add(node);
220        assert_eq!(ret.is_err(), true);
221    }
222
223    #[test]
224    fn test_bucket_add_error_lim() {
225        let mut bucket = gen_bucket(1);
226        let node = gen_node("test");
227        bucket.try_add(node).unwrap();
228        let node = gen_node("test2");
229        let ret = bucket.try_add(node);
230        assert_eq!(ret.is_err(), true);
231    }
232
233    #[test]
234    fn test_bucket_add_disregard() {
235        let mut bucket = gen_bucket(1);
236        let node = gen_node("test");
237        bucket.add(node);
238        let node = gen_node("test2");
239        bucket.add(node);
240        assert_eq!(bucket.len(), 1);
241    }
242
243    #[test]
244    fn test_bucket_dedup() {
245        let mut bucket = gen_bucket(10);
246        let node = gen_node("abc");
247        bucket.add(node);
248        let node = gen_node("abc");
249        bucket.add(node);
250        bucket.dedup();
251        assert_eq!(bucket.len(), 1);
252    }
253
254    #[test]
255    fn test_bucket_split_root() {
256        let mut root = Bucket::new(20);
257        root.add(gen_node("first"));
258        root.add(gen_node("second"));
259        root.add(gen_node("another"));
260        let center = gen_center();
261        let (near, far) = root.split(¢er, 255);
262        assert_eq!(near.len(), 2);
263        assert_eq!(far.len(), 1);
264    }
265
266    #[test]
267    fn test_bucket_get() {
268        let mut root = Bucket::new(20);
269        root.add(gen_node("first"));
270        root.add(gen_node("second"));
271        root.add(gen_node("another"));
272        let targets = root.get(2);
273        assert_eq!(targets.len(), 2);
274    }
275
276    #[test]
277    fn test_bucket_remove() {
278        let mut root = Bucket::new(20);
279        root.add(gen_node("first"));
280        root.add(gen_node("second"));
281        let target = gen_node("first").address;
282        root.remove(&target).unwrap();
283        assert_eq!(root.len(), 1);
284    }
285
286    #[test]
287    fn test_bucket_remove_empty() {
288        let mut root = Bucket::new(20);
289        let target = gen_node("first").address;
290
291        assert_eq!(root.remove(&target).is_err(), true);
292    }
293
294    fn gen_bucket(l: usize) -> Bucket {
295        Bucket::new(l)
296    }
297
298    fn gen_node(s: &str) -> Node {
299        Node::new(Address::generate(s), None)
300    }
301
302    fn gen_center() -> Center {
303        let mut b = [0; 32];
304        b[0] = 42;
305        let s = SecretKey::from_slice(&b).unwrap();
306        Center::new(s, String::from(""), 8080)
307    }
308}