litep2p/protocol/libp2p/kademlia/
bucket.rs1use crate::{
25 protocol::libp2p::kademlia::types::{ConnectionType, KademliaPeer, Key},
26 PeerId,
27};
28
29#[derive(Debug, PartialEq, Eq)]
31pub enum KBucketEntry<'a> {
32 LocalNode,
34
35 Occupied(&'a mut KademliaPeer),
37
38 Vacant(&'a mut KademliaPeer),
40
41 NoSlot,
43}
44
45impl<'a> KBucketEntry<'a> {
46 pub fn insert(&'a mut self, new: KademliaPeer) {
48 if let KBucketEntry::Vacant(old) = self {
49 old.peer = new.peer;
50 old.key = Key::from(new.peer);
51 old.addresses = new.addresses;
52 old.connection = new.connection;
53 }
54 }
55}
56
57pub struct KBucket {
59 nodes: Vec<KademliaPeer>,
61}
62
63impl KBucket {
64 pub fn new() -> Self {
66 Self {
67 nodes: Vec::with_capacity(20),
68 }
69 }
70
71 pub fn entry<K: Clone>(&mut self, key: Key<K>) -> KBucketEntry<'_> {
74 for i in 0..self.nodes.len() {
75 if self.nodes[i].key == key {
76 return KBucketEntry::Occupied(&mut self.nodes[i]);
77 }
78 }
79
80 if self.nodes.len() < 20 {
81 self.nodes.push(KademliaPeer::new(
82 PeerId::random(),
83 vec![],
84 ConnectionType::NotConnected,
85 ));
86 let len = self.nodes.len() - 1;
87 return KBucketEntry::Vacant(&mut self.nodes[len]);
88 }
89
90 for i in 0..self.nodes.len() {
91 match self.nodes[i].connection {
92 ConnectionType::NotConnected | ConnectionType::CannotConnect => {
93 return KBucketEntry::Vacant(&mut self.nodes[i]);
94 }
95 _ => continue,
96 }
97 }
98
99 KBucketEntry::NoSlot
100 }
101
102 pub fn closest_iter<K: Clone>(&self, target: &Key<K>) -> impl Iterator<Item = KademliaPeer> {
105 let mut nodes = self.nodes.clone();
106 nodes.sort_by(|a, b| target.distance(&a.key).cmp(&target.distance(&b.key)));
107 nodes.into_iter().filter(|peer| !peer.addresses.is_empty())
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn closest_iter() {
117 let mut bucket = KBucket::new();
118
119 let _ = (0..10)
121 .map(|_| {
122 let peer = PeerId::random();
123 bucket.nodes.push(KademliaPeer::new(peer, vec![], ConnectionType::Connected));
124
125 peer
126 })
127 .collect::<Vec<_>>();
128
129 let target = Key::from(PeerId::random());
130 let mut iter = bucket.closest_iter(&target);
131 let mut prev = None;
132
133 while let Some(node) = iter.next() {
134 if let Some(distance) = prev {
135 assert!(distance < target.distance(&node.key));
136 }
137
138 prev = Some(target.distance(&node.key));
139 }
140 }
141
142 #[test]
143 fn ignore_peers_with_no_addresses() {
144 let mut bucket = KBucket::new();
145
146 let _ = (0..10)
148 .map(|_| {
149 let peer = PeerId::random();
150 bucket.nodes.push(KademliaPeer::new(
151 peer,
152 vec![],
153 ConnectionType::NotConnected,
154 ));
155
156 peer
157 })
158 .collect::<Vec<_>>();
159
160 let _ = (0..3)
162 .map(|_| {
163 let peer = PeerId::random();
164 bucket.nodes.push(KademliaPeer::new(
165 peer,
166 vec!["/ip6/::/tcp/0".parse().unwrap()],
167 ConnectionType::Connected,
168 ));
169
170 peer
171 })
172 .collect::<Vec<_>>();
173
174 let target = Key::from(PeerId::random());
175 let mut iter = bucket.closest_iter(&target);
176 let mut prev = None;
177 let mut num_peers = 0usize;
178
179 while let Some(node) = iter.next() {
180 if let Some(distance) = prev {
181 assert!(distance < target.distance(&node.key));
182 }
183
184 num_peers += 1;
185 prev = Some(target.distance(&node.key));
186 }
187
188 assert_eq!(num_peers, 3usize);
189 }
190}