1use crate::{
19 budget::{DEFAULT_BUDGET_TRY_DRAIN_NETWORK_HANDLE_CHANNEL, DEFAULT_BUDGET_TRY_DRAIN_SWARM},
20 config::NetworkConfig,
21 discovery::Discovery,
22 error::{NetworkError, ServiceKind},
23 eth_requests::IncomingEthRequest,
24 import::{BlockImport, BlockImportEvent, BlockImportOutcome, BlockValidation, NewBlockEvent},
25 listener::ConnectionListener,
26 message::{NewBlockMessage, PeerMessage},
27 metrics::{
28 BackedOffPeersMetrics, ClosedSessionsMetrics, DirectionalDisconnectMetrics, NetworkMetrics,
29 PendingSessionFailureMetrics,
30 },
31 network::{NetworkHandle, NetworkHandleMessage},
32 peers::{BackoffReason, PeersManager},
33 poll_nested_stream_with_budget,
34 protocol::IntoRlpxSubProtocol,
35 required_block_filter::RequiredBlockFilter,
36 session::SessionManager,
37 state::NetworkState,
38 swarm::{Swarm, SwarmEvent},
39 transactions::NetworkTransactionEvent,
40 FetchClient, NetworkBuilder,
41};
42use futures::{Future, StreamExt};
43use parking_lot::Mutex;
44use reth_chainspec::EnrForkIdEntry;
45use reth_eth_wire::{DisconnectReason, EthNetworkPrimitives, NetworkPrimitives};
46use reth_fs_util::{self as fs, FsPathError};
47use reth_metrics::common::mpsc::MemoryBoundedSender;
48use reth_network_api::{
49 events::{PeerEvent, SessionInfo},
50 test_utils::PeersHandle,
51 EthProtocolInfo, NetworkEvent, NetworkStatus, PeerInfo, PeerRequest,
52};
53use reth_network_peers::{NodeRecord, PeerId};
54use reth_network_types::ReputationChangeKind;
55use reth_storage_api::BlockNumReader;
56use reth_tasks::shutdown::GracefulShutdown;
57use reth_tokio_util::EventSender;
58use secp256k1::SecretKey;
59use std::{
60 net::SocketAddr,
61 path::Path,
62 pin::Pin,
63 sync::{
64 atomic::{AtomicU64, AtomicUsize, Ordering},
65 Arc,
66 },
67 task::{Context, Poll},
68 time::{Duration, Instant},
69};
70use tokio::sync::mpsc::{self, error::TrySendError};
71use tokio_stream::wrappers::UnboundedReceiverStream;
72use tracing::{debug, error, trace, warn};
73
74#[cfg_attr(doc, aquamarine::aquamarine)]
75#[derive(Debug)]
107#[must_use = "The NetworkManager does nothing unless polled"]
108pub struct NetworkManager<N: NetworkPrimitives = EthNetworkPrimitives> {
109 swarm: Swarm<N>,
111 handle: NetworkHandle<N>,
113 from_handle_rx: UnboundedReceiverStream<NetworkHandleMessage<N>>,
115 block_import: Box<dyn BlockImport<N::NewBlockPayload>>,
117 event_sender: EventSender<NetworkEvent<PeerRequest<N>>>,
119 to_transactions_manager: Option<MemoryBoundedSender<NetworkTransactionEvent<N>>>,
122 to_eth_request_handler: Option<mpsc::Sender<IncomingEthRequest<N>>>,
136 num_active_peers: Arc<AtomicUsize>,
141 metrics: NetworkMetrics,
143 disconnect_metrics: DirectionalDisconnectMetrics,
145 closed_sessions_metrics: ClosedSessionsMetrics,
147 pending_session_failure_metrics: PendingSessionFailureMetrics,
149 backed_off_peers_metrics: BackedOffPeersMetrics,
151}
152
153impl NetworkManager {
154 pub async fn eth<C: BlockNumReader + 'static>(
167 config: NetworkConfig<C, EthNetworkPrimitives>,
168 ) -> Result<Self, NetworkError> {
169 Self::new(config).await
170 }
171}
172
173impl<N: NetworkPrimitives> NetworkManager<N> {
174 pub fn with_transactions(
177 mut self,
178 tx: MemoryBoundedSender<NetworkTransactionEvent<N>>,
179 ) -> Self {
180 self.set_transactions(tx);
181 self
182 }
183
184 pub fn set_transactions(&mut self, tx: MemoryBoundedSender<NetworkTransactionEvent<N>>) {
187 self.to_transactions_manager = Some(tx);
188 }
189
190 pub fn with_eth_request_handler(mut self, tx: mpsc::Sender<IncomingEthRequest<N>>) -> Self {
193 self.set_eth_request_handler(tx);
194 self
195 }
196
197 pub fn set_eth_request_handler(&mut self, tx: mpsc::Sender<IncomingEthRequest<N>>) {
200 self.to_eth_request_handler = Some(tx);
201 }
202
203 pub fn add_rlpx_sub_protocol(&mut self, protocol: impl IntoRlpxSubProtocol) {
205 self.swarm.add_rlpx_sub_protocol(protocol)
206 }
207
208 pub const fn handle(&self) -> &NetworkHandle<N> {
212 &self.handle
213 }
214
215 pub const fn secret_key(&self) -> SecretKey {
217 self.swarm.sessions().secret_key()
218 }
219
220 #[inline]
221 fn update_poll_metrics(&self, start: Instant, poll_durations: NetworkManagerPollDurations) {
222 let metrics = &self.metrics;
223
224 let NetworkManagerPollDurations { acc_network_handle, acc_swarm } = poll_durations;
225
226 metrics.duration_poll_network_manager.set(start.elapsed().as_secs_f64());
228 metrics.acc_duration_poll_network_handle.set(acc_network_handle.as_secs_f64());
230 metrics.acc_duration_poll_swarm.set(acc_swarm.as_secs_f64());
231 }
232
233 pub async fn new<C: BlockNumReader + 'static>(
238 config: NetworkConfig<C, N>,
239 ) -> Result<Self, NetworkError> {
240 let NetworkConfig {
241 client,
242 secret_key,
243 discovery_v4_addr,
244 mut discovery_v4_config,
245 mut discovery_v5_config,
246 listener_addr,
247 peers_config,
248 sessions_config,
249 chain_id,
250 block_import,
251 network_mode,
252 boot_nodes,
253 executor,
254 hello_message,
255 status,
256 fork_filter,
257 dns_discovery_config,
258 extra_protocols,
259 tx_gossip_disabled,
260 transactions_manager_config: _,
261 nat,
262 handshake,
263 eth_max_message_size,
264 required_block_hashes,
265 } = config;
266
267 let peers_manager = PeersManager::new(peers_config);
268 let peers_handle = peers_manager.handle();
269
270 let incoming = ConnectionListener::bind(listener_addr).await.map_err(|err| {
271 NetworkError::from_io_error(err, ServiceKind::Listener(listener_addr))
272 })?;
273
274 let listener_addr = incoming.local_address();
276
277 let resolved_boot_nodes =
279 futures::future::try_join_all(boot_nodes.iter().map(|record| record.resolve())).await?;
280
281 if let Some(disc_config) = discovery_v4_config.as_mut() {
282 disc_config.bootstrap_nodes.extend(resolved_boot_nodes.clone());
284 disc_config.add_eip868_pair("eth", EnrForkIdEntry::from(status.forkid));
287 }
288
289 if let Some(discv5) = discovery_v5_config.as_mut() {
290 discv5.extend_unsigned_boot_nodes(resolved_boot_nodes)
292 }
293
294 let discovery = Discovery::new(
295 listener_addr,
296 discovery_v4_addr,
297 secret_key,
298 discovery_v4_config,
299 discovery_v5_config,
300 dns_discovery_config,
301 nat.clone(),
302 )
303 .await?;
304 let local_peer_id = discovery.local_id();
306 let discv4 = discovery.discv4();
307 let discv5 = discovery.discv5();
308
309 let num_active_peers = Arc::new(AtomicUsize::new(0));
310
311 let sessions = SessionManager::new(
312 secret_key,
313 sessions_config,
314 executor,
315 status,
316 hello_message,
317 fork_filter,
318 extra_protocols,
319 handshake,
320 eth_max_message_size,
321 network_mode.is_stake(),
322 );
323
324 let state = NetworkState::new(
325 crate::state::BlockNumReader::new(client),
326 discovery,
327 peers_manager,
328 Arc::clone(&num_active_peers),
329 );
330
331 let swarm = Swarm::new(incoming, sessions, state);
332
333 let (to_manager_tx, from_handle_rx) = mpsc::unbounded_channel();
334
335 let event_sender: EventSender<NetworkEvent<PeerRequest<N>>> = Default::default();
336
337 let handle = NetworkHandle::new(
338 Arc::clone(&num_active_peers),
339 Arc::new(Mutex::new(listener_addr)),
340 to_manager_tx,
341 secret_key,
342 local_peer_id,
343 peers_handle,
344 network_mode,
345 Arc::new(AtomicU64::new(chain_id)),
346 tx_gossip_disabled,
347 discv4,
348 discv5,
349 event_sender.clone(),
350 nat,
351 );
352
353 if !required_block_hashes.is_empty() {
355 let filter = RequiredBlockFilter::new(handle.clone(), required_block_hashes);
356 filter.spawn();
357 }
358
359 Ok(Self {
360 swarm,
361 handle,
362 from_handle_rx: UnboundedReceiverStream::new(from_handle_rx),
363 block_import,
364 event_sender,
365 to_transactions_manager: None,
366 to_eth_request_handler: None,
367 num_active_peers,
368 metrics: Default::default(),
369 disconnect_metrics: Default::default(),
370 closed_sessions_metrics: Default::default(),
371 pending_session_failure_metrics: Default::default(),
372 backed_off_peers_metrics: Default::default(),
373 })
374 }
375
376 pub async fn builder<C: BlockNumReader + 'static>(
409 config: NetworkConfig<C, N>,
410 ) -> Result<NetworkBuilder<(), (), N>, NetworkError> {
411 let network = Self::new(config).await?;
412 Ok(network.into_builder())
413 }
414
415 pub const fn into_builder(self) -> NetworkBuilder<(), (), N> {
417 NetworkBuilder { network: self, transactions: (), request_handler: () }
418 }
419
420 pub const fn local_addr(&self) -> SocketAddr {
422 self.swarm.listener().local_address()
423 }
424
425 pub fn num_connected_peers(&self) -> usize {
427 self.swarm.state().num_active_peers()
428 }
429
430 pub fn peer_id(&self) -> &PeerId {
432 self.handle.peer_id()
433 }
434
435 pub fn all_peers(&self) -> impl Iterator<Item = NodeRecord> + '_ {
437 self.swarm.peers().iter_peers()
438 }
439
440 pub fn num_known_peers(&self) -> usize {
442 self.swarm.peers().num_known_peers()
443 }
444
445 pub fn peers_handle(&self) -> PeersHandle {
449 self.swarm.peers().handle()
450 }
451
452 pub fn write_peers_to_file(&self, persistent_peers_file: &Path) -> Result<(), FsPathError> {
458 let peers = self.swarm.peers().persistable_peers().collect::<Vec<_>>();
459 persistent_peers_file.parent().map(fs::create_dir_all).transpose()?;
460 reth_fs_util::write_json_file(persistent_peers_file, &peers)?;
461 Ok(())
462 }
463
464 pub fn fetch_client(&self) -> FetchClient<N> {
469 self.swarm.state().fetch_client()
470 }
471
472 pub fn status(&self) -> NetworkStatus {
474 let sessions = self.swarm.sessions();
475 let status = sessions.status();
476 let hello_message = sessions.hello_message();
477
478 #[expect(deprecated)]
479 NetworkStatus {
480 client_version: hello_message.client_version,
481 protocol_version: hello_message.protocol_version as u64,
482 eth_protocol_info: EthProtocolInfo {
483 difficulty: None,
484 head: status.blockhash,
485 network: status.chain.id(),
486 genesis: status.genesis,
487 config: Default::default(),
488 },
489 capabilities: hello_message
490 .protocols
491 .into_iter()
492 .map(|protocol| protocol.cap)
493 .collect(),
494 }
495 }
496
497 fn notify_tx_manager(&self, event: NetworkTransactionEvent<N>) {
500 if let Some(ref tx) = self.to_transactions_manager &&
501 let Err(e) = tx.try_send(event)
502 {
503 match e {
504 TrySendError::Full(_) => {
505 trace!(target: "net", "Transaction events channel at capacity, dropping event");
506 self.metrics.total_dropped_tx_events_at_full_capacity.increment(1);
507 }
508 TrySendError::Closed(_) => {}
509 }
510 }
511 }
512
513 fn delegate_eth_request(&self, event: IncomingEthRequest<N>) {
516 if let Some(ref reqs) = self.to_eth_request_handler {
517 let _ = reqs.try_send(event).map_err(|e| {
518 if let TrySendError::Full(_) = e {
519 debug!(target:"net", "EthRequestHandler channel is full!");
520 self.metrics.total_dropped_eth_requests_at_full_capacity.increment(1);
521 }
522 });
523 }
524 }
525
526 fn on_eth_request(&self, peer_id: PeerId, req: PeerRequest<N>) {
528 match req {
529 PeerRequest::GetBlockHeaders { request, response } => {
530 self.delegate_eth_request(IncomingEthRequest::GetBlockHeaders {
531 peer_id,
532 request,
533 response,
534 })
535 }
536 PeerRequest::GetBlockBodies { request, response } => {
537 self.delegate_eth_request(IncomingEthRequest::GetBlockBodies {
538 peer_id,
539 request,
540 response,
541 })
542 }
543 PeerRequest::GetNodeData { request, response } => {
544 self.delegate_eth_request(IncomingEthRequest::GetNodeData {
545 peer_id,
546 request,
547 response,
548 })
549 }
550 PeerRequest::GetReceipts { request, response } => {
551 self.delegate_eth_request(IncomingEthRequest::GetReceipts {
552 peer_id,
553 request,
554 response,
555 })
556 }
557 PeerRequest::GetReceipts69 { request, response } => {
558 self.delegate_eth_request(IncomingEthRequest::GetReceipts69 {
559 peer_id,
560 request,
561 response,
562 })
563 }
564 PeerRequest::GetReceipts70 { request, response } => {
565 self.delegate_eth_request(IncomingEthRequest::GetReceipts70 {
566 peer_id,
567 request,
568 response,
569 })
570 }
571 PeerRequest::GetBlockAccessLists { request, response } => {
572 self.delegate_eth_request(IncomingEthRequest::GetBlockAccessLists {
573 peer_id,
574 request,
575 response,
576 })
577 }
578 PeerRequest::GetCells { request, response } => self
579 .delegate_eth_request(IncomingEthRequest::GetCells { peer_id, request, response }),
580 PeerRequest::GetPooledTransactions { request, response } => {
581 self.notify_tx_manager(NetworkTransactionEvent::GetPooledTransactions {
582 peer_id,
583 request,
584 response,
585 });
586 }
587 PeerRequest::GetSnap { request, response } => self
588 .delegate_eth_request(IncomingEthRequest::GetSnap { peer_id, request, response }),
589 }
590 }
591
592 fn on_block_import_result(&mut self, event: BlockImportEvent<N::NewBlockPayload>) {
594 match event {
595 BlockImportEvent::Announcement(validation) => match validation {
596 BlockValidation::ValidHeader { block } => {
597 self.swarm.state_mut().announce_new_block(block);
598 }
599 BlockValidation::ValidBlock { block } => {
600 self.swarm.state_mut().announce_new_block_hash(block);
601 }
602 },
603 BlockImportEvent::Outcome(outcome) => {
604 let BlockImportOutcome { peer, result } = outcome;
605 match result {
606 Ok(validated_block) => match validated_block {
607 BlockValidation::ValidHeader { block } => {
608 self.swarm.state_mut().update_peer_block(
609 &peer,
610 block.hash,
611 block.number(),
612 );
613 self.swarm.state_mut().announce_new_block(block);
614 }
615 BlockValidation::ValidBlock { block } => {
616 self.swarm.state_mut().announce_new_block_hash(block);
617 }
618 },
619 Err(_err) => {
620 self.swarm
621 .state_mut()
622 .peers_mut()
623 .apply_reputation_change(&peer, ReputationChangeKind::BadBlock);
624 }
625 }
626 }
627 }
628 }
629
630 fn within_pow_or_disconnect<F>(&mut self, peer_id: PeerId, only_pow: F)
636 where
637 F: FnOnce(&mut Self),
638 {
639 if self.handle.mode().is_stake() {
641 self.swarm
643 .sessions_mut()
644 .disconnect(peer_id, Some(DisconnectReason::SubprotocolSpecific));
645 } else {
646 only_pow(self);
647 }
648 }
649
650 fn on_peer_message(&mut self, peer_id: PeerId, msg: PeerMessage<N>) {
652 match msg {
653 PeerMessage::NewBlockHashes(hashes) => {
654 self.within_pow_or_disconnect(peer_id, |this| {
655 this.swarm.state_mut().on_new_block_hashes(peer_id, hashes.to_vec());
657 this.block_import.on_new_block(peer_id, NewBlockEvent::Hashes(hashes));
659 })
660 }
661 PeerMessage::NewBlock(block) => {
662 self.within_pow_or_disconnect(peer_id, move |this| {
663 this.swarm.state_mut().on_new_block(peer_id, block.hash);
664 this.block_import.on_new_block(peer_id, NewBlockEvent::Block(block));
666 });
667 }
668 PeerMessage::PooledTransactions(msg) => {
669 self.notify_tx_manager(NetworkTransactionEvent::IncomingPooledTransactionHashes {
670 peer_id,
671 msg,
672 });
673 }
674 PeerMessage::EthRequest(req) => {
675 self.on_eth_request(peer_id, req);
676 }
677 PeerMessage::ReceivedTransaction(msg) => {
678 self.notify_tx_manager(NetworkTransactionEvent::IncomingTransactions {
679 peer_id,
680 msg,
681 });
682 }
683 PeerMessage::SendTransactions(_) | PeerMessage::SendBroadcastPoolTransactions(_) => {
684 unreachable!("Not emitted by session")
685 }
686 PeerMessage::BlockRangeUpdated(_) => {}
687 PeerMessage::Other(other) => {
688 debug!(target: "net", message_id=%other.id, "Ignoring unsupported message");
689 }
690 }
691 }
692
693 fn on_handle_message(&mut self, msg: NetworkHandleMessage<N>) {
695 match msg {
696 NetworkHandleMessage::DiscoveryListener(tx) => {
697 self.swarm.state_mut().discovery_mut().add_listener(tx);
698 }
699 NetworkHandleMessage::AnnounceBlock(block, hash) => {
700 if self.handle.mode().is_stake() {
701 warn!(target: "net", "Peer performed block propagation, but it is not supported in proof of stake (EIP-3675)");
703 return
704 }
705 let msg = NewBlockMessage { hash, block: Arc::new(block) };
706 self.swarm.state_mut().announce_new_block(msg);
707 }
708 NetworkHandleMessage::EthRequest { peer_id, request } => {
709 self.swarm.sessions_mut().send_message(&peer_id, PeerMessage::EthRequest(request))
710 }
711 NetworkHandleMessage::SendTransaction { peer_id, msg } => {
712 self.swarm.sessions_mut().send_message(&peer_id, PeerMessage::SendTransactions(msg))
713 }
714 NetworkHandleMessage::SendBroadcastPoolTransactions { peer_id, msg } => self
715 .swarm
716 .sessions_mut()
717 .send_message(&peer_id, PeerMessage::SendBroadcastPoolTransactions(msg)),
718 NetworkHandleMessage::SendPooledTransactionHashes { peer_id, msg } => self
719 .swarm
720 .sessions_mut()
721 .send_message(&peer_id, PeerMessage::PooledTransactions(msg)),
722 NetworkHandleMessage::AddTrustedPeerId(peer_id) => {
723 self.swarm.state_mut().add_trusted_peer_id(peer_id);
724 }
725 NetworkHandleMessage::AddTrustedPeerNode(trusted_peer) => {
726 if !self.swarm.is_shutting_down() {
727 self.swarm.state_mut().add_trusted_peer_node(trusted_peer);
728 }
729 }
730 NetworkHandleMessage::AddPeerAddress(peer, kind, addr) => {
731 if !self.swarm.is_shutting_down() {
733 self.swarm.state_mut().add_peer_kind(peer, kind, addr);
734 }
735 }
736 NetworkHandleMessage::RemovePeer(peer_id, kind) => {
737 self.swarm.state_mut().remove_peer_kind(peer_id, kind);
738 }
739 NetworkHandleMessage::DisconnectPeer(peer_id, reason) => {
740 self.swarm.sessions_mut().disconnect(peer_id, reason);
741 }
742 NetworkHandleMessage::BanPeer(peer_id) => {
743 self.swarm.peers_mut().ban_peer_by_admin(peer_id);
744 }
745 NetworkHandleMessage::UnbanPeer(peer_id) => {
746 self.swarm.peers_mut().unban_peer_by_admin(peer_id);
747 }
748 NetworkHandleMessage::ConnectPeer(peer_id, kind, addr) => {
749 self.swarm.state_mut().add_and_connect(peer_id, kind, addr);
750 }
751 NetworkHandleMessage::SetNetworkState(net_state) => {
752 self.swarm.on_network_state_change(net_state);
757 }
758
759 NetworkHandleMessage::Shutdown(tx) => {
760 self.perform_network_shutdown();
761 let _ = tx.send(());
762 }
763 NetworkHandleMessage::ReputationChange(peer_id, kind) => {
764 self.swarm.peers_mut().apply_reputation_change(&peer_id, kind);
765 }
766 NetworkHandleMessage::GetReputationById(peer_id, tx) => {
767 let _ = tx.send(self.swarm.peers().get_reputation(&peer_id));
768 }
769 NetworkHandleMessage::FetchClient(tx) => {
770 let _ = tx.send(self.fetch_client());
771 }
772 NetworkHandleMessage::GetStatus(tx) => {
773 let _ = tx.send(self.status());
774 }
775 NetworkHandleMessage::StatusUpdate { head } => {
776 if let Some(transition) = self.swarm.sessions_mut().on_status_update(head) {
777 self.swarm.state_mut().update_fork_id(transition.current);
778 }
779 }
780 NetworkHandleMessage::SetForkFilter { fork_filter } => {
781 let fork_id = self.swarm.sessions_mut().set_fork_filter(fork_filter);
782 self.swarm.state_mut().update_fork_id(fork_id);
783 }
784 NetworkHandleMessage::GetPeerInfos(tx) => {
785 let _ = tx.send(self.get_peer_infos());
786 }
787 NetworkHandleMessage::GetPeerInfoById(peer_id, tx) => {
788 let _ = tx.send(self.get_peer_info_by_id(peer_id));
789 }
790 NetworkHandleMessage::GetPeerInfosByIds(peer_ids, tx) => {
791 let _ = tx.send(self.get_peer_infos_by_ids(peer_ids));
792 }
793 NetworkHandleMessage::GetPeerInfosByPeerKind(kind, tx) => {
794 let peer_ids = self.swarm.peers().peers_by_kind(kind);
795 let _ = tx.send(self.get_peer_infos_by_ids(peer_ids));
796 }
797 NetworkHandleMessage::AddRlpxSubProtocol(proto) => self.add_rlpx_sub_protocol(proto),
798 NetworkHandleMessage::GetTransactionsHandle(tx) => {
799 if let Some(ref tx_inner) = self.to_transactions_manager {
800 let _ = tx_inner.try_send(NetworkTransactionEvent::GetTransactionsHandle(tx));
801 } else {
802 let _ = tx.send(None);
803 }
804 }
805 NetworkHandleMessage::InternalBlockRangeUpdate(block_range_update) => {
806 self.swarm.sessions_mut().update_advertised_block_range(block_range_update);
807 }
808 NetworkHandleMessage::EthMessage { peer_id, message } => {
809 self.swarm.sessions_mut().send_message(&peer_id, message)
810 }
811 }
812 }
813
814 fn on_swarm_event(&mut self, event: SwarmEvent<N>) {
815 match event {
817 SwarmEvent::ValidMessage { peer_id, message } => self.on_peer_message(peer_id, message),
818 SwarmEvent::TcpListenerClosed { remote_addr } => {
819 trace!(target: "net", ?remote_addr, "TCP listener closed.");
820 }
821 SwarmEvent::TcpListenerError(err) => {
822 trace!(target: "net", %err, "TCP connection error.");
823 }
824 SwarmEvent::IncomingTcpConnection { remote_addr, session_id } => {
825 trace!(target: "net", ?session_id, ?remote_addr, "Incoming connection");
826 self.metrics.total_incoming_connections.increment(1);
827 self.update_pending_connection_metrics();
828 self.metrics
829 .incoming_connections
830 .set(self.swarm.peers().num_inbound_connections() as f64);
831 }
832 SwarmEvent::OutgoingTcpConnection { remote_addr, peer_id } => {
833 trace!(target: "net", ?remote_addr, ?peer_id, "Starting outbound connection.");
834 self.metrics.total_outgoing_connections.increment(1);
835 self.update_pending_connection_metrics()
836 }
837 SwarmEvent::SessionEstablished {
838 peer_id,
839 remote_addr,
840 client_version,
841 capabilities,
842 version,
843 messages,
844 status,
845 direction,
846 } => {
847 let total_active = self.num_active_peers.fetch_add(1, Ordering::Relaxed) + 1;
848 self.metrics.connected_peers.set(total_active as f64);
849 debug!(
850 target: "net",
851 ?remote_addr,
852 %client_version,
853 ?peer_id,
854 ?total_active,
855 kind=%direction,
856 peer_enode=%NodeRecord::new(remote_addr, peer_id),
857 "Session established"
858 );
859
860 if direction.is_incoming() {
861 self.swarm
862 .state_mut()
863 .peers_mut()
864 .on_incoming_session_established(peer_id, remote_addr);
865 }
866
867 if direction.is_outgoing() {
868 self.swarm.peers_mut().on_active_outgoing_established(peer_id);
869 }
870
871 self.update_active_connection_metrics();
872 self.update_pending_connection_metrics();
873
874 let peer_kind = self
875 .swarm
876 .state()
877 .peers()
878 .peer_by_id(peer_id)
879 .map(|(_, kind)| kind)
880 .unwrap_or_default();
881 let session_info = SessionInfo {
882 peer_id,
883 remote_addr,
884 client_version,
885 capabilities,
886 status,
887 version,
888 peer_kind,
889 };
890
891 self.event_sender
892 .notify(NetworkEvent::ActivePeerSession { info: session_info, messages });
893 }
894 SwarmEvent::PeerAdded(peer_id) => {
895 trace!(target: "net", ?peer_id, "Peer added");
896 self.event_sender.notify(NetworkEvent::Peer(PeerEvent::PeerAdded(peer_id)));
897 self.metrics.tracked_peers.set(self.swarm.peers().num_known_peers() as f64);
898 }
899 SwarmEvent::PeerRemoved(peer_id) => {
900 trace!(target: "net", ?peer_id, "Peer dropped");
901 self.event_sender.notify(NetworkEvent::Peer(PeerEvent::PeerRemoved(peer_id)));
902 self.metrics.tracked_peers.set(self.swarm.peers().num_known_peers() as f64);
903 }
904 SwarmEvent::SessionClosed { peer_id, remote_addr, error } => {
905 let total_active = self.num_active_peers.fetch_sub(1, Ordering::Relaxed) - 1;
906 self.metrics.connected_peers.set(total_active as f64);
907 trace!(
908 target: "net",
909 ?remote_addr,
910 ?peer_id,
911 ?total_active,
912 ?error,
913 "Session disconnected"
914 );
915
916 let is_inbound = self.swarm.peers().is_inbound_peer(&peer_id);
918
919 let reason = if let Some(ref err) = error {
920 self.swarm.peers_mut().on_active_session_dropped(&remote_addr, &peer_id, err);
923 self.backed_off_peers_metrics.increment_for_reason(
924 BackoffReason::from_disconnect(err.as_disconnected()),
925 );
926 err.as_disconnected()
927 } else {
928 self.swarm.peers_mut().on_active_session_gracefully_closed(peer_id);
930 self.backed_off_peers_metrics
931 .increment_for_reason(BackoffReason::GracefulClose);
932 None
933 };
934 self.closed_sessions_metrics.active.increment(1);
935 self.update_active_connection_metrics();
936
937 if let Some(reason) = reason {
938 if is_inbound {
939 self.disconnect_metrics.increment_inbound(reason);
940 } else {
941 self.disconnect_metrics.increment_outbound(reason);
942 }
943 }
944 self.metrics.backed_off_peers.set(self.swarm.peers().num_backed_off_peers() as f64);
945 self.event_sender
946 .notify(NetworkEvent::Peer(PeerEvent::SessionClosed { peer_id, reason }));
947 }
948 SwarmEvent::IncomingPendingSessionClosed { remote_addr, error } => {
949 trace!(
950 target: "net",
951 ?remote_addr,
952 ?error,
953 "Incoming pending session failed"
954 );
955
956 if let Some(ref err) = error {
957 self.swarm
958 .state_mut()
959 .peers_mut()
960 .on_incoming_pending_session_dropped(remote_addr, err);
961 self.pending_session_failure_metrics.inbound.increment(1);
962 if let Some(reason) = err.as_disconnected() {
963 self.disconnect_metrics.increment_inbound(reason);
964 }
965 } else {
966 self.swarm
967 .state_mut()
968 .peers_mut()
969 .on_incoming_pending_session_gracefully_closed();
970 }
971 self.closed_sessions_metrics.incoming_pending.increment(1);
972 self.update_pending_connection_metrics();
973 self.metrics
974 .incoming_connections
975 .set(self.swarm.peers().num_inbound_connections() as f64);
976 }
977 SwarmEvent::OutgoingPendingSessionClosed { remote_addr, peer_id, error } => {
978 trace!(
979 target: "net",
980 ?remote_addr,
981 ?peer_id,
982 ?error,
983 "Outgoing pending session failed"
984 );
985
986 if let Some(ref err) = error {
987 self.swarm.peers_mut().on_outgoing_pending_session_dropped(
988 &remote_addr,
989 &peer_id,
990 err,
991 );
992 self.pending_session_failure_metrics.outbound.increment(1);
993 self.backed_off_peers_metrics.increment_for_reason(
994 BackoffReason::from_disconnect(err.as_disconnected()),
995 );
996 if let Some(reason) = err.as_disconnected() {
997 self.disconnect_metrics.increment_outbound(reason);
998 }
999 } else {
1000 self.swarm
1001 .state_mut()
1002 .peers_mut()
1003 .on_outgoing_pending_session_gracefully_closed(&peer_id);
1004 }
1005 self.closed_sessions_metrics.outgoing_pending.increment(1);
1006 self.update_pending_connection_metrics();
1007 self.metrics.backed_off_peers.set(self.swarm.peers().num_backed_off_peers() as f64);
1008 }
1009 SwarmEvent::OutgoingConnectionError { remote_addr, peer_id, error } => {
1010 trace!(
1011 target: "net",
1012 ?remote_addr,
1013 ?peer_id,
1014 %error,
1015 "Outgoing connection error"
1016 );
1017
1018 self.swarm.peers_mut().on_outgoing_connection_failure(
1019 &remote_addr,
1020 &peer_id,
1021 &error,
1022 );
1023
1024 self.backed_off_peers_metrics.increment_for_reason(BackoffReason::ConnectionError);
1025 self.metrics.backed_off_peers.set(self.swarm.peers().num_backed_off_peers() as f64);
1026 self.update_pending_connection_metrics();
1027 }
1028 SwarmEvent::BadMessage { peer_id } => {
1029 self.swarm
1030 .state_mut()
1031 .peers_mut()
1032 .apply_reputation_change(&peer_id, ReputationChangeKind::BadMessage);
1033 self.metrics.invalid_messages_received.increment(1);
1034 }
1035 SwarmEvent::ProtocolBreach { peer_id } => {
1036 self.swarm
1037 .state_mut()
1038 .peers_mut()
1039 .apply_reputation_change(&peer_id, ReputationChangeKind::BadProtocol);
1040 }
1041 }
1042 }
1043
1044 fn get_peer_infos(&self) -> Vec<PeerInfo> {
1046 self.swarm
1047 .sessions()
1048 .active_sessions()
1049 .iter()
1050 .filter_map(|(&peer_id, session)| {
1051 self.swarm
1052 .state()
1053 .peers()
1054 .peer_by_id(peer_id)
1055 .map(|(record, kind)| session.peer_info(&record, kind))
1056 })
1057 .collect()
1058 }
1059
1060 fn get_peer_info_by_id(&self, peer_id: PeerId) -> Option<PeerInfo> {
1064 self.swarm.sessions().active_sessions().get(&peer_id).and_then(|session| {
1065 self.swarm
1066 .state()
1067 .peers()
1068 .peer_by_id(peer_id)
1069 .map(|(record, kind)| session.peer_info(&record, kind))
1070 })
1071 }
1072
1073 fn get_peer_infos_by_ids(&self, peer_ids: impl IntoIterator<Item = PeerId>) -> Vec<PeerInfo> {
1077 peer_ids.into_iter().filter_map(|peer_id| self.get_peer_info_by_id(peer_id)).collect()
1078 }
1079
1080 #[inline]
1082 fn update_active_connection_metrics(&self) {
1083 self.metrics.incoming_connections.set(self.swarm.peers().num_inbound_connections() as f64);
1084 self.metrics.outgoing_connections.set(self.swarm.peers().num_outbound_connections() as f64);
1085 }
1086
1087 #[inline]
1089 fn update_pending_connection_metrics(&self) {
1090 self.metrics
1091 .pending_outgoing_connections
1092 .set(self.swarm.peers().num_pending_outbound_connections() as f64);
1093 self.metrics
1094 .total_pending_connections
1095 .set(self.swarm.sessions().num_pending_connections() as f64);
1096 }
1097
1098 pub async fn run_until_graceful_shutdown<F, R>(
1102 mut self,
1103 shutdown: GracefulShutdown,
1104 shutdown_hook: F,
1105 ) -> R
1106 where
1107 F: FnOnce(Self) -> R,
1108 {
1109 let mut graceful_guard = None;
1110 tokio::select! {
1111 _ = &mut self => {},
1112 guard = shutdown => {
1113 graceful_guard = Some(guard);
1114 },
1115 }
1116
1117 self.perform_network_shutdown();
1118 let res = shutdown_hook(self);
1119 drop(graceful_guard);
1120 res
1121 }
1122
1123 fn perform_network_shutdown(&mut self) {
1126 self.swarm.on_shutdown_requested();
1130 self.swarm.sessions_mut().disconnect_all(Some(DisconnectReason::ClientQuitting));
1132 self.swarm.sessions_mut().disconnect_all_pending();
1134 }
1135}
1136
1137impl<N: NetworkPrimitives> Future for NetworkManager<N> {
1138 type Output = ();
1139
1140 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1141 let start = Instant::now();
1142 let mut poll_durations = NetworkManagerPollDurations::default();
1143
1144 let this = self.get_mut();
1145
1146 while let Poll::Ready(outcome) = this.block_import.poll(cx) {
1148 this.on_block_import_result(outcome);
1149 }
1150
1151 let start_network_handle = Instant::now();
1175 let maybe_more_handle_messages = poll_nested_stream_with_budget!(
1176 "net",
1177 "Network message channel",
1178 DEFAULT_BUDGET_TRY_DRAIN_NETWORK_HANDLE_CHANNEL,
1179 this.from_handle_rx.poll_next_unpin(cx),
1180 |msg| this.on_handle_message(msg),
1181 error!("Network channel closed");
1182 );
1183 poll_durations.acc_network_handle = start_network_handle.elapsed();
1184
1185 let maybe_more_swarm_events = poll_nested_stream_with_budget!(
1187 "net",
1188 "Swarm events stream",
1189 DEFAULT_BUDGET_TRY_DRAIN_SWARM,
1190 this.swarm.poll_next_unpin(cx),
1191 |event| this.on_swarm_event(event),
1192 );
1193 poll_durations.acc_swarm =
1194 start_network_handle.elapsed() - poll_durations.acc_network_handle;
1195
1196 if maybe_more_handle_messages || maybe_more_swarm_events {
1198 cx.waker().wake_by_ref();
1200 return Poll::Pending
1201 }
1202
1203 this.update_poll_metrics(start, poll_durations);
1204
1205 Poll::Pending
1206 }
1207}
1208
1209#[derive(Debug, Default)]
1210struct NetworkManagerPollDurations {
1211 acc_network_handle: Duration,
1212 acc_swarm: Duration,
1213}
1214
1215#[cfg(test)]
1216mod tests {
1217 use super::*;
1218 use crate::{NetworkConfigBuilder, PeersConfig, SessionsConfig};
1219 use futures::{future::poll_fn, task::noop_waker_ref};
1220 use metrics::{atomics::AtomicU64, Gauge};
1221 use reth_network_types::{PeerAddr, PeerKind, SessionLimits};
1222 use reth_storage_api::noop::NoopProvider;
1223 use reth_tasks::Runtime;
1224 use tokio::net::{TcpListener, TcpStream};
1225
1226 #[tokio::test]
1227 async fn rejected_dials_release_slots_and_refill() {
1228 for limit in [Some(0), Some(1), None] {
1229 let mut networks = Vec::new();
1230 for index in 0..3 {
1231 let sessions = SessionsConfig {
1232 limits: SessionLimits {
1233 max_pending_outbound: if index == 0 { limit } else { None },
1234 ..Default::default()
1235 },
1236 ..Default::default()
1237 };
1238 let config = NetworkConfigBuilder::<EthNetworkPrimitives>::new(
1239 SecretKey::new(&mut rand_08::thread_rng()),
1240 Runtime::test(),
1241 )
1242 .disable_discovery()
1243 .listener_addr("127.0.0.1:0".parse().unwrap())
1244 .peer_config(PeersConfig::test().with_max_outbound(2))
1245 .sessions_config(sessions)
1246 .build(NoopProvider::default());
1247 networks.push(NetworkManager::new(config).await.unwrap());
1248 }
1249 let (local, remotes) = networks.split_first_mut().unwrap();
1250 for remote in remotes.iter() {
1251 local.swarm.peers_mut().add_and_connect_kind(
1252 *remote.peer_id(),
1253 PeerKind::Basic,
1254 PeerAddr::from_tcp(remote.swarm.listener().local_address()),
1255 None,
1256 );
1257 }
1258 let mut cx = Context::from_waker(noop_waker_ref());
1259 assert!(Pin::new(&mut *local).poll(&mut cx).is_pending());
1260 assert_eq!(
1261 local.swarm.peers().num_pending_outbound_connections(),
1262 limit.map_or(2, |limit| limit as usize),
1263 );
1264 assert_eq!(local.swarm.peers().num_outbound_connections(), 0);
1265 if limit == Some(0) {
1266 continue
1267 }
1268
1269 tokio::time::timeout(
1270 Duration::from_secs(5),
1271 poll_fn(|cx| {
1272 assert!(Pin::new(&mut *local).poll(cx).is_pending());
1273 for remote in remotes.iter_mut() {
1274 assert!(Pin::new(remote).poll(cx).is_pending());
1275 }
1276 if local.swarm.peers().num_outbound_connections() == 2 {
1277 Poll::Ready(())
1278 } else {
1279 Poll::Pending
1280 }
1281 }),
1282 )
1283 .await
1284 .expect("rejected peers must be retried after session capacity becomes available");
1285 assert_eq!(local.swarm.peers().num_pending_outbound_connections(), 0);
1286 }
1287 }
1288
1289 #[tokio::test]
1290 async fn inbound_replacement_refreshes_pending_connection_metrics() {
1291 let config = || {
1292 NetworkConfigBuilder::<EthNetworkPrimitives>::new(
1293 SecretKey::new(&mut rand_08::thread_rng()),
1294 Runtime::test(),
1295 )
1296 .disable_discovery()
1297 .listener_addr("127.0.0.1:0".parse().unwrap())
1298 .peer_config(PeersConfig::test())
1299 .build(NoopProvider::default())
1300 };
1301 let mut local = NetworkManager::new(config()).await.unwrap();
1302 let mut remote = NetworkManager::new(config()).await.unwrap();
1303 let stalled = TcpListener::bind("127.0.0.1:0").await.unwrap();
1304 let pending_outgoing = Arc::new(AtomicU64::new(0));
1305 let total_pending = Arc::new(AtomicU64::new(0));
1306 local.metrics.pending_outgoing_connections = Gauge::from_arc(pending_outgoing.clone());
1307 local.metrics.total_pending_connections = Gauge::from_arc(total_pending.clone());
1308 local.swarm.peers_mut().add_and_connect_kind(
1309 *remote.peer_id(),
1310 PeerKind::Basic,
1311 PeerAddr::from_tcp(stalled.local_addr().unwrap()),
1312 None,
1313 );
1314 assert!(futures::poll!(Pin::new(&mut local)).is_pending());
1315 assert_eq!(f64::from_bits(pending_outgoing.load(Ordering::Relaxed)), 1.0);
1316 remote.swarm.peers_mut().add_and_connect_kind(
1317 *local.peer_id(),
1318 PeerKind::Basic,
1319 PeerAddr::from_tcp(local.local_addr()),
1320 None,
1321 );
1322 tokio::time::timeout(
1323 Duration::from_secs(5),
1324 poll_fn(|cx| {
1325 assert!(Pin::new(&mut local).poll(cx).is_pending());
1326 assert!(Pin::new(&mut remote).poll(cx).is_pending());
1327 if local.swarm.peers().num_inbound_connections() == 1 {
1328 Poll::Ready(())
1329 } else {
1330 Poll::Pending
1331 }
1332 }),
1333 )
1334 .await
1335 .unwrap();
1336 assert_eq!(local.swarm.peers().num_pending_outbound_connections(), 0);
1337 assert_eq!(f64::from_bits(pending_outgoing.load(Ordering::Relaxed)), 0.0);
1338 assert_eq!(f64::from_bits(total_pending.load(Ordering::Relaxed)), 0.0);
1339 }
1340
1341 #[tokio::test]
1342 async fn incoming_handshake_failure_refreshes_pending_connection_metrics() {
1343 let config = NetworkConfigBuilder::<EthNetworkPrimitives>::new(
1344 SecretKey::new(&mut rand_08::thread_rng()),
1345 Runtime::test(),
1346 )
1347 .disable_discovery()
1348 .listener_addr("127.0.0.1:0".parse().unwrap())
1349 .peer_config(PeersConfig::test())
1350 .build(NoopProvider::default());
1351 let mut network = NetworkManager::new(config).await.unwrap();
1352 let total_pending = Arc::new(AtomicU64::new(0));
1353 network.metrics.total_pending_connections = Gauge::from_arc(total_pending.clone());
1354 let stream = TcpStream::connect(network.local_addr()).await.unwrap();
1355 tokio::time::timeout(
1356 Duration::from_secs(5),
1357 poll_fn(|cx| {
1358 assert!(Pin::new(&mut network).poll(cx).is_pending());
1359 if network.swarm.sessions().num_pending_connections() == 1 {
1360 Poll::Ready(())
1361 } else {
1362 Poll::Pending
1363 }
1364 }),
1365 )
1366 .await
1367 .unwrap();
1368 assert_eq!(f64::from_bits(total_pending.load(Ordering::Relaxed)), 1.0);
1369 drop(stream);
1370 tokio::time::timeout(
1371 Duration::from_secs(5),
1372 poll_fn(|cx| {
1373 assert!(Pin::new(&mut network).poll(cx).is_pending());
1374 if network.swarm.sessions().num_pending_connections() == 0 {
1375 Poll::Ready(())
1376 } else {
1377 Poll::Pending
1378 }
1379 }),
1380 )
1381 .await
1382 .unwrap();
1383 assert_eq!(f64::from_bits(total_pending.load(Ordering::Relaxed)), 0.0);
1384 }
1385}