Skip to main content

reth_network/
manager.rs

1//! High level network management.
2//!
3//! The [`NetworkManager`] contains the state of the network as a whole. It controls how connections
4//! are handled and keeps track of connections to peers.
5//!
6//! ## Capabilities
7//!
8//! The network manages peers depending on their announced capabilities via their `RLPx` sessions. Most importantly the [Ethereum Wire Protocol](https://github.com/ethereum/devp2p/blob/master/caps/eth.md)(`eth`).
9//!
10//! ## Overview
11//!
12//! The [`NetworkManager`] is responsible for advancing the state of the `network`. The `network` is
13//! made up of peer-to-peer connections between nodes that are available on the same network.
14//! Responsible for peer discovery is ethereum's discovery protocol (discv4, discv5). If the address
15//! (IP+port) of our node is published via discovery, remote peers can initiate inbound connections
16//! to the local node. Once a (tcp) connection is established, both peers start to authenticate a [RLPx session](https://github.com/ethereum/devp2p/blob/master/rlpx.md) via a handshake. If the handshake was successful, both peers announce their capabilities and are now ready to exchange sub-protocol messages via the `RLPx` session.
17
18use 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, NETWORK_POOL_TRANSACTIONS_SCOPE,
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::UnboundedMeteredSender;
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// TODO: Inlined diagram due to a bug in aquamarine library, should become an include when it's
76// fixed. See https://github.com/mersinvald/aquamarine/issues/50
77// include_mmd!("docs/mermaid/network-manager.mmd")
78/// Manages the _entire_ state of the network.
79///
80/// This is an endless [`Future`] that consistently drives the state of the entire network forward.
81///
82/// The [`NetworkManager`] is the container type for all parts involved with advancing the network.
83///
84/// ```mermaid
85/// graph TB
86///   handle(NetworkHandle)
87///   events(NetworkEvents)
88///   transactions(Transactions Task)
89///   ethrequest(ETH Request Task)
90///   discovery(Discovery Task)
91///   subgraph NetworkManager
92///     direction LR
93///     subgraph Swarm
94///         direction TB
95///         B1[(Session Manager)]
96///         B2[(Connection Listener)]
97///         B3[(Network State)]
98///     end
99///  end
100///  handle <--> |request response channel| NetworkManager
101///  NetworkManager --> |Network events| events
102///  transactions <--> |transactions| NetworkManager
103///  ethrequest <--> |ETH request handing| NetworkManager
104///  discovery --> |Discovered peers| NetworkManager
105/// ```
106#[derive(Debug)]
107#[must_use = "The NetworkManager does nothing unless polled"]
108pub struct NetworkManager<N: NetworkPrimitives = EthNetworkPrimitives> {
109    /// The type that manages the actual network part, which includes connections.
110    swarm: Swarm<N>,
111    /// Underlying network handle that can be shared.
112    handle: NetworkHandle<N>,
113    /// Receiver half of the command channel set up between this type and the [`NetworkHandle`]
114    from_handle_rx: UnboundedReceiverStream<NetworkHandleMessage<N>>,
115    /// Handles block imports according to the `eth` protocol.
116    block_import: Box<dyn BlockImport<N::NewBlockPayload>>,
117    /// Sender for high level network events.
118    event_sender: EventSender<NetworkEvent<PeerRequest<N>>>,
119    /// Sender half to send events to the
120    /// [`TransactionsManager`](crate::transactions::TransactionsManager) task, if configured.
121    to_transactions_manager: Option<UnboundedMeteredSender<NetworkTransactionEvent<N>>>,
122    /// Sender half to send events to the
123    /// [`EthRequestHandler`](crate::eth_requests::EthRequestHandler) task, if configured.
124    ///
125    /// The channel that originally receives and bundles all requests from all sessions is already
126    /// bounded. However, since handling an eth request is more I/O intensive than delegating
127    /// them from the bounded channel to the eth-request channel, it is possible that this
128    /// builds up if the node is flooded with requests.
129    ///
130    /// Even though nonmalicious requests are relatively cheap, it's possible to craft
131    /// body requests with bogus data up until the allowed max message size limit.
132    /// Thus, we use a bounded channel here to avoid unbounded build up if the node is flooded with
133    /// requests. This channel size is set at
134    /// [`ETH_REQUEST_CHANNEL_CAPACITY`](crate::builder::ETH_REQUEST_CHANNEL_CAPACITY)
135    to_eth_request_handler: Option<mpsc::Sender<IncomingEthRequest<N>>>,
136    /// Tracks the number of active session (connected peers).
137    ///
138    /// This is updated via internal events and shared via `Arc` with the [`NetworkHandle`]
139    /// Updated by the `NetworkWorker` and loaded by the `NetworkService`.
140    num_active_peers: Arc<AtomicUsize>,
141    /// Metrics for the Network
142    metrics: NetworkMetrics,
143    /// Disconnect metrics for the Network, split by connection direction.
144    disconnect_metrics: DirectionalDisconnectMetrics,
145    /// Closed sessions metrics, split by direction.
146    closed_sessions_metrics: ClosedSessionsMetrics,
147    /// Pending session failure metrics, split by direction.
148    pending_session_failure_metrics: PendingSessionFailureMetrics,
149    /// Backed off peers metrics, split by reason.
150    backed_off_peers_metrics: BackedOffPeersMetrics,
151}
152
153impl NetworkManager {
154    /// Creates the manager of a new network with [`EthNetworkPrimitives`] types.
155    ///
156    /// ```no_run
157    /// # async fn f() {
158    /// use reth_chainspec::MAINNET;
159    /// use reth_network::{NetworkConfig, NetworkManager};
160    /// use reth_tasks::Runtime;
161    /// let config = NetworkConfig::builder_with_rng_secret_key(Runtime::test())
162    ///     .build_with_noop_provider(MAINNET.clone());
163    /// let manager = NetworkManager::eth(config).await;
164    /// # }
165    /// ```
166    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    /// Sets the dedicated channel for events intended for the
175    /// [`TransactionsManager`](crate::transactions::TransactionsManager).
176    pub fn with_transactions(
177        mut self,
178        tx: mpsc::UnboundedSender<NetworkTransactionEvent<N>>,
179    ) -> Self {
180        self.set_transactions(tx);
181        self
182    }
183
184    /// Sets the dedicated channel for events intended for the
185    /// [`TransactionsManager`](crate::transactions::TransactionsManager).
186    pub fn set_transactions(&mut self, tx: mpsc::UnboundedSender<NetworkTransactionEvent<N>>) {
187        self.to_transactions_manager =
188            Some(UnboundedMeteredSender::new(tx, NETWORK_POOL_TRANSACTIONS_SCOPE));
189    }
190
191    /// Sets the dedicated channel for events intended for the
192    /// [`EthRequestHandler`](crate::eth_requests::EthRequestHandler).
193    pub fn with_eth_request_handler(mut self, tx: mpsc::Sender<IncomingEthRequest<N>>) -> Self {
194        self.set_eth_request_handler(tx);
195        self
196    }
197
198    /// Sets the dedicated channel for events intended for the
199    /// [`EthRequestHandler`](crate::eth_requests::EthRequestHandler).
200    pub fn set_eth_request_handler(&mut self, tx: mpsc::Sender<IncomingEthRequest<N>>) {
201        self.to_eth_request_handler = Some(tx);
202    }
203
204    /// Adds an additional protocol handler to the `RLPx` sub-protocol list.
205    pub fn add_rlpx_sub_protocol(&mut self, protocol: impl IntoRlpxSubProtocol) {
206        self.swarm.add_rlpx_sub_protocol(protocol)
207    }
208
209    /// Returns the [`NetworkHandle`] that can be cloned and shared.
210    ///
211    /// The [`NetworkHandle`] can be used to interact with this [`NetworkManager`]
212    pub const fn handle(&self) -> &NetworkHandle<N> {
213        &self.handle
214    }
215
216    /// Returns the secret key used for authenticating sessions.
217    pub const fn secret_key(&self) -> SecretKey {
218        self.swarm.sessions().secret_key()
219    }
220
221    #[inline]
222    fn update_poll_metrics(&self, start: Instant, poll_durations: NetworkManagerPollDurations) {
223        let metrics = &self.metrics;
224
225        let NetworkManagerPollDurations { acc_network_handle, acc_swarm } = poll_durations;
226
227        // update metrics for whole poll function
228        metrics.duration_poll_network_manager.set(start.elapsed().as_secs_f64());
229        // update poll metrics for nested items
230        metrics.acc_duration_poll_network_handle.set(acc_network_handle.as_secs_f64());
231        metrics.acc_duration_poll_swarm.set(acc_swarm.as_secs_f64());
232    }
233
234    /// Creates the manager of a new network.
235    ///
236    /// The [`NetworkManager`] is an endless future that needs to be polled in order to advance the
237    /// state of the entire network.
238    pub async fn new<C: BlockNumReader + 'static>(
239        config: NetworkConfig<C, N>,
240    ) -> Result<Self, NetworkError> {
241        let NetworkConfig {
242            client,
243            secret_key,
244            discovery_v4_addr,
245            mut discovery_v4_config,
246            mut discovery_v5_config,
247            listener_addr,
248            peers_config,
249            sessions_config,
250            chain_id,
251            block_import,
252            network_mode,
253            boot_nodes,
254            executor,
255            hello_message,
256            status,
257            fork_filter,
258            dns_discovery_config,
259            extra_protocols,
260            tx_gossip_disabled,
261            transactions_manager_config: _,
262            nat,
263            handshake,
264            eth_max_message_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        // retrieve the tcp address of the socket
276        let listener_addr = incoming.local_address();
277
278        // resolve boot nodes
279        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            // merge configured boot nodes
284            disc_config.bootstrap_nodes.extend(resolved_boot_nodes.clone());
285            // add the forkid entry for EIP-868, but wrap it in an `EnrForkIdEntry` for proper
286            // encoding
287            disc_config.add_eip868_pair("eth", EnrForkIdEntry::from(status.forkid));
288        }
289
290        if let Some(discv5) = discovery_v5_config.as_mut() {
291            // merge configured boot nodes
292            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        )
303        .await?;
304        // need to retrieve the addr here since provided port could be `0`
305        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        );
322
323        let state = NetworkState::new(
324            crate::state::BlockNumReader::new(client),
325            discovery,
326            peers_manager,
327            Arc::clone(&num_active_peers),
328        );
329
330        let swarm = Swarm::new(incoming, sessions, state);
331
332        let (to_manager_tx, from_handle_rx) = mpsc::unbounded_channel();
333
334        let event_sender: EventSender<NetworkEvent<PeerRequest<N>>> = Default::default();
335
336        let handle = NetworkHandle::new(
337            Arc::clone(&num_active_peers),
338            Arc::new(Mutex::new(listener_addr)),
339            to_manager_tx,
340            secret_key,
341            local_peer_id,
342            peers_handle,
343            network_mode,
344            Arc::new(AtomicU64::new(chain_id)),
345            tx_gossip_disabled,
346            discv4,
347            discv5,
348            event_sender.clone(),
349            nat,
350        );
351
352        // Spawn required block peer filter if configured
353        if !required_block_hashes.is_empty() {
354            let filter = RequiredBlockFilter::new(handle.clone(), required_block_hashes);
355            filter.spawn();
356        }
357
358        Ok(Self {
359            swarm,
360            handle,
361            from_handle_rx: UnboundedReceiverStream::new(from_handle_rx),
362            block_import,
363            event_sender,
364            to_transactions_manager: None,
365            to_eth_request_handler: None,
366            num_active_peers,
367            metrics: Default::default(),
368            disconnect_metrics: Default::default(),
369            closed_sessions_metrics: Default::default(),
370            pending_session_failure_metrics: Default::default(),
371            backed_off_peers_metrics: Default::default(),
372        })
373    }
374
375    /// Create a new [`NetworkManager`] instance and start a [`NetworkBuilder`] to configure all
376    /// components of the network
377    ///
378    /// ```
379    /// use reth_network::{
380    ///     config::rng_secret_key, EthNetworkPrimitives, NetworkConfig, NetworkManager,
381    /// };
382    /// use reth_network_peers::mainnet_nodes;
383    /// use reth_storage_api::noop::NoopProvider;
384    /// use reth_tasks::Runtime;
385    /// use reth_transaction_pool::TransactionPool;
386    /// async fn launch<Pool: TransactionPool>(pool: Pool) {
387    ///     // This block provider implementation is used for testing purposes.
388    ///     let client = NoopProvider::default();
389    ///
390    ///     // The key that's used for encrypting sessions and to identify our node.
391    ///     let local_key = rng_secret_key();
392    ///
393    ///     let config = NetworkConfig::<_, EthNetworkPrimitives>::builder(local_key, Runtime::test())
394    ///         .boot_nodes(mainnet_nodes())
395    ///         .build(client.clone());
396    ///     let transactions_manager_config = config.transactions_manager_config.clone();
397    ///
398    ///     // create the network instance
399    ///     let (handle, network, transactions, request_handler) = NetworkManager::builder(config)
400    ///         .await
401    ///         .unwrap()
402    ///         .transactions(pool, transactions_manager_config)
403    ///         .request_handler(client)
404    ///         .split_with_handle();
405    /// }
406    /// ```
407    pub async fn builder<C: BlockNumReader + 'static>(
408        config: NetworkConfig<C, N>,
409    ) -> Result<NetworkBuilder<(), (), N>, NetworkError> {
410        let network = Self::new(config).await?;
411        Ok(network.into_builder())
412    }
413
414    /// Create a [`NetworkBuilder`] to configure all components of the network
415    pub const fn into_builder(self) -> NetworkBuilder<(), (), N> {
416        NetworkBuilder { network: self, transactions: (), request_handler: () }
417    }
418
419    /// Returns the [`SocketAddr`] that listens for incoming tcp connections.
420    pub const fn local_addr(&self) -> SocketAddr {
421        self.swarm.listener().local_address()
422    }
423
424    /// How many peers we're currently connected to.
425    pub fn num_connected_peers(&self) -> usize {
426        self.swarm.state().num_active_peers()
427    }
428
429    /// Returns the [`PeerId`] used in the network.
430    pub fn peer_id(&self) -> &PeerId {
431        self.handle.peer_id()
432    }
433
434    /// Returns an iterator over all peers in the peer set.
435    pub fn all_peers(&self) -> impl Iterator<Item = NodeRecord> + '_ {
436        self.swarm.peers().iter_peers()
437    }
438
439    /// Returns the number of peers in the peer set.
440    pub fn num_known_peers(&self) -> usize {
441        self.swarm.peers().num_known_peers()
442    }
443
444    /// Returns a new [`PeersHandle`] that can be cloned and shared.
445    ///
446    /// The [`PeersHandle`] can be used to interact with the network's peer set.
447    pub fn peers_handle(&self) -> PeersHandle {
448        self.swarm.peers().handle()
449    }
450
451    /// Collect the peers from the [`NetworkManager`] and write them to the given
452    /// `persistent_peers_file`.
453    ///
454    /// Only persists peers that are not currently backed off or banned. Includes metadata like
455    /// peer kind, fork ID, and reputation.
456    pub fn write_peers_to_file(&self, persistent_peers_file: &Path) -> Result<(), FsPathError> {
457        let peers = self.swarm.peers().persistable_peers().collect::<Vec<_>>();
458        persistent_peers_file.parent().map(fs::create_dir_all).transpose()?;
459        reth_fs_util::write_json_file(persistent_peers_file, &peers)?;
460        Ok(())
461    }
462
463    /// Returns a new [`FetchClient`] that can be cloned and shared.
464    ///
465    /// The [`FetchClient`] is the entrypoint for sending requests to the network.
466    pub fn fetch_client(&self) -> FetchClient<N> {
467        self.swarm.state().fetch_client()
468    }
469
470    /// Returns the current [`NetworkStatus`] for the local node.
471    pub fn status(&self) -> NetworkStatus {
472        let sessions = self.swarm.sessions();
473        let status = sessions.status();
474        let hello_message = sessions.hello_message();
475
476        #[expect(deprecated)]
477        NetworkStatus {
478            client_version: hello_message.client_version,
479            protocol_version: hello_message.protocol_version as u64,
480            eth_protocol_info: EthProtocolInfo {
481                difficulty: None,
482                head: status.blockhash,
483                network: status.chain.id(),
484                genesis: status.genesis,
485                config: Default::default(),
486            },
487            capabilities: hello_message
488                .protocols
489                .into_iter()
490                .map(|protocol| protocol.cap)
491                .collect(),
492        }
493    }
494
495    /// Sends an event to the [`TransactionsManager`](crate::transactions::TransactionsManager) if
496    /// configured.
497    fn notify_tx_manager(&self, event: NetworkTransactionEvent<N>) {
498        if let Some(ref tx) = self.to_transactions_manager {
499            let _ = tx.send(event);
500        }
501    }
502
503    /// Sends an event to the [`EthRequestManager`](crate::eth_requests::EthRequestHandler) if
504    /// configured.
505    fn delegate_eth_request(&self, event: IncomingEthRequest<N>) {
506        if let Some(ref reqs) = self.to_eth_request_handler {
507            let _ = reqs.try_send(event).map_err(|e| {
508                if let TrySendError::Full(_) = e {
509                    debug!(target:"net", "EthRequestHandler channel is full!");
510                    self.metrics.total_dropped_eth_requests_at_full_capacity.increment(1);
511                }
512            });
513        }
514    }
515
516    /// Handle an incoming request from the peer
517    fn on_eth_request(&self, peer_id: PeerId, req: PeerRequest<N>) {
518        match req {
519            PeerRequest::GetBlockHeaders { request, response } => {
520                self.delegate_eth_request(IncomingEthRequest::GetBlockHeaders {
521                    peer_id,
522                    request,
523                    response,
524                })
525            }
526            PeerRequest::GetBlockBodies { request, response } => {
527                self.delegate_eth_request(IncomingEthRequest::GetBlockBodies {
528                    peer_id,
529                    request,
530                    response,
531                })
532            }
533            PeerRequest::GetNodeData { request, response } => {
534                self.delegate_eth_request(IncomingEthRequest::GetNodeData {
535                    peer_id,
536                    request,
537                    response,
538                })
539            }
540            PeerRequest::GetReceipts { request, response } => {
541                self.delegate_eth_request(IncomingEthRequest::GetReceipts {
542                    peer_id,
543                    request,
544                    response,
545                })
546            }
547            PeerRequest::GetReceipts69 { request, response } => {
548                self.delegate_eth_request(IncomingEthRequest::GetReceipts69 {
549                    peer_id,
550                    request,
551                    response,
552                })
553            }
554            PeerRequest::GetReceipts70 { request, response } => {
555                self.delegate_eth_request(IncomingEthRequest::GetReceipts70 {
556                    peer_id,
557                    request,
558                    response,
559                })
560            }
561            PeerRequest::GetBlockAccessLists { request, response } => {
562                self.delegate_eth_request(IncomingEthRequest::GetBlockAccessLists {
563                    peer_id,
564                    request,
565                    response,
566                })
567            }
568            PeerRequest::GetPooledTransactions { request, response } => {
569                self.notify_tx_manager(NetworkTransactionEvent::GetPooledTransactions {
570                    peer_id,
571                    request,
572                    response,
573                });
574            }
575        }
576    }
577
578    /// Invoked after a `NewBlock` message from the peer was validated
579    fn on_block_import_result(&mut self, event: BlockImportEvent<N::NewBlockPayload>) {
580        match event {
581            BlockImportEvent::Announcement(validation) => match validation {
582                BlockValidation::ValidHeader { block } => {
583                    self.swarm.state_mut().announce_new_block(block);
584                }
585                BlockValidation::ValidBlock { block } => {
586                    self.swarm.state_mut().announce_new_block_hash(block);
587                }
588            },
589            BlockImportEvent::Outcome(outcome) => {
590                let BlockImportOutcome { peer, result } = outcome;
591                match result {
592                    Ok(validated_block) => match validated_block {
593                        BlockValidation::ValidHeader { block } => {
594                            self.swarm.state_mut().update_peer_block(
595                                &peer,
596                                block.hash,
597                                block.number(),
598                            );
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                    Err(_err) => {
606                        self.swarm
607                            .state_mut()
608                            .peers_mut()
609                            .apply_reputation_change(&peer, ReputationChangeKind::BadBlock);
610                    }
611                }
612            }
613        }
614    }
615
616    /// Enforces [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#devp2p) consensus rules for the network protocol
617    ///
618    /// Depending on the mode of the network:
619    ///    - disconnect peer if in POS
620    ///    - execute the closure if in POW
621    fn within_pow_or_disconnect<F>(&mut self, peer_id: PeerId, only_pow: F)
622    where
623        F: FnOnce(&mut Self),
624    {
625        // reject message in POS
626        if self.handle.mode().is_stake() {
627            // connections to peers which send invalid messages should be terminated
628            self.swarm
629                .sessions_mut()
630                .disconnect(peer_id, Some(DisconnectReason::SubprotocolSpecific));
631        } else {
632            only_pow(self);
633        }
634    }
635
636    /// Handles a received Message from the peer's session.
637    fn on_peer_message(&mut self, peer_id: PeerId, msg: PeerMessage<N>) {
638        match msg {
639            PeerMessage::NewBlockHashes(hashes) => {
640                self.within_pow_or_disconnect(peer_id, |this| {
641                    // update peer's state, to track what blocks this peer has seen
642                    this.swarm.state_mut().on_new_block_hashes(peer_id, hashes.to_vec());
643                    // start block import process for the hashes
644                    this.block_import.on_new_block(peer_id, NewBlockEvent::Hashes(hashes));
645                })
646            }
647            PeerMessage::NewBlock(block) => {
648                self.within_pow_or_disconnect(peer_id, move |this| {
649                    this.swarm.state_mut().on_new_block(peer_id, block.hash);
650                    // start block import process
651                    this.block_import.on_new_block(peer_id, NewBlockEvent::Block(block));
652                });
653            }
654            PeerMessage::PooledTransactions(msg) => {
655                self.notify_tx_manager(NetworkTransactionEvent::IncomingPooledTransactionHashes {
656                    peer_id,
657                    msg,
658                });
659            }
660            PeerMessage::EthRequest(req) => {
661                self.on_eth_request(peer_id, req);
662            }
663            PeerMessage::ReceivedTransaction(msg) => {
664                self.notify_tx_manager(NetworkTransactionEvent::IncomingTransactions {
665                    peer_id,
666                    msg,
667                });
668            }
669            PeerMessage::SendTransactions(_) => {
670                unreachable!("Not emitted by session")
671            }
672            PeerMessage::BlockRangeUpdated(_) => {}
673            PeerMessage::Other(other) => {
674                debug!(target: "net", message_id=%other.id, "Ignoring unsupported message");
675            }
676        }
677    }
678
679    /// Handler for received messages from a handle
680    fn on_handle_message(&mut self, msg: NetworkHandleMessage<N>) {
681        match msg {
682            NetworkHandleMessage::DiscoveryListener(tx) => {
683                self.swarm.state_mut().discovery_mut().add_listener(tx);
684            }
685            NetworkHandleMessage::AnnounceBlock(block, hash) => {
686                if self.handle.mode().is_stake() {
687                    // See [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#devp2p)
688                    warn!(target: "net", "Peer performed block propagation, but it is not supported in proof of stake (EIP-3675)");
689                    return
690                }
691                let msg = NewBlockMessage { hash, block: Arc::new(block) };
692                self.swarm.state_mut().announce_new_block(msg);
693            }
694            NetworkHandleMessage::EthRequest { peer_id, request } => {
695                self.swarm.sessions_mut().send_message(&peer_id, PeerMessage::EthRequest(request))
696            }
697            NetworkHandleMessage::SendTransaction { peer_id, msg } => {
698                self.swarm.sessions_mut().send_message(&peer_id, PeerMessage::SendTransactions(msg))
699            }
700            NetworkHandleMessage::SendPooledTransactionHashes { peer_id, msg } => self
701                .swarm
702                .sessions_mut()
703                .send_message(&peer_id, PeerMessage::PooledTransactions(msg)),
704            NetworkHandleMessage::AddTrustedPeerId(peer_id) => {
705                self.swarm.state_mut().add_trusted_peer_id(peer_id);
706            }
707            NetworkHandleMessage::AddPeerAddress(peer, kind, addr) => {
708                // only add peer if we are not shutting down
709                if !self.swarm.is_shutting_down() {
710                    self.swarm.state_mut().add_peer_kind(peer, kind, addr);
711                }
712            }
713            NetworkHandleMessage::RemovePeer(peer_id, kind) => {
714                self.swarm.state_mut().remove_peer_kind(peer_id, kind);
715            }
716            NetworkHandleMessage::DisconnectPeer(peer_id, reason) => {
717                self.swarm.sessions_mut().disconnect(peer_id, reason);
718            }
719            NetworkHandleMessage::ConnectPeer(peer_id, kind, addr) => {
720                self.swarm.state_mut().add_and_connect(peer_id, kind, addr);
721            }
722            NetworkHandleMessage::SetNetworkState(net_state) => {
723                // Sets network connection state between Active and Hibernate.
724                // If hibernate stops the node to fill new outbound
725                // connections, this is beneficial for sync stages that do not require a network
726                // connection.
727                self.swarm.on_network_state_change(net_state);
728            }
729
730            NetworkHandleMessage::Shutdown(tx) => {
731                self.perform_network_shutdown();
732                let _ = tx.send(());
733            }
734            NetworkHandleMessage::ReputationChange(peer_id, kind) => {
735                self.swarm.peers_mut().apply_reputation_change(&peer_id, kind);
736            }
737            NetworkHandleMessage::GetReputationById(peer_id, tx) => {
738                let _ = tx.send(self.swarm.peers().get_reputation(&peer_id));
739            }
740            NetworkHandleMessage::FetchClient(tx) => {
741                let _ = tx.send(self.fetch_client());
742            }
743            NetworkHandleMessage::GetStatus(tx) => {
744                let _ = tx.send(self.status());
745            }
746            NetworkHandleMessage::StatusUpdate { head } => {
747                if let Some(transition) = self.swarm.sessions_mut().on_status_update(head) {
748                    self.swarm.state_mut().update_fork_id(transition.current);
749                }
750            }
751            NetworkHandleMessage::GetPeerInfos(tx) => {
752                let _ = tx.send(self.get_peer_infos());
753            }
754            NetworkHandleMessage::GetPeerInfoById(peer_id, tx) => {
755                let _ = tx.send(self.get_peer_info_by_id(peer_id));
756            }
757            NetworkHandleMessage::GetPeerInfosByIds(peer_ids, tx) => {
758                let _ = tx.send(self.get_peer_infos_by_ids(peer_ids));
759            }
760            NetworkHandleMessage::GetPeerInfosByPeerKind(kind, tx) => {
761                let peer_ids = self.swarm.peers().peers_by_kind(kind);
762                let _ = tx.send(self.get_peer_infos_by_ids(peer_ids));
763            }
764            NetworkHandleMessage::AddRlpxSubProtocol(proto) => self.add_rlpx_sub_protocol(proto),
765            NetworkHandleMessage::GetTransactionsHandle(tx) => {
766                if let Some(ref tx_inner) = self.to_transactions_manager {
767                    let _ = tx_inner.send(NetworkTransactionEvent::GetTransactionsHandle(tx));
768                } else {
769                    let _ = tx.send(None);
770                }
771            }
772            NetworkHandleMessage::InternalBlockRangeUpdate(block_range_update) => {
773                self.swarm.sessions_mut().update_advertised_block_range(block_range_update);
774            }
775            NetworkHandleMessage::EthMessage { peer_id, message } => {
776                self.swarm.sessions_mut().send_message(&peer_id, message)
777            }
778        }
779    }
780
781    fn on_swarm_event(&mut self, event: SwarmEvent<N>) {
782        // handle event
783        match event {
784            SwarmEvent::ValidMessage { peer_id, message } => self.on_peer_message(peer_id, message),
785            SwarmEvent::TcpListenerClosed { remote_addr } => {
786                trace!(target: "net", ?remote_addr, "TCP listener closed.");
787            }
788            SwarmEvent::TcpListenerError(err) => {
789                trace!(target: "net", %err, "TCP connection error.");
790            }
791            SwarmEvent::IncomingTcpConnection { remote_addr, session_id } => {
792                trace!(target: "net", ?session_id, ?remote_addr, "Incoming connection");
793                self.metrics.total_incoming_connections.increment(1);
794                self.metrics
795                    .incoming_connections
796                    .set(self.swarm.peers().num_inbound_connections() as f64);
797            }
798            SwarmEvent::OutgoingTcpConnection { remote_addr, peer_id } => {
799                trace!(target: "net", ?remote_addr, ?peer_id, "Starting outbound connection.");
800                self.metrics.total_outgoing_connections.increment(1);
801                self.update_pending_connection_metrics()
802            }
803            SwarmEvent::SessionEstablished {
804                peer_id,
805                remote_addr,
806                client_version,
807                capabilities,
808                version,
809                messages,
810                status,
811                direction,
812            } => {
813                let total_active = self.num_active_peers.fetch_add(1, Ordering::Relaxed) + 1;
814                self.metrics.connected_peers.set(total_active as f64);
815                debug!(
816                    target: "net",
817                    ?remote_addr,
818                    %client_version,
819                    ?peer_id,
820                    ?total_active,
821                    kind=%direction,
822                    peer_enode=%NodeRecord::new(remote_addr, peer_id),
823                    "Session established"
824                );
825
826                if direction.is_incoming() {
827                    self.swarm
828                        .state_mut()
829                        .peers_mut()
830                        .on_incoming_session_established(peer_id, remote_addr);
831                }
832
833                if direction.is_outgoing() {
834                    self.swarm.peers_mut().on_active_outgoing_established(peer_id);
835                }
836
837                self.update_active_connection_metrics();
838
839                let peer_kind = self
840                    .swarm
841                    .state()
842                    .peers()
843                    .peer_by_id(peer_id)
844                    .map(|(_, kind)| kind)
845                    .unwrap_or_default();
846                let session_info = SessionInfo {
847                    peer_id,
848                    remote_addr,
849                    client_version,
850                    capabilities,
851                    status,
852                    version,
853                    peer_kind,
854                };
855
856                self.event_sender
857                    .notify(NetworkEvent::ActivePeerSession { info: session_info, messages });
858            }
859            SwarmEvent::PeerAdded(peer_id) => {
860                trace!(target: "net", ?peer_id, "Peer added");
861                self.event_sender.notify(NetworkEvent::Peer(PeerEvent::PeerAdded(peer_id)));
862                self.metrics.tracked_peers.set(self.swarm.peers().num_known_peers() as f64);
863            }
864            SwarmEvent::PeerRemoved(peer_id) => {
865                trace!(target: "net", ?peer_id, "Peer dropped");
866                self.event_sender.notify(NetworkEvent::Peer(PeerEvent::PeerRemoved(peer_id)));
867                self.metrics.tracked_peers.set(self.swarm.peers().num_known_peers() as f64);
868            }
869            SwarmEvent::SessionClosed { peer_id, remote_addr, error } => {
870                let total_active = self.num_active_peers.fetch_sub(1, Ordering::Relaxed) - 1;
871                self.metrics.connected_peers.set(total_active as f64);
872                trace!(
873                    target: "net",
874                    ?remote_addr,
875                    ?peer_id,
876                    ?total_active,
877                    ?error,
878                    "Session disconnected"
879                );
880
881                // Capture direction before state is reset to Idle
882                let is_inbound = self.swarm.peers().is_inbound_peer(&peer_id);
883
884                let reason = if let Some(ref err) = error {
885                    // If the connection was closed due to an error, we report
886                    // the peer
887                    self.swarm.peers_mut().on_active_session_dropped(&remote_addr, &peer_id, err);
888                    self.backed_off_peers_metrics.increment_for_reason(
889                        BackoffReason::from_disconnect(err.as_disconnected()),
890                    );
891                    err.as_disconnected()
892                } else {
893                    // Gracefully disconnected
894                    self.swarm.peers_mut().on_active_session_gracefully_closed(peer_id);
895                    self.backed_off_peers_metrics
896                        .increment_for_reason(BackoffReason::GracefulClose);
897                    None
898                };
899                self.closed_sessions_metrics.active.increment(1);
900                self.update_active_connection_metrics();
901
902                if let Some(reason) = reason {
903                    if is_inbound {
904                        self.disconnect_metrics.increment_inbound(reason);
905                    } else {
906                        self.disconnect_metrics.increment_outbound(reason);
907                    }
908                }
909                self.metrics.backed_off_peers.set(self.swarm.peers().num_backed_off_peers() as f64);
910                self.event_sender
911                    .notify(NetworkEvent::Peer(PeerEvent::SessionClosed { peer_id, reason }));
912            }
913            SwarmEvent::IncomingPendingSessionClosed { remote_addr, error } => {
914                trace!(
915                    target: "net",
916                    ?remote_addr,
917                    ?error,
918                    "Incoming pending session failed"
919                );
920
921                if let Some(ref err) = error {
922                    self.swarm
923                        .state_mut()
924                        .peers_mut()
925                        .on_incoming_pending_session_dropped(remote_addr, err);
926                    self.pending_session_failure_metrics.inbound.increment(1);
927                    if let Some(reason) = err.as_disconnected() {
928                        self.disconnect_metrics.increment_inbound(reason);
929                    }
930                } else {
931                    self.swarm
932                        .state_mut()
933                        .peers_mut()
934                        .on_incoming_pending_session_gracefully_closed();
935                }
936                self.closed_sessions_metrics.incoming_pending.increment(1);
937                self.metrics
938                    .incoming_connections
939                    .set(self.swarm.peers().num_inbound_connections() as f64);
940            }
941            SwarmEvent::OutgoingPendingSessionClosed { remote_addr, peer_id, error } => {
942                trace!(
943                    target: "net",
944                    ?remote_addr,
945                    ?peer_id,
946                    ?error,
947                    "Outgoing pending session failed"
948                );
949
950                if let Some(ref err) = error {
951                    self.swarm.peers_mut().on_outgoing_pending_session_dropped(
952                        &remote_addr,
953                        &peer_id,
954                        err,
955                    );
956                    self.pending_session_failure_metrics.outbound.increment(1);
957                    self.backed_off_peers_metrics.increment_for_reason(
958                        BackoffReason::from_disconnect(err.as_disconnected()),
959                    );
960                    if let Some(reason) = err.as_disconnected() {
961                        self.disconnect_metrics.increment_outbound(reason);
962                    }
963                } else {
964                    self.swarm
965                        .state_mut()
966                        .peers_mut()
967                        .on_outgoing_pending_session_gracefully_closed(&peer_id);
968                }
969                self.closed_sessions_metrics.outgoing_pending.increment(1);
970                self.update_pending_connection_metrics();
971                self.metrics.backed_off_peers.set(self.swarm.peers().num_backed_off_peers() as f64);
972            }
973            SwarmEvent::OutgoingConnectionError { remote_addr, peer_id, error } => {
974                trace!(
975                    target: "net",
976                    ?remote_addr,
977                    ?peer_id,
978                    %error,
979                    "Outgoing connection error"
980                );
981
982                self.swarm.peers_mut().on_outgoing_connection_failure(
983                    &remote_addr,
984                    &peer_id,
985                    &error,
986                );
987
988                self.backed_off_peers_metrics.increment_for_reason(BackoffReason::ConnectionError);
989                self.metrics.backed_off_peers.set(self.swarm.peers().num_backed_off_peers() as f64);
990                self.update_pending_connection_metrics();
991            }
992            SwarmEvent::BadMessage { peer_id } => {
993                self.swarm
994                    .state_mut()
995                    .peers_mut()
996                    .apply_reputation_change(&peer_id, ReputationChangeKind::BadMessage);
997                self.metrics.invalid_messages_received.increment(1);
998            }
999            SwarmEvent::ProtocolBreach { peer_id } => {
1000                self.swarm
1001                    .state_mut()
1002                    .peers_mut()
1003                    .apply_reputation_change(&peer_id, ReputationChangeKind::BadProtocol);
1004            }
1005        }
1006    }
1007
1008    /// Returns [`PeerInfo`] for all connected peers
1009    fn get_peer_infos(&self) -> Vec<PeerInfo> {
1010        self.swarm
1011            .sessions()
1012            .active_sessions()
1013            .iter()
1014            .filter_map(|(&peer_id, session)| {
1015                self.swarm
1016                    .state()
1017                    .peers()
1018                    .peer_by_id(peer_id)
1019                    .map(|(record, kind)| session.peer_info(&record, kind))
1020            })
1021            .collect()
1022    }
1023
1024    /// Returns [`PeerInfo`] for a given peer.
1025    ///
1026    /// Returns `None` if there's no active session to the peer.
1027    fn get_peer_info_by_id(&self, peer_id: PeerId) -> Option<PeerInfo> {
1028        self.swarm.sessions().active_sessions().get(&peer_id).and_then(|session| {
1029            self.swarm
1030                .state()
1031                .peers()
1032                .peer_by_id(peer_id)
1033                .map(|(record, kind)| session.peer_info(&record, kind))
1034        })
1035    }
1036
1037    /// Returns [`PeerInfo`] for a given peers.
1038    ///
1039    /// Ignore the non-active peer.
1040    fn get_peer_infos_by_ids(&self, peer_ids: impl IntoIterator<Item = PeerId>) -> Vec<PeerInfo> {
1041        peer_ids.into_iter().filter_map(|peer_id| self.get_peer_info_by_id(peer_id)).collect()
1042    }
1043
1044    /// Updates the metrics for active,established connections
1045    #[inline]
1046    fn update_active_connection_metrics(&self) {
1047        self.metrics.incoming_connections.set(self.swarm.peers().num_inbound_connections() as f64);
1048        self.metrics.outgoing_connections.set(self.swarm.peers().num_outbound_connections() as f64);
1049    }
1050
1051    /// Updates the metrics for pending connections
1052    #[inline]
1053    fn update_pending_connection_metrics(&self) {
1054        self.metrics
1055            .pending_outgoing_connections
1056            .set(self.swarm.peers().num_pending_outbound_connections() as f64);
1057        self.metrics
1058            .total_pending_connections
1059            .set(self.swarm.sessions().num_pending_connections() as f64);
1060    }
1061
1062    /// Drives the [`NetworkManager`] future until a [`GracefulShutdown`] signal is received.
1063    ///
1064    /// This invokes the given function `shutdown_hook` while holding the graceful shutdown guard.
1065    pub async fn run_until_graceful_shutdown<F, R>(
1066        mut self,
1067        shutdown: GracefulShutdown,
1068        shutdown_hook: F,
1069    ) -> R
1070    where
1071        F: FnOnce(Self) -> R,
1072    {
1073        let mut graceful_guard = None;
1074        tokio::select! {
1075            _ = &mut self => {},
1076            guard = shutdown => {
1077                graceful_guard = Some(guard);
1078            },
1079        }
1080
1081        self.perform_network_shutdown();
1082        let res = shutdown_hook(self);
1083        drop(graceful_guard);
1084        res
1085    }
1086
1087    /// Performs a graceful network shutdown by stopping new connections from being accepted while
1088    /// draining current and pending connections.
1089    fn perform_network_shutdown(&mut self) {
1090        // Set connection status to `Shutdown`. Stops node from accepting
1091        // new incoming connections as well as sending connection requests to newly
1092        // discovered nodes.
1093        self.swarm.on_shutdown_requested();
1094        // Disconnect all active connections
1095        self.swarm.sessions_mut().disconnect_all(Some(DisconnectReason::ClientQuitting));
1096        // drop pending connections
1097        self.swarm.sessions_mut().disconnect_all_pending();
1098    }
1099}
1100
1101impl<N: NetworkPrimitives> Future for NetworkManager<N> {
1102    type Output = ();
1103
1104    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1105        let start = Instant::now();
1106        let mut poll_durations = NetworkManagerPollDurations::default();
1107
1108        let this = self.get_mut();
1109
1110        // poll new block imports (expected to be a noop for POS)
1111        while let Poll::Ready(outcome) = this.block_import.poll(cx) {
1112            this.on_block_import_result(outcome);
1113        }
1114
1115        // These loops drive the entire state of network and does a lot of work. Under heavy load
1116        // (many messages/events), data may arrive faster than it can be processed (incoming
1117        // messages/requests -> events), and it is possible that more data has already arrived by
1118        // the time an internal event is processed. Which could turn this loop into a busy loop.
1119        // Without yielding back to the executor, it can starve other tasks waiting on that
1120        // executor to execute them, or drive underlying resources To prevent this, we
1121        // preemptively return control when the `budget` is exhausted. The value itself is chosen
1122        // somewhat arbitrarily, it is high enough so the swarm can make meaningful progress but
1123        // low enough that this loop does not starve other tasks for too long. If the budget is
1124        // exhausted we manually yield back control to the (coop) scheduler. This manual yield
1125        // point should prevent situations where polling appears to be frozen. See also
1126        // <https://tokio.rs/blog/2020-04-preemption> And tokio's docs on cooperative scheduling
1127        // <https://docs.rs/tokio/latest/tokio/task/#cooperative-scheduling>
1128        //
1129        // Testing has shown that this loop naturally reaches the pending state within 1-5
1130        // iterations in << 100µs in most cases. On average it requires ~50µs, which is inside the
1131        // range of what's recommended as rule of thumb.
1132        // <https://ryhl.io/blog/async-what-is-blocking/>
1133
1134        // process incoming messages from a handle (`TransactionsManager` has one)
1135        //
1136        // will only be closed if the channel was deliberately closed since we always have an
1137        // instance of `NetworkHandle`
1138        let start_network_handle = Instant::now();
1139        let maybe_more_handle_messages = poll_nested_stream_with_budget!(
1140            "net",
1141            "Network message channel",
1142            DEFAULT_BUDGET_TRY_DRAIN_NETWORK_HANDLE_CHANNEL,
1143            this.from_handle_rx.poll_next_unpin(cx),
1144            |msg| this.on_handle_message(msg),
1145            error!("Network channel closed");
1146        );
1147        poll_durations.acc_network_handle = start_network_handle.elapsed();
1148
1149        // process incoming messages from the network
1150        let maybe_more_swarm_events = poll_nested_stream_with_budget!(
1151            "net",
1152            "Swarm events stream",
1153            DEFAULT_BUDGET_TRY_DRAIN_SWARM,
1154            this.swarm.poll_next_unpin(cx),
1155            |event| this.on_swarm_event(event),
1156        );
1157        poll_durations.acc_swarm =
1158            start_network_handle.elapsed() - poll_durations.acc_network_handle;
1159
1160        // all streams are fully drained and import futures pending
1161        if maybe_more_handle_messages || maybe_more_swarm_events {
1162            // make sure we're woken up again
1163            cx.waker().wake_by_ref();
1164            return Poll::Pending
1165        }
1166
1167        this.update_poll_metrics(start, poll_durations);
1168
1169        Poll::Pending
1170    }
1171}
1172
1173#[derive(Debug, Default)]
1174struct NetworkManagerPollDurations {
1175    acc_network_handle: Duration,
1176    acc_swarm: Duration,
1177}