1#![expect(
2 clippy::rest_pattern_accessible_field,
3 reason = "Too verbose otherwise"
4)]
5
6use crate::behavior::persistent_parameters::{
7 KnownPeersRegistry, PeerAddressRemovedEvent, append_p2p_suffix, remove_p2p_suffix,
8};
9use crate::behavior::{Behavior, Event};
10use crate::constructor::DummyRecordStore;
11use crate::constructor::temporary_bans::TemporaryBans;
12use crate::protocols::request_response::request_response_factory::{
13 Event as RequestResponseEvent, IfDisconnected,
14};
15use crate::shared::{Command, CreatedSubscription, PeerDiscovered, Shared};
16use crate::utils::{SubspaceMetrics, is_global_address_or_dns, strip_peer_id};
17use async_lock::Mutex as AsyncMutex;
18use bytes::Bytes;
19use event_listener_primitives::HandlerId;
20use futures::channel::mpsc;
21use futures::future::Fuse;
22use futures::{FutureExt, StreamExt};
23use libp2p::autonat::{Event as AutonatEvent, NatStatus, OutboundProbeEvent};
24use libp2p::core::ConnectedPoint;
25use libp2p::gossipsub::{Event as GossipsubEvent, TopicHash};
26use libp2p::identify::Event as IdentifyEvent;
27use libp2p::kad::{
28 Behaviour as Kademlia, BootstrapOk, Event as KademliaEvent, GetClosestPeersError,
29 GetClosestPeersOk, GetProvidersError, GetProvidersOk, GetRecordError, GetRecordOk,
30 InboundRequest, KBucketKey, PeerRecord, ProgressStep, PutRecordOk, QueryId, QueryResult,
31 Quorum, Record, RecordKey,
32};
33use libp2p::metrics::{Metrics, Recorder};
34use libp2p::multiaddr::Protocol;
35use libp2p::swarm::dial_opts::DialOpts;
36use libp2p::swarm::{DialError, SwarmEvent};
37use libp2p::{Multiaddr, PeerId, Swarm, TransportError};
38use nohash_hasher::IntMap;
39use parking_lot::Mutex;
40use std::collections::hash_map::Entry;
41use std::collections::{HashMap, HashSet};
42use std::net::IpAddr;
43use std::pin::Pin;
44use std::sync::atomic::Ordering;
45use std::sync::{Arc as StdArc, Weak};
46use std::time::Duration;
47use std::{fmt, slice};
48use tokio::sync::OwnedSemaphorePermit;
49use tokio::task::yield_now;
50use tokio::time::Sleep;
51use tracing::{debug, error, trace, warn};
52use triomphe::Arc;
53
54enum QueryResultSender {
55 Value {
56 sender: mpsc::UnboundedSender<PeerRecord>,
57 _permit: OwnedSemaphorePermit,
59 },
60 ClosestPeers {
61 sender: mpsc::UnboundedSender<PeerId>,
62 _permit: Option<OwnedSemaphorePermit>,
64 },
65 Providers {
66 key: RecordKey,
67 sender: mpsc::UnboundedSender<PeerId>,
68 _permit: Option<OwnedSemaphorePermit>,
70 },
71 PutValue {
72 sender: mpsc::UnboundedSender<()>,
73 _permit: OwnedSemaphorePermit,
75 },
76 Bootstrap {
77 sender: mpsc::UnboundedSender<()>,
78 },
79}
80
81#[derive(Debug, Default)]
82enum BootstrapCommandState {
83 #[default]
84 NotStarted,
85 InProgress(mpsc::UnboundedReceiver<()>),
86 Finished,
87}
88
89#[must_use = "Node does not function properly unless its runner is driven forward"]
91pub struct NodeRunner {
92 allow_non_global_addresses_in_dht: bool,
94 is_listening: bool,
96 command_receiver: mpsc::Receiver<Command>,
97 swarm: Swarm<Behavior>,
98 shared_weak: Weak<Shared>,
99 next_random_query_interval: Duration,
101 query_id_receivers: HashMap<QueryId, QueryResultSender>,
102 next_subscription_id: usize,
105 topic_subscription_senders: HashMap<TopicHash, IntMap<usize, mpsc::UnboundedSender<Bytes>>>,
108 random_query_timeout: Pin<Box<Fuse<Sleep>>>,
109 periodical_tasks_interval: Pin<Box<Fuse<Sleep>>>,
111 known_peers_registry: Box<dyn KnownPeersRegistry>,
113 connected_servers: HashSet<PeerId>,
114 reserved_peers: HashMap<PeerId, Multiaddr>,
116 temporary_bans: Arc<Mutex<TemporaryBans>>,
118 libp2p_metrics: Option<Metrics>,
120 metrics: Option<SubspaceMetrics>,
122 peer_ip_addresses: HashMap<PeerId, HashSet<IpAddr>>,
124 protocol_version: String,
126 bootstrap_addresses: Vec<Multiaddr>,
128 bootstrap_command_state: Arc<AsyncMutex<BootstrapCommandState>>,
130 removed_addresses_rx: mpsc::UnboundedReceiver<PeerAddressRemovedEvent>,
132 _address_removal_task_handler_id: Option<HandlerId>,
135}
136
137impl fmt::Debug for NodeRunner {
138 #[inline]
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 f.debug_struct("NodeRunner").finish_non_exhaustive()
141 }
142}
143
144pub(crate) struct NodeRunnerConfig {
146 pub(crate) allow_non_global_addresses_in_dht: bool,
147 pub(crate) is_listening: bool,
149 pub(crate) command_receiver: mpsc::Receiver<Command>,
150 pub(crate) swarm: Swarm<Behavior>,
151 pub(crate) shared_weak: Weak<Shared>,
152 pub(crate) next_random_query_interval: Duration,
153 pub(crate) known_peers_registry: Box<dyn KnownPeersRegistry>,
154 pub(crate) reserved_peers: HashMap<PeerId, Multiaddr>,
155 pub(crate) temporary_bans: Arc<Mutex<TemporaryBans>>,
156 pub(crate) libp2p_metrics: Option<Metrics>,
157 pub(crate) metrics: Option<SubspaceMetrics>,
158 pub(crate) protocol_version: String,
159 pub(crate) bootstrap_addresses: Vec<Multiaddr>,
160}
161
162impl NodeRunner {
163 pub(crate) fn new(
164 NodeRunnerConfig {
165 allow_non_global_addresses_in_dht,
166 is_listening,
167 command_receiver,
168 swarm,
169 shared_weak,
170 next_random_query_interval,
171 mut known_peers_registry,
172 reserved_peers,
173 temporary_bans,
174 libp2p_metrics,
175 metrics,
176 protocol_version,
177 bootstrap_addresses,
178 }: NodeRunnerConfig,
179 ) -> Self {
180 let (removed_addresses_tx, removed_addresses_rx) = mpsc::unbounded();
182 let mut address_removal_task_handler_id = None;
183 if let Some(handler_id) = known_peers_registry.on_unreachable_address({
184 StdArc::new(move |event| {
185 if let Err(error) = removed_addresses_tx.unbounded_send(event.clone()) {
186 debug!(?error, ?event, "Cannot send PeerAddressRemovedEvent");
187 }
188 })
189 }) {
190 address_removal_task_handler_id.replace(handler_id);
191 }
192
193 Self {
194 allow_non_global_addresses_in_dht,
195 is_listening,
196 command_receiver,
197 swarm,
198 shared_weak,
199 next_random_query_interval,
200 query_id_receivers: HashMap::default(),
201 next_subscription_id: 0,
202 topic_subscription_senders: HashMap::default(),
203 random_query_timeout: Box::pin(tokio::time::sleep(Duration::from_secs(0)).fuse()),
205 periodical_tasks_interval: Box::pin(tokio::time::sleep(Duration::from_secs(0)).fuse()),
207 known_peers_registry,
208 connected_servers: HashSet::new(),
209 reserved_peers,
210 temporary_bans,
211 libp2p_metrics,
212 metrics,
213 peer_ip_addresses: HashMap::new(),
214 protocol_version,
215 bootstrap_addresses,
216 bootstrap_command_state: Arc::new(AsyncMutex::new(BootstrapCommandState::default())),
217 removed_addresses_rx,
218 _address_removal_task_handler_id: address_removal_task_handler_id,
219 }
220 }
221
222 pub async fn run(&mut self) {
224 if self.is_listening {
225 loop {
228 if self.swarm.listeners().next().is_some() {
229 break;
230 }
231
232 if let Some(swarm_event) = self.swarm.next().await {
233 self.register_event_metrics(&swarm_event);
234 self.handle_swarm_event(swarm_event).await;
235 } else {
236 break;
237 }
238 }
239 }
240
241 self.bootstrap().await;
242
243 loop {
244 futures::select! {
245 () = &mut self.random_query_timeout => {
246 self.handle_random_query_interval();
247 self.random_query_timeout =
249 Box::pin(tokio::time::sleep(self.next_random_query_interval).fuse());
250 self.next_random_query_interval =
251 (self.next_random_query_interval * 2).min(Duration::from_mins(1));
252 },
253 swarm_event = self.swarm.next() => {
254 if let Some(swarm_event) = swarm_event {
255 self.register_event_metrics(&swarm_event);
256 self.handle_swarm_event(swarm_event).await;
257 } else {
258 break;
259 }
260 },
261 command = self.command_receiver.next() => {
262 if let Some(command) = command {
263 self.handle_command(command);
264 } else {
265 break;
266 }
267 },
268 () = self.known_peers_registry.run().fuse() => {
269 trace!("Network parameters registry runner exited");
270 },
271 () = &mut self.periodical_tasks_interval => {
272 self.handle_periodical_tasks();
273
274 self.periodical_tasks_interval =
275 Box::pin(tokio::time::sleep(Duration::from_secs(5)).fuse());
276 },
277 event = self.removed_addresses_rx.select_next_some() => {
278 self.handle_removed_address_event(event);
279 },
280 }
281
282 yield_now().await;
284 }
285 }
286
287 async fn bootstrap(&mut self) {
289 for (peer_id, address) in strip_peer_id(self.bootstrap_addresses.clone()) {
291 self.swarm
292 .behaviour_mut()
293 .kademlia
294 .add_address(&peer_id, address);
295 }
296
297 let known_peers = self.known_peers_registry.all_known_peers().await;
298
299 if !known_peers.is_empty() {
300 for (peer_id, addresses) in known_peers {
301 for address in addresses.clone() {
302 let address = match address.with_p2p(peer_id) {
303 Ok(address) => address,
304 Err(address) => {
305 warn!(%peer_id, %address, "Failed to add peer ID to known peer address");
306 break;
307 }
308 };
309 self.swarm
310 .behaviour_mut()
311 .kademlia
312 .add_address(&peer_id, address);
313 }
314
315 if let Err(error) = self
316 .swarm
317 .dial(DialOpts::peer_id(peer_id).addresses(addresses).build())
318 {
319 warn!(%peer_id, %error, "Failed to dial peer during bootstrapping");
320 }
321 }
322
323 self.handle_command(Command::Bootstrap {
325 result_sender: None,
326 });
327 return;
328 }
329
330 let bootstrap_command_state = Arc::clone(&self.bootstrap_command_state);
331 let mut bootstrap_command_state = bootstrap_command_state.lock().await;
332 let bootstrap_command_receiver = match &mut *bootstrap_command_state {
333 BootstrapCommandState::NotStarted => {
334 debug!("Bootstrap started.");
335
336 let (bootstrap_command_sender, bootstrap_command_receiver) = mpsc::unbounded();
337
338 self.handle_command(Command::Bootstrap {
339 result_sender: Some(bootstrap_command_sender),
340 });
341
342 *bootstrap_command_state =
343 BootstrapCommandState::InProgress(bootstrap_command_receiver);
344 match &mut *bootstrap_command_state {
345 BootstrapCommandState::InProgress(bootstrap_command_receiver) => {
346 bootstrap_command_receiver
347 }
348 _ => {
349 unreachable!("Was just set to that exact value");
350 }
351 }
352 }
353 BootstrapCommandState::InProgress(bootstrap_command_receiver) => {
354 bootstrap_command_receiver
355 }
356 BootstrapCommandState::Finished => {
357 return;
358 }
359 };
360
361 let mut bootstrap_step = 0usize;
362 loop {
363 futures::select! {
364 swarm_event = self.swarm.next() => {
365 if let Some(swarm_event) = swarm_event {
366 self.register_event_metrics(&swarm_event);
367 self.handle_swarm_event(swarm_event).await;
368 } else {
369 break;
370 }
371 },
372 result = bootstrap_command_receiver.next() => {
373 if result.is_some() {
374 debug!(%bootstrap_step, "Kademlia bootstrapping...");
375 bootstrap_step += 1;
376 } else {
377 break;
378 }
379 }
380 }
381 }
382
383 debug!("Bootstrap finished.");
384 *bootstrap_command_state = BootstrapCommandState::Finished;
385 }
386
387 fn handle_periodical_tasks(&mut self) {
389 let network_info = self.swarm.network_info();
391 let connections = network_info.connection_counters();
392
393 debug!(?connections, "Current connections and limits.");
394
395 let mut external_addresses = self.swarm.external_addresses().cloned().collect::<Vec<_>>();
397
398 if let Some(shared) = self.shared_weak.upgrade() {
399 debug!(?external_addresses, "Renew external addresses.");
400 let mut addresses = shared.external_addresses.lock();
401 addresses.clear();
402 addresses.append(&mut external_addresses);
403 }
404
405 self.log_kademlia_stats();
406 }
407
408 fn handle_random_query_interval(&mut self) {
409 let random_peer_id = PeerId::random();
410
411 trace!("Starting random Kademlia query for {}", random_peer_id);
412
413 self.swarm
414 .behaviour_mut()
415 .kademlia
416 .get_closest_peers(random_peer_id);
417 }
418
419 fn handle_removed_address_event(&mut self, event: PeerAddressRemovedEvent) {
420 trace!(?event, "Peer address removed event.");
421
422 let bootstrap_node_ids = strip_peer_id(self.bootstrap_addresses.clone())
423 .into_iter()
424 .map(|(peer_id, _)| peer_id)
425 .collect::<Vec<_>>();
426
427 if bootstrap_node_ids.contains(&event.peer_id) {
428 debug!(
429 ?event,
430 ?bootstrap_node_ids,
431 "Skipped removing bootstrap node from Kademlia buckets."
432 );
433
434 return;
435 }
436
437 self.swarm.behaviour_mut().kademlia.remove_address(
439 &event.peer_id,
440 &append_p2p_suffix(event.peer_id, event.address.clone()),
441 );
442
443 self.swarm
444 .behaviour_mut()
445 .kademlia
446 .remove_address(&event.peer_id, &remove_p2p_suffix(event.address));
447 }
448
449 fn handle_remove_listeners(&mut self, removed_listeners: &[Multiaddr]) {
450 let Some(shared) = self.shared_weak.upgrade() else {
451 return;
452 };
453
454 let peer_id = shared.id;
456 shared.listeners.lock().retain(|old_listener| {
457 !removed_listeners.contains(&append_p2p_suffix(peer_id, old_listener.clone()))
458 && !removed_listeners.contains(&remove_p2p_suffix(old_listener.clone()))
459 });
460 }
461
462 async fn handle_swarm_event(&mut self, swarm_event: SwarmEvent<Event>) {
463 #[expect(clippy::ref_patterns, reason = "Much less awkward this way")]
464 match swarm_event {
465 SwarmEvent::Behaviour(Event::Identify(event)) => {
466 self.handle_identify_event(*event);
467 }
468 SwarmEvent::Behaviour(Event::Kademlia(event)) => {
469 self.handle_kademlia_event(event);
470 }
471 SwarmEvent::Behaviour(Event::Gossipsub(event)) => {
472 self.handle_gossipsub_event(event);
473 }
474 SwarmEvent::Behaviour(Event::RequestResponse(event)) => {
475 self.handle_request_response_event(event);
476 }
477 SwarmEvent::Behaviour(Event::Autonat(event)) => {
478 self.handle_autonat_event(event);
479 }
480 ref event @ SwarmEvent::NewListenAddr { ref address, .. } => {
481 trace!(?event, "New local listener event.");
482
483 let Some(shared) = self.shared_weak.upgrade() else {
484 return;
485 };
486 shared.listeners.lock().push(address.clone());
487 shared.handlers.new_listener.call_simple(address);
488 }
489 ref event @ SwarmEvent::ListenerClosed { ref addresses, .. } => {
490 trace!(?event, "Local listener closed event.");
491 self.handle_remove_listeners(addresses);
492 }
493 ref event @ SwarmEvent::ExpiredListenAddr { ref address, .. } => {
494 trace!(?event, "Local listener expired event.");
495 self.handle_remove_listeners(slice::from_ref(address));
496 }
497 SwarmEvent::ConnectionEstablished {
498 peer_id,
499 endpoint,
500 num_established,
501 ..
502 } => {
503 if let ConnectedPoint::Dialer { address, .. } = &endpoint {
505 if self.allow_non_global_addresses_in_dht || is_global_address_or_dns(address) {
507 self.known_peers_registry
508 .add_known_peer(peer_id, vec![address.clone()])
509 .await;
510 }
511 }
512
513 let Some(shared) = self.shared_weak.upgrade() else {
514 return;
515 };
516
517 let is_reserved_peer = self.reserved_peers.contains_key(&peer_id);
518 debug!(
519 %peer_id,
520 %is_reserved_peer,
521 ?endpoint,
522 %num_established,
523 "Connection established"
524 );
525
526 let maybe_remote_ip =
527 endpoint
528 .get_remote_address()
529 .iter()
530 .find_map(|protocol| match protocol {
531 Protocol::Ip4(ip) => Some(IpAddr::V4(ip)),
532 Protocol::Ip6(ip) => Some(IpAddr::V6(ip)),
533 _ => None,
534 });
535 if let Some(ip) = maybe_remote_ip {
536 self.peer_ip_addresses
537 .entry(peer_id)
538 .and_modify(|ips| {
539 ips.insert(ip);
540 })
541 .or_insert(HashSet::from([ip]));
542 }
543
544 let num_established_peer_connections = shared
545 .num_established_peer_connections
546 .fetch_add(1, Ordering::SeqCst)
547 + 1;
548
549 shared
550 .handlers
551 .num_established_peer_connections_change
552 .call_simple(&num_established_peer_connections);
553
554 if num_established.get() == 1 {
556 shared.handlers.connected_peer.call_simple(&peer_id);
557 }
558
559 if let Some(metrics) = self.metrics.as_ref() {
560 metrics.inc_established_connections();
561 }
562 }
563 SwarmEvent::ConnectionClosed {
564 peer_id,
565 num_established,
566 cause,
567 ..
568 } => {
569 let Some(shared) = self.shared_weak.upgrade() else {
570 return;
571 };
572
573 debug!(
574 %peer_id,
575 ?cause,
576 %num_established,
577 "Connection closed with peer"
578 );
579
580 if num_established == 0 {
581 self.peer_ip_addresses.remove(&peer_id);
582 self.connected_servers.remove(&peer_id);
583 }
584 let num_established_peer_connections = shared
585 .num_established_peer_connections
586 .fetch_sub(1, Ordering::SeqCst)
587 - 1;
588
589 shared
590 .handlers
591 .num_established_peer_connections_change
592 .call_simple(&num_established_peer_connections);
593
594 if num_established == 0 {
596 shared.handlers.disconnected_peer.call_simple(&peer_id);
597 }
598
599 if let Some(metrics) = self.metrics.as_ref() {
600 metrics.dec_established_connections();
601 }
602 }
603 SwarmEvent::OutgoingConnectionError { peer_id, error, .. } => {
604 if let Some(peer_id) = &peer_id {
605 let should_ban_temporarily =
606 self.should_temporary_ban_on_dial_error(peer_id, &error);
607
608 trace!(%should_ban_temporarily, "Temporary bans conditions.");
609
610 if should_ban_temporarily {
611 self.temporary_bans.lock().create_or_extend(peer_id);
612 debug!(%peer_id, ?error, "Peer was temporarily banned.");
613 }
614 }
615
616 debug!(
617 ?peer_id,
618 ?error,
619 "SwarmEvent::OutgoingConnectionError for peer."
620 );
621
622 match error {
623 DialError::Transport(ref addresses) => {
624 for (addr, _) in addresses {
625 trace!(?error, ?peer_id, %addr, "SwarmEvent::OutgoingConnectionError (DialError::Transport) for peer.");
626 if let Some(peer_id) = peer_id {
627 self.known_peers_registry
628 .remove_known_peer_addresses(peer_id, vec![addr.clone()])
629 .await;
630 }
631 }
632 }
633 DialError::WrongPeerId { obtained, .. } => {
634 trace!(?error, ?peer_id, obtained_peer_id=?obtained, "SwarmEvent::WrongPeerId (DialError::WrongPeerId) for peer.");
635
636 if let Some(ref peer_id) = peer_id {
637 let kademlia = &mut self.swarm.behaviour_mut().kademlia;
638 let _: Option<_> = kademlia.remove_peer(peer_id);
639 }
640 }
641 _ => {
642 trace!(?error, ?peer_id, "SwarmEvent::OutgoingConnectionError");
643 }
644 }
645 }
646 SwarmEvent::NewExternalAddrCandidate { address } => {
647 trace!(%address, "External address candidate");
648 }
649 SwarmEvent::ExternalAddrConfirmed { address } => {
650 debug!(%address, "Confirmed external address");
651
652 let connected_peers = self.swarm.connected_peers().copied().collect::<Vec<_>>();
653 self.swarm.behaviour_mut().identify.push(connected_peers);
654 }
655 SwarmEvent::ExternalAddrExpired { address } => {
656 debug!(%address, "External address expired");
657
658 let connected_peers = self.swarm.connected_peers().copied().collect::<Vec<_>>();
659 self.swarm.behaviour_mut().identify.push(connected_peers);
660 }
661 other => {
662 trace!("Other swarm event: {:?}", other);
663 }
664 }
665 }
666
667 fn should_temporary_ban_on_dial_error(&self, peer_id: &PeerId, error: &DialError) -> bool {
668 if true {
670 return false;
671 }
672
673 if self.swarm.is_connected(peer_id) {
675 return false;
676 }
677
678 match &error {
679 DialError::Transport(addresses) => {
680 for (_, error) in addresses {
681 match error {
682 TransportError::MultiaddrNotSupported(_) => {
683 return true;
684 }
685 TransportError::Other(_) => {
686 if self.temporary_bans.lock().is_banned(peer_id) {
688 return false;
689 }
690 }
691 }
692 }
693 true
695 }
696 DialError::LocalPeerId { .. } => {
697 debug!("Local peer dial attempt detected.");
699
700 false
701 }
702 DialError::NoAddresses => {
703 true
705 }
706 DialError::DialPeerConditionFalse(_) => {
707 false
709 }
710 DialError::Aborted => {
711 false
713 }
714 DialError::WrongPeerId { .. } => {
715 false
717 }
718 DialError::Denied { .. } => {
719 false
721 }
722 }
723 }
724
725 fn handle_identify_event(&mut self, event: IdentifyEvent) {
726 let local_peer_id = *self.swarm.local_peer_id();
727
728 if let IdentifyEvent::Received {
729 peer_id, mut info, ..
730 } = event
731 {
732 debug!(?peer_id, protocols = ?info.protocols, "IdentifyEvent::Received");
733
734 if info.protocol_version != self.protocol_version {
736 debug!(
737 %local_peer_id,
738 %peer_id,
739 local_protocol_version = %self.protocol_version,
740 peer_protocol_version = %info.protocol_version,
741 "Peer has different protocol version, banning temporarily",
742 );
743
744 self.temporary_bans.lock().create_or_extend(&peer_id);
745 let _: Result<(), ()> = self.swarm.disconnect_peer_id(peer_id);
747 self.swarm.behaviour_mut().kademlia.remove_peer(&peer_id);
748 self.known_peers_registry
749 .remove_all_known_peer_addresses(peer_id);
750
751 return;
752 }
753
754 self.temporary_bans.lock().remove(&peer_id);
756
757 if info.listen_addrs.len() > 30 {
758 debug!(
759 %local_peer_id,
760 %peer_id,
761 "Node has reported more than 30 addresses; it is identified by {} and {}",
762 info.protocol_version, info.agent_version
763 );
764 info.listen_addrs.truncate(30);
765 }
766
767 let kademlia = &mut self.swarm.behaviour_mut().kademlia;
768 let full_kademlia_support = kademlia
769 .protocol_names()
770 .iter()
771 .all(|local_protocol| info.protocols.contains(local_protocol));
772
773 if full_kademlia_support {
774 let received_addresses = info
775 .listen_addrs
776 .into_iter()
777 .filter(|address| {
778 if self.allow_non_global_addresses_in_dht
779 || is_global_address_or_dns(address)
780 {
781 true
782 } else {
783 trace!(
784 %local_peer_id,
785 %peer_id,
786 %address,
787 "Ignoring self-reported non-global address",
788 );
789
790 false
791 }
792 })
793 .collect::<Vec<_>>();
794 let received_address_strings = received_addresses
795 .iter()
796 .map(ToString::to_string)
797 .collect::<Vec<_>>();
798 let old_addresses = kademlia
799 .kbucket(peer_id)
800 .and_then(|peers| {
801 let key = peer_id.into();
802 peers.iter().find_map(|peer| {
803 (peer.node.key == &key).then_some(
804 peer.node
805 .value
806 .iter()
807 .filter(|existing_address| {
808 let existing_address = existing_address.to_string();
809
810 !received_address_strings.iter().any(|received_address| {
811 received_address.starts_with(&existing_address)
812 || existing_address.starts_with(received_address)
813 })
814 })
815 .cloned()
816 .collect::<Vec<_>>(),
817 )
818 })
819 })
820 .unwrap_or_default();
821
822 for address in received_addresses {
823 debug!(
824 %local_peer_id,
825 %peer_id,
826 %address,
827 protocol_names = ?kademlia.protocol_names(),
828 "Adding self-reported address to Kademlia DHT",
829 );
830
831 kademlia.add_address(&peer_id, address);
832 }
833
834 for old_address in old_addresses {
835 trace!(
836 %local_peer_id,
837 %peer_id,
838 %old_address,
839 "Removing old self-reported address from Kademlia DHT",
840 );
841
842 kademlia.remove_address(&peer_id, &old_address);
843 }
844
845 self.connected_servers.insert(peer_id);
846 } else {
847 debug!(
848 %local_peer_id,
849 %peer_id,
850 peer_protocols = ?info.protocols,
851 protocol_names = ?kademlia.protocol_names(),
852 "Peer doesn't support our Kademlia DHT protocol",
853 );
854
855 kademlia.remove_peer(&peer_id);
856 self.connected_servers.remove(&peer_id);
857 }
858 }
859 }
860
861 fn handle_kademlia_event(&mut self, event: KademliaEvent) {
862 trace!("Kademlia event: {:?}", event);
863
864 match event {
865 KademliaEvent::InboundRequest {
866 request: InboundRequest::AddProvider { record },
867 } => {
868 debug!("Unexpected AddProvider request received: {:?}", record);
869 }
870 KademliaEvent::UnroutablePeer { peer } => {
871 debug!(%peer, "Unroutable peer detected");
872
873 self.swarm.behaviour_mut().kademlia.remove_peer(&peer);
874
875 if let Some(shared) = self.shared_weak.upgrade() {
876 shared
877 .handlers
878 .peer_discovered
879 .call_simple(&PeerDiscovered::UnroutablePeer { peer_id: peer });
880 }
881 }
882 KademliaEvent::RoutablePeer { peer, address } => {
883 debug!(?address, "Routable peer detected: {:?}", peer);
884
885 if let Some(shared) = self.shared_weak.upgrade() {
886 shared
887 .handlers
888 .peer_discovered
889 .call_simple(&PeerDiscovered::RoutablePeer {
890 peer_id: peer,
891 address,
892 });
893 }
894 }
895 KademliaEvent::PendingRoutablePeer { peer, address } => {
896 debug!(?address, "Pending routable peer detected: {:?}", peer);
897
898 if let Some(shared) = self.shared_weak.upgrade() {
899 shared
900 .handlers
901 .peer_discovered
902 .call_simple(&PeerDiscovered::RoutablePeer {
903 peer_id: peer,
904 address,
905 });
906 }
907 }
908 KademliaEvent::OutboundQueryProgressed {
909 step: ProgressStep { last, .. },
910 id,
911 result: QueryResult::GetClosestPeers(result),
912 ..
913 } => {
914 let mut cancelled = false;
915 if let Some(QueryResultSender::ClosestPeers { sender, .. }) =
916 self.query_id_receivers.get(&id)
917 {
918 match result {
919 Ok(GetClosestPeersOk { key, peers }) => {
920 trace!(
921 "Get closest peers query for {} yielded {} results",
922 hex::encode(key),
923 peers.len(),
924 );
925
926 if peers.is_empty()
927 && self.swarm.connected_peers().next().is_some()
929 {
930 debug!("Random Kademlia query has yielded empty list of peers");
931 }
932
933 for peer in peers {
934 cancelled = Self::unbounded_send_and_cancel_on_error(
935 &mut self.swarm.behaviour_mut().kademlia,
936 sender,
937 peer.peer_id,
938 "GetClosestPeersOk",
939 id,
940 ) || cancelled;
941 }
942 }
943 Err(GetClosestPeersError::Timeout { key, peers }) => {
944 debug!(
945 "Get closest peers query for {} timed out with {} results",
946 hex::encode(key),
947 peers.len(),
948 );
949
950 for peer in peers {
951 cancelled = Self::unbounded_send_and_cancel_on_error(
952 &mut self.swarm.behaviour_mut().kademlia,
953 sender,
954 peer.peer_id,
955 "GetClosestPeersError::Timeout",
956 id,
957 ) || cancelled;
958 }
959 }
960 }
961 }
962
963 if last || cancelled {
964 self.query_id_receivers.remove(&id);
966 }
967 }
968 KademliaEvent::OutboundQueryProgressed {
969 step: ProgressStep { last, .. },
970 id,
971 result: QueryResult::GetRecord(result),
972 ..
973 } => {
974 let mut cancelled = false;
975 if let Some(QueryResultSender::Value { sender, .. }) =
976 self.query_id_receivers.get(&id)
977 {
978 match result {
979 Ok(GetRecordOk::FoundRecord(rec)) => {
980 trace!(
981 key = hex::encode(&rec.record.key),
982 "Get record query succeeded",
983 );
984
985 cancelled = Self::unbounded_send_and_cancel_on_error(
986 &mut self.swarm.behaviour_mut().kademlia,
987 sender,
988 rec,
989 "GetRecordOk",
990 id,
991 ) || cancelled;
992 }
993 Ok(GetRecordOk::FinishedWithNoAdditionalRecord { .. }) => {
994 trace!("Get record query yielded no results");
995 }
996 Err(error) => match error {
997 GetRecordError::NotFound { key, .. } => {
998 debug!(
999 key = hex::encode(&key),
1000 "Get record query failed with no results",
1001 );
1002 }
1003 GetRecordError::Timeout { key } => {
1004 debug!(key = hex::encode(&key), "Get record query timed out");
1005 }
1006 },
1007 }
1008 }
1009
1010 if last || cancelled {
1011 self.query_id_receivers.remove(&id);
1013 }
1014 }
1015 KademliaEvent::OutboundQueryProgressed {
1016 step: ProgressStep { last, .. },
1017 id,
1018 result: QueryResult::GetProviders(result),
1019 ..
1020 } => {
1021 let mut cancelled = false;
1022 if let Some(QueryResultSender::Providers { key, sender, .. }) =
1023 self.query_id_receivers.get(&id)
1024 {
1025 match result {
1026 Ok(GetProvidersOk::FoundProviders { key, providers }) => {
1027 trace!(
1028 key = hex::encode(&key),
1029 "Get providers query yielded {} results",
1030 providers.len(),
1031 );
1032
1033 for provider in providers {
1034 cancelled = Self::unbounded_send_and_cancel_on_error(
1035 &mut self.swarm.behaviour_mut().kademlia,
1036 sender,
1037 provider,
1038 "GetProvidersOk",
1039 id,
1040 ) || cancelled;
1041 }
1042 }
1043 Ok(GetProvidersOk::FinishedWithNoAdditionalRecord { closest_peers }) => {
1044 trace!(
1045 key = hex::encode(key),
1046 closest_peers = %closest_peers.len(),
1047 "Get providers query yielded no results"
1048 );
1049 }
1050 Err(error) => {
1051 let GetProvidersError::Timeout { key, .. } = error;
1052
1053 debug!(
1054 key = hex::encode(&key),
1055 "Get providers query failed with no results",
1056 );
1057 }
1058 }
1059 }
1060
1061 if last || cancelled {
1062 self.query_id_receivers.remove(&id);
1064 }
1065 }
1066 KademliaEvent::OutboundQueryProgressed {
1067 step: ProgressStep { last, .. },
1068 id,
1069 result: QueryResult::PutRecord(result),
1070 ..
1071 } => {
1072 let mut cancelled = false;
1073 if let Some(QueryResultSender::PutValue { sender, .. }) =
1074 self.query_id_receivers.get(&id)
1075 {
1076 match result {
1077 Ok(PutRecordOk { key }) => {
1078 trace!("Put record query for {} succeeded", hex::encode(&key));
1079
1080 cancelled = Self::unbounded_send_and_cancel_on_error(
1081 &mut self.swarm.behaviour_mut().kademlia,
1082 sender,
1083 (),
1084 "PutRecordOk",
1085 id,
1086 ) || cancelled;
1087 }
1088 Err(error) => {
1089 debug!(?error, "Put record query failed.");
1090 }
1091 }
1092 }
1093
1094 if last || cancelled {
1095 self.query_id_receivers.remove(&id);
1097 }
1098 }
1099 KademliaEvent::OutboundQueryProgressed {
1100 step: ProgressStep { last, count },
1101 id,
1102 result: QueryResult::Bootstrap(result),
1103 stats,
1104 } => {
1105 debug!(?stats, %last, %count, ?id, ?result, "Bootstrap OutboundQueryProgressed step.");
1106
1107 let mut cancelled = false;
1108 if let Some(QueryResultSender::Bootstrap { sender }) =
1109 self.query_id_receivers.get_mut(&id)
1110 {
1111 match result {
1112 Ok(BootstrapOk {
1113 peer,
1114 num_remaining,
1115 }) => {
1116 trace!(%peer, %num_remaining, %last, "Bootstrap query step succeeded");
1117
1118 cancelled = Self::unbounded_send_and_cancel_on_error(
1119 &mut self.swarm.behaviour_mut().kademlia,
1120 sender,
1121 (),
1122 "Bootstrap",
1123 id,
1124 ) || cancelled;
1125 }
1126 Err(error) => {
1127 debug!(?error, "Bootstrap query failed.");
1128 }
1129 }
1130 }
1131
1132 if last || cancelled {
1133 self.query_id_receivers.remove(&id);
1135 }
1136 }
1137 _ => {}
1138 }
1139 }
1140
1141 fn unbounded_send_and_cancel_on_error<T>(
1143 kademlia: &mut Kademlia<DummyRecordStore>,
1144 sender: &mpsc::UnboundedSender<T>,
1145 value: T,
1146 channel: &'static str,
1147 id: QueryId,
1148 ) -> bool {
1149 if sender.unbounded_send(value).is_err() {
1150 debug!("{} channel was dropped", channel);
1151
1152 if let Some(mut query) = kademlia.query_mut(&id) {
1154 query.finish();
1155 }
1156 true
1157 } else {
1158 false
1159 }
1160 }
1161
1162 fn handle_gossipsub_event(&mut self, event: GossipsubEvent) {
1163 if let GossipsubEvent::Message { message, .. } = event
1164 && let Some(senders) = self.topic_subscription_senders.get(&message.topic)
1165 {
1166 let bytes = Bytes::from(message.data);
1167
1168 for sender in senders.values() {
1169 let _: Result<(), _> = sender.unbounded_send(bytes.clone());
1171 }
1172 }
1173 }
1174
1175 fn handle_request_response_event(&mut self, event: RequestResponseEvent) {
1176 trace!("Request response event: {:?}", event);
1178 }
1179
1180 fn handle_autonat_event(&mut self, event: AutonatEvent) {
1181 trace!(?event, "Autonat event received.");
1182 let autonat = &self.swarm.behaviour().autonat;
1183 debug!(
1184 public_address=?autonat.public_address(),
1185 confidence=%autonat.confidence(),
1186 "Current public address confidence."
1187 );
1188
1189 match event {
1190 AutonatEvent::InboundProbe(_inbound_probe_event) => {
1191 }
1193 AutonatEvent::OutboundProbe(outbound_probe_event) => {
1194 match outbound_probe_event {
1195 OutboundProbeEvent::Request { peer, .. } => {
1196 self.swarm
1199 .behaviour_mut()
1200 .connection_limits
1201 .add_to_incoming_allow_list(
1203 peer,
1204 self.peer_ip_addresses
1205 .get(&peer)
1206 .iter()
1207 .flat_map(|ip_addresses| ip_addresses.iter())
1208 .copied(),
1209 1,
1210 );
1211 }
1212 OutboundProbeEvent::Response { peer, .. } => {
1213 self.swarm
1214 .behaviour_mut()
1215 .connection_limits
1216 .remove_from_incoming_allow_list(&peer, Some(1));
1217 }
1218 OutboundProbeEvent::Error { peer, .. } => {
1219 if let Some(peer) = peer {
1220 self.swarm
1221 .behaviour_mut()
1222 .connection_limits
1223 .remove_from_incoming_allow_list(&peer, Some(1));
1224 }
1225 }
1226 }
1227 }
1228 AutonatEvent::StatusChanged { old, new } => {
1229 debug!(?old, ?new, "Public address status changed.");
1230
1231 if let (NatStatus::Public(old_address), NatStatus::Private) = (old, new.clone()) {
1233 self.swarm.remove_external_address(&old_address);
1234 debug!(
1235 ?old_address,
1236 new_status = ?new,
1237 "Removing old external address...",
1238 );
1239
1240 self.swarm.behaviour_mut().kademlia.set_mode(None);
1242 }
1243
1244 let connected_peers = self.swarm.connected_peers().copied().collect::<Vec<_>>();
1245 self.swarm.behaviour_mut().identify.push(connected_peers);
1246 }
1247 }
1248 }
1249
1250 fn handle_command(&mut self, command: Command) {
1251 match command {
1252 Command::GetValue {
1253 key,
1254 result_sender,
1255 permit,
1256 } => {
1257 let query_id = self
1258 .swarm
1259 .behaviour_mut()
1260 .kademlia
1261 .get_record(key.to_bytes().into());
1262
1263 self.query_id_receivers.insert(
1264 query_id,
1265 QueryResultSender::Value {
1266 sender: result_sender,
1267 _permit: permit,
1268 },
1269 );
1270 }
1271 Command::PutValue {
1272 key,
1273 value,
1274 result_sender,
1275 permit,
1276 } => {
1277 let local_peer_id = *self.swarm.local_peer_id();
1278
1279 let record = Record {
1280 key: key.into(),
1281 value,
1282 publisher: Some(local_peer_id),
1283 expires: None, };
1285 let query_result = self
1286 .swarm
1287 .behaviour_mut()
1288 .kademlia
1289 .put_record(record, Quorum::One);
1290
1291 match query_result {
1292 Ok(query_id) => {
1293 self.query_id_receivers.insert(
1294 query_id,
1295 QueryResultSender::PutValue {
1296 sender: result_sender,
1297 _permit: permit,
1298 },
1299 );
1300 }
1301 Err(err) => {
1302 warn!(?err, "Failed to put value.");
1303 }
1304 }
1305 }
1306 Command::Subscribe {
1307 topic,
1308 result_sender,
1309 } => {
1310 assert!(
1311 self.swarm.behaviour().gossipsub.is_enabled(),
1312 "Gossipsub protocol is disabled."
1313 );
1314
1315 let topic_hash = topic.hash();
1316 let (sender, receiver) = mpsc::unbounded();
1317
1318 let subscription_id = self.next_subscription_id;
1320 self.next_subscription_id += 1;
1321
1322 let created_subscription = CreatedSubscription {
1323 subscription_id,
1324 receiver,
1325 };
1326
1327 match self.topic_subscription_senders.entry(topic_hash) {
1328 Entry::Occupied(mut entry) => {
1329 if result_sender.send(Ok(created_subscription)).is_ok() {
1331 entry.get_mut().insert(subscription_id, sender);
1332 }
1333 }
1334 Entry::Vacant(entry) => {
1335 if let Some(gossipsub) = self.swarm.behaviour_mut().gossipsub.as_mut() {
1338 match gossipsub.subscribe(&topic) {
1339 Ok(true) => {
1340 if result_sender.send(Ok(created_subscription)).is_ok() {
1341 entry
1342 .insert(IntMap::from_iter([(subscription_id, sender)]));
1343 }
1344 }
1345 Ok(false) => {
1346 panic!(
1347 "Logic error, topic subscription wasn't created, this \
1348 must never happen"
1349 );
1350 }
1351 Err(error) => {
1352 let _: Result<(), _> = result_sender.send(Err(error));
1353 }
1354 }
1355 }
1356 }
1357 }
1358 }
1359 Command::Unsubscribe {
1360 topic,
1361 subscription_id,
1362 } => {
1363 assert!(
1364 self.swarm.behaviour().gossipsub.is_enabled(),
1365 "Gossipsub protocol is disabled."
1366 );
1367
1368 if let Entry::Occupied(mut entry) =
1369 self.topic_subscription_senders.entry(topic.hash())
1370 {
1371 entry.get_mut().remove(&subscription_id);
1372
1373 if entry.get().is_empty() {
1375 entry.remove_entry();
1376
1377 if let Some(gossipsub) = self.swarm.behaviour_mut().gossipsub.as_mut()
1378 && !gossipsub.unsubscribe(&topic)
1379 {
1380 warn!(
1381 "Can't unsubscribe from topic {topic} because subscription doesn't \
1382 exist, this is a logic error in the subspace or swarm libraries"
1383 );
1384 }
1385 }
1386 } else {
1387 error!(
1388 "Can't unsubscribe from topic {topic} because subscription doesn't exist, \
1389 this is a logic error in the subspace library"
1390 );
1391 }
1392 }
1393 Command::Publish {
1394 topic,
1395 message,
1396 result_sender,
1397 } => {
1398 assert!(
1399 self.swarm.behaviour().gossipsub.is_enabled(),
1400 "Gossipsub protocol is disabled"
1401 );
1402
1403 if let Some(gossipsub) = self.swarm.behaviour_mut().gossipsub.as_mut() {
1404 let _: Result<(), _> =
1406 result_sender.send(gossipsub.publish(topic, message).map(|_message_id| ()));
1407 }
1408 }
1409 Command::GetClosestPeers {
1410 key,
1411 result_sender,
1412 permit,
1413 } => {
1414 let query_id = self.swarm.behaviour_mut().kademlia.get_closest_peers(key);
1415
1416 self.query_id_receivers.insert(
1417 query_id,
1418 QueryResultSender::ClosestPeers {
1419 sender: result_sender,
1420 _permit: permit,
1421 },
1422 );
1423 }
1424 Command::GetClosestLocalPeers {
1425 key,
1426 source,
1427 result_sender,
1428 } => {
1429 let source = source.unwrap_or_else(|| *self.swarm.local_peer_id());
1430 let result = self
1431 .swarm
1432 .behaviour_mut()
1433 .kademlia
1434 .find_closest_local_peers(&KBucketKey::from(key), &source)
1435 .filter(|peer| !peer.multiaddrs.is_empty())
1436 .map(|peer| (peer.node_id, peer.multiaddrs))
1437 .collect();
1438
1439 let _: Result<(), _> = result_sender.send(result);
1441 }
1442 Command::GenericRequest {
1443 peer_id,
1444 addresses,
1445 protocol_name,
1446 request,
1447 result_sender,
1448 } => {
1449 self.swarm.behaviour_mut().request_response.send_request(
1450 &peer_id,
1451 protocol_name,
1452 request,
1453 result_sender,
1454 IfDisconnected::TryConnect,
1455 addresses,
1456 );
1457 }
1458 Command::GetProviders {
1459 key,
1460 result_sender,
1461 permit,
1462 } => {
1463 let query_id = self
1464 .swarm
1465 .behaviour_mut()
1466 .kademlia
1467 .get_providers(key.clone());
1468
1469 self.query_id_receivers.insert(
1470 query_id,
1471 QueryResultSender::Providers {
1472 key,
1473 sender: result_sender,
1474 _permit: permit,
1475 },
1476 );
1477 }
1478 Command::BanPeer { peer_id } => {
1479 self.ban_peer(peer_id);
1480 }
1481 Command::Dial { address } => {
1482 let _: Result<(), _> = self.swarm.dial(address);
1483 }
1484 Command::ConnectedPeers { result_sender } => {
1485 let connected_peers = self.swarm.connected_peers().copied().collect();
1486
1487 let _: Result<(), _> = result_sender.send(connected_peers);
1488 }
1489 Command::ConnectedServers { result_sender } => {
1490 let connected_servers = self.connected_servers.iter().copied().collect();
1491
1492 let _: Result<(), _> = result_sender.send(connected_servers);
1493 }
1494 Command::Bootstrap { result_sender } => {
1495 let kademlia = &mut self.swarm.behaviour_mut().kademlia;
1496
1497 match kademlia.bootstrap() {
1498 Ok(query_id) => {
1499 if let Some(result_sender) = result_sender {
1500 self.query_id_receivers.insert(
1501 query_id,
1502 QueryResultSender::Bootstrap {
1503 sender: result_sender,
1504 },
1505 );
1506 }
1507 }
1508 Err(err) => {
1509 debug!(?err, "Bootstrap error.");
1510 }
1511 }
1512 }
1513 }
1514 }
1515
1516 fn ban_peer(&mut self, peer_id: PeerId) {
1517 self.temporary_bans.lock().remove(&peer_id);
1519
1520 debug!(?peer_id, "Banning peer on network level");
1521
1522 self.swarm.behaviour_mut().block_list.block_peer(peer_id);
1523 self.swarm.behaviour_mut().kademlia.remove_peer(&peer_id);
1524 self.known_peers_registry
1525 .remove_all_known_peer_addresses(peer_id);
1526
1527 let _: Result<(), ()> = self.swarm.disconnect_peer_id(peer_id);
1529 }
1530
1531 fn register_event_metrics(&mut self, swarm_event: &SwarmEvent<Event>) {
1532 if let Some(ref mut metrics) = self.libp2p_metrics {
1533 match swarm_event {
1534 SwarmEvent::Behaviour(Event::Ping(ping_event)) => {
1535 metrics.record(ping_event);
1536 }
1537 SwarmEvent::Behaviour(Event::Identify(identify_event)) => {
1538 metrics.record(identify_event.as_ref());
1539 }
1540 SwarmEvent::Behaviour(Event::Kademlia(kademlia_event)) => {
1541 metrics.record(kademlia_event);
1542 }
1543 SwarmEvent::Behaviour(Event::Gossipsub(gossipsub_event)) => {
1544 metrics.record(gossipsub_event);
1545 }
1546 swarm_event => {
1551 metrics.record(swarm_event);
1552 }
1553 }
1554 }
1555 }
1556
1557 fn log_kademlia_stats(&mut self) {
1558 let mut peer_counter = 0usize;
1559 let mut peer_with_no_address_counter = 0usize;
1560 for kbucket in self.swarm.behaviour_mut().kademlia.kbuckets() {
1561 for entry in kbucket.iter() {
1562 peer_counter += 1;
1563 if entry.node.value.len() == 0 {
1564 peer_with_no_address_counter += 1;
1565 }
1566 }
1567 }
1568
1569 debug!(
1570 peers = %peer_counter,
1571 peers_with_no_address = %peer_with_no_address_counter,
1572 "Kademlia stats"
1573 );
1574 }
1575}