1use reth_eth_wire_types::{
4 message::RequestPair, snap::SnapProtocolMessage, BlockAccessLists, BlockBodies, BlockHeaders,
5 Capabilities, Cells, DisconnectReason, EthMessage, EthNetworkPrimitives, EthVersion,
6 GetBlockAccessLists, GetBlockBodies, GetBlockHeaders, GetCells, GetNodeData,
7 GetPooledTransactions, GetReceipts, GetReceipts70, NetworkPrimitives, NodeData,
8 PooledTransactions, Receipts, Receipts69, Receipts70, UnifiedStatus,
9};
10use reth_ethereum_forks::ForkId;
11use reth_network_p2p::{
12 error::{RequestError, RequestResult},
13 snap::client::SnapResponse,
14};
15use reth_network_peers::{NodeRecord, PeerId};
16use reth_network_types::{PeerAddr, PeerKind};
17use reth_tokio_util::EventStream;
18use std::{
19 fmt,
20 net::SocketAddr,
21 pin::Pin,
22 sync::Arc,
23 task::{Context, Poll},
24};
25use tokio::sync::{mpsc, oneshot};
26use tokio_stream::{wrappers::UnboundedReceiverStream, Stream, StreamExt};
27
28pub struct PeerEventStream(Pin<Box<dyn Stream<Item = PeerEvent> + Send + Sync>>);
30
31impl fmt::Debug for PeerEventStream {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 f.debug_struct("PeerEventStream").finish_non_exhaustive()
34 }
35}
36
37impl PeerEventStream {
38 pub fn new<S, T>(stream: S) -> Self
41 where
42 S: Stream<Item = T> + Send + Sync + 'static,
43 T: Into<PeerEvent> + 'static,
44 {
45 let mapped_stream = stream.map(Into::into);
46 Self(Box::pin(mapped_stream))
47 }
48}
49
50impl Stream for PeerEventStream {
51 type Item = PeerEvent;
52
53 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
54 self.0.as_mut().poll_next(cx)
55 }
56}
57
58#[derive(Debug, Clone)]
60pub struct SessionInfo {
61 pub peer_id: PeerId,
63 pub remote_addr: SocketAddr,
65 pub client_version: Arc<str>,
67 pub capabilities: Arc<Capabilities>,
69 pub status: Arc<UnifiedStatus>,
71 pub version: EthVersion,
73 pub peer_kind: PeerKind,
75}
76
77#[derive(Debug, Clone)]
83pub enum PeerEvent {
84 SessionClosed {
86 peer_id: PeerId,
88 reason: Option<DisconnectReason>,
90 },
91 SessionEstablished(SessionInfo),
93 PeerAdded(PeerId),
95 PeerRemoved(PeerId),
97}
98
99#[derive(Debug)]
101pub enum NetworkEvent<R = PeerRequest> {
102 Peer(PeerEvent),
104 ActivePeerSession {
106 info: SessionInfo,
108 messages: PeerRequestSender<R>,
110 },
111}
112
113impl<R> Clone for NetworkEvent<R> {
114 fn clone(&self) -> Self {
115 match self {
116 Self::Peer(event) => Self::Peer(event.clone()),
117 Self::ActivePeerSession { info, messages } => {
118 Self::ActivePeerSession { info: info.clone(), messages: messages.clone() }
119 }
120 }
121 }
122}
123
124impl<R> From<NetworkEvent<R>> for PeerEvent {
125 fn from(event: NetworkEvent<R>) -> Self {
126 match event {
127 NetworkEvent::Peer(peer_event) => peer_event,
128 NetworkEvent::ActivePeerSession { info, .. } => Self::SessionEstablished(info),
129 }
130 }
131}
132
133#[auto_impl::auto_impl(&, Arc)]
135pub trait NetworkPeersEvents: Send + Sync {
136 fn peer_events(&self) -> PeerEventStream;
138}
139
140#[auto_impl::auto_impl(&, Arc)]
142pub trait NetworkEventListenerProvider: NetworkPeersEvents {
143 type Primitives: NetworkPrimitives;
145
146 fn event_listener(&self) -> EventStream<NetworkEvent<PeerRequest<Self::Primitives>>>;
148 fn discovery_listener(&self) -> UnboundedReceiverStream<DiscoveryEvent>;
152}
153
154#[derive(Debug, Clone, PartialEq, Eq)]
156pub enum DiscoveryEvent {
157 NewNode(DiscoveredEvent),
159 EnrForkId(NodeRecord, ForkId),
166}
167
168#[derive(Debug, Clone, PartialEq, Eq)]
170pub enum DiscoveredEvent {
171 EventQueued {
183 peer_id: PeerId,
185 addr: PeerAddr,
187 fork_id: Option<ForkId>,
190 },
191}
192
193#[derive(Debug)]
195pub enum PeerRequest<N: NetworkPrimitives = EthNetworkPrimitives> {
196 GetBlockHeaders {
200 request: GetBlockHeaders,
202 response: oneshot::Sender<RequestResult<BlockHeaders<N::BlockHeader>>>,
204 },
205 GetBlockBodies {
209 request: GetBlockBodies,
211 response: oneshot::Sender<RequestResult<BlockBodies<N::BlockBody>>>,
213 },
214 GetPooledTransactions {
218 request: GetPooledTransactions,
220 response: oneshot::Sender<RequestResult<PooledTransactions<N::PooledTransaction>>>,
222 },
223 GetNodeData {
227 request: GetNodeData,
229 response: oneshot::Sender<RequestResult<NodeData>>,
231 },
232 GetReceipts {
238 request: GetReceipts,
240 response: oneshot::Sender<RequestResult<Receipts<N::Receipt>>>,
242 },
243 GetReceipts69 {
249 request: GetReceipts,
251 response: oneshot::Sender<RequestResult<Receipts69<N::Receipt>>>,
253 },
254 GetReceipts70 {
260 request: GetReceipts70,
262 response: oneshot::Sender<RequestResult<Receipts70<N::Receipt>>>,
264 },
265 GetBlockAccessLists {
269 request: GetBlockAccessLists,
271 response: oneshot::Sender<RequestResult<BlockAccessLists>>,
273 },
274 GetCells {
278 request: GetCells,
280 response: oneshot::Sender<RequestResult<Cells>>,
282 },
283 GetSnap {
287 request: SnapProtocolMessage,
289 response: oneshot::Sender<RequestResult<SnapResponse>>,
291 },
292}
293
294#[derive(Debug)]
297pub enum RequestMessage<N: NetworkPrimitives = EthNetworkPrimitives> {
298 Eth(EthMessage<N>),
300 Snap(SnapProtocolMessage),
302}
303
304impl<N: NetworkPrimitives> PeerRequest<N> {
307 pub fn send_bad_response(self) {
309 self.send_err_response(RequestError::BadResponse)
310 }
311
312 pub fn send_err_response(self, err: RequestError) {
314 let _ = match self {
315 Self::GetBlockHeaders { response, .. } => response.send(Err(err)).ok(),
316 Self::GetBlockBodies { response, .. } => response.send(Err(err)).ok(),
317 Self::GetPooledTransactions { response, .. } => response.send(Err(err)).ok(),
318 Self::GetNodeData { response, .. } => response.send(Err(err)).ok(),
319 Self::GetReceipts { response, .. } => response.send(Err(err)).ok(),
320 Self::GetReceipts69 { response, .. } => response.send(Err(err)).ok(),
321 Self::GetReceipts70 { response, .. } => response.send(Err(err)).ok(),
322 Self::GetBlockAccessLists { response, .. } => response.send(Err(err)).ok(),
323 Self::GetCells { response, .. } => response.send(Err(err)).ok(),
324 Self::GetSnap { response, .. } => response.send(Err(err)).ok(),
325 };
326 }
327
328 #[inline]
330 pub fn is_supported_by_eth_version(&self, version: EthVersion) -> bool {
331 match self {
332 Self::GetReceipts { .. } => version < EthVersion::Eth69,
335 Self::GetReceipts69 { .. } => version == EthVersion::Eth69,
336 Self::GetReceipts70 { .. } => version >= EthVersion::Eth70,
337 Self::GetBlockAccessLists { .. } => version >= EthVersion::Eth71,
338 Self::GetCells { .. } => version >= EthVersion::Eth72,
339 _ => true,
340 }
341 }
342
343 pub fn create_request_message(&self, request_id: u64) -> RequestMessage<N> {
345 match self {
346 Self::GetBlockHeaders { request, .. } => {
347 RequestMessage::Eth(EthMessage::GetBlockHeaders(RequestPair {
348 request_id,
349 message: *request,
350 }))
351 }
352 Self::GetBlockBodies { request, .. } => {
353 RequestMessage::Eth(EthMessage::GetBlockBodies(RequestPair {
354 request_id,
355 message: request.clone(),
356 }))
357 }
358 Self::GetPooledTransactions { request, .. } => {
359 RequestMessage::Eth(EthMessage::GetPooledTransactions(RequestPair {
360 request_id,
361 message: request.clone(),
362 }))
363 }
364 Self::GetNodeData { request, .. } => {
365 RequestMessage::Eth(EthMessage::GetNodeData(RequestPair {
366 request_id,
367 message: request.clone(),
368 }))
369 }
370 Self::GetReceipts { request, .. } | Self::GetReceipts69 { request, .. } => {
371 RequestMessage::Eth(EthMessage::GetReceipts(RequestPair {
372 request_id,
373 message: request.clone(),
374 }))
375 }
376 Self::GetReceipts70 { request, .. } => {
377 RequestMessage::Eth(EthMessage::GetReceipts70(RequestPair {
378 request_id,
379 message: request.clone(),
380 }))
381 }
382 Self::GetBlockAccessLists { request, .. } => {
383 RequestMessage::Eth(EthMessage::GetBlockAccessLists(RequestPair {
384 request_id,
385 message: request.clone(),
386 }))
387 }
388 Self::GetCells { request, .. } => {
389 RequestMessage::Eth(EthMessage::GetCells(RequestPair {
390 request_id,
391 message: request.clone(),
392 }))
393 }
394 Self::GetSnap { request, .. } => {
395 let mut message = request.clone();
396 message.set_request_id(request_id);
397 RequestMessage::Snap(message)
398 }
399 }
400 }
401
402 pub fn into_get_pooled_transactions(self) -> Option<GetPooledTransactions> {
404 match self {
405 Self::GetPooledTransactions { request, .. } => Some(request),
406 _ => None,
407 }
408 }
409}
410
411pub struct PeerRequestSender<R = PeerRequest> {
413 pub peer_id: PeerId,
415 pub to_session_tx: mpsc::Sender<R>,
417}
418
419impl<R> Clone for PeerRequestSender<R> {
420 fn clone(&self) -> Self {
421 Self { peer_id: self.peer_id, to_session_tx: self.to_session_tx.clone() }
422 }
423}
424
425impl<R> PeerRequestSender<R> {
428 pub const fn new(peer_id: PeerId, to_session_tx: mpsc::Sender<R>) -> Self {
430 Self { peer_id, to_session_tx }
431 }
432
433 pub fn try_send(&self, req: R) -> Result<(), mpsc::error::TrySendError<R>> {
435 self.to_session_tx.try_send(req)
436 }
437
438 pub const fn peer_id(&self) -> &PeerId {
440 &self.peer_id
441 }
442}
443
444impl<R> fmt::Debug for PeerRequestSender<R> {
445 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446 f.debug_struct("PeerRequestSender").field("peer_id", &self.peer_id).finish_non_exhaustive()
447 }
448}
449
450#[cfg(test)]
451mod tests {
452 use super::*;
453
454 #[test]
455 fn test_get_block_access_lists_version_support() {
456 let (tx, _rx) = oneshot::channel();
457 let req: PeerRequest<EthNetworkPrimitives> =
458 PeerRequest::GetBlockAccessLists { request: GetBlockAccessLists(vec![]), response: tx };
459
460 assert!(!req.is_supported_by_eth_version(EthVersion::Eth70));
461 assert!(req.is_supported_by_eth_version(EthVersion::Eth71));
462 }
463
464 #[test]
465 fn test_get_cells_version_support() {
466 let (tx, _rx) = oneshot::channel();
467 let req: PeerRequest<EthNetworkPrimitives> =
468 PeerRequest::GetCells { request: GetCells::default(), response: tx };
469
470 assert!(!req.is_supported_by_eth_version(EthVersion::Eth71));
471 assert!(req.is_supported_by_eth_version(EthVersion::Eth72));
472 }
473
474 #[test]
475 fn test_get_receipts_version_support() {
476 let (tx, _rx) = oneshot::channel();
477 let req = PeerRequest::<EthNetworkPrimitives>::GetReceipts {
478 request: GetReceipts(vec![]),
479 response: tx,
480 };
481
482 assert!(req.is_supported_by_eth_version(EthVersion::Eth68));
483 assert!(!req.is_supported_by_eth_version(EthVersion::Eth69));
484
485 let (tx, _rx) = oneshot::channel();
486 let req = PeerRequest::<EthNetworkPrimitives>::GetReceipts69 {
487 request: GetReceipts(vec![]),
488 response: tx,
489 };
490
491 assert!(!req.is_supported_by_eth_version(EthVersion::Eth68));
492 assert!(req.is_supported_by_eth_version(EthVersion::Eth69));
493 assert!(!req.is_supported_by_eth_version(EthVersion::Eth70));
494
495 let (tx, _rx) = oneshot::channel();
496 let req = PeerRequest::<EthNetworkPrimitives>::GetReceipts70 {
497 request: GetReceipts70 { first_block_receipt_index: 0, block_hashes: vec![] },
498 response: tx,
499 };
500
501 assert!(!req.is_supported_by_eth_version(EthVersion::Eth69));
502 assert!(req.is_supported_by_eth_version(EthVersion::Eth70));
503 assert!(req.is_supported_by_eth_version(EthVersion::Eth71));
504 }
505}