1use std::time::{Duration, SystemTime, UNIX_EPOCH};
5
6use crate::prelude::*;
7use crate::{blocks::GossipBlock, rpc::net::NetInfoResult};
8use crate::{chain::ChainStore, utils::encoding::from_slice_with_fallback};
9use crate::{
10 libp2p_bitswap::{BitswapStoreReadWrite, request_manager::BitswapRequestManager},
11 utils::flume::FlumeSenderExt as _,
12};
13use crate::{message::SignedMessage, networks::GenesisNetworkName};
14use ahash::{HashMap, HashSet};
15use anyhow::Context as _;
16use flume::Sender;
17use futures::{select, stream::StreamExt as _};
18pub use libp2p::gossipsub::{IdentTopic, Topic};
19use libp2p::{
20 PeerId, Swarm, SwarmBuilder,
21 autonat::NatStatus,
22 connection_limits::Exceeded,
23 core::Multiaddr,
24 gossipsub, identify,
25 identity::Keypair,
26 metrics::{Metrics, Recorder},
27 multiaddr::Protocol,
28 noise, ping, request_response,
29 swarm::{DialError, SwarmEvent},
30 tcp, yamux,
31};
32use nonzero_ext::nonzero;
33use tokio_stream::wrappers::IntervalStream;
34use tracing::{debug, error, info, trace, warn};
35
36use super::{
37 ForestBehaviour, ForestBehaviourEvent, Libp2pConfig,
38 chain_exchange::{ChainExchangeRequest, ChainExchangeResponse, make_chain_exchange_response},
39 discovery::{DerivedDiscoveryBehaviourEvent, PeerInfo},
40};
41use crate::libp2p::{
42 PeerManager, PeerOperation,
43 chain_exchange::ChainExchangeBehaviour,
44 discovery::DiscoveryEvent,
45 hello::{HelloBehaviour, HelloRequest, HelloResponse},
46 rpc::RequestResponseError,
47};
48
49pub(in crate::libp2p) mod metrics {
50 use prometheus_client::metrics::{family::Family, gauge::Gauge};
51 use std::sync::LazyLock;
52
53 use crate::metrics::KindLabel;
54
55 pub static NETWORK_CONTAINER_CAPACITIES: LazyLock<Family<KindLabel, Gauge>> = {
56 LazyLock::new(|| {
57 let metric = Family::default();
58 crate::metrics::default_registry().register(
59 "network_container_capacities",
60 "Capacity for each container",
61 metric.clone(),
62 );
63 metric
64 })
65 };
66
67 pub mod values {
68 use crate::metrics::KindLabel;
69
70 pub const HELLO_REQUEST_TABLE: KindLabel = KindLabel::new("hello_request_table");
71 pub const CHAIN_EXCHANGE_REQUEST_TABLE: KindLabel = KindLabel::new("cx_request_table");
72 }
73}
74
75crate::def_is_env_truthy!(libp2p_metrics_enabled, "FOREST_LIBP2P_METRICS_ENABLED");
76
77pub const PUBSUB_BLOCK_STR: &str = "/fil/blocks";
79pub const PUBSUB_MSG_STR: &str = "/fil/msgs";
81
82const PUBSUB_TOPICS: [&str; 2] = [PUBSUB_BLOCK_STR, PUBSUB_MSG_STR];
83
84pub const BITSWAP_TIMEOUT: Duration = Duration::from_secs(30);
85
86#[allow(clippy::large_enum_variant)]
88#[derive(Debug)]
89pub enum NetworkEvent {
90 PubsubMessage {
91 message: PubsubMessage,
92 },
93 HelloRequestInbound,
94 HelloResponseOutbound {
95 source: PeerId,
96 request: HelloRequest,
97 },
98 HelloRequestOutbound,
99 HelloResponseInbound,
100 ChainExchangeRequestOutbound,
101 ChainExchangeResponseInbound,
102 ChainExchangeRequestInbound,
103 ChainExchangeResponseOutbound,
104 PeerConnected(PeerId),
105 PeerDisconnected(PeerId),
106}
107
108#[allow(clippy::large_enum_variant)]
110#[derive(Debug, Clone)]
111pub enum PubsubMessage {
112 Block(GossipBlock),
114 Message(SignedMessage),
116}
117
118#[derive(Debug)]
120pub enum NetworkMessage {
121 PubsubMessage {
122 topic: IdentTopic,
123 message: Vec<u8>,
124 },
125 ChainExchangeRequest {
126 peer_id: PeerId,
127 request: ChainExchangeRequest,
128 response_channel: flume::Sender<Result<ChainExchangeResponse, RequestResponseError>>,
129 },
130 HelloRequest {
131 peer_id: PeerId,
132 request: HelloRequest,
133 response_channel: flume::Sender<HelloResponse>,
134 },
135 BitswapRequest {
136 cid: Cid,
137 response_channel: flume::Sender<bool>,
138 },
139 JSONRPCRequest {
140 method: NetRPCMethods,
141 },
142}
143
144#[derive(Debug)]
146pub enum NetRPCMethods {
147 AddrsListen(flume::Sender<(PeerId, HashSet<Multiaddr>)>),
148 Peer(flume::Sender<Option<HashSet<Multiaddr>>>, PeerId),
149 Peers(flume::Sender<HashMap<PeerId, HashSet<Multiaddr>>>),
150 ProtectPeer(flume::Sender<()>, HashSet<PeerId>),
151 UnprotectPeer(flume::Sender<()>, HashSet<PeerId>),
152 ListProtectedPeers(flume::Sender<HashSet<PeerId>>),
153 Info(flume::Sender<NetInfoResult>),
154 Connect(flume::Sender<bool>, PeerId, HashSet<Multiaddr>),
155 Disconnect(flume::Sender<()>, PeerId),
156 AgentVersion(flume::Sender<Option<String>>, PeerId),
157 AutoNATStatus(flume::Sender<NatStatus>),
158}
159
160pub struct Libp2pService {
162 swarm: Swarm<ForestBehaviour>,
163 bootstrap_peers: HashMap<PeerId, Multiaddr>,
164 cs: ChainStore,
165 peer_manager: Arc<PeerManager>,
166 network_receiver_in: flume::Receiver<NetworkMessage>,
167 network_sender_in: Sender<NetworkMessage>,
168 network_receiver_out: flume::Receiver<NetworkEvent>,
169 network_sender_out: Sender<NetworkEvent>,
170 network_name: String,
171 genesis_cid: Cid,
172}
173
174impl Libp2pService {
175 pub async fn new(
176 config: Libp2pConfig,
177 cs: ChainStore,
178 peer_manager: Arc<PeerManager>,
179 net_keypair: Keypair,
180 network_name: GenesisNetworkName,
181 genesis_cid: Cid,
182 ) -> anyhow::Result<Self> {
183 let behaviour =
184 ForestBehaviour::new(&net_keypair, &config, &network_name, peer_manager.clone())
185 .await?;
186 let mut swarm = SwarmBuilder::with_existing_identity(net_keypair)
187 .with_tokio()
188 .with_tcp(
189 tcp::Config::default().nodelay(true),
190 noise::Config::new,
191 yamux::Config::default,
192 )?
193 .with_quic()
194 .with_dns()?
195 .with_bandwidth_metrics(&mut crate::metrics::collector_registry())
196 .with_behaviour(|_| behaviour)?
197 .with_swarm_config(|config| {
198 config
199 .with_notify_handler_buffer_size(nonzero!(20usize))
200 .with_per_connection_event_buffer_size(64)
201 .with_idle_connection_timeout(Duration::from_secs(60 * 10))
202 })
203 .build();
204
205 for topic in PUBSUB_TOPICS.iter() {
207 let t = Topic::new(format!("{topic}/{network_name}"));
208 swarm
209 .behaviour_mut()
210 .subscribe(&t)
211 .with_context(|| format!("Failed to subscribe gossipsub topic {t}"))?;
212 }
213
214 let (network_sender_in, network_receiver_in) = flume::unbounded();
215 let (network_sender_out, network_receiver_out) = flume::unbounded();
216
217 info!("p2p network peer id: {}", swarm.local_peer_id());
221
222 for addr in &config.listening_multiaddrs {
224 match swarm.listen_on(addr.clone()) {
225 Ok(id) => loop {
226 if let SwarmEvent::NewListenAddr {
227 address,
228 listener_id,
229 } = swarm.select_next_some().await
230 && id == listener_id
231 {
232 info!("p2p peer is now listening on: {address}");
233 break;
234 }
235 },
236 Err(err) => error!("Fail to listen on {addr}: {err}"),
237 }
238 }
239
240 if swarm.listeners().count() == 0 {
241 anyhow::bail!("p2p peer failed to listen on any network endpoints");
242 }
243
244 let bootstrap_peers = config
245 .bootstrap_peers
246 .iter()
247 .filter_map(|ma| match ma.iter().last() {
248 Some(Protocol::P2p(peer)) => Some((peer, ma.clone())),
249 _ => None,
250 })
251 .collect();
252
253 Ok(Libp2pService {
254 swarm,
255 bootstrap_peers,
256 cs,
257 peer_manager,
258 network_receiver_in,
259 network_sender_in,
260 network_receiver_out,
261 network_sender_out,
262 network_name: network_name.into(),
263 genesis_cid,
264 })
265 }
266
267 pub async fn run(mut self) -> anyhow::Result<()> {
270 info!("Running libp2p service");
271
272 if let Err(e) = self.swarm.behaviour_mut().bootstrap() {
274 warn!("Failed to bootstrap with Kademlia: {e:#}");
275 }
276
277 let bitswap_request_manager = self.swarm.behaviour().bitswap.request_manager();
278 let mut swarm_stream = self.swarm.fuse();
279 let mut network_stream = self.network_receiver_in.stream().fuse();
280 let mut interval =
281 IntervalStream::new(tokio::time::interval(Duration::from_secs(15))).fuse();
282 let pubsub_block_str = format!("{}/{}", PUBSUB_BLOCK_STR, self.network_name);
283 let pubsub_msg_str = format!("{}/{}", PUBSUB_MSG_STR, self.network_name);
284
285 let (cx_response_tx, cx_response_rx) = flume::unbounded();
286
287 let mut cx_response_rx_stream = cx_response_rx.stream().fuse();
288 let mut bitswap_outbound_request_stream =
289 bitswap_request_manager.outbound_request_stream().fuse();
290 let mut peer_ops_rx_stream = self.peer_manager.peer_ops_rx().stream().fuse();
291 let metrics = if libp2p_metrics_enabled() {
292 Some(Metrics::new(&mut crate::metrics::collector_registry()))
293 } else {
294 None
295 };
296
297 const BOOTSTRAP_PEER_DIALER_INTERVAL: tokio::time::Duration =
298 tokio::time::Duration::from_secs(60);
299 let mut bootstrap_peer_dialer_interval_stream =
300 IntervalStream::new(tokio::time::interval_at(
301 tokio::time::Instant::now() + BOOTSTRAP_PEER_DIALER_INTERVAL,
302 BOOTSTRAP_PEER_DIALER_INTERVAL,
303 ))
304 .fuse();
305 loop {
306 select! {
307 swarm_event = swarm_stream.next() => match swarm_event {
308 Some(SwarmEvent::Behaviour(event)) => {
310 if let Some(m) = &metrics {
311 m.record(&event);
312 }
313 handle_forest_behaviour_event(
314 swarm_stream.get_mut(),
315 &bitswap_request_manager,
316 &self.peer_manager,
317 event,
318 &self.cs,
319 &self.genesis_cid,
320 &self.network_sender_out,
321 cx_response_tx.clone(),
322 &pubsub_block_str,
323 &pubsub_msg_str,).await;
324 },
325 None => { break; },
326 _ => { },
327 },
328 rpc_message = network_stream.next() => match rpc_message {
329 Some(message) => {
331 handle_network_message(
332 swarm_stream.get_mut(),
333 self.cs.db_owned(),
334 bitswap_request_manager.shallow_clone(),
335 message,
336 &self.network_sender_out,
337 &self.peer_manager).await;
338 }
339 None => { break; }
340 },
341 interval_event = interval.next() => if interval_event.is_some() {
342 trace!("Peers connected: {}", swarm_stream.get_mut().behaviour_mut().peers().len());
344 },
345 cs_pair_opt = cx_response_rx_stream.next() => {
346 if let Some((_request_id, channel, cx_response)) = cs_pair_opt {
347 let behaviour = swarm_stream.get_mut().behaviour_mut();
348 if let Err(e) = behaviour.chain_exchange.send_response(channel, cx_response) {
349 debug!("Error sending chain exchange response: {e:?}");
350 }
351 }
352 },
353 bitswap_outbound_request_opt = bitswap_outbound_request_stream.next() => {
354 if let Some((peer, request)) = bitswap_outbound_request_opt {
355 let bitswap = &mut swarm_stream.get_mut().behaviour_mut().bitswap;
356 bitswap.send_request(&peer, request);
357 }
358 }
359 peer_ops_opt = peer_ops_rx_stream.next() => {
360 if let Some(peer_ops) = peer_ops_opt {
361 handle_peer_ops(swarm_stream.get_mut(), peer_ops, &self.bootstrap_peers);
362 }
363 },
364 _ = bootstrap_peer_dialer_interval_stream.next() => {
365 dial_to_bootstrap_peers_if_needed(swarm_stream.get_mut(), &self.bootstrap_peers);
366 }
367 };
368 }
369 Ok(())
370 }
371
372 pub fn network_sender(&self) -> Sender<NetworkMessage> {
374 self.network_sender_in.clone()
375 }
376
377 pub fn network_receiver(&self) -> flume::Receiver<NetworkEvent> {
379 self.network_receiver_out.clone()
380 }
381
382 pub fn peer_manager(&self) -> &Arc<PeerManager> {
383 &self.peer_manager
384 }
385}
386
387fn dial_to_bootstrap_peers_if_needed(
388 swarm: &mut Swarm<ForestBehaviour>,
389 bootstrap_peers: &HashMap<PeerId, Multiaddr>,
390) {
391 for (peer, ma) in bootstrap_peers {
392 if !swarm.behaviour().peers().contains(peer) {
393 info!("Re-dialing to bootstrap peer at {ma}");
394 if let Err(e) = swarm.dial(ma.clone()) {
395 warn!("{e}");
396 }
397 }
398 }
399}
400
401fn handle_peer_ops(
402 swarm: &mut Swarm<ForestBehaviour>,
403 peer_ops: PeerOperation,
404 bootstrap_peers: &HashMap<PeerId, Multiaddr>,
405) {
406 use PeerOperation::*;
407 match peer_ops {
408 Ban {
409 peer,
410 user_agent,
411 reason,
412 } => {
413 if !bootstrap_peers.contains_key(&peer) {
415 let user_agent = user_agent.unwrap_or_default();
416 debug!(%peer, %user_agent, %reason, "Banning peer");
417 swarm.behaviour_mut().blocked_peers.block_peer(peer);
418 }
419 }
420 Unban(peer) => {
421 debug!(%peer, "Unbanning peer");
422 swarm.behaviour_mut().blocked_peers.unblock_peer(peer);
423 }
424 }
425}
426
427async fn handle_network_message(
428 swarm: &mut Swarm<ForestBehaviour>,
429 store: impl BitswapStoreReadWrite + ShallowClone,
430 bitswap_request_manager: Arc<BitswapRequestManager>,
431 message: NetworkMessage,
432 network_sender_out: &Sender<NetworkEvent>,
433 peer_manager: &PeerManager,
434) {
435 match message {
436 NetworkMessage::PubsubMessage { topic, message } => {
437 match swarm.behaviour_mut().publish(topic, message) {
438 Ok(_) => (),
439 Err(gossipsub::PublishError::Duplicate) => {
440 debug!("Failed to send gossipsub message: duplicate");
443 }
444 Err(e) => {
445 warn!("Failed to send gossipsub message: {e:#}");
446 }
447 }
448 }
449 NetworkMessage::HelloRequest {
450 peer_id,
451 request,
452 response_channel,
453 } => {
454 let _request_id =
455 swarm
456 .behaviour_mut()
457 .hello
458 .send_request(&peer_id, request, response_channel);
459 emit_event(network_sender_out, NetworkEvent::HelloRequestOutbound).await;
460 }
461 NetworkMessage::ChainExchangeRequest {
462 peer_id,
463 request,
464 response_channel,
465 } => {
466 let _request_id = swarm.behaviour_mut().chain_exchange.send_request(
467 &peer_id,
468 request,
469 response_channel,
470 );
471 emit_event(
472 network_sender_out,
473 NetworkEvent::ChainExchangeRequestOutbound,
474 )
475 .await;
476 }
477 NetworkMessage::BitswapRequest {
478 cid,
479 response_channel,
480 } => {
481 bitswap_request_manager.get_block(
482 store,
483 cid,
484 BITSWAP_TIMEOUT,
485 Some(response_channel),
486 None,
487 );
488 }
489 NetworkMessage::JSONRPCRequest { method } => {
490 match method {
491 NetRPCMethods::AddrsListen(response_channel) => {
492 let listeners = Swarm::listeners(swarm).cloned().collect();
493 let peer_id = Swarm::local_peer_id(swarm);
494 response_channel.send_or_warn((*peer_id, listeners));
495 }
496 NetRPCMethods::Peer(response_channel, peer) => {
497 let addresses = swarm.behaviour().peer_addresses().get(&peer).cloned();
498 response_channel.send_or_warn(addresses);
499 }
500 NetRPCMethods::Peers(response_channel) => {
501 let peer_addresses = swarm.behaviour().peer_addresses();
502 response_channel.send_or_warn(peer_addresses);
503 }
504 NetRPCMethods::ProtectPeer(tx, peer_ids) => {
505 peer_ids.into_iter().for_each(|peer_id| {
506 peer_manager.protect_peer(peer_id);
507 });
508 tx.send_or_warn(());
509 }
510 NetRPCMethods::ListProtectedPeers(tx) => {
511 tx.send_or_warn(peer_manager.list_protected_peers());
512 }
513 NetRPCMethods::UnprotectPeer(tx, peer_ids) => {
514 peer_ids.iter().for_each(|peer_id| {
515 peer_manager.unprotect_peer(peer_id);
516 });
517 tx.send_or_warn(());
518 }
519 NetRPCMethods::Info(response_channel) => {
520 response_channel.send_or_warn(swarm.network_info().into());
521 }
522 NetRPCMethods::Connect(response_channel, peer_id, addresses) => {
523 let mut success = false;
524 for mut multiaddr in addresses {
525 multiaddr.push(Protocol::P2p(peer_id));
526
527 match Swarm::dial(swarm, multiaddr.clone()) {
528 Ok(_) => {
529 info!("Dialed {multiaddr}");
530 success = true;
531 break;
532 }
533 Err(e) => {
534 match e {
535 DialError::Denied { cause } => {
536 if let Some(cause) = cause.downcast_ref::<Exceeded>() {
538 error!(
539 "Denied dialing (limits exceeded) {multiaddr}: {cause}"
540 );
541 } else {
542 error!("Denied dialing {multiaddr}: {cause}")
543 }
544 }
545 e => {
546 error!("Failed to dial {multiaddr}: {e}");
547 }
548 };
549 }
550 };
551 }
552
553 response_channel.send_or_warn(success);
554 }
555 NetRPCMethods::Disconnect(response_channel, peer_id) => {
556 let _ = Swarm::disconnect_peer_id(swarm, peer_id);
557 response_channel.send_or_warn(());
558 }
559 NetRPCMethods::AgentVersion(response_channel, peer_id) => {
560 let agent_version = swarm.behaviour().peer_info(&peer_id).and_then(|info| {
561 info.identify_info
562 .as_ref()
563 .map(|id| id.agent_version.clone())
564 });
565 response_channel.send_or_warn(agent_version);
566 }
567 NetRPCMethods::AutoNATStatus(response_channel) => {
568 let nat_status = swarm.behaviour().discovery.nat_status();
569 response_channel.send_or_warn(nat_status);
570 }
571 }
572 }
573 }
574}
575
576async fn handle_discovery_event(
577 peer_info_map: &HashMap<PeerId, PeerInfo>,
578 discovery_out: DiscoveryEvent,
579 network_sender_out: &Sender<NetworkEvent>,
580 peer_manager: &PeerManager,
581) {
582 match discovery_out {
583 DiscoveryEvent::PeerConnected(peer_id) => {
584 trace!("Peer connected, {peer_id}");
585 emit_event(network_sender_out, NetworkEvent::PeerConnected(peer_id)).await;
586 }
587 DiscoveryEvent::PeerDisconnected(peer_id) => {
588 trace!("Peer disconnected, {peer_id}");
589 emit_event(network_sender_out, NetworkEvent::PeerDisconnected(peer_id)).await;
590 }
591 DiscoveryEvent::Discovery(discovery_event) => match &*discovery_event {
592 DerivedDiscoveryBehaviourEvent::Identify(identify::Event::Received {
593 peer_id,
594 info,
595 ..
596 }) => {
597 let protocols = HashSet::from_iter(info.protocols.iter().map(|p| p.to_string()));
598 if !protocols.contains(super::hello::HELLO_PROTOCOL_NAME) {
599 peer_manager
600 .ban_peer_with_default_duration(
601 *peer_id,
602 "hello protocol unsupported",
603 |p| get_user_agent(peer_info_map, p),
604 )
605 .await;
606 } else if !protocols.contains(super::chain_exchange::CHAIN_EXCHANGE_PROTOCOL_NAME) {
607 peer_manager
608 .ban_peer_with_default_duration(
609 *peer_id,
610 "chain exchange protocol unsupported",
611 |p| get_user_agent(peer_info_map, p),
612 )
613 .await;
614 }
615 }
616 DerivedDiscoveryBehaviourEvent::Identify(_) => {}
617 _ => {}
618 },
619 }
620}
621
622async fn handle_gossip_event(
623 e: gossipsub::Event,
624 network_sender_out: &Sender<NetworkEvent>,
625 pubsub_block_str: &str,
626 pubsub_msg_str: &str,
627) {
628 if let gossipsub::Event::Message {
629 propagation_source: source,
630 message,
631 ..
632 } = e
633 {
634 let topic = message.topic.as_str();
635 let message = message.data;
636 trace!("Got a Gossip Message from {:?}", source);
637 if topic == pubsub_block_str {
638 match from_slice_with_fallback::<GossipBlock>(&message) {
639 Ok(b) => {
640 emit_event(
641 network_sender_out,
642 NetworkEvent::PubsubMessage {
643 message: PubsubMessage::Block(b),
644 },
645 )
646 .await;
647 }
648 Err(e) => {
649 warn!("Gossip Block from peer {source:?} could not be deserialized: {e:#}",);
650 }
651 }
652 } else if topic == pubsub_msg_str {
653 match from_slice_with_fallback::<SignedMessage>(&message) {
654 Ok(m) => {
655 emit_event(
656 network_sender_out,
657 NetworkEvent::PubsubMessage {
658 message: PubsubMessage::Message(m),
659 },
660 )
661 .await;
662 }
663 Err(e) => {
664 warn!("Gossip Message from peer {source:?} could not be deserialized: {e:#}");
665 }
666 }
667 } else {
668 warn!("Getting gossip messages from unknown topic: {topic}");
669 }
670 }
671}
672
673async fn handle_hello_event(
674 peer_info_map: &HashMap<PeerId, PeerInfo>,
675 hello: &mut HelloBehaviour,
676 event: request_response::Event<HelloRequest, HelloResponse, HelloResponse>,
677 peer_manager: &PeerManager,
678 genesis_cid: &Cid,
679 network_sender_out: &Sender<NetworkEvent>,
680) {
681 match event {
682 request_response::Event::Message { peer, message, .. } => match message {
683 request_response::Message::Request {
684 request, channel, ..
685 } => {
686 emit_event(network_sender_out, NetworkEvent::HelloRequestInbound).await;
687
688 let arrival = SystemTime::now()
689 .duration_since(UNIX_EPOCH)
690 .expect("System time before unix epoch")
691 .as_nanos()
692 .try_into()
693 .expect("System time since unix epoch should not exceed u64");
694
695 trace!("Received hello request: {:?}", request);
696 if &request.genesis_cid != genesis_cid {
697 peer_manager
698 .ban_peer_with_default_duration(
699 peer,
700 format!(
701 "Genesis hash mismatch: {} received, {genesis_cid} expected",
702 request.genesis_cid
703 ),
704 |p| get_user_agent(peer_info_map, p),
705 )
706 .await;
707 } else {
708 let sent = SystemTime::now()
709 .duration_since(UNIX_EPOCH)
710 .expect("System time before unix epoch")
711 .as_nanos()
712 .try_into()
713 .expect("System time since unix epoch should not exceed u64");
714
715 if let Err(e) = hello.send_response(channel, HelloResponse { arrival, sent }) {
718 warn!("Failed to send HelloResponse: {e:?}");
719 } else {
720 emit_event(
721 network_sender_out,
722 NetworkEvent::HelloResponseOutbound {
723 source: peer,
724 request,
725 },
726 )
727 .await;
728 }
729 }
730 }
731 request_response::Message::Response {
732 request_id,
733 response,
734 } => {
735 emit_event(network_sender_out, NetworkEvent::HelloResponseInbound).await;
736 hello.handle_response(&request_id, response).await;
737 }
738 },
739 request_response::Event::OutboundFailure {
740 request_id,
741 peer,
742 error,
743 ..
744 } => {
745 hello.on_outbound_failure(&request_id);
746 match error {
747 request_response::OutboundFailure::UnsupportedProtocols => {
748 peer_manager
749 .ban_peer_with_default_duration(peer, "Hello protocol unsupported", |p| {
750 get_user_agent(peer_info_map, p)
751 })
752 .await;
753 }
754 _ => {
755 peer_manager.mark_peer_bad(peer, format!("Hello outbound failure {error}"));
756 }
757 }
758 }
759 request_response::Event::InboundFailure { .. } => {}
760 request_response::Event::ResponseSent { .. } => (),
761 }
762}
763
764async fn handle_ping_event(ping_event: ping::Event) {
765 match ping_event.result {
766 Ok(rtt) => {
767 trace!(
768 "PingSuccess::Ping rtt to {} is {} ms",
769 ping_event.peer,
770 rtt.as_millis()
771 );
772 }
773 Err(ping::Failure::Unsupported) => {
774 debug!(peer=%ping_event.peer, "Ping protocol unsupported");
775 }
776 Err(ping::Failure::Timeout) => {
777 debug!("Ping timeout: {}", ping_event.peer);
778 }
779 Err(ping::Failure::Other { error }) => {
780 debug!("Ping failure: {error}");
781 }
782 }
783}
784
785async fn handle_chain_exchange_event(
786 chain_exchange: &mut ChainExchangeBehaviour,
787 ce_event: request_response::Event<ChainExchangeRequest, ChainExchangeResponse>,
788 db: &ChainStore,
789 network_sender_out: &Sender<NetworkEvent>,
790 cx_response_tx: Sender<(
791 request_response::InboundRequestId,
792 request_response::ResponseChannel<ChainExchangeResponse>,
793 ChainExchangeResponse,
794 )>,
795) {
796 const CHAIN_EXCHANGE_RESPONSE_TIMEOUT: Duration = Duration::from_mins(5);
797 match ce_event {
798 request_response::Event::Message { peer, message, .. } => match message {
799 request_response::Message::Request {
800 request,
801 channel,
802 request_id,
803 } => {
804 let Some(per_peer_permit) = chain_exchange.try_acquire_peer_permit(peer) else {
805 debug!("Rejecting chain_exchange request from {peer}: per-peer cap reached");
806 let _ = chain_exchange.send_response(
807 channel,
808 ChainExchangeResponse::go_away("per-peer concurrent request cap reached"),
809 );
810 return;
811 };
812 let Some(global_permit) = chain_exchange.try_acquire_request_permit() else {
813 debug!("Rejecting chain_exchange request from {peer}: global cap reached");
814 let _ = chain_exchange.send_response(
815 channel,
816 ChainExchangeResponse::go_away("global concurrent request cap reached"),
817 );
818 return;
819 };
820
821 trace!(
822 "Received chain_exchange request (request_id:{request_id}, peer_id: {peer:?})",
823 );
824 emit_event(
825 network_sender_out,
826 NetworkEvent::ChainExchangeRequestInbound,
827 )
828 .await;
829
830 let db = db.shallow_clone();
831 tokio::task::spawn(tokio::time::timeout(
832 CHAIN_EXCHANGE_RESPONSE_TIMEOUT,
833 async move {
834 let _per_peer_permit = per_peer_permit;
835 let _global_permit = global_permit;
836 if let Err(e) = cx_response_tx
837 .send_async((
838 request_id,
839 channel,
840 make_chain_exchange_response(&db, &request),
841 ))
842 .await
843 {
844 debug!("Failed to send ChainExchangeResponse: {e:?}");
845 }
846 },
847 ));
848 }
849 request_response::Message::Response {
850 request_id,
851 response,
852 } => {
853 emit_event(
854 network_sender_out,
855 NetworkEvent::ChainExchangeResponseInbound,
856 )
857 .await;
858 chain_exchange
859 .handle_inbound_response(&request_id, response)
860 .await;
861 }
862 },
863 request_response::Event::OutboundFailure {
864 request_id, error, ..
865 } => {
866 chain_exchange.on_outbound_error(&request_id, error);
867 }
868 request_response::Event::InboundFailure { peer, error, .. } => {
869 debug!(
870 "ChainExchange inbound error (peer: {:?}): {:?}",
871 peer, error
872 );
873 }
874 request_response::Event::ResponseSent { .. } => {
875 emit_event(
876 network_sender_out,
877 NetworkEvent::ChainExchangeResponseOutbound,
878 )
879 .await;
880 }
881 }
882}
883
884#[allow(clippy::too_many_arguments)]
885async fn handle_forest_behaviour_event(
886 swarm: &mut Swarm<ForestBehaviour>,
887 bitswap_request_manager: &Arc<BitswapRequestManager>,
888 peer_manager: &PeerManager,
889 event: ForestBehaviourEvent,
890 db: &ChainStore,
891 genesis_cid: &Cid,
892 network_sender_out: &Sender<NetworkEvent>,
893 cx_response_tx: Sender<(
894 request_response::InboundRequestId,
895 request_response::ResponseChannel<ChainExchangeResponse>,
896 ChainExchangeResponse,
897 )>,
898 pubsub_block_str: &str,
899 pubsub_msg_str: &str,
900) {
901 match event {
902 ForestBehaviourEvent::Discovery(discovery_out) => {
903 handle_discovery_event(
904 &swarm.behaviour().discovery.peer_info,
905 discovery_out,
906 network_sender_out,
907 peer_manager,
908 )
909 .await
910 }
911 ForestBehaviourEvent::Gossipsub(e) => {
912 handle_gossip_event(e, network_sender_out, pubsub_block_str, pubsub_msg_str).await
913 }
914 ForestBehaviourEvent::Hello(rr_event) => {
915 let behaviour_mut = swarm.behaviour_mut();
916 handle_hello_event(
917 &behaviour_mut.discovery.peer_info,
918 &mut behaviour_mut.hello,
919 rr_event,
920 peer_manager,
921 genesis_cid,
922 network_sender_out,
923 )
924 .await
925 }
926 ForestBehaviourEvent::Bitswap(event) => {
927 if let Err(e) = bitswap_request_manager.handle_event(
928 &mut swarm.behaviour_mut().bitswap,
929 db.db(),
930 event,
931 ) {
932 warn!("bitswap: {e:#}");
933 }
934 }
935 ForestBehaviourEvent::Ping(ping_event) => handle_ping_event(ping_event).await,
936 ForestBehaviourEvent::ConnectionLimits(_) => {}
937 ForestBehaviourEvent::BlockedPeers(_) => {}
938 ForestBehaviourEvent::ChainExchange(ce_event) => {
939 handle_chain_exchange_event(
940 &mut swarm.behaviour_mut().chain_exchange,
941 ce_event,
942 db,
943 network_sender_out,
944 cx_response_tx,
945 )
946 .await
947 }
948 }
949}
950
951async fn emit_event(sender: &Sender<NetworkEvent>, event: NetworkEvent) {
952 if sender.send_async(event).await.is_err() {
953 error!("Failed to emit event: Network channel receiver has been dropped");
954 }
955}
956
957fn get_user_agent(peer_info_map: &HashMap<PeerId, PeerInfo>, peer: &PeerId) -> Option<String> {
958 peer_info_map
959 .get(peer)
960 .and_then(|i| i.identify_info.as_ref())
961 .map(|i| i.agent_version.clone())
962}