sc_authority_discovery/worker/
addr_cache.rs1use sc_network::{multiaddr::Protocol, Multiaddr};
20use sc_network_types::PeerId;
21use sp_authority_discovery::AuthorityId;
22use std::collections::{hash_map::Entry, HashMap, HashSet};
23
24pub(super) struct AddrCache {
27 authority_id_to_addresses: HashMap<AuthorityId, HashSet<Multiaddr>>,
35 peer_id_to_authority_ids: HashMap<PeerId, HashSet<AuthorityId>>,
36}
37
38impl AddrCache {
39 pub fn new() -> Self {
40 AddrCache {
41 authority_id_to_addresses: HashMap::new(),
42 peer_id_to_authority_ids: HashMap::new(),
43 }
44 }
45
46 pub fn insert(&mut self, authority_id: AuthorityId, addresses: Vec<Multiaddr>) {
49 let addresses = addresses.into_iter().collect::<HashSet<_>>();
50 let peer_ids = addresses_to_peer_ids(&addresses);
51
52 if peer_ids.is_empty() {
53 log::debug!(
54 target: super::LOG_TARGET,
55 "Authority({:?}) provides no addresses or addresses without peer ids. Adresses: {:?}",
56 authority_id,
57 addresses,
58 );
59
60 return
61 } else if peer_ids.len() > 1 {
62 log::warn!(
63 target: super::LOG_TARGET,
64 "Authority({:?}) can be reached through multiple peer ids: {:?}",
65 authority_id,
66 peer_ids
67 );
68 }
69
70 log::debug!(
71 target: super::LOG_TARGET,
72 "Found addresses for authority {authority_id:?}: {addresses:?}",
73 );
74
75 let old_addresses = self.authority_id_to_addresses.insert(authority_id.clone(), addresses);
76 let old_peer_ids = addresses_to_peer_ids(&old_addresses.unwrap_or_default());
77
78 peer_ids.difference(&old_peer_ids).for_each(|new_peer_id| {
80 self.peer_id_to_authority_ids
81 .entry(*new_peer_id)
82 .or_default()
83 .insert(authority_id.clone());
84 });
85
86 self.remove_authority_id_from_peer_ids(&authority_id, old_peer_ids.difference(&peer_ids));
88 }
89
90 fn remove_authority_id_from_peer_ids<'a>(
94 &mut self,
95 authority_id: &AuthorityId,
96 peer_ids: impl Iterator<Item = &'a PeerId>,
97 ) {
98 peer_ids.for_each(|peer_id| {
99 if let Entry::Occupied(mut e) = self.peer_id_to_authority_ids.entry(*peer_id) {
100 e.get_mut().remove(authority_id);
101
102 if e.get().is_empty() {
104 e.remove();
105 }
106 }
107 })
108 }
109
110 pub fn num_authority_ids(&self) -> usize {
112 self.authority_id_to_addresses.len()
113 }
114
115 pub fn get_addresses_by_authority_id(
117 &self,
118 authority_id: &AuthorityId,
119 ) -> Option<&HashSet<Multiaddr>> {
120 self.authority_id_to_addresses.get(authority_id)
121 }
122
123 pub fn get_authority_ids_by_peer_id(&self, peer_id: &PeerId) -> Option<&HashSet<AuthorityId>> {
128 self.peer_id_to_authority_ids.get(peer_id)
129 }
130
131 pub fn retain_ids(&mut self, authority_ids: &[AuthorityId]) {
134 let authority_ids_to_remove = self
136 .authority_id_to_addresses
137 .iter()
138 .filter(|(id, _addresses)| !authority_ids.contains(id))
139 .map(|entry| entry.0)
140 .cloned()
141 .collect::<Vec<AuthorityId>>();
142
143 for authority_id_to_remove in authority_ids_to_remove {
144 let addresses = if let Some(addresses) =
146 self.authority_id_to_addresses.remove(&authority_id_to_remove)
147 {
148 addresses
149 } else {
150 continue
151 };
152
153 self.remove_authority_id_from_peer_ids(
154 &authority_id_to_remove,
155 addresses_to_peer_ids(&addresses).iter(),
156 );
157 }
158 }
159}
160
161fn peer_id_from_multiaddr(addr: &Multiaddr) -> Option<PeerId> {
162 addr.iter().last().and_then(|protocol| {
163 if let Protocol::P2p(multihash) = protocol {
164 PeerId::from_multihash(multihash).ok()
165 } else {
166 None
167 }
168 })
169}
170
171fn addresses_to_peer_ids(addresses: &HashSet<Multiaddr>) -> HashSet<PeerId> {
172 addresses.iter().filter_map(peer_id_from_multiaddr).collect::<HashSet<_>>()
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 use quickcheck::{Arbitrary, Gen, QuickCheck, TestResult};
180 use sc_network_types::multihash::{Code, Multihash};
181
182 use sp_authority_discovery::{AuthorityId, AuthorityPair};
183 use sp_core::crypto::Pair;
184
185 #[derive(Clone, Debug)]
186 struct TestAuthorityId(AuthorityId);
187
188 impl Arbitrary for TestAuthorityId {
189 fn arbitrary(g: &mut Gen) -> Self {
190 let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
191 TestAuthorityId(AuthorityPair::from_seed_slice(&seed).unwrap().public())
192 }
193 }
194
195 #[derive(Clone, Debug)]
196 struct TestMultiaddr(Multiaddr);
197
198 impl Arbitrary for TestMultiaddr {
199 fn arbitrary(g: &mut Gen) -> Self {
200 let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
201 let peer_id =
202 PeerId::from_multihash(Multihash::wrap(Code::Sha2_256.into(), &seed).unwrap())
203 .unwrap();
204 let multiaddr = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333"
205 .parse::<Multiaddr>()
206 .unwrap()
207 .with(Protocol::P2p(peer_id.into()));
208
209 TestMultiaddr(multiaddr)
210 }
211 }
212
213 #[derive(Clone, Debug)]
214 struct TestMultiaddrsSamePeerCombo(Multiaddr, Multiaddr);
215
216 impl Arbitrary for TestMultiaddrsSamePeerCombo {
217 fn arbitrary(g: &mut Gen) -> Self {
218 let seed = (0..32).map(|_| u8::arbitrary(g)).collect::<Vec<_>>();
219 let peer_id =
220 PeerId::from_multihash(Multihash::wrap(Code::Sha2_256.into(), &seed).unwrap())
221 .unwrap();
222 let multiaddr1 = "/ip6/2001:db8:0:0:0:0:0:2/tcp/30333"
223 .parse::<Multiaddr>()
224 .unwrap()
225 .with(Protocol::P2p(peer_id.into()));
226 let multiaddr2 = "/ip6/2002:db8:0:0:0:0:0:2/tcp/30133"
227 .parse::<Multiaddr>()
228 .unwrap()
229 .with(Protocol::P2p(peer_id.into()));
230 TestMultiaddrsSamePeerCombo(multiaddr1, multiaddr2)
231 }
232 }
233
234 #[test]
235 fn retains_only_entries_of_provided_authority_ids() {
236 fn property(
237 first: (TestAuthorityId, TestMultiaddr),
238 second: (TestAuthorityId, TestMultiaddr),
239 third: (TestAuthorityId, TestMultiaddr),
240 ) -> TestResult {
241 let first: (AuthorityId, Multiaddr) = ((first.0).0, (first.1).0);
242 let second: (AuthorityId, Multiaddr) = ((second.0).0, (second.1).0);
243 let third: (AuthorityId, Multiaddr) = ((third.0).0, (third.1).0);
244
245 let mut cache = AddrCache::new();
246
247 cache.insert(first.0.clone(), vec![first.1.clone()]);
248 cache.insert(second.0.clone(), vec![second.1.clone()]);
249 cache.insert(third.0.clone(), vec![third.1.clone()]);
250
251 assert_eq!(
252 Some(&HashSet::from([third.1.clone()])),
253 cache.get_addresses_by_authority_id(&third.0),
254 "Expect `get_addresses_by_authority_id` to return addresses of third authority.",
255 );
256 assert_eq!(
257 Some(&HashSet::from([third.0.clone()])),
258 cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&third.1).unwrap()),
259 "Expect `get_authority_id_by_peer_id` to return `AuthorityId` of third authority.",
260 );
261
262 cache.retain_ids(&vec![first.0.clone(), second.0]);
263
264 assert_eq!(
265 None,
266 cache.get_addresses_by_authority_id(&third.0),
267 "Expect `get_addresses_by_authority_id` to not return `None` for third authority.",
268 );
269 assert_eq!(
270 None,
271 cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&third.1).unwrap()),
272 "Expect `get_authority_id_by_peer_id` to return `None` for third authority.",
273 );
274
275 TestResult::passed()
276 }
277
278 QuickCheck::new()
279 .max_tests(10)
280 .quickcheck(property as fn(_, _, _) -> TestResult)
281 }
282
283 #[test]
284 fn keeps_consistency_between_authority_id_and_peer_id() {
285 fn property(
286 authority1: TestAuthorityId,
287 authority2: TestAuthorityId,
288 multiaddr1: TestMultiaddr,
289 multiaddr2: TestMultiaddr,
290 multiaddr3: TestMultiaddrsSamePeerCombo,
291 ) -> TestResult {
292 let authority1 = authority1.0;
293 let authority2 = authority2.0;
294 let multiaddr1 = multiaddr1.0;
295 let multiaddr2 = multiaddr2.0;
296 let TestMultiaddrsSamePeerCombo(multiaddr3, multiaddr4) = multiaddr3;
297
298 let mut cache = AddrCache::new();
299
300 cache.insert(authority1.clone(), vec![multiaddr1.clone()]);
301 cache.insert(
302 authority1.clone(),
303 vec![multiaddr2.clone(), multiaddr3.clone(), multiaddr4.clone()],
304 );
305
306 assert_eq!(
307 None,
308 cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr1).unwrap())
309 );
310 assert_eq!(
311 Some(&HashSet::from([authority1.clone()])),
312 cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr2).unwrap())
313 );
314 assert_eq!(
315 Some(&HashSet::from([authority1.clone()])),
316 cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr3).unwrap())
317 );
318 assert_eq!(
319 Some(&HashSet::from([authority1.clone()])),
320 cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr4).unwrap())
321 );
322
323 cache.insert(authority2.clone(), vec![multiaddr2.clone()]);
324
325 assert_eq!(
326 Some(&HashSet::from([authority2.clone(), authority1.clone()])),
327 cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr2).unwrap())
328 );
329 assert_eq!(
330 Some(&HashSet::from([authority1.clone()])),
331 cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr3).unwrap())
332 );
333 assert_eq!(cache.get_addresses_by_authority_id(&authority1).unwrap().len(), 3);
334
335 cache.insert(authority2.clone(), vec![multiaddr2.clone(), multiaddr3.clone()]);
336
337 assert_eq!(
338 Some(&HashSet::from([authority2.clone(), authority1.clone()])),
339 cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr2).unwrap())
340 );
341 assert_eq!(
342 Some(&HashSet::from([authority2.clone(), authority1.clone()])),
343 cache.get_authority_ids_by_peer_id(&peer_id_from_multiaddr(&multiaddr3).unwrap())
344 );
345 assert_eq!(
346 &HashSet::from([multiaddr2.clone(), multiaddr3.clone(), multiaddr4.clone()]),
347 cache.get_addresses_by_authority_id(&authority1).unwrap(),
348 );
349
350 TestResult::passed()
351 }
352
353 QuickCheck::new()
354 .max_tests(10)
355 .quickcheck(property as fn(_, _, _, _, _) -> TestResult)
356 }
357
358 #[test]
362 fn adding_two_authority_ids_for_the_same_peer_id() {
363 let mut addr_cache = AddrCache::new();
364
365 let peer_id = PeerId::random();
366 let addr = Multiaddr::empty().with(Protocol::P2p(peer_id.into()));
367
368 let authority_id0 = AuthorityPair::generate().0.public();
369 let authority_id1 = AuthorityPair::generate().0.public();
370
371 addr_cache.insert(authority_id0.clone(), vec![addr.clone()]);
372 addr_cache.insert(authority_id1.clone(), vec![addr.clone()]);
373
374 assert_eq!(2, addr_cache.num_authority_ids());
375 assert_eq!(
376 &HashSet::from([addr.clone()]),
377 addr_cache.get_addresses_by_authority_id(&authority_id0).unwrap()
378 );
379 assert_eq!(
380 &HashSet::from([addr]),
381 addr_cache.get_addresses_by_authority_id(&authority_id1).unwrap()
382 );
383 }
384}