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