Skip to main content

hopr_transport_p2p/
lib.rs

1//! # P2P
2//!
3//! The underlying technology for managing the peer-to-peer networking used by this package is the [`rust-libp2p`](https://github.com/libp2p/rust-libp2p) library ([documentation](https://docs.libp2p.io/)).
4//!
5//! ## Modularity
6//!
7//! `rust-libp2p` is highly modular allowing for reimplmenting expected behavior using custom implementations for API
8//! traits.
9//!
10//! This way it is possible to experiment with and combine different components of the library in order to construct a
11//! specific targeted use case.
12//!
13//! ## `rust-libp2p` connectivity
14//!
15//! As per the [official documentation](https://connectivity.libp2p.io/), the connectivity types in the library are divided into the `standalone` (implementation of network over host) and `browser` (implementation of network over browser).
16//!
17//! Nodes that are not located behind a blocking firewall or NAT are designated as **public nodes** and can utilize the
18//! `TCP` or `QUIC` connectivity, with the recommendation to use QUIC if possible.
19//!
20//! Browser based solutions are almost always located behind a private network or a blocking firewall and to open a
21//! connection towards the standalone nodes these utilize either the `WebSocket` approach (by hijacking the `TCP`
22//! connection) or the (not yet fully speced up) `WebTransport` (by hijacking the `QUIC` connection).
23
24/// Constants exported by the crate.
25pub mod constants;
26
27/// Errors generated by the crate.
28pub mod errors;
29
30/// In-memory peer store for network multiaddresses.
31pub mod peer_store;
32
33/// Raw swarm definition for the HOPR network.
34pub mod swarm;
35
36/// P2P behavior definitions for the transport level interactions not related to the HOPR protocol
37mod behavior;
38
39use std::{collections::HashSet, sync::Arc};
40
41use dashmap::DashSet;
42use futures::{AsyncRead, AsyncWrite};
43pub use hopr_api::network::Health;
44use hopr_api::network::{NetworkView, traits::NetworkStreamControl};
45use libp2p::{Multiaddr, PeerId};
46
47mod utils;
48
49pub use crate::{
50    behavior::{HoprNetworkBehavior, HoprNetworkBehaviorEvent},
51    swarm::HoprLibp2pNetworkBuilder,
52};
53
54/// Events required for bootstrapping the p2p network.
55#[derive(Debug, Clone)]
56pub enum PeerDiscovery {
57    Announce(PeerId, Vec<Multiaddr>),
58}
59
60#[derive(Clone)]
61pub struct HoprNetwork {
62    tracker: Arc<DashSet<PeerId>>,
63    store: Arc<crate::peer_store::NetworkPeerStore>,
64    control: libp2p_stream::Control,
65    protocol: libp2p::StreamProtocol,
66    event_rx: async_broadcast::InactiveReceiver<hopr_api::network::NetworkEvent>,
67}
68
69impl std::fmt::Debug for HoprNetwork {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        f.debug_struct("HoprNetwork")
72            .field("tracker", &self.tracker)
73            .field("store", &self.store)
74            .field("protocol", &self.protocol)
75            .finish()
76    }
77}
78
79impl NetworkView for HoprNetwork {
80    fn listening_as(&self) -> HashSet<Multiaddr> {
81        self.store.get(self.store.me()).unwrap_or_else(|| {
82            tracing::error!("failed to get own peer info from the peer store");
83            std::collections::HashSet::new()
84        })
85    }
86
87    #[inline]
88    fn discovered_peers(&self) -> HashSet<PeerId> {
89        self.store.iter_keys().collect()
90    }
91
92    #[inline]
93    fn connected_peers(&self) -> HashSet<PeerId> {
94        self.tracker.iter().map(|r| *r).collect()
95    }
96
97    fn is_connected(&self, peer: &PeerId) -> bool {
98        self.tracker.contains(peer)
99    }
100
101    #[inline]
102    fn multiaddress_of(&self, peer: &PeerId) -> Option<HashSet<Multiaddr>> {
103        self.store.get(peer)
104    }
105
106    fn health(&self) -> Health {
107        match self.tracker.len() {
108            0 => Health::Red,
109            1 => Health::Orange,
110            2..4 => Health::Yellow,
111            _ => Health::Green,
112        }
113    }
114
115    fn subscribe_network_events(
116        &self,
117    ) -> impl futures::Stream<Item = hopr_api::network::NetworkEvent> + Send + 'static {
118        self.event_rx.clone().activate()
119    }
120}
121
122#[async_trait::async_trait]
123impl NetworkStreamControl for HoprNetwork {
124    fn accept(
125        mut self,
126    ) -> Result<impl futures::Stream<Item = (PeerId, impl AsyncRead + AsyncWrite + Send)> + Send, impl std::error::Error>
127    {
128        self.control.accept(self.protocol)
129    }
130
131    async fn open(mut self, peer: PeerId) -> Result<impl AsyncRead + AsyncWrite + Send, impl std::error::Error> {
132        self.control.open_stream(peer, self.protocol).await
133    }
134}