refactor: split NetworkEventListenerProvider (#12972)

This commit is contained in:
Léa Narzis
2024-12-04 19:27:58 +01:00
committed by GitHub
parent 0daa456f3a
commit fbd2d6eeda
15 changed files with 346 additions and 254 deletions

5
Cargo.lock generated
View File

@ -3067,6 +3067,7 @@ dependencies = [
"reth-chainspec", "reth-chainspec",
"reth-discv4", "reth-discv4",
"reth-network", "reth-network",
"reth-network-api",
"reth-primitives", "reth-primitives",
"reth-tracing", "reth-tracing",
"secp256k1", "secp256k1",
@ -9560,9 +9561,9 @@ dependencies = [
[[package]] [[package]]
name = "revm-inspectors" name = "revm-inspectors"
version = "0.12.0" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41bbeb6004cc4ed48d27756f0479011df91a6f5642a3abab9309eda5ce67c4ad" checksum = "0b7f5f8a2deafb3c76f357bbf9e71b73bddb915c4994bbbe3208fbfbe8fc7f8e"
dependencies = [ dependencies = [
"alloy-primitives", "alloy-primitives",
"alloy-rpc-types-eth", "alloy-rpc-types-eth",

View File

@ -14,6 +14,7 @@ workspace = true
reth-chainspec.workspace = true reth-chainspec.workspace = true
reth-tracing.workspace = true reth-tracing.workspace = true
reth-db = { workspace = true, features = ["test-utils"] } reth-db = { workspace = true, features = ["test-utils"] }
reth-network-api.workspace = true
reth-rpc-layer.workspace = true reth-rpc-layer.workspace = true
reth-rpc-server-types.workspace = true reth-rpc-server-types.workspace = true
reth-rpc-eth-api.workspace = true reth-rpc-eth-api.workspace = true
@ -23,7 +24,6 @@ reth-payload-builder-primitives.workspace = true
reth-payload-primitives.workspace = true reth-payload-primitives.workspace = true
reth-primitives.workspace = true reth-primitives.workspace = true
reth-provider.workspace = true reth-provider.workspace = true
reth-network-api.workspace = true
reth-network.workspace = true reth-network.workspace = true
reth-node-api.workspace = true reth-node-api.workspace = true
reth-node-core.workspace = true reth-node-core.workspace = true

View File

@ -1,6 +1,7 @@
use futures_util::StreamExt; use futures_util::StreamExt;
use reth_network_api::{ use reth_network_api::{
test_utils::PeersHandleProvider, NetworkEvent, NetworkEventListenerProvider, PeersInfo, events::PeerEvent, test_utils::PeersHandleProvider, NetworkEvent, NetworkEventListenerProvider,
PeersInfo,
}; };
use reth_network_peers::{NodeRecord, PeerId}; use reth_network_peers::{NodeRecord, PeerId};
use reth_tokio_util::EventStream; use reth_tokio_util::EventStream;
@ -28,7 +29,7 @@ where
self.network.peers_handle().add_peer(node_record.id, node_record.tcp_addr()); self.network.peers_handle().add_peer(node_record.id, node_record.tcp_addr());
match self.network_events.next().await { match self.network_events.next().await {
Some(NetworkEvent::PeerAdded(_)) => (), Some(NetworkEvent::Peer(PeerEvent::PeerAdded(_))) => (),
ev => panic!("Expected a peer added event, got: {ev:?}"), ev => panic!("Expected a peer added event, got: {ev:?}"),
} }
} }
@ -42,7 +43,9 @@ where
pub async fn next_session_established(&mut self) -> Option<PeerId> { pub async fn next_session_established(&mut self) -> Option<PeerId> {
while let Some(ev) = self.network_events.next().await { while let Some(ev) = self.network_events.next().await {
match ev { match ev {
NetworkEvent::SessionEstablished { peer_id, .. } => { NetworkEvent::ActivePeerSession { info, .. } |
NetworkEvent::Peer(PeerEvent::SessionEstablished(info)) => {
let peer_id = info.peer_id;
info!("Session established with peer: {:?}", peer_id); info!("Session established with peer: {:?}", peer_id);
return Some(peer_id) return Some(peer_id)
} }

View File

@ -1,7 +1,5 @@
//! API related to listening for network events. //! API related to listening for network events.
use std::{fmt, net::SocketAddr, sync::Arc};
use reth_eth_wire_types::{ use reth_eth_wire_types::{
message::RequestPair, BlockBodies, BlockHeaders, Capabilities, DisconnectReason, EthMessage, message::RequestPair, BlockBodies, BlockHeaders, Capabilities, DisconnectReason, EthMessage,
EthNetworkPrimitives, EthVersion, GetBlockBodies, GetBlockHeaders, GetNodeData, EthNetworkPrimitives, EthVersion, GetBlockBodies, GetBlockHeaders, GetNodeData,
@ -13,26 +11,70 @@ use reth_network_p2p::error::{RequestError, RequestResult};
use reth_network_peers::PeerId; use reth_network_peers::PeerId;
use reth_network_types::PeerAddr; use reth_network_types::PeerAddr;
use reth_tokio_util::EventStream; use reth_tokio_util::EventStream;
use std::{
fmt,
net::SocketAddr,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use tokio::sync::{mpsc, oneshot}; use tokio::sync::{mpsc, oneshot};
use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::{wrappers::UnboundedReceiverStream, Stream, StreamExt};
/// Provides event subscription for the network. /// A boxed stream of network peer events that provides a type-erased interface.
#[auto_impl::auto_impl(&, Arc)] pub struct PeerEventStream(Pin<Box<dyn Stream<Item = PeerEvent> + Send + Sync>>);
pub trait NetworkEventListenerProvider: Send + Sync {
/// Creates a new [`NetworkEvent`] listener channel. impl fmt::Debug for PeerEventStream {
fn event_listener(&self) -> EventStream<NetworkEvent>; fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// Returns a new [`DiscoveryEvent`] stream. f.debug_struct("PeerEventStream").finish_non_exhaustive()
/// }
/// This stream yields [`DiscoveryEvent`]s for each peer that is discovered.
fn discovery_listener(&self) -> UnboundedReceiverStream<DiscoveryEvent>;
} }
/// (Non-exhaustive) Events emitted by the network that are of interest for subscribers. impl PeerEventStream {
/// Create a new stream [`PeerEventStream`] by converting the provided stream's items into peer
/// events [`PeerEvent`]
pub fn new<S, T>(stream: S) -> Self
where
S: Stream<Item = T> + Send + Sync + 'static,
T: Into<PeerEvent> + 'static,
{
let mapped_stream = stream.map(Into::into);
Self(Box::pin(mapped_stream))
}
}
impl Stream for PeerEventStream {
type Item = PeerEvent;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.0.as_mut().poll_next(cx)
}
}
/// Represents information about an established peer session.
#[derive(Debug, Clone)]
pub struct SessionInfo {
/// The identifier of the peer to which a session was established.
pub peer_id: PeerId,
/// The remote addr of the peer to which a session was established.
pub remote_addr: SocketAddr,
/// The client version of the peer to which a session was established.
pub client_version: Arc<str>,
/// Capabilities the peer announced.
pub capabilities: Arc<Capabilities>,
/// The status of the peer to which a session was established.
pub status: Arc<Status>,
/// Negotiated eth version of the session.
pub version: EthVersion,
}
/// (Non-exhaustive) List of the different events emitted by the network that are of interest for
/// subscribers.
/// ///
/// This includes any event types that may be relevant to tasks, for metrics, keep track of peers /// This includes any event types that may be relevant to tasks, for metrics, keep track of peers
/// etc. /// etc.
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum NetworkEvent<R = PeerRequest> { pub enum PeerEvent {
/// Closed the peer session. /// Closed the peer session.
SessionClosed { SessionClosed {
/// The identifier of the peer to which a session was closed. /// The identifier of the peer to which a session was closed.
@ -41,57 +83,65 @@ pub enum NetworkEvent<R = PeerRequest> {
reason: Option<DisconnectReason>, reason: Option<DisconnectReason>,
}, },
/// Established a new session with the given peer. /// Established a new session with the given peer.
SessionEstablished { SessionEstablished(SessionInfo),
/// The identifier of the peer to which a session was established.
peer_id: PeerId,
/// The remote addr of the peer to which a session was established.
remote_addr: SocketAddr,
/// The client version of the peer to which a session was established.
client_version: Arc<str>,
/// Capabilities the peer announced
capabilities: Arc<Capabilities>,
/// A request channel to the session task.
messages: PeerRequestSender<R>,
/// The status of the peer to which a session was established.
status: Arc<Status>,
/// negotiated eth version of the session
version: EthVersion,
},
/// Event emitted when a new peer is added /// Event emitted when a new peer is added
PeerAdded(PeerId), PeerAdded(PeerId),
/// Event emitted when a new peer is removed /// Event emitted when a new peer is removed
PeerRemoved(PeerId), PeerRemoved(PeerId),
} }
/// (Non-exhaustive) Network events representing peer lifecycle events and session requests.
#[derive(Debug)]
pub enum NetworkEvent<R = PeerRequest> {
/// Basic peer lifecycle event.
Peer(PeerEvent),
/// Session established with requests.
ActivePeerSession {
/// Session information
info: SessionInfo,
/// A request channel to the session task.
messages: PeerRequestSender<R>,
},
}
impl<R> Clone for NetworkEvent<R> { impl<R> Clone for NetworkEvent<R> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
match self { match self {
Self::SessionClosed { peer_id, reason } => { Self::Peer(event) => Self::Peer(event.clone()),
Self::SessionClosed { peer_id: *peer_id, reason: *reason } Self::ActivePeerSession { info, messages } => {
Self::ActivePeerSession { info: info.clone(), messages: messages.clone() }
} }
Self::SessionEstablished {
peer_id,
remote_addr,
client_version,
capabilities,
messages,
status,
version,
} => Self::SessionEstablished {
peer_id: *peer_id,
remote_addr: *remote_addr,
client_version: client_version.clone(),
capabilities: capabilities.clone(),
messages: messages.clone(),
status: status.clone(),
version: *version,
},
Self::PeerAdded(peer) => Self::PeerAdded(*peer),
Self::PeerRemoved(peer) => Self::PeerRemoved(*peer),
} }
} }
} }
impl<R> From<NetworkEvent<R>> for PeerEvent {
fn from(event: NetworkEvent<R>) -> Self {
match event {
NetworkEvent::Peer(peer_event) => peer_event,
NetworkEvent::ActivePeerSession { info, .. } => Self::SessionEstablished(info),
}
}
}
/// Provides peer event subscription for the network.
#[auto_impl::auto_impl(&, Arc)]
pub trait NetworkPeersEvents: Send + Sync {
/// Creates a new peer event listener stream.
fn peer_events(&self) -> PeerEventStream;
}
/// Provides event subscription for the network.
#[auto_impl::auto_impl(&, Arc)]
pub trait NetworkEventListenerProvider<R = PeerRequest>: NetworkPeersEvents {
/// Creates a new [`NetworkEvent`] listener channel.
fn event_listener(&self) -> EventStream<NetworkEvent<R>>;
/// Returns a new [`DiscoveryEvent`] stream.
///
/// This stream yields [`DiscoveryEvent`]s for each peer that is discovered.
fn discovery_listener(&self) -> UnboundedReceiverStream<DiscoveryEvent>;
}
/// Events produced by the `Discovery` manager. /// Events produced by the `Discovery` manager.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum DiscoveryEvent { pub enum DiscoveryEvent {

View File

@ -44,7 +44,9 @@ use reth_eth_wire::{
use reth_fs_util::{self as fs, FsPathError}; use reth_fs_util::{self as fs, FsPathError};
use reth_metrics::common::mpsc::UnboundedMeteredSender; use reth_metrics::common::mpsc::UnboundedMeteredSender;
use reth_network_api::{ use reth_network_api::{
test_utils::PeersHandle, EthProtocolInfo, NetworkEvent, NetworkStatus, PeerInfo, PeerRequest, events::{PeerEvent, SessionInfo},
test_utils::PeersHandle,
EthProtocolInfo, NetworkEvent, NetworkStatus, PeerInfo, PeerRequest,
}; };
use reth_network_peers::{NodeRecord, PeerId}; use reth_network_peers::{NodeRecord, PeerId};
use reth_network_types::ReputationChangeKind; use reth_network_types::ReputationChangeKind;
@ -712,24 +714,26 @@ impl<N: NetworkPrimitives> NetworkManager<N> {
self.update_active_connection_metrics(); self.update_active_connection_metrics();
self.event_sender.notify(NetworkEvent::SessionEstablished { let session_info = SessionInfo {
peer_id, peer_id,
remote_addr, remote_addr,
client_version, client_version,
capabilities, capabilities,
version,
status, status,
messages, version,
}); };
self.event_sender
.notify(NetworkEvent::ActivePeerSession { info: session_info, messages });
} }
SwarmEvent::PeerAdded(peer_id) => { SwarmEvent::PeerAdded(peer_id) => {
trace!(target: "net", ?peer_id, "Peer added"); trace!(target: "net", ?peer_id, "Peer added");
self.event_sender.notify(NetworkEvent::PeerAdded(peer_id)); self.event_sender.notify(NetworkEvent::Peer(PeerEvent::PeerAdded(peer_id)));
self.metrics.tracked_peers.set(self.swarm.state().peers().num_known_peers() as f64); self.metrics.tracked_peers.set(self.swarm.state().peers().num_known_peers() as f64);
} }
SwarmEvent::PeerRemoved(peer_id) => { SwarmEvent::PeerRemoved(peer_id) => {
trace!(target: "net", ?peer_id, "Peer dropped"); trace!(target: "net", ?peer_id, "Peer dropped");
self.event_sender.notify(NetworkEvent::PeerRemoved(peer_id)); self.event_sender.notify(NetworkEvent::Peer(PeerEvent::PeerRemoved(peer_id)));
self.metrics.tracked_peers.set(self.swarm.state().peers().num_known_peers() as f64); self.metrics.tracked_peers.set(self.swarm.state().peers().num_known_peers() as f64);
} }
SwarmEvent::SessionClosed { peer_id, remote_addr, error } => { SwarmEvent::SessionClosed { peer_id, remote_addr, error } => {
@ -772,7 +776,8 @@ impl<N: NetworkPrimitives> NetworkManager<N> {
.saturating_sub(1) .saturating_sub(1)
as f64, as f64,
); );
self.event_sender.notify(NetworkEvent::SessionClosed { peer_id, reason }); self.event_sender
.notify(NetworkEvent::Peer(PeerEvent::SessionClosed { peer_id, reason }));
} }
SwarmEvent::IncomingPendingSessionClosed { remote_addr, error } => { SwarmEvent::IncomingPendingSessionClosed { remote_addr, error } => {
trace!( trace!(

View File

@ -4,6 +4,7 @@ use crate::{
}; };
use alloy_primitives::B256; use alloy_primitives::B256;
use enr::Enr; use enr::Enr;
use futures::StreamExt;
use parking_lot::Mutex; use parking_lot::Mutex;
use reth_discv4::{Discv4, NatResolver}; use reth_discv4::{Discv4, NatResolver};
use reth_discv5::Discv5; use reth_discv5::Discv5;
@ -13,6 +14,7 @@ use reth_eth_wire::{
}; };
use reth_ethereum_forks::Head; use reth_ethereum_forks::Head;
use reth_network_api::{ use reth_network_api::{
events::{NetworkPeersEvents, PeerEvent, PeerEventStream},
test_utils::{PeersHandle, PeersHandleProvider}, test_utils::{PeersHandle, PeersHandleProvider},
BlockDownloaderProvider, DiscoveryEvent, NetworkError, NetworkEvent, BlockDownloaderProvider, DiscoveryEvent, NetworkError, NetworkEvent,
NetworkEventListenerProvider, NetworkInfo, NetworkStatus, PeerInfo, PeerRequest, Peers, NetworkEventListenerProvider, NetworkInfo, NetworkStatus, PeerInfo, PeerRequest, Peers,
@ -192,6 +194,17 @@ impl<N: NetworkPrimitives> NetworkHandle<N> {
// === API Implementations === // === API Implementations ===
impl<N: NetworkPrimitives> NetworkPeersEvents for NetworkHandle<N> {
/// Returns an event stream of peer-specific network events.
fn peer_events(&self) -> PeerEventStream {
let peer_events = self.inner.event_sender.new_listener().map(|event| match event {
NetworkEvent::Peer(peer_event) => peer_event,
NetworkEvent::ActivePeerSession { info, .. } => PeerEvent::SessionEstablished(info),
});
PeerEventStream::new(peer_events)
}
}
impl NetworkEventListenerProvider for NetworkHandle<EthNetworkPrimitives> { impl NetworkEventListenerProvider for NetworkHandle<EthNetworkPrimitives> {
fn event_listener(&self) -> EventStream<NetworkEvent<PeerRequest<EthNetworkPrimitives>>> { fn event_listener(&self) -> EventStream<NetworkEvent<PeerRequest<EthNetworkPrimitives>>> {
self.inner.event_sender.new_listener() self.inner.event_sender.new_listener()

View File

@ -13,6 +13,7 @@ use pin_project::pin_project;
use reth_chainspec::{Hardforks, MAINNET}; use reth_chainspec::{Hardforks, MAINNET};
use reth_eth_wire::{protocol::Protocol, DisconnectReason, HelloMessageWithProtocols}; use reth_eth_wire::{protocol::Protocol, DisconnectReason, HelloMessageWithProtocols};
use reth_network_api::{ use reth_network_api::{
events::{PeerEvent, SessionInfo},
test_utils::{PeersHandle, PeersHandleProvider}, test_utils::{PeersHandle, PeersHandleProvider},
NetworkEvent, NetworkEventListenerProvider, NetworkInfo, Peers, NetworkEvent, NetworkEventListenerProvider, NetworkInfo, Peers,
}; };
@ -641,7 +642,9 @@ impl NetworkEventStream {
pub async fn next_session_closed(&mut self) -> Option<(PeerId, Option<DisconnectReason>)> { pub async fn next_session_closed(&mut self) -> Option<(PeerId, Option<DisconnectReason>)> {
while let Some(ev) = self.inner.next().await { while let Some(ev) = self.inner.next().await {
match ev { match ev {
NetworkEvent::SessionClosed { peer_id, reason } => return Some((peer_id, reason)), NetworkEvent::Peer(PeerEvent::SessionClosed { peer_id, reason }) => {
return Some((peer_id, reason))
}
_ => continue, _ => continue,
} }
} }
@ -652,7 +655,10 @@ impl NetworkEventStream {
pub async fn next_session_established(&mut self) -> Option<PeerId> { pub async fn next_session_established(&mut self) -> Option<PeerId> {
while let Some(ev) = self.inner.next().await { while let Some(ev) = self.inner.next().await {
match ev { match ev {
NetworkEvent::SessionEstablished { peer_id, .. } => return Some(peer_id), NetworkEvent::ActivePeerSession { info, .. } |
NetworkEvent::Peer(PeerEvent::SessionEstablished(info)) => {
return Some(info.peer_id)
}
_ => continue, _ => continue,
} }
} }
@ -667,7 +673,7 @@ impl NetworkEventStream {
let mut peers = Vec::with_capacity(num); let mut peers = Vec::with_capacity(num);
while let Some(ev) = self.inner.next().await { while let Some(ev) = self.inner.next().await {
match ev { match ev {
NetworkEvent::SessionEstablished { peer_id, .. } => { NetworkEvent::ActivePeerSession { info: SessionInfo { peer_id, .. }, .. } => {
peers.push(peer_id); peers.push(peer_id);
num -= 1; num -= 1;
if num == 0 { if num == 0 {
@ -680,18 +686,24 @@ impl NetworkEventStream {
peers peers
} }
/// Ensures that the first two events are a [`NetworkEvent::PeerAdded`] and /// Ensures that the first two events are a [`NetworkEvent::Peer(PeerEvent::PeerAdded`] and
/// [`NetworkEvent::SessionEstablished`], returning the [`PeerId`] of the established /// [`NetworkEvent::ActivePeerSession`], returning the [`PeerId`] of the established
/// session. /// session.
pub async fn peer_added_and_established(&mut self) -> Option<PeerId> { pub async fn peer_added_and_established(&mut self) -> Option<PeerId> {
let peer_id = match self.inner.next().await { let peer_id = match self.inner.next().await {
Some(NetworkEvent::PeerAdded(peer_id)) => peer_id, Some(NetworkEvent::Peer(PeerEvent::PeerAdded(peer_id))) => peer_id,
_ => return None, _ => return None,
}; };
match self.inner.next().await { match self.inner.next().await {
Some(NetworkEvent::SessionEstablished { peer_id: peer_id2, .. }) => { Some(NetworkEvent::ActivePeerSession {
debug_assert_eq!(peer_id, peer_id2, "PeerAdded peer_id {peer_id} does not match SessionEstablished peer_id {peer_id2}"); info: SessionInfo { peer_id: peer_id2, .. },
..
}) => {
debug_assert_eq!(
peer_id, peer_id2,
"PeerAdded peer_id {peer_id} does not match SessionEstablished peer_id {peer_id2}"
);
Some(peer_id) Some(peer_id)
} }
_ => None, _ => None,

View File

@ -40,6 +40,7 @@ use reth_eth_wire::{
}; };
use reth_metrics::common::mpsc::UnboundedMeteredReceiver; use reth_metrics::common::mpsc::UnboundedMeteredReceiver;
use reth_network_api::{ use reth_network_api::{
events::{PeerEvent, SessionInfo},
NetworkEvent, NetworkEventListenerProvider, PeerRequest, PeerRequestSender, Peers, NetworkEvent, NetworkEventListenerProvider, PeerRequest, PeerRequestSender, Peers,
}; };
use reth_network_p2p::{ use reth_network_p2p::{
@ -1050,55 +1051,81 @@ where
} }
} }
/// Handles session establishment and peer transactions initialization.
fn handle_peer_session(
&mut self,
info: SessionInfo,
messages: PeerRequestSender<PeerRequest<N>>,
) {
let SessionInfo { peer_id, client_version, version, .. } = info;
// Insert a new peer into the peerset.
let peer = PeerMetadata::<N>::new(
messages,
version,
client_version,
self.config.max_transactions_seen_by_peer_history,
);
let peer = match self.peers.entry(peer_id) {
Entry::Occupied(mut entry) => {
entry.insert(peer);
entry.into_mut()
}
Entry::Vacant(entry) => entry.insert(peer),
};
// Send a `NewPooledTransactionHashes` to the peer with up to
// `SOFT_LIMIT_COUNT_HASHES_IN_NEW_POOLED_TRANSACTIONS_BROADCAST_MESSAGE`
// transactions in the pool.
if self.network.is_initially_syncing() || self.network.tx_gossip_disabled() {
trace!(target: "net::tx", ?peer_id, "Skipping transaction broadcast: node syncing or gossip disabled");
return
}
// Get transactions to broadcast
let pooled_txs = self.pool.pooled_transactions_max(
SOFT_LIMIT_COUNT_HASHES_IN_NEW_POOLED_TRANSACTIONS_BROADCAST_MESSAGE,
);
if pooled_txs.is_empty() {
trace!(target: "net::tx", ?peer_id, "No transactions in the pool to broadcast");
return;
}
// Build and send transaction hashes message
let mut msg_builder = PooledTransactionsHashesBuilder::new(version);
for pooled_tx in pooled_txs {
peer.seen_transactions.insert(*pooled_tx.hash());
msg_builder.push_pooled(pooled_tx);
}
debug!(target: "net::tx", ?peer_id, tx_count = msg_builder.is_empty(), "Broadcasting transaction hashes");
let msg = msg_builder.build();
self.network.send_transactions_hashes(peer_id, msg);
}
/// Handles a received event related to common network events. /// Handles a received event related to common network events.
fn on_network_event(&mut self, event_result: NetworkEvent<PeerRequest<N>>) { fn on_network_event(&mut self, event_result: NetworkEvent<PeerRequest<N>>) {
match event_result { match event_result {
NetworkEvent::SessionClosed { peer_id, .. } => { NetworkEvent::Peer(PeerEvent::SessionClosed { peer_id, .. }) => {
// remove the peer // remove the peer
self.peers.remove(&peer_id); self.peers.remove(&peer_id);
self.transaction_fetcher.remove_peer(&peer_id); self.transaction_fetcher.remove_peer(&peer_id);
} }
NetworkEvent::SessionEstablished { NetworkEvent::ActivePeerSession { info, messages } => {
peer_id, client_version, messages, version, .. // process active peer session and broadcast available transaction from the pool
} => { self.handle_peer_session(info, messages);
// Insert a new peer into the peerset. }
let peer = PeerMetadata::new( NetworkEvent::Peer(PeerEvent::SessionEstablished(info)) => {
messages, let peer_id = info.peer_id;
version, // get messages from existing peer
client_version, let messages = match self.peers.get(&peer_id) {
self.config.max_transactions_seen_by_peer_history, Some(p) => p.request_tx.clone(),
); None => {
let peer = match self.peers.entry(peer_id) { debug!(target: "net::tx", ?peer_id, "No peer request sender found");
Entry::Occupied(mut entry) => { return;
entry.insert(peer);
entry.into_mut()
} }
Entry::Vacant(entry) => entry.insert(peer),
}; };
self.handle_peer_session(info, messages);
// Send a `NewPooledTransactionHashes` to the peer with up to
// `SOFT_LIMIT_COUNT_HASHES_IN_NEW_POOLED_TRANSACTIONS_BROADCAST_MESSAGE`
// transactions in the pool.
if self.network.is_initially_syncing() || self.network.tx_gossip_disabled() {
return
}
let pooled_txs = self.pool.pooled_transactions_max(
SOFT_LIMIT_COUNT_HASHES_IN_NEW_POOLED_TRANSACTIONS_BROADCAST_MESSAGE,
);
if pooled_txs.is_empty() {
// do not send a message if there are no transactions in the pool
return
}
let mut msg_builder = PooledTransactionsHashesBuilder::new(version);
for pooled_tx in pooled_txs {
peer.seen_transactions.insert(*pooled_tx.hash());
msg_builder.push_pooled(pooled_tx);
}
let msg = msg_builder.build();
self.network.send_transactions_hashes(peer_id, msg);
} }
_ => {} _ => {}
} }
@ -1987,27 +2014,12 @@ mod tests {
let mut established = listener0.take(2); let mut established = listener0.take(2);
while let Some(ev) = established.next().await { while let Some(ev) = established.next().await {
match ev { match ev {
NetworkEvent::SessionEstablished { NetworkEvent::Peer(PeerEvent::SessionEstablished(info)) => {
peer_id,
remote_addr,
client_version,
capabilities,
messages,
status,
version,
} => {
// to insert a new peer in transactions peerset // to insert a new peer in transactions peerset
transactions.on_network_event(NetworkEvent::SessionEstablished { transactions
peer_id, .on_network_event(NetworkEvent::Peer(PeerEvent::SessionEstablished(info)))
remote_addr,
client_version,
capabilities,
messages,
status,
version,
})
} }
NetworkEvent::PeerAdded(_peer_id) => continue, NetworkEvent::Peer(PeerEvent::PeerAdded(_peer_id)) => continue,
ev => { ev => {
error!("unexpected event {ev:?}") error!("unexpected event {ev:?}")
} }
@ -2073,28 +2085,13 @@ mod tests {
let mut established = listener0.take(2); let mut established = listener0.take(2);
while let Some(ev) = established.next().await { while let Some(ev) = established.next().await {
match ev { match ev {
NetworkEvent::SessionEstablished { NetworkEvent::ActivePeerSession { .. } |
peer_id, NetworkEvent::Peer(PeerEvent::SessionEstablished(_)) => {
remote_addr,
client_version,
capabilities,
messages,
status,
version,
} => {
// to insert a new peer in transactions peerset // to insert a new peer in transactions peerset
transactions.on_network_event(NetworkEvent::SessionEstablished { transactions.on_network_event(ev);
peer_id,
remote_addr,
client_version,
capabilities,
messages,
status,
version,
})
} }
NetworkEvent::PeerAdded(_peer_id) => continue, NetworkEvent::Peer(PeerEvent::PeerAdded(_peer_id)) => continue,
ev => { _ => {
error!("unexpected event {ev:?}") error!("unexpected event {ev:?}")
} }
} }
@ -2157,27 +2154,12 @@ mod tests {
let mut established = listener0.take(2); let mut established = listener0.take(2);
while let Some(ev) = established.next().await { while let Some(ev) = established.next().await {
match ev { match ev {
NetworkEvent::SessionEstablished { NetworkEvent::ActivePeerSession { .. } |
peer_id, NetworkEvent::Peer(PeerEvent::SessionEstablished(_)) => {
remote_addr,
client_version,
capabilities,
messages,
status,
version,
} => {
// to insert a new peer in transactions peerset // to insert a new peer in transactions peerset
transactions.on_network_event(NetworkEvent::SessionEstablished { transactions.on_network_event(ev);
peer_id,
remote_addr,
client_version,
capabilities,
messages,
status,
version,
})
} }
NetworkEvent::PeerAdded(_peer_id) => continue, NetworkEvent::Peer(PeerEvent::PeerAdded(_peer_id)) => continue,
ev => { ev => {
error!("unexpected event {ev:?}") error!("unexpected event {ev:?}")
} }
@ -2248,24 +2230,11 @@ mod tests {
let mut established = listener0.take(2); let mut established = listener0.take(2);
while let Some(ev) = established.next().await { while let Some(ev) = established.next().await {
match ev { match ev {
NetworkEvent::SessionEstablished { NetworkEvent::ActivePeerSession { .. } |
peer_id, NetworkEvent::Peer(PeerEvent::SessionEstablished(_)) => {
remote_addr, transactions.on_network_event(ev);
client_version, }
capabilities, NetworkEvent::Peer(PeerEvent::PeerAdded(_peer_id)) => continue,
messages,
status,
version,
} => transactions.on_network_event(NetworkEvent::SessionEstablished {
peer_id,
remote_addr,
client_version,
capabilities,
messages,
status,
version,
}),
NetworkEvent::PeerAdded(_peer_id) => continue,
ev => { ev => {
error!("unexpected event {ev:?}") error!("unexpected event {ev:?}")
} }
@ -2495,17 +2464,18 @@ mod tests {
network.handle().update_sync_state(SyncState::Idle); network.handle().update_sync_state(SyncState::Idle);
// mock a peer // mock a peer
let (tx, _rx) = mpsc::channel(1); let (tx, _rx) = mpsc::channel::<PeerRequest>(1);
tx_manager.on_network_event(NetworkEvent::SessionEstablished { let session_info = SessionInfo {
peer_id, peer_id,
remote_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0), remote_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0),
client_version: Arc::from(""), client_version: Arc::from(""),
capabilities: Arc::new(vec![].into()), capabilities: Arc::new(vec![].into()),
messages: PeerRequestSender::new(peer_id, tx),
status: Arc::new(Default::default()), status: Arc::new(Default::default()),
version: EthVersion::Eth68, version: EthVersion::Eth68,
}); };
let messages: PeerRequestSender<PeerRequest> = PeerRequestSender::new(peer_id, tx);
tx_manager
.on_network_event(NetworkEvent::ActivePeerSession { info: session_info, messages });
let mut propagate = vec![]; let mut propagate = vec![];
let mut factory = MockTransactionFactory::default(); let mut factory = MockTransactionFactory::default();
let eip1559_tx = Arc::new(factory.create_eip1559()); let eip1559_tx = Arc::new(factory.create_eip1559());

View File

@ -15,7 +15,10 @@ use reth_network::{
BlockDownloaderProvider, NetworkConfigBuilder, NetworkEvent, NetworkEventListenerProvider, BlockDownloaderProvider, NetworkConfigBuilder, NetworkEvent, NetworkEventListenerProvider,
NetworkManager, PeersConfig, NetworkManager, PeersConfig,
}; };
use reth_network_api::{NetworkInfo, Peers, PeersInfo}; use reth_network_api::{
events::{PeerEvent, SessionInfo},
NetworkInfo, Peers, PeersInfo,
};
use reth_network_p2p::{ use reth_network_p2p::{
headers::client::{HeadersClient, HeadersRequest}, headers::client::{HeadersClient, HeadersRequest},
sync::{NetworkSyncUpdater, SyncState}, sync::{NetworkSyncUpdater, SyncState},
@ -59,13 +62,15 @@ async fn test_establish_connections() {
let mut established = listener0.take(4); let mut established = listener0.take(4);
while let Some(ev) = established.next().await { while let Some(ev) = established.next().await {
match ev { match ev {
NetworkEvent::SessionClosed { .. } | NetworkEvent::PeerRemoved(_) => { NetworkEvent::Peer(PeerEvent::SessionClosed { .. } | PeerEvent::PeerRemoved(_)) => {
panic!("unexpected event") panic!("unexpected event")
} }
NetworkEvent::SessionEstablished { peer_id, .. } => { NetworkEvent::ActivePeerSession { info, .. } |
assert!(expected_connections.remove(&peer_id)) NetworkEvent::Peer(PeerEvent::SessionEstablished(info)) => {
let SessionInfo { peer_id, .. } = info;
assert!(expected_connections.remove(&peer_id));
} }
NetworkEvent::PeerAdded(peer_id) => { NetworkEvent::Peer(PeerEvent::PeerAdded(peer_id)) => {
assert!(expected_peers.remove(&peer_id)) assert!(expected_peers.remove(&peer_id))
} }
} }
@ -496,11 +501,16 @@ async fn test_geth_disconnect() {
handle.add_peer(geth_peer_id, geth_socket); handle.add_peer(geth_peer_id, geth_socket);
match events.next().await { match events.next().await {
Some(NetworkEvent::PeerAdded(peer_id)) => assert_eq!(peer_id, geth_peer_id), Some(NetworkEvent::Peer(PeerEvent::PeerAdded(peer_id))) => {
assert_eq!(peer_id, geth_peer_id)
}
_ => panic!("Expected a peer added event"), _ => panic!("Expected a peer added event"),
} }
if let Some(NetworkEvent::SessionEstablished { peer_id, .. }) = events.next().await { if let Some(NetworkEvent::Peer(PeerEvent::SessionEstablished(session_info))) =
events.next().await
{
let SessionInfo { peer_id, .. } = session_info;
assert_eq!(peer_id, geth_peer_id); assert_eq!(peer_id, geth_peer_id);
} else { } else {
panic!("Expected a session established event"); panic!("Expected a session established event");
@ -510,7 +520,9 @@ async fn test_geth_disconnect() {
handle.disconnect_peer(geth_peer_id); handle.disconnect_peer(geth_peer_id);
// wait for a disconnect from geth // wait for a disconnect from geth
if let Some(NetworkEvent::SessionClosed { peer_id, .. }) = events.next().await { if let Some(NetworkEvent::Peer(PeerEvent::SessionClosed { peer_id, .. })) =
events.next().await
{
assert_eq!(peer_id, geth_peer_id); assert_eq!(peer_id, geth_peer_id);
} else { } else {
panic!("Expected a session closed event"); panic!("Expected a session closed event");

View File

@ -6,7 +6,10 @@ use reth_network::{
test_utils::{PeerConfig, Testnet}, test_utils::{PeerConfig, Testnet},
NetworkEvent, NetworkEventListenerProvider, NetworkEvent, NetworkEventListenerProvider,
}; };
use reth_network_api::{NetworkInfo, Peers}; use reth_network_api::{
events::{PeerEvent, SessionInfo},
NetworkInfo, Peers,
};
use reth_provider::test_utils::NoopProvider; use reth_provider::test_utils::NoopProvider;
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
@ -28,10 +31,11 @@ async fn test_session_established_with_highest_version() {
while let Some(event) = events.next().await { while let Some(event) = events.next().await {
match event { match event {
NetworkEvent::PeerAdded(peer_id) => { NetworkEvent::Peer(PeerEvent::PeerAdded(peer_id)) => {
assert_eq!(handle1.peer_id(), &peer_id); assert_eq!(handle1.peer_id(), &peer_id);
} }
NetworkEvent::SessionEstablished { peer_id, status, .. } => { NetworkEvent::ActivePeerSession { info, .. } => {
let SessionInfo { peer_id, status, .. } = info;
assert_eq!(handle1.peer_id(), &peer_id); assert_eq!(handle1.peer_id(), &peer_id);
assert_eq!(status.version, EthVersion::Eth68); assert_eq!(status.version, EthVersion::Eth68);
} }
@ -66,10 +70,11 @@ async fn test_session_established_with_different_capability() {
while let Some(event) = events.next().await { while let Some(event) = events.next().await {
match event { match event {
NetworkEvent::PeerAdded(peer_id) => { NetworkEvent::Peer(PeerEvent::PeerAdded(peer_id)) => {
assert_eq!(handle1.peer_id(), &peer_id); assert_eq!(handle1.peer_id(), &peer_id);
} }
NetworkEvent::SessionEstablished { peer_id, status, .. } => { NetworkEvent::ActivePeerSession { info, .. } => {
let SessionInfo { peer_id, status, .. } = info;
assert_eq!(handle1.peer_id(), &peer_id); assert_eq!(handle1.peer_id(), &peer_id);
assert_eq!(status.version, EthVersion::Eth66); assert_eq!(status.version, EthVersion::Eth66);
} }

View File

@ -7,7 +7,7 @@ use alloy_primitives::{PrimitiveSignature as Signature, U256};
use futures::StreamExt; use futures::StreamExt;
use rand::thread_rng; use rand::thread_rng;
use reth_network::{test_utils::Testnet, NetworkEvent, NetworkEventListenerProvider}; use reth_network::{test_utils::Testnet, NetworkEvent, NetworkEventListenerProvider};
use reth_network_api::PeersInfo; use reth_network_api::{events::PeerEvent, PeersInfo};
use reth_primitives::TransactionSigned; use reth_primitives::TransactionSigned;
use reth_provider::test_utils::{ExtendedAccount, MockEthProvider}; use reth_provider::test_utils::{ExtendedAccount, MockEthProvider};
use reth_transaction_pool::{test_utils::TransactionGenerator, PoolTransaction, TransactionPool}; use reth_transaction_pool::{test_utils::TransactionGenerator, PoolTransaction, TransactionPool};
@ -139,16 +139,17 @@ async fn test_sending_invalid_transactions() {
// await disconnect for bad tx spam // await disconnect for bad tx spam
if let Some(ev) = peer1_events.next().await { if let Some(ev) = peer1_events.next().await {
match ev { match ev {
NetworkEvent::SessionClosed { peer_id, .. } => { NetworkEvent::Peer(PeerEvent::SessionClosed { peer_id, .. }) => {
assert_eq!(peer_id, *peer0.peer_id()); assert_eq!(peer_id, *peer0.peer_id());
} }
NetworkEvent::SessionEstablished { .. } => { NetworkEvent::ActivePeerSession { .. } |
NetworkEvent::Peer(PeerEvent::SessionEstablished { .. }) => {
panic!("unexpected SessionEstablished event") panic!("unexpected SessionEstablished event")
} }
NetworkEvent::PeerAdded(_) => { NetworkEvent::Peer(PeerEvent::PeerAdded(_)) => {
panic!("unexpected PeerAdded event") panic!("unexpected PeerAdded event")
} }
NetworkEvent::PeerRemoved(_) => { NetworkEvent::Peer(PeerEvent::PeerRemoved(_)) => {
panic!("unexpected PeerRemoved event") panic!("unexpected PeerRemoved event")
} }
} }

View File

@ -787,8 +787,24 @@ The `TransactionsManager.network_events` stream is the first to have all of its
The events received in this channel are of type `NetworkEvent`: The events received in this channel are of type `NetworkEvent`:
[File: crates/net/network/src/manager.rs](https://github.com/paradigmxyz/reth/blob/1563506aea09049a85e5cc72c2894f3f7a371581/crates/net/network/src/manager.rs) [File: crates/net/network/src/manager.rs](https://github.com/paradigmxyz/reth/blob/1563506aea09049a85e5cc72c2894f3f7a371581/crates/net/network/src/manager.rs)
```rust,ignore ```rust,ignore
pub enum NetworkEvent { pub enum NetworkEvent<R = PeerRequest> {
/// Basic peer lifecycle event.
Peer(PeerEvent),
/// Session established with requests.
ActivePeerSession {
/// Session information
info: SessionInfo,
/// A request channel to the session task.
messages: PeerRequestSender<R>,
},
}
```
and with
```rust,ignore
pub enum PeerEvent {
/// Closed the peer session. /// Closed the peer session.
SessionClosed { SessionClosed {
/// The identifier of the peer to which a session was closed. /// The identifier of the peer to which a session was closed.
@ -797,29 +813,29 @@ pub enum NetworkEvent {
reason: Option<DisconnectReason>, reason: Option<DisconnectReason>,
}, },
/// Established a new session with the given peer. /// Established a new session with the given peer.
SessionEstablished { SessionEstablished(SessionInfo),
/// The identifier of the peer to which a session was established.
peer_id: PeerId,
/// Capabilities the peer announced
capabilities: Arc<Capabilities>,
/// A request channel to the session task.
messages: PeerRequestSender,
/// The status of the peer to which a session was established.
status: Status,
},
/// Event emitted when a new peer is added /// Event emitted when a new peer is added
PeerAdded(PeerId), PeerAdded(PeerId),
/// Event emitted when a new peer is removed /// Event emitted when a new peer is removed
PeerRemoved(PeerId), PeerRemoved(PeerId),
} }
``` ```
[File: crates/net/network-api/src/events.rs](https://github.com/paradigmxyz/reth/blob/c46b5fc1157d12184d1dceb4dc45e26cf74b2bc6/crates/net/network-api/src/events.rs)
They're handled with the `on_network_event` method, which responds to the two variants of the `NetworkEvent` enum in the following ways: They're handled with the `on_network_event` method, which processes session events through both `NetworkEvent::Peer(PeerEvent::SessionClosed)`, `NetworkEvent::Peer(PeerEvent::SessionEstablished)`, and `NetworkEvent::ActivePeerSession` for initializing peer connections and transaction broadcasting.
**`NetworkEvent::SessionClosed`** Variants of the `PeerEvent` enum are defined in the following ways:
**`PeerEvent::PeerAdded`**
Adds a peer to the network node via network handle
**`PeerEvent::PeerRemoved`**
Removes the peer given by `NetworkEvent::SessionClosed.peer_id` from the `TransactionsManager.peers` map. Removes the peer given by `NetworkEvent::SessionClosed.peer_id` from the `TransactionsManager.peers` map.
**`NetworkEvent::SessionEstablished`** **`PeerEvent::SessionClosed`**
Closes the peer session after disconnection
**`PeerEvent::SessionEstablished`**
Begins by inserting a `Peer` into `TransactionsManager.peers` by `peer_id`, which is a struct of the following form: Begins by inserting a `Peer` into `TransactionsManager.peers` by `peer_id`, which is a struct of the following form:
[File: crates/net/network/src/transactions.rs](https://github.com/paradigmxyz/reth/blob/1563506aea09049a85e5cc72c2894f3f7a371581/crates/net/network/src/transactions.rs) [File: crates/net/network/src/transactions.rs](https://github.com/paradigmxyz/reth/blob/1563506aea09049a85e5cc72c2894f3f7a371581/crates/net/network/src/transactions.rs)
@ -840,33 +856,30 @@ After the `Peer` is added to `TransactionsManager.peers`, the hashes of all of t
[File: crates/net/network/src/transactions.rs](https://github.com/paradigmxyz/reth/blob/1563506aea09049a85e5cc72c2894f3f7a371581/crates/net/network/src/transactions.rs) [File: crates/net/network/src/transactions.rs](https://github.com/paradigmxyz/reth/blob/1563506aea09049a85e5cc72c2894f3f7a371581/crates/net/network/src/transactions.rs)
```rust,ignore ```rust,ignore
fn on_network_event(&mut self, event: NetworkEvent) { fn on_network_event(&mut self, event_result: NetworkEvent) {
match event { match event_result {
NetworkEvent::SessionClosed { peer_id, .. } => { NetworkEvent::Peer(PeerEvent::SessionClosed { peer_id, .. }) => {
// remove the peer // remove the peer
self.peers.remove(&peer_id); self.peers.remove(&peer_id);
self.transaction_fetcher.remove_peer(&peer_id);
} }
NetworkEvent::SessionEstablished { peer_id, messages, .. } => { NetworkEvent::ActivePeerSession { info, messages } => {
// insert a new peer // process active peer session and broadcast available transaction from the pool
self.peers.insert( self.handle_peer_session(info, messages);
peer_id,
Peer {
transactions: LruCache::new(
NonZeroUsize::new(PEER_TRANSACTION_CACHE_LIMIT).unwrap(),
),
request_tx: messages,
},
);
// Send a `NewPooledTransactionHashes` to the peer with _all_ transactions in the
// pool
let msg = NewPooledTransactionHashes(self.pool.pooled_transactions());
self.network.send_message(NetworkHandleMessage::SendPooledTransactionHashes {
peer_id,
msg,
})
} }
_ => {} NetworkEvent::Peer(PeerEvent::SessionEstablished(info)) => {
let peer_id = info.peer_id;
// get messages from existing peer
let messages = match self.peers.get(&peer_id) {
Some(p) => p.request_tx.clone(),
None => {
debug!(target: "net::tx", ?peer_id, "No peer request sender found");
return;
}
};
self.handle_peer_session(info, messages);
}
_ => {}
} }
} }
``` ```

View File

@ -17,7 +17,10 @@ use reth_discv4::Discv4ConfigBuilder;
use reth_network::{ use reth_network::{
EthNetworkPrimitives, NetworkConfig, NetworkEvent, NetworkEventListenerProvider, NetworkManager, EthNetworkPrimitives, NetworkConfig, NetworkEvent, NetworkEventListenerProvider, NetworkManager,
}; };
use reth_network_api::PeersInfo; use reth_network_api::{
events::{PeerEvent, SessionInfo},
PeersInfo,
};
use reth_primitives::{ForkHash, ForkId}; use reth_primitives::{ForkHash, ForkId};
use reth_tracing::{ use reth_tracing::{
tracing::info, tracing_subscriber::filter::LevelFilter, LayerInfo, LogFormat, RethTracer, tracing::info, tracing_subscriber::filter::LevelFilter, LayerInfo, LogFormat, RethTracer,
@ -78,10 +81,11 @@ async fn main() {
// For the sake of the example we only print the session established event // For the sake of the example we only print the session established event
// with the chain specific details // with the chain specific details
match evt { match evt {
NetworkEvent::SessionEstablished { status, client_version, peer_id, .. } => { NetworkEvent::ActivePeerSession { info, .. } => {
let SessionInfo { status, client_version, peer_id, .. } = info;
info!(peers=%net_handle.num_connected_peers() , %peer_id, chain = %status.chain, ?client_version, "Session established with a new peer."); info!(peers=%net_handle.num_connected_peers() , %peer_id, chain = %status.chain, ?client_version, "Session established with a new peer.");
} }
NetworkEvent::SessionClosed { peer_id, reason } => { NetworkEvent::Peer(PeerEvent::SessionClosed { peer_id, reason }) => {
info!(peers=%net_handle.num_connected_peers() , %peer_id, ?reason, "Session closed."); info!(peers=%net_handle.num_connected_peers() , %peer_id, ?reason, "Session closed.");
} }

View File

@ -16,6 +16,7 @@ secp256k1 = { workspace = true, features = [
tokio.workspace = true tokio.workspace = true
reth-network.workspace = true reth-network.workspace = true
reth-chainspec.workspace = true reth-chainspec.workspace = true
reth-network-api.workspace = true
reth-primitives.workspace = true reth-primitives.workspace = true
serde_json.workspace = true serde_json.workspace = true
reth-tracing.workspace = true reth-tracing.workspace = true

View File

@ -15,6 +15,7 @@ use reth_network::{
config::NetworkMode, EthNetworkPrimitives, NetworkConfig, NetworkEvent, config::NetworkMode, EthNetworkPrimitives, NetworkConfig, NetworkEvent,
NetworkEventListenerProvider, NetworkManager, NetworkEventListenerProvider, NetworkManager,
}; };
use reth_network_api::events::SessionInfo;
use reth_tracing::{ use reth_tracing::{
tracing::info, tracing_subscriber::filter::LevelFilter, LayerInfo, LogFormat, RethTracer, tracing::info, tracing_subscriber::filter::LevelFilter, LayerInfo, LogFormat, RethTracer,
Tracer, Tracer,
@ -71,7 +72,8 @@ async fn main() {
while let Some(evt) = events.next().await { while let Some(evt) = events.next().await {
// For the sake of the example we only print the session established event // For the sake of the example we only print the session established event
// with the chain specific details // with the chain specific details
if let NetworkEvent::SessionEstablished { status, client_version, .. } = evt { if let NetworkEvent::ActivePeerSession { info, .. } = evt {
let SessionInfo { status, client_version, .. } = info;
let chain = status.chain; let chain = status.chain;
info!(?chain, ?client_version, "Session established with a new peer."); info!(?chain, ?client_version, "Session established with a new peer.");
} }