1use core::sync::atomic::Ordering;
4use std::{
5 collections::VecDeque,
6 future::Future,
7 net::SocketAddr,
8 pin::Pin,
9 sync::{
10 atomic::{AtomicU64, AtomicUsize},
11 Arc,
12 },
13 task::{ready, Context, Poll},
14 time::{Duration, Instant},
15};
16
17use crate::{
18 message::{NewBlockMessage, PeerMessage, PeerResponse, PeerResponseResult},
19 session::{
20 conn::EthRlpxConnection,
21 handle::{ActiveSessionMessage, SessionCommand},
22 BlockRangeInfo, EthVersion, SessionId,
23 },
24};
25use alloy_eips::merge::{EPOCH_DURATION, EPOCH_SLOTS};
26use alloy_primitives::Sealable;
27use futures::{stream::Fuse, SinkExt, StreamExt};
28use metrics::{Counter, Gauge};
29use reth_eth_wire::{
30 errors::{EthHandshakeError, EthStreamError},
31 message::{EthBroadcastMessage, MessageError},
32 Capabilities, DisconnectP2P, DisconnectReason, EthMessage, EthSnapMessage, NetworkPrimitives,
33 NewBlockPayload,
34};
35use reth_eth_wire_types::{
36 message::RequestPair, snap::SnapProtocolMessage, NewPooledTransactionHashes,
37 RawCapabilityMessage,
38};
39use reth_metrics::common::mpsc::MeteredPollSender;
40use reth_network_api::{PeerRequest, RequestMessage};
41use reth_network_p2p::{error::RequestError, snap::client::SnapResponse};
42use reth_network_peers::PeerId;
43use reth_network_types::session::config::INITIAL_REQUEST_TIMEOUT;
44use reth_primitives_traits::Block;
45use rustc_hash::FxHashMap;
46use tokio::{
47 sync::{mpsc, mpsc::error::TrySendError, oneshot},
48 time::Interval,
49};
50use tokio_stream::wrappers::ReceiverStream;
51use tokio_util::sync::PollSender;
52use tracing::{debug, trace};
53
54pub(super) const RANGE_UPDATE_INTERVAL: Duration = EPOCH_DURATION;
60
61const MINIMUM_TIMEOUT: Duration = Duration::from_secs(2);
65
66const MAXIMUM_TIMEOUT: Duration = INITIAL_REQUEST_TIMEOUT;
68const SAMPLE_IMPACT: f64 = 0.1;
70const TIMEOUT_SCALING: u32 = 3;
72
73const MAX_QUEUED_OUTGOING_RESPONSES: usize = 4;
85
86const SHRINK_CAPACITY_THRESHOLD: usize = 64;
89
90const RECEIVE_MESSAGE_BUDGET: usize = 16;
98
99const MAX_QUEUED_BROADCAST_ITEMS: usize = 4096;
105
106#[derive(Debug, Clone)]
112pub(crate) struct BroadcastItemCounter(Arc<AtomicUsize>);
113
114impl BroadcastItemCounter {
115 pub(crate) fn new() -> Self {
117 Self(Arc::new(AtomicUsize::new(0)))
118 }
119
120 pub(crate) fn get(&self) -> usize {
122 self.0.load(Ordering::Relaxed)
123 }
124
125 pub(crate) fn try_add(&self, n: usize) -> bool {
127 let prev = self.0.fetch_add(n, Ordering::Relaxed);
128 if prev >= MAX_QUEUED_BROADCAST_ITEMS {
129 self.0.fetch_sub(n, Ordering::Relaxed);
130 false
131 } else {
132 true
133 }
134 }
135
136 pub(crate) fn sub(&self, n: usize) {
138 self.0.fetch_sub(n, Ordering::Relaxed);
139 }
140}
141
142#[expect(dead_code)]
152pub(crate) struct ActiveSession<N: NetworkPrimitives> {
153 pub(crate) next_id: u64,
155 pub(crate) conn: EthRlpxConnection<N>,
157 pub(crate) remote_peer_id: PeerId,
159 pub(crate) remote_addr: SocketAddr,
161 pub(crate) remote_capabilities: Arc<Capabilities>,
163 pub(crate) session_id: SessionId,
165 pub(crate) commands_rx: ReceiverStream<SessionCommand<N>>,
167 pub(crate) unbounded_rx: mpsc::UnboundedReceiver<SessionCommand<N>>,
170 pub(crate) unbounded_broadcast_msgs: Counter,
172 pub(crate) to_session_manager: MeteredPollSender<ActiveSessionMessage<N>>,
174 pub(crate) pending_message_to_session: Option<ActiveSessionMessage<N>>,
176 pub(crate) internal_request_rx: Fuse<ReceiverStream<PeerRequest<N>>>,
178 pub(crate) inflight_requests: FxHashMap<u64, InflightRequest<PeerRequest<N>>>,
181 pub(crate) received_requests_from_remote: Vec<ReceivedRequest<N>>,
183 pub(crate) queued_outgoing: QueuedOutgoingMessages<N>,
185 pub(crate) internal_request_timeout: Arc<AtomicU64>,
187 pub(crate) internal_request_timeout_interval: Interval,
189 pub(crate) protocol_breach_request_timeout: Duration,
192 pub(crate) terminate_message:
194 Option<(PollSender<ActiveSessionMessage<N>>, ActiveSessionMessage<N>)>,
195 pub(crate) range_info: Option<BlockRangeInfo>,
198 pub(crate) local_range_info: BlockRangeInfo,
201 pub(crate) range_update_interval: Option<Interval>,
205 pub(crate) last_sent_latest_block: Option<u64>,
208}
209
210impl<N: NetworkPrimitives> ActiveSession<N> {
211 fn is_disconnecting(&self) -> bool {
213 self.conn.inner().is_disconnecting()
214 }
215
216 const fn next_id(&mut self) -> u64 {
218 let id = self.next_id;
219 self.next_id += 1;
220 id
221 }
222
223 pub fn shrink_to_fit(&mut self) {
229 self.queued_outgoing.shrink_to_fit();
230 }
231
232 fn poll_send_queued(&mut self, cx: &mut Context<'_>) -> Result<bool, EthStreamError> {
244 let mut progress = false;
245 while let Poll::Ready(ready) = self.conn.poll_ready_unpin(cx) {
246 ready?;
247 let Some(msg) = self.queued_outgoing.pop_front() else { break };
248 progress = true;
249 let res = match msg {
250 OutgoingMessage::Snap(msg) => self.conn.start_send_snap(msg),
251 OutgoingMessage::Eth(msg) => self.conn.start_send_unpin(msg),
252 OutgoingMessage::Broadcast(msg) => self.conn.start_send_broadcast(msg),
253 OutgoingMessage::Raw(msg) => self.conn.start_send_raw(msg),
254 };
255 res?;
256 }
257 Ok(progress)
258 }
259
260 fn on_incoming_message(&mut self, msg: EthMessage<N>) -> OnIncomingMessageOutcome<N> {
264 macro_rules! on_request {
268 ($req:ident, $resp_item:ident, $req_item:ident) => {{
269 let RequestPair { request_id, message: request } = $req;
270 let (tx, response) = oneshot::channel();
271 let received = ReceivedRequest {
272 request_id,
273 rx: PeerResponse::$resp_item { response },
274 received: Instant::now(),
275 };
276 self.received_requests_from_remote.push(received);
277 self.try_emit_request(PeerMessage::EthRequest(PeerRequest::$req_item {
278 request,
279 response: tx,
280 }))
281 .into()
282 }};
283 }
284
285 macro_rules! on_response {
287 ($resp:ident, $item:ident) => {{
288 let RequestPair { request_id, message } = $resp;
289 if let Some(req) = self.inflight_requests.remove(&request_id) {
290 match req.request {
291 RequestState::Waiting(PeerRequest::$item { response, .. }) => {
292 trace!(peer_id=?self.remote_peer_id, ?request_id, "received response from peer");
293 let _ = response.send(Ok(message));
294 self.update_request_timeout(req.timestamp, Instant::now());
295 }
296 RequestState::Waiting(request) => {
297 debug!(target: "net::session", ?request_id, remote_peer_id=?self.remote_peer_id, "received response of wrong type");
302 self.on_bad_message();
303 request.send_bad_response();
304 }
305 RequestState::TimedOut => {
306 self.update_request_timeout(req.timestamp, Instant::now());
308 }
309 }
310 } else {
311 trace!(peer_id=?self.remote_peer_id, ?request_id, "received response to unknown request");
312 self.on_bad_message();
314 }
315
316 OnIncomingMessageOutcome::Ok
317 }};
318 }
319
320 match msg {
321 message @ EthMessage::Status(_) => OnIncomingMessageOutcome::BadMessage {
322 error: EthStreamError::EthHandshakeError(EthHandshakeError::StatusNotInHandshake),
323 message,
324 },
325 EthMessage::NewBlockHashes(msg) => {
326 self.try_emit_broadcast(PeerMessage::NewBlockHashes(msg)).into()
327 }
328 EthMessage::NewBlock(msg) => {
329 let block = NewBlockMessage {
330 hash: msg.block().header().hash_slow(),
331 block: Arc::new(*msg),
332 };
333 self.try_emit_broadcast(PeerMessage::NewBlock(block)).into()
334 }
335 EthMessage::Transactions(msg) => {
336 self.try_emit_broadcast(PeerMessage::ReceivedTransaction(msg)).into()
337 }
338 EthMessage::NewPooledTransactionHashes66(msg) => {
339 self.try_emit_broadcast(PeerMessage::PooledTransactions(msg.into())).into()
340 }
341 EthMessage::NewPooledTransactionHashes68(msg) => {
342 self.try_emit_broadcast(PeerMessage::PooledTransactions(msg.into())).into()
343 }
344 EthMessage::NewPooledTransactionHashes72(msg) => {
345 self.try_emit_broadcast(PeerMessage::PooledTransactions(msg.into())).into()
346 }
347 EthMessage::GetBlockHeaders(req) => {
348 on_request!(req, BlockHeaders, GetBlockHeaders)
349 }
350 EthMessage::BlockHeaders(resp) => {
351 on_response!(resp, GetBlockHeaders)
352 }
353 EthMessage::GetBlockBodies(req) => {
354 on_request!(req, BlockBodies, GetBlockBodies)
355 }
356 EthMessage::BlockBodies(resp) => {
357 on_response!(resp, GetBlockBodies)
358 }
359 EthMessage::GetPooledTransactions(req) => {
360 on_request!(req, PooledTransactions, GetPooledTransactions)
361 }
362 EthMessage::PooledTransactions(resp) => {
363 on_response!(resp, GetPooledTransactions)
364 }
365 EthMessage::GetNodeData(req) => {
366 on_request!(req, NodeData, GetNodeData)
367 }
368 EthMessage::NodeData(resp) => {
369 on_response!(resp, GetNodeData)
370 }
371 EthMessage::GetReceipts(req) => {
372 if self.conn.version() >= EthVersion::Eth69 {
373 on_request!(req, Receipts69, GetReceipts69)
374 } else {
375 on_request!(req, Receipts, GetReceipts)
376 }
377 }
378 EthMessage::GetReceipts70(req) => {
379 on_request!(req, Receipts70, GetReceipts70)
380 }
381 EthMessage::Receipts(resp) => {
382 on_response!(resp, GetReceipts)
383 }
384 EthMessage::Receipts69(resp) => {
385 on_response!(resp, GetReceipts69)
386 }
387 EthMessage::Receipts70(resp) => {
388 on_response!(resp, GetReceipts70)
389 }
390 EthMessage::GetBlockAccessLists(req) => {
391 on_request!(req, BlockAccessLists, GetBlockAccessLists)
392 }
393 EthMessage::BlockAccessLists(resp) => {
394 on_response!(resp, GetBlockAccessLists)
395 }
396 EthMessage::Cells(resp) => {
397 on_response!(resp, GetCells)
398 }
399 EthMessage::BlockRangeUpdate(msg) => {
400 if msg.earliest > msg.latest {
402 return OnIncomingMessageOutcome::BadMessage {
403 error: EthStreamError::InvalidMessage(MessageError::Other(format!(
404 "invalid block range: earliest ({}) > latest ({})",
405 msg.earliest, msg.latest
406 ))),
407 message: EthMessage::BlockRangeUpdate(msg),
408 };
409 }
410
411 if msg.latest_hash.is_zero() {
413 return OnIncomingMessageOutcome::BadMessage {
414 error: EthStreamError::InvalidMessage(MessageError::Other(
415 "invalid block range: latest_hash cannot be zero".to_string(),
416 )),
417 message: EthMessage::BlockRangeUpdate(msg),
418 };
419 }
420
421 if let Some(range_info) = self.range_info.as_ref() {
422 range_info.update(msg.earliest, msg.latest, msg.latest_hash);
423 }
424
425 OnIncomingMessageOutcome::Ok
426 }
427 EthMessage::GetCells(resp) => {
428 on_request!(resp, Cells, GetCells)
429 }
430 EthMessage::Other(bytes) => self.try_emit_broadcast(PeerMessage::Other(bytes)).into(),
431 }
432 }
433
434 fn on_incoming_snap_message(
441 &mut self,
442 mut msg: SnapProtocolMessage,
443 ) -> OnIncomingMessageOutcome<N> {
444 let request_id = msg.request_id();
445 if !msg.is_response() {
446 let (tx, response) = oneshot::channel();
447 self.received_requests_from_remote.push(ReceivedRequest {
448 request_id,
449 rx: PeerResponse::Snap { response },
450 received: Instant::now(),
451 });
452 return self
453 .try_emit_request(PeerMessage::EthRequest(PeerRequest::GetSnap {
454 request: msg,
455 response: tx,
456 }))
457 .into()
458 }
459
460 let Some(req) = self.inflight_requests.remove(&request_id) else {
461 trace!(target: "net::session", ?request_id, remote_peer_id=?self.remote_peer_id, "received snap response to unknown request");
462 self.on_bad_message();
463 return OnIncomingMessageOutcome::Ok
464 };
465
466 match req.request {
467 RequestState::Waiting(PeerRequest::GetSnap { request, response }) => {
468 if Some(msg.message_id()) != request.message_id().response() {
469 debug!(target: "net::session", ?request_id, msg_id=?msg.message_id(), remote_peer_id=?self.remote_peer_id, "received snap response of wrong type");
470 self.on_bad_message();
471 let _ = response.send(Err(RequestError::BadResponse));
472 return OnIncomingMessageOutcome::Ok
473 }
474 msg.set_request_id(request.request_id());
476 match SnapResponse::try_from(msg) {
477 Ok(snap_response) => {
478 trace!(target: "net::session", ?request_id, remote_peer_id=?self.remote_peer_id, "received snap response from peer");
479 let _ = response.send(Ok(snap_response));
480 self.update_request_timeout(req.timestamp, Instant::now());
481 }
482 Err(_) => {
483 let _ = response.send(Err(RequestError::BadResponse));
484 }
485 }
486 }
487 RequestState::Waiting(request) => {
488 debug!(target: "net::session", ?request_id, msg_id=?msg.message_id(), remote_peer_id=?self.remote_peer_id, "received snap response for non-snap request");
492 self.on_bad_message();
493 request.send_bad_response();
494 }
495 RequestState::TimedOut => {
496 self.update_request_timeout(req.timestamp, Instant::now());
497 }
498 }
499 OnIncomingMessageOutcome::Ok
500 }
501
502 fn on_internal_peer_request(&mut self, request: PeerRequest<N>, deadline: Instant) {
504 let version = self.conn.version();
505 if !Self::is_request_supported_for_version(&request, version) {
506 debug!(
507 target: "net",
508 ?request,
509 peer_id=?self.remote_peer_id,
510 ?version,
511 "Request not supported for negotiated eth version",
512 );
513 request.send_err_response(RequestError::UnsupportedCapability);
514 return;
515 }
516
517 if matches!(request, PeerRequest::GetSnap { .. }) && !self.conn.supports_snap() {
520 request.send_err_response(RequestError::UnsupportedCapability);
521 return;
522 }
523
524 let request_id = self.next_id();
525 trace!(?request, peer_id=?self.remote_peer_id, ?request_id, "sending request to peer");
526 let msg = match request.create_request_message(request_id) {
527 RequestMessage::Eth(msg) => msg.into(),
528 RequestMessage::Snap(msg) => OutgoingMessage::Snap(msg),
529 };
530
531 self.queued_outgoing.push_back(msg);
532 let req = InflightRequest {
533 request: RequestState::Waiting(request),
534 timestamp: Instant::now(),
535 deadline,
536 };
537 self.inflight_requests.insert(request_id, req);
538 }
539
540 #[inline]
541 fn is_request_supported_for_version(request: &PeerRequest<N>, version: EthVersion) -> bool {
542 request.is_supported_by_eth_version(version)
543 }
544
545 fn on_internal_peer_message(&mut self, msg: PeerMessage<N>) {
547 match msg {
548 PeerMessage::NewBlockHashes(msg) => {
549 self.queued_outgoing.push_back(EthMessage::NewBlockHashes(msg).into());
550 }
551 PeerMessage::NewBlock(msg) => {
552 self.queued_outgoing.push_back(EthBroadcastMessage::NewBlock(msg.block).into());
553 }
554 PeerMessage::PooledTransactions(msg) => {
555 if msg.is_valid_for_version(self.conn.version()) {
556 self.queued_outgoing.push_pooled_hashes(msg);
557 } else {
558 self.queued_outgoing.broadcast_items.sub(msg.len());
559 debug!(target: "net", ?msg, version=?self.conn.version(), "Message is invalid for connection version, skipping");
560 }
561 }
562 PeerMessage::EthRequest(req) => {
563 let deadline = self.request_deadline();
564 self.on_internal_peer_request(req, deadline);
565 }
566 PeerMessage::SendTransactions(msg) => {
567 self.queued_outgoing.push_back(EthBroadcastMessage::Transactions(msg).into());
568 }
569 PeerMessage::SendBroadcastPoolTransactions(msg) => {
570 self.queued_outgoing
571 .push_back(EthBroadcastMessage::BroadcastPoolTransactions(msg).into());
572 }
573 PeerMessage::BlockRangeUpdated(_) => {}
574 PeerMessage::ReceivedTransaction(_) => {
575 unreachable!("Not emitted by network")
576 }
577 PeerMessage::Other(other) => {
578 self.queued_outgoing.push_back(OutgoingMessage::Raw(other));
579 }
580 }
581 }
582
583 fn request_deadline(&self) -> Instant {
585 Instant::now() +
586 Duration::from_millis(self.internal_request_timeout.load(Ordering::Relaxed))
587 }
588
589 fn handle_outgoing_response(&mut self, id: u64, resp: PeerResponseResult<N>) {
593 match resp.try_into_message(id) {
594 Ok(RequestMessage::Eth(msg)) => {
595 self.queued_outgoing.push_back(msg.into());
596 }
597 Ok(RequestMessage::Snap(msg)) => {
598 self.queued_outgoing.push_back(OutgoingMessage::Snap(msg));
599 }
600 Err(err) => {
601 debug!(target: "net", %err, "Failed to respond to received request");
602 }
603 }
604 }
605
606 #[expect(clippy::result_large_err)]
610 fn try_emit_broadcast(&self, message: PeerMessage<N>) -> Result<(), ActiveSessionMessage<N>> {
611 let Some(sender) = self.to_session_manager.inner().get_ref() else { return Ok(()) };
612
613 match sender
614 .try_send(ActiveSessionMessage::ValidMessage { peer_id: self.remote_peer_id, message })
615 {
616 Ok(_) => Ok(()),
617 Err(err) => {
618 trace!(
619 target: "net",
620 %err,
621 "no capacity for incoming broadcast",
622 );
623 match err {
624 TrySendError::Full(msg) => Err(msg),
625 TrySendError::Closed(_) => Ok(()),
626 }
627 }
628 }
629 }
630
631 #[expect(clippy::result_large_err)]
636 fn try_emit_request(&self, message: PeerMessage<N>) -> Result<(), ActiveSessionMessage<N>> {
637 let Some(sender) = self.to_session_manager.inner().get_ref() else { return Ok(()) };
638
639 match sender
640 .try_send(ActiveSessionMessage::ValidMessage { peer_id: self.remote_peer_id, message })
641 {
642 Ok(_) => Ok(()),
643 Err(err) => {
644 trace!(
645 target: "net",
646 %err,
647 "no capacity for incoming request",
648 );
649 match err {
650 TrySendError::Full(msg) => Err(msg),
651 TrySendError::Closed(_) => {
652 Ok(())
655 }
656 }
657 }
658 }
659 }
660
661 fn on_bad_message(&self) {
663 let Some(sender) = self.to_session_manager.inner().get_ref() else { return };
664 let _ = sender.try_send(ActiveSessionMessage::BadMessage { peer_id: self.remote_peer_id });
665 }
666
667 fn emit_disconnect(&mut self, cx: &mut Context<'_>) -> Poll<()> {
669 trace!(target: "net::session", remote_peer_id=?self.remote_peer_id, "emitting disconnect");
670 let msg = ActiveSessionMessage::Disconnected {
671 peer_id: self.remote_peer_id,
672 remote_addr: self.remote_addr,
673 };
674
675 self.terminate_message = Some((self.to_session_manager.inner().clone(), msg));
676 self.poll_terminate_message(cx).expect("message is set")
677 }
678
679 fn close_on_error(&mut self, error: EthStreamError, cx: &mut Context<'_>) -> Poll<()> {
681 let msg = ActiveSessionMessage::ClosedOnConnectionError {
682 peer_id: self.remote_peer_id,
683 remote_addr: self.remote_addr,
684 error,
685 };
686 self.terminate_message = Some((self.to_session_manager.inner().clone(), msg));
687 self.poll_terminate_message(cx).expect("message is set")
688 }
689
690 fn start_disconnect(&mut self, reason: DisconnectReason) -> Result<(), EthStreamError> {
692 Ok(self.conn.inner_mut().start_disconnect(reason)?)
693 }
694
695 fn poll_disconnect(&mut self, cx: &mut Context<'_>) -> Poll<()> {
697 debug_assert!(self.is_disconnecting(), "not disconnecting");
698
699 let _ = ready!(self.conn.poll_close_unpin(cx));
701 self.emit_disconnect(cx)
702 }
703
704 fn try_disconnect(&mut self, reason: DisconnectReason, cx: &mut Context<'_>) -> Poll<()> {
706 match self.start_disconnect(reason) {
707 Ok(()) => {
708 self.poll_disconnect(cx)
710 }
711 Err(err) => {
712 debug!(target: "net::session", %err, remote_peer_id=?self.remote_peer_id, "could not send disconnect");
713 self.close_on_error(err, cx)
714 }
715 }
716 }
717
718 #[must_use]
727 fn check_timed_out_requests(&mut self, now: Instant) -> bool {
728 for (id, req) in &mut self.inflight_requests {
729 if req.is_timed_out(now) {
730 if req.is_waiting() {
731 debug!(target: "net::session", ?id, remote_peer_id=?self.remote_peer_id, "timed out outgoing request");
732 req.timeout();
733 } else if now - req.timestamp > self.protocol_breach_request_timeout {
734 return true
735 }
736 }
737 }
738
739 false
740 }
741
742 fn update_request_timeout(&mut self, sent: Instant, received: Instant) {
744 let elapsed = received.saturating_duration_since(sent);
745
746 let current = Duration::from_millis(self.internal_request_timeout.load(Ordering::Relaxed));
747 let request_timeout = calculate_new_timeout(current, elapsed);
748 self.internal_request_timeout.store(request_timeout.as_millis() as u64, Ordering::Relaxed);
749 self.internal_request_timeout_interval = request_timeout_interval(request_timeout);
750 }
751
752 fn poll_terminate_message(&mut self, cx: &mut Context<'_>) -> Option<Poll<()>> {
754 let (mut tx, msg) = self.terminate_message.take()?;
755 match tx.poll_reserve(cx) {
756 Poll::Pending => {
757 self.terminate_message = Some((tx, msg));
758 return Some(Poll::Pending)
759 }
760 Poll::Ready(Ok(())) => {
761 let _ = tx.send_item(msg);
762 }
763 Poll::Ready(Err(_)) => {
764 }
766 }
767 Some(Poll::Ready(()))
769 }
770}
771
772impl<N: NetworkPrimitives> Future for ActiveSession<N> {
773 type Output = ();
774
775 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
776 let this = self.get_mut();
777
778 if let Some(terminate) = this.poll_terminate_message(cx) {
780 return terminate
781 }
782
783 if this.is_disconnecting() {
784 return this.poll_disconnect(cx)
785 }
786
787 let mut budget = RECEIVE_MESSAGE_BUDGET;
793
794 'main: loop {
796 let mut progress = false;
797 let mut receive_pending = false;
798
799 loop {
801 match this.commands_rx.poll_next_unpin(cx) {
802 Poll::Pending => break,
803 Poll::Ready(None) => {
804 return Poll::Ready(())
807 }
808 Poll::Ready(Some(cmd)) => {
809 progress = true;
810 match cmd {
811 SessionCommand::Disconnect { reason } => {
812 debug!(
813 target: "net::session",
814 ?reason,
815 remote_peer_id=?this.remote_peer_id,
816 "Received disconnect command for session"
817 );
818 let reason =
819 reason.unwrap_or(DisconnectReason::DisconnectRequested);
820
821 return this.try_disconnect(reason, cx)
822 }
823 SessionCommand::Message(msg) => {
824 this.on_internal_peer_message(msg);
825 }
826 }
827 }
828 }
829 }
830
831 while let Poll::Ready(Some(cmd)) = this.unbounded_rx.poll_recv(cx) {
833 progress = true;
834 match cmd {
835 SessionCommand::Message(msg) => {
836 this.unbounded_broadcast_msgs.increment(1);
837 this.on_internal_peer_message(msg);
838 }
839 SessionCommand::Disconnect { reason } => {
840 let reason = reason.unwrap_or(DisconnectReason::DisconnectRequested);
841 return this.try_disconnect(reason, cx);
842 }
843 }
844 }
845
846 let deadline = this.request_deadline();
847
848 while let Poll::Ready(Some(req)) = this.internal_request_rx.poll_next_unpin(cx) {
849 progress = true;
850 this.on_internal_peer_request(req, deadline);
851 }
852
853 for idx in (0..this.received_requests_from_remote.len()).rev() {
856 let mut req = this.received_requests_from_remote.swap_remove(idx);
857 match req.rx.poll(cx) {
858 Poll::Pending => {
859 this.received_requests_from_remote.push(req);
861 }
862 Poll::Ready(resp) => {
863 this.handle_outgoing_response(req.request_id, resp);
864 }
865 }
866 }
867
868 match this.poll_send_queued(cx) {
873 Ok(sent) => progress |= sent,
874 Err(err) => {
875 debug!(target: "net::session", %err, remote_peer_id=?this.remote_peer_id, "failed to send message");
876 return this.close_on_error(err, cx)
878 }
879 }
880
881 'receive: loop {
883 budget -= 1;
885 if budget == 0 {
886 cx.waker().wake_by_ref();
888 break 'main
889 }
890
891 if let Some(msg) = this.pending_message_to_session.take() {
895 match this.to_session_manager.poll_reserve(cx) {
896 Poll::Ready(Ok(_)) => {
897 let _ = this.to_session_manager.send_item(msg);
898 }
899 Poll::Ready(Err(_)) => return Poll::Ready(()),
900 Poll::Pending => {
901 this.pending_message_to_session = Some(msg);
902 break 'receive
903 }
904 };
905 }
906
907 if this.received_requests_from_remote.len() > MAX_QUEUED_OUTGOING_RESPONSES {
909 break 'receive
915 }
916
917 if this.queued_outgoing.response_count() > MAX_QUEUED_OUTGOING_RESPONSES {
919 break 'receive
926 }
927
928 match this.conn.poll_next_unpin(cx) {
929 Poll::Pending => {
930 receive_pending = true;
931 break
932 }
933 Poll::Ready(None) => {
934 if this.is_disconnecting() {
935 break
936 }
937 debug!(target: "net::session", remote_peer_id=?this.remote_peer_id, "eth stream completed");
938 return this.emit_disconnect(cx)
939 }
940 Poll::Ready(Some(res)) => {
941 match res {
942 Ok(msg) => {
943 let outcome = match msg {
944 EthSnapMessage::Eth(msg) => {
945 trace!(target: "net::session", msg_id=?msg.message_id(), remote_peer_id=?this.remote_peer_id, "received eth message");
946 this.on_incoming_message(msg)
948 }
949 EthSnapMessage::Snap(msg) => this.on_incoming_snap_message(msg),
950 };
951 match outcome {
952 OnIncomingMessageOutcome::Ok => {
953 progress = true;
955 }
956 OnIncomingMessageOutcome::BadMessage { error, message } => {
957 debug!(target: "net::session", %error, msg=?message, remote_peer_id=?this.remote_peer_id, "received invalid protocol message");
958 this.on_bad_message();
959 return this
960 .try_disconnect(DisconnectReason::ProtocolBreach, cx)
961 }
962 OnIncomingMessageOutcome::NoCapacity(msg) => {
963 this.pending_message_to_session = Some(msg);
965 }
966 }
967 }
968 Err(err) => {
969 debug!(target: "net::session", %err, remote_peer_id=?this.remote_peer_id, "failed to receive message");
970 if err.is_protocol_breach() {
971 this.on_bad_message();
972 return this.try_disconnect(DisconnectReason::ProtocolBreach, cx)
973 }
974 return this.close_on_error(err, cx)
975 }
976 }
977 }
978 }
979 }
980
981 if receive_pending &&
984 this.queued_outgoing.is_empty() &&
985 this.pending_message_to_session.is_none() &&
986 this.received_requests_from_remote.is_empty()
987 {
988 break 'main
989 }
990
991 if !progress {
992 break 'main
993 }
994 }
995
996 if let Some(interval) = &mut this.range_update_interval {
997 while interval.poll_tick(cx).is_ready() {
999 let current_latest = this.local_range_info.latest();
1000 let should_send = this.last_sent_latest_block.is_none_or(|last_sent| {
1003 current_latest.saturating_sub(last_sent) >= EPOCH_SLOTS
1004 });
1005
1006 if should_send {
1007 this.queued_outgoing.push_back(
1008 EthMessage::BlockRangeUpdate(this.local_range_info.to_message()).into(),
1009 );
1010 this.last_sent_latest_block = Some(current_latest);
1011 }
1012 }
1013 }
1014
1015 if !this.inflight_requests.is_empty() {
1016 while this.internal_request_timeout_interval.poll_tick(cx).is_ready() {
1017 if this.check_timed_out_requests(Instant::now()) &&
1019 let Poll::Ready(Ok(_)) = this.to_session_manager.poll_reserve(cx)
1020 {
1021 let msg = ActiveSessionMessage::ProtocolBreach { peer_id: this.remote_peer_id };
1022 this.pending_message_to_session = Some(msg);
1023 }
1024 }
1025 }
1026
1027 if let Err(err) = this.poll_send_queued(cx) {
1031 debug!(target: "net::session", %err, remote_peer_id=?this.remote_peer_id, "failed to send message");
1032 return this.close_on_error(err, cx)
1033 }
1034 match this.conn.poll_flush_unpin(cx) {
1035 Poll::Pending | Poll::Ready(Ok(())) => {}
1036 Poll::Ready(Err(err)) => {
1037 debug!(target: "net::session", %err, remote_peer_id=?this.remote_peer_id, "failed to flush connection");
1038 return this.close_on_error(err, cx)
1039 }
1040 }
1041
1042 this.shrink_to_fit();
1043
1044 Poll::Pending
1045 }
1046}
1047
1048pub(crate) struct ReceivedRequest<N: NetworkPrimitives> {
1050 request_id: u64,
1052 rx: PeerResponse<N>,
1054 #[expect(dead_code)]
1056 received: Instant,
1057}
1058
1059pub(crate) struct InflightRequest<R> {
1061 request: RequestState<R>,
1063 timestamp: Instant,
1065 deadline: Instant,
1067}
1068
1069impl<N: NetworkPrimitives> InflightRequest<PeerRequest<N>> {
1070 #[inline]
1072 fn is_timed_out(&self, now: Instant) -> bool {
1073 now > self.deadline
1074 }
1075
1076 #[inline]
1078 const fn is_waiting(&self) -> bool {
1079 matches!(self.request, RequestState::Waiting(_))
1080 }
1081
1082 fn timeout(&mut self) {
1084 let mut req = RequestState::TimedOut;
1085 std::mem::swap(&mut self.request, &mut req);
1086
1087 if let RequestState::Waiting(req) = req {
1088 req.send_err_response(RequestError::Timeout);
1089 }
1090 }
1091}
1092
1093enum OnIncomingMessageOutcome<N: NetworkPrimitives> {
1095 Ok,
1097 BadMessage { error: EthStreamError, message: EthMessage<N> },
1099 NoCapacity(ActiveSessionMessage<N>),
1101}
1102
1103impl<N: NetworkPrimitives> From<Result<(), ActiveSessionMessage<N>>>
1104 for OnIncomingMessageOutcome<N>
1105{
1106 fn from(res: Result<(), ActiveSessionMessage<N>>) -> Self {
1107 match res {
1108 Ok(_) => Self::Ok,
1109 Err(msg) => Self::NoCapacity(msg),
1110 }
1111 }
1112}
1113
1114enum RequestState<R> {
1115 Waiting(R),
1117 TimedOut,
1119}
1120
1121#[derive(Debug)]
1123pub(crate) enum OutgoingMessage<N: NetworkPrimitives> {
1124 Eth(EthMessage<N>),
1126 Broadcast(EthBroadcastMessage<N>),
1128 Raw(RawCapabilityMessage),
1130 Snap(SnapProtocolMessage),
1132}
1133
1134impl<N: NetworkPrimitives> OutgoingMessage<N> {
1135 const fn is_response(&self) -> bool {
1137 match self {
1138 Self::Eth(msg) => msg.is_response(),
1139 Self::Snap(msg) => msg.is_response(),
1142 Self::Broadcast(_) | Self::Raw(_) => false,
1143 }
1144 }
1145
1146 fn broadcast_item_count(&self) -> usize {
1152 match self {
1153 Self::Eth(msg) => match msg {
1154 EthMessage::NewBlockHashes(h) => h.len(),
1155 EthMessage::NewPooledTransactionHashes66(h) => h.len(),
1156 EthMessage::NewPooledTransactionHashes68(h) => h.hashes.len(),
1157 EthMessage::NewPooledTransactionHashes72(h) => h.hashes.len(),
1158 _ => 0,
1159 },
1160 Self::Broadcast(msg) => match msg {
1161 EthBroadcastMessage::NewBlock(_) => 1,
1162 EthBroadcastMessage::Transactions(txs) => txs.len(),
1163 EthBroadcastMessage::BroadcastPoolTransactions(txs) => txs.len(),
1164 },
1165 Self::Raw(_) | Self::Snap(_) => 0,
1166 }
1167 }
1168
1169 fn try_merge_hashes(
1172 &mut self,
1173 incoming: NewPooledTransactionHashes,
1174 ) -> Option<NewPooledTransactionHashes> {
1175 let Self::Eth(eth) = self else { return Some(incoming) };
1176 match (eth, incoming) {
1177 (
1178 EthMessage::NewPooledTransactionHashes66(existing),
1179 NewPooledTransactionHashes::Eth66(inc),
1180 ) => {
1181 existing.extend(inc);
1182 None
1183 }
1184 (
1185 EthMessage::NewPooledTransactionHashes68(existing),
1186 NewPooledTransactionHashes::Eth68(inc),
1187 ) => {
1188 existing.hashes.extend(inc.hashes);
1189 existing.sizes.extend(inc.sizes);
1190 existing.types.extend(inc.types);
1191 None
1192 }
1193 (
1194 EthMessage::NewPooledTransactionHashes72(existing),
1195 NewPooledTransactionHashes::Eth72(inc),
1196 ) => {
1197 if existing.cell_mask != inc.cell_mask {
1199 return Some(inc.into())
1200 }
1201 existing.hashes.extend(inc.hashes);
1202 existing.sizes.extend(inc.sizes);
1203 existing.types.extend(inc.types);
1204 None
1205 }
1206 (_, incoming) => Some(incoming),
1207 }
1208 }
1209}
1210
1211impl<N: NetworkPrimitives> From<EthMessage<N>> for OutgoingMessage<N> {
1212 fn from(value: EthMessage<N>) -> Self {
1213 Self::Eth(value)
1214 }
1215}
1216
1217impl<N: NetworkPrimitives> From<EthBroadcastMessage<N>> for OutgoingMessage<N> {
1218 fn from(value: EthBroadcastMessage<N>) -> Self {
1219 Self::Broadcast(value)
1220 }
1221}
1222
1223pub(super) fn request_timeout_interval(timeout: Duration) -> Interval {
1228 let mut interval = tokio::time::interval(timeout);
1229 interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1230 interval
1231}
1232
1233#[inline]
1235fn calculate_new_timeout(current_timeout: Duration, estimated_rtt: Duration) -> Duration {
1236 let new_timeout = estimated_rtt.mul_f64(SAMPLE_IMPACT) * TIMEOUT_SCALING;
1237
1238 let smoothened_timeout = current_timeout.mul_f64(1.0 - SAMPLE_IMPACT) + new_timeout;
1240
1241 smoothened_timeout.clamp(MINIMUM_TIMEOUT, MAXIMUM_TIMEOUT)
1242}
1243
1244pub(crate) struct QueuedOutgoingMessages<N: NetworkPrimitives> {
1251 messages: VecDeque<OutgoingMessage<N>>,
1252 queued_responses: usize,
1255 count: Gauge,
1256 broadcast_items: BroadcastItemCounter,
1258}
1259
1260impl<N: NetworkPrimitives> QueuedOutgoingMessages<N> {
1261 pub(crate) const fn new(metric: Gauge, broadcast_items: BroadcastItemCounter) -> Self {
1262 Self { messages: VecDeque::new(), queued_responses: 0, count: metric, broadcast_items }
1263 }
1264
1265 pub(crate) const fn response_count(&self) -> usize {
1267 self.queued_responses
1268 }
1269
1270 pub(crate) fn is_empty(&self) -> bool {
1271 self.messages.is_empty()
1272 }
1273
1274 pub(crate) fn push_back(&mut self, message: OutgoingMessage<N>) {
1275 self.queued_responses += message.is_response() as usize;
1276 self.messages.push_back(message);
1277 self.count.increment(1);
1278 }
1279
1280 pub(crate) fn pop_front(&mut self) -> Option<OutgoingMessage<N>> {
1281 self.messages.pop_front().inspect(|msg| {
1282 self.count.decrement(1);
1283 self.queued_responses -= msg.is_response() as usize;
1284 let items = msg.broadcast_item_count();
1285 if items > 0 {
1286 self.broadcast_items.sub(items);
1287 }
1288 })
1289 }
1290
1291 pub(crate) fn push_pooled_hashes(&mut self, msg: NewPooledTransactionHashes) {
1294 let msg = if let Some(last) = self.messages.back_mut() {
1295 match last.try_merge_hashes(msg) {
1296 None => return,
1297 Some(msg) => msg,
1298 }
1299 } else {
1300 msg
1301 };
1302 self.messages.push_back(EthMessage::from(msg).into());
1303 self.count.increment(1);
1304 }
1305
1306 pub(crate) fn shrink_to_fit(&mut self) {
1310 if self.messages.is_empty() && self.messages.capacity() > SHRINK_CAPACITY_THRESHOLD {
1311 self.messages.shrink_to(MAX_QUEUED_OUTGOING_RESPONSES);
1312 }
1313 }
1314}
1315
1316impl<N: NetworkPrimitives> Drop for QueuedOutgoingMessages<N> {
1317 fn drop(&mut self) {
1318 let remaining = self.messages.len();
1320 if remaining > 0 {
1321 self.count.decrement(remaining as f64);
1322 }
1323 }
1324}
1325
1326#[cfg(test)]
1327mod tests {
1328 use super::*;
1329 use crate::session::{handle::PendingSessionEvent, start_pending_incoming_session};
1330 use alloy_eips::eip2124::ForkFilter;
1331 use alloy_primitives::{B128, B256};
1332 use futures::task::noop_waker;
1333 use reth_chainspec::MAINNET;
1334 use reth_ecies::stream::ECIESStream;
1335 use reth_eth_wire::{
1336 handshake::EthHandshake, protocol::Protocol, BlockBodies, BlockHeaders,
1337 EthNetworkPrimitives, EthStream, GetBlockAccessLists, GetBlockBodies,
1338 HelloMessageWithProtocols, P2PStream, StatusBuilder, UnauthedEthStream, UnauthedP2PStream,
1339 UnifiedStatus, MAX_PAYLOAD_SIZE,
1340 };
1341 use reth_eth_wire_types::{
1342 message::MAX_MESSAGE_SIZE,
1343 snap::{
1344 AccountRangeMessage, BlockAccessListsMessage, GetAccountRangeMessage,
1345 GetBlockAccessListsMessage,
1346 },
1347 BlockAccessLists, EthMessageID, NewPooledTransactionHashes72,
1348 };
1349 use reth_ethereum_forks::EthereumHardfork;
1350 use reth_network_p2p::error::RequestResult;
1351 use reth_network_peers::pk2id;
1352 use reth_network_types::session::config::PROTOCOL_BREACH_REQUEST_TIMEOUT;
1353 use secp256k1::SecretKey;
1354 use tokio::{
1355 net::{TcpListener, TcpStream},
1356 sync::mpsc,
1357 };
1358
1359 fn eth_hello(server_key: &SecretKey) -> HelloMessageWithProtocols {
1361 HelloMessageWithProtocols::builder(pk2id(&server_key.public_key())).build()
1362 }
1363
1364 struct SessionBuilder<N: NetworkPrimitives = EthNetworkPrimitives> {
1365 _remote_capabilities: Arc<Capabilities>,
1366 active_session_tx: mpsc::Sender<ActiveSessionMessage<N>>,
1367 active_session_rx: ReceiverStream<ActiveSessionMessage<N>>,
1368 to_sessions: Vec<mpsc::Sender<SessionCommand<N>>>,
1369 secret_key: SecretKey,
1370 local_peer_id: PeerId,
1371 hello: HelloMessageWithProtocols,
1372 status: UnifiedStatus,
1373 fork_filter: ForkFilter,
1374 next_id: usize,
1375 }
1376
1377 impl<N: NetworkPrimitives> SessionBuilder<N> {
1378 fn next_id(&mut self) -> SessionId {
1379 let id = self.next_id;
1380 self.next_id += 1;
1381 SessionId(id)
1382 }
1383
1384 fn with_client_stream<F, O>(
1386 &self,
1387 local_addr: SocketAddr,
1388 f: F,
1389 ) -> Pin<Box<dyn Future<Output = ()> + Send>>
1390 where
1391 F: FnOnce(EthStream<P2PStream<ECIESStream<TcpStream>>, N>) -> O + Send + 'static,
1392 O: Future<Output = ()> + Send + Sync,
1393 {
1394 let mut status = self.status;
1395 let fork_filter = self.fork_filter.clone();
1396 let local_peer_id = self.local_peer_id;
1397 let mut hello = self.hello.clone();
1398 let key = SecretKey::new(&mut rand::rng());
1399 hello.id = pk2id(&key.public_key());
1400 Box::pin(async move {
1401 let outgoing = TcpStream::connect(local_addr).await.unwrap();
1402 let sink = ECIESStream::connect(outgoing, key, local_peer_id).await.unwrap();
1403
1404 let (p2p_stream, _) = UnauthedP2PStream::new(sink).handshake(hello).await.unwrap();
1405
1406 let eth_version = p2p_stream.shared_capabilities().eth_version().unwrap();
1407 status.set_eth_version(eth_version);
1408
1409 let (client_stream, _) = UnauthedEthStream::new(p2p_stream)
1410 .handshake(status, fork_filter)
1411 .await
1412 .unwrap();
1413 f(client_stream).await
1414 })
1415 }
1416
1417 async fn connect_incoming(&mut self, stream: TcpStream) -> ActiveSession<N> {
1418 let remote_addr = stream.local_addr().unwrap();
1419 let session_id = self.next_id();
1420 let (_disconnect_tx, disconnect_rx) = oneshot::channel();
1421 let (pending_sessions_tx, pending_sessions_rx) = mpsc::channel(1);
1422
1423 tokio::task::spawn(start_pending_incoming_session(
1424 Arc::new(EthHandshake::default()),
1425 MAX_MESSAGE_SIZE,
1426 MAX_PAYLOAD_SIZE,
1427 disconnect_rx,
1428 session_id,
1429 stream,
1430 pending_sessions_tx,
1431 remote_addr,
1432 self.secret_key,
1433 self.hello.clone(),
1434 self.status,
1435 self.fork_filter.clone(),
1436 Default::default(),
1437 ));
1438
1439 let mut stream = ReceiverStream::new(pending_sessions_rx);
1440
1441 match stream.next().await.unwrap() {
1442 PendingSessionEvent::Established {
1443 session_id,
1444 remote_addr,
1445 peer_id,
1446 capabilities,
1447 conn,
1448 ..
1449 } => {
1450 let (_to_session_tx, messages_rx) = mpsc::channel(10);
1451 let (commands_to_session, commands_rx) = mpsc::channel(10);
1452 let (_unbounded_tx, unbounded_rx) = mpsc::unbounded_channel();
1453 let poll_sender = PollSender::new(self.active_session_tx.clone());
1454
1455 self.to_sessions.push(commands_to_session);
1456
1457 ActiveSession {
1458 next_id: 0,
1459 remote_peer_id: peer_id,
1460 remote_addr,
1461 remote_capabilities: Arc::clone(&capabilities),
1462 session_id,
1463 commands_rx: ReceiverStream::new(commands_rx),
1464 unbounded_rx,
1465 unbounded_broadcast_msgs: Counter::noop(),
1466 to_session_manager: MeteredPollSender::new(
1467 poll_sender,
1468 "network_active_session",
1469 ),
1470 pending_message_to_session: None,
1471 internal_request_rx: ReceiverStream::new(messages_rx).fuse(),
1472 inflight_requests: Default::default(),
1473 conn,
1474 queued_outgoing: QueuedOutgoingMessages::new(
1475 Gauge::noop(),
1476 BroadcastItemCounter::new(),
1477 ),
1478 received_requests_from_remote: Default::default(),
1479 internal_request_timeout_interval: request_timeout_interval(
1480 INITIAL_REQUEST_TIMEOUT,
1481 ),
1482 internal_request_timeout: Arc::new(AtomicU64::new(
1483 INITIAL_REQUEST_TIMEOUT.as_millis() as u64,
1484 )),
1485 protocol_breach_request_timeout: PROTOCOL_BREACH_REQUEST_TIMEOUT,
1486 terminate_message: None,
1487 range_info: None,
1488 local_range_info: BlockRangeInfo::new(
1489 0,
1490 1000,
1491 alloy_primitives::B256::ZERO,
1492 ),
1493 range_update_interval: None,
1494 last_sent_latest_block: None,
1495 }
1496 }
1497 ev => {
1498 panic!("unexpected message {ev:?}")
1499 }
1500 }
1501 }
1502 }
1503
1504 impl Default for SessionBuilder {
1505 fn default() -> Self {
1506 let (active_session_tx, active_session_rx) = mpsc::channel(100);
1507
1508 let (secret_key, pk) = secp256k1::generate_keypair(&mut rand::rng());
1509 let local_peer_id = pk2id(&pk);
1510
1511 Self {
1512 next_id: 0,
1513 _remote_capabilities: Arc::new(Capabilities::from(vec![])),
1514 active_session_tx,
1515 active_session_rx: ReceiverStream::new(active_session_rx),
1516 to_sessions: vec![],
1517 hello: eth_hello(&secret_key),
1518 secret_key,
1519 local_peer_id,
1520 status: StatusBuilder::default().build(),
1521 fork_filter: MAINNET
1522 .hardfork_fork_filter(EthereumHardfork::Frontier)
1523 .expect("The Frontier fork filter should exist on mainnet"),
1524 }
1525 }
1526 }
1527
1528 fn snap_session_builder() -> SessionBuilder {
1532 let mut builder = SessionBuilder::default();
1533 builder.hello.try_add_protocol(Protocol::snap_2()).unwrap();
1534 builder
1535 }
1536
1537 fn dispatch_snap_request(
1540 session: &mut ActiveSession<EthNetworkPrimitives>,
1541 caller_request_id: u64,
1542 ) -> (u64, oneshot::Receiver<RequestResult<SnapResponse>>) {
1543 let (response, rx) = oneshot::channel();
1544 let request = SnapProtocolMessage::GetBlockAccessLists(GetBlockAccessListsMessage {
1545 request_id: caller_request_id,
1546 block_hashes: Vec::new(),
1547 response_bytes: 0,
1548 });
1549 let deadline = session.request_deadline();
1550 session.on_internal_peer_request(PeerRequest::GetSnap { request, response }, deadline);
1551 let id = *session.inflight_requests.keys().next().expect("snap request tracked");
1552 (id, rx)
1553 }
1554
1555 fn dispatch_block_bodies_request(
1559 session: &mut ActiveSession<EthNetworkPrimitives>,
1560 ) -> (u64, oneshot::Receiver<RequestResult<BlockBodies>>) {
1561 let (response, rx) = oneshot::channel();
1562 let deadline = session.request_deadline();
1563 session.on_internal_peer_request(
1564 PeerRequest::GetBlockBodies { request: GetBlockBodies(Vec::new()), response },
1565 deadline,
1566 );
1567 let id = *session.inflight_requests.keys().next().expect("eth request tracked");
1568 (id, rx)
1569 }
1570
1571 #[tokio::test(flavor = "multi_thread")]
1572 async fn test_disconnect() {
1573 let mut builder = SessionBuilder::default();
1574
1575 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1576 let local_addr = listener.local_addr().unwrap();
1577
1578 let expected_disconnect = DisconnectReason::UselessPeer;
1579
1580 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
1581 let msg = client_stream.next().await.unwrap().unwrap_err();
1582 assert_eq!(msg.as_disconnected().unwrap(), expected_disconnect);
1583 });
1584
1585 tokio::task::spawn(async move {
1586 let (incoming, _) = listener.accept().await.unwrap();
1587 let mut session = builder.connect_incoming(incoming).await;
1588
1589 session.start_disconnect(expected_disconnect).unwrap();
1590 session.await
1591 });
1592
1593 fut.await;
1594 }
1595
1596 #[tokio::test(flavor = "multi_thread")]
1597 async fn test_invalid_message_disconnects_with_protocol_breach() {
1598 let mut builder = SessionBuilder::default();
1599
1600 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1601 let local_addr = listener.local_addr().unwrap();
1602
1603 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
1604 client_stream
1605 .start_send_raw(RawCapabilityMessage::eth(
1606 EthMessageID::PooledTransactions,
1607 vec![0xc0].into(),
1608 ))
1609 .unwrap();
1610 client_stream.flush().await.unwrap();
1611
1612 let msg = client_stream.next().await.unwrap().unwrap_err();
1613 assert_eq!(msg.as_disconnected(), Some(DisconnectReason::ProtocolBreach));
1614 });
1615
1616 let (tx, rx) = oneshot::channel();
1617
1618 tokio::task::spawn(async move {
1619 let (incoming, _) = listener.accept().await.unwrap();
1620 let session = builder.connect_incoming(incoming).await;
1621 session.await;
1622
1623 tx.send(()).unwrap();
1624 });
1625
1626 fut.await;
1627 rx.await.unwrap();
1628 }
1629
1630 #[tokio::test(flavor = "multi_thread")]
1631 async fn test_unsolicited_response_disconnects_with_protocol_breach() {
1632 let mut builder = SessionBuilder::default();
1633
1634 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1635 let local_addr = listener.local_addr().unwrap();
1636
1637 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
1638 assert_eq!(client_stream.version(), EthVersion::Eth71);
1639 client_stream
1640 .send(EthMessage::BlockAccessLists(RequestPair {
1641 request_id: 7,
1642 message: BlockAccessLists(vec![None; 1024]),
1643 }))
1644 .await
1645 .unwrap();
1646
1647 let msg = client_stream.next().await.unwrap().unwrap_err();
1648 assert_eq!(msg.as_disconnected(), Some(DisconnectReason::ProtocolBreach));
1649 });
1650
1651 let (tx, rx) = oneshot::channel();
1652
1653 tokio::task::spawn(async move {
1654 let (incoming, _) = listener.accept().await.unwrap();
1655 let session = builder.connect_incoming(incoming).await;
1656 session.await;
1657
1658 tx.send(()).unwrap();
1659 });
1660
1661 fut.await;
1662 rx.await.unwrap();
1663 }
1664
1665 #[tokio::test(flavor = "multi_thread")]
1666 async fn handle_dropped_stream() {
1667 let mut builder = SessionBuilder::default();
1668
1669 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1670 let local_addr = listener.local_addr().unwrap();
1671
1672 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1673 drop(client_stream);
1674 tokio::time::sleep(Duration::from_secs(1)).await
1675 });
1676
1677 let (tx, rx) = oneshot::channel();
1678
1679 tokio::task::spawn(async move {
1680 let (incoming, _) = listener.accept().await.unwrap();
1681 let session = builder.connect_incoming(incoming).await;
1682 session.await;
1683
1684 tx.send(()).unwrap();
1685 });
1686
1687 tokio::task::spawn(fut);
1688
1689 rx.await.unwrap();
1690 }
1691
1692 #[tokio::test(flavor = "multi_thread")]
1693 async fn test_send_many_messages() {
1694 reth_tracing::init_test_tracing();
1695 let mut builder = SessionBuilder::default();
1696
1697 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1698 let local_addr = listener.local_addr().unwrap();
1699
1700 let num_messages = 100;
1701
1702 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
1703 for _ in 0..num_messages {
1704 client_stream
1705 .send(EthMessage::NewPooledTransactionHashes66(Vec::new().into()))
1706 .await
1707 .unwrap();
1708 }
1709 });
1710
1711 let (tx, rx) = oneshot::channel();
1712
1713 tokio::task::spawn(async move {
1714 let (incoming, _) = listener.accept().await.unwrap();
1715 let session = builder.connect_incoming(incoming).await;
1716 session.await;
1717
1718 tx.send(()).unwrap();
1719 });
1720
1721 tokio::task::spawn(fut);
1722
1723 rx.await.unwrap();
1724 }
1725
1726 #[tokio::test(flavor = "multi_thread")]
1727 async fn test_request_timeout() {
1728 reth_tracing::init_test_tracing();
1729
1730 let mut builder = SessionBuilder::default();
1731
1732 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1733 let local_addr = listener.local_addr().unwrap();
1734
1735 let request_timeout = Duration::from_millis(100);
1736 let drop_timeout = Duration::from_millis(1500);
1737
1738 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1739 let _client_stream = client_stream;
1740 tokio::time::sleep(drop_timeout * 60).await;
1741 });
1742 tokio::task::spawn(fut);
1743
1744 let (incoming, _) = listener.accept().await.unwrap();
1745 let mut session = builder.connect_incoming(incoming).await;
1746 session
1747 .internal_request_timeout
1748 .store(request_timeout.as_millis() as u64, Ordering::Relaxed);
1749 session.protocol_breach_request_timeout = drop_timeout;
1750 session.internal_request_timeout_interval =
1751 tokio::time::interval_at(tokio::time::Instant::now(), request_timeout);
1752 session
1753 .internal_request_timeout_interval
1754 .set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1755 let (tx, rx) = oneshot::channel();
1756 let req = PeerRequest::GetBlockBodies { request: GetBlockBodies(vec![]), response: tx };
1757 session.on_internal_peer_request(req, Instant::now());
1758 tokio::spawn(session);
1759
1760 let err = rx.await.unwrap().unwrap_err();
1761 assert_eq!(err, RequestError::Timeout);
1762
1763 let msg = builder.active_session_rx.next().await.unwrap();
1765 match msg {
1766 ActiveSessionMessage::ProtocolBreach { .. } => {}
1767 ev => unreachable!("{ev:?}"),
1768 }
1769 }
1770
1771 #[tokio::test(flavor = "multi_thread")]
1772 async fn snap_request_is_assigned_unique_id_and_response_correlated() {
1773 let mut builder = snap_session_builder();
1774 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1775 let local_addr = listener.local_addr().unwrap();
1776 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1777 let _client_stream = client_stream;
1778 tokio::time::sleep(Duration::from_secs(60)).await;
1779 });
1780 tokio::task::spawn(fut);
1781 let (incoming, _) = listener.accept().await.unwrap();
1782 let mut session = builder.connect_incoming(incoming).await;
1783
1784 let (id, rx) = dispatch_snap_request(&mut session, u64::MAX);
1786 assert_ne!(id, u64::MAX, "session must assign its own request id");
1787
1788 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::BlockAccessLists(
1790 BlockAccessListsMessage {
1791 request_id: id,
1792 block_access_lists: BlockAccessLists(Vec::new()),
1793 },
1794 ));
1795 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1796 assert!(!session.inflight_requests.contains_key(&id));
1797
1798 let response = rx.await.unwrap().unwrap();
1800 assert!(matches!(
1801 response,
1802 SnapResponse::BlockAccessLists(m) if m.request_id == u64::MAX
1803 ));
1804 }
1805
1806 #[tokio::test(flavor = "multi_thread")]
1807 async fn wrong_type_snap_response_is_rejected() {
1808 let mut builder = snap_session_builder();
1809 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1810 let local_addr = listener.local_addr().unwrap();
1811 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1812 let _client_stream = client_stream;
1813 tokio::time::sleep(Duration::from_secs(60)).await;
1814 });
1815 tokio::task::spawn(fut);
1816 let (incoming, _) = listener.accept().await.unwrap();
1817 let mut session = builder.connect_incoming(incoming).await;
1818
1819 let (id, rx) = dispatch_snap_request(&mut session, 0);
1820
1821 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::AccountRange(
1823 AccountRangeMessage { request_id: id, accounts: Vec::new(), proof: Vec::new() },
1824 ));
1825 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1826 assert!(!session.inflight_requests.contains_key(&id));
1827 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::BadResponse);
1828 assert!(matches!(
1829 builder.active_session_rx.next().await,
1830 Some(ActiveSessionMessage::BadMessage { .. })
1831 ));
1832 }
1833
1834 #[tokio::test(flavor = "multi_thread")]
1835 async fn late_snap_response_is_consumed_without_penalty() {
1836 let mut builder = snap_session_builder();
1837 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1838 let local_addr = listener.local_addr().unwrap();
1839 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1840 let _client_stream = client_stream;
1841 tokio::time::sleep(Duration::from_secs(60)).await;
1842 });
1843 tokio::task::spawn(fut);
1844 let (incoming, _) = listener.accept().await.unwrap();
1845 let mut session = builder.connect_incoming(incoming).await;
1846
1847 session.internal_request_timeout.store(1, Ordering::Relaxed);
1848 let (id, rx) = dispatch_snap_request(&mut session, 0);
1849 tokio::time::sleep(Duration::from_millis(20)).await;
1850 assert!(!session.check_timed_out_requests(Instant::now()));
1851 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::Timeout);
1852
1853 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::BlockAccessLists(
1855 BlockAccessListsMessage {
1856 request_id: id,
1857 block_access_lists: BlockAccessLists(Vec::new()),
1858 },
1859 ));
1860 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1861 assert!(!session.inflight_requests.contains_key(&id));
1862 assert!(futures::FutureExt::now_or_never(builder.active_session_rx.next())
1863 .flatten()
1864 .is_none());
1865 }
1866
1867 #[tokio::test(flavor = "multi_thread")]
1868 async fn unknown_snap_response_is_penalized() {
1869 let mut builder = snap_session_builder();
1870 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1871 let local_addr = listener.local_addr().unwrap();
1872 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1873 let _client_stream = client_stream;
1874 tokio::time::sleep(Duration::from_secs(60)).await;
1875 });
1876 tokio::task::spawn(fut);
1877 let (incoming, _) = listener.accept().await.unwrap();
1878 let mut session = builder.connect_incoming(incoming).await;
1879
1880 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::BlockAccessLists(
1882 BlockAccessListsMessage {
1883 request_id: 999,
1884 block_access_lists: BlockAccessLists(Vec::new()),
1885 },
1886 ));
1887 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1888 assert!(session.inflight_requests.is_empty());
1889 assert!(session.queued_outgoing.pop_front().is_none());
1890 assert!(matches!(
1891 builder.active_session_rx.next().await,
1892 Some(ActiveSessionMessage::BadMessage { .. })
1893 ));
1894 }
1895
1896 #[tokio::test(flavor = "multi_thread")]
1897 async fn wrong_type_eth_response_is_penalized() {
1898 let mut builder = SessionBuilder::default();
1899 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1900 let local_addr = listener.local_addr().unwrap();
1901 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1902 let _client_stream = client_stream;
1903 tokio::time::sleep(Duration::from_secs(60)).await;
1904 });
1905 tokio::task::spawn(fut);
1906 let (incoming, _) = listener.accept().await.unwrap();
1907 let mut session = builder.connect_incoming(incoming).await;
1908
1909 let (id, rx) = dispatch_block_bodies_request(&mut session);
1910
1911 let outcome = session.on_incoming_message(EthMessage::BlockHeaders(RequestPair {
1915 request_id: id,
1916 message: BlockHeaders(Vec::new()),
1917 }));
1918 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1919 assert!(!session.inflight_requests.contains_key(&id));
1920 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::BadResponse);
1921 assert!(matches!(
1922 futures::FutureExt::now_or_never(builder.active_session_rx.next()).flatten(),
1923 Some(ActiveSessionMessage::BadMessage { .. })
1924 ));
1925 }
1926
1927 #[tokio::test(flavor = "multi_thread")]
1928 async fn matching_eth_response_is_not_penalized() {
1929 let mut builder = SessionBuilder::default();
1930 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1931 let local_addr = listener.local_addr().unwrap();
1932 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1933 let _client_stream = client_stream;
1934 tokio::time::sleep(Duration::from_secs(60)).await;
1935 });
1936 tokio::task::spawn(fut);
1937 let (incoming, _) = listener.accept().await.unwrap();
1938 let mut session = builder.connect_incoming(incoming).await;
1939
1940 let (id, rx) = dispatch_block_bodies_request(&mut session);
1941
1942 let outcome = session.on_incoming_message(EthMessage::BlockBodies(RequestPair {
1943 request_id: id,
1944 message: BlockBodies(Vec::new()),
1945 }));
1946 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1947 assert!(!session.inflight_requests.contains_key(&id));
1948 assert!(rx.await.unwrap().is_ok());
1949 assert!(futures::FutureExt::now_or_never(builder.active_session_rx.next())
1950 .flatten()
1951 .is_none());
1952 }
1953
1954 #[tokio::test(flavor = "multi_thread")]
1955 async fn snap_response_to_eth_request_is_penalized() {
1956 let mut builder = snap_session_builder();
1957 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1958 let local_addr = listener.local_addr().unwrap();
1959 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1960 let _client_stream = client_stream;
1961 tokio::time::sleep(Duration::from_secs(60)).await;
1962 });
1963 tokio::task::spawn(fut);
1964 let (incoming, _) = listener.accept().await.unwrap();
1965 let mut session = builder.connect_incoming(incoming).await;
1966
1967 let (id, rx) = dispatch_block_bodies_request(&mut session);
1970
1971 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::AccountRange(
1972 AccountRangeMessage { request_id: id, accounts: Vec::new(), proof: Vec::new() },
1973 ));
1974 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1975 assert!(!session.inflight_requests.contains_key(&id));
1976 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::BadResponse);
1977 assert!(matches!(
1978 futures::FutureExt::now_or_never(builder.active_session_rx.next()).flatten(),
1979 Some(ActiveSessionMessage::BadMessage { .. })
1980 ));
1981 }
1982
1983 #[tokio::test(flavor = "multi_thread")]
1984 async fn get_snap_request_rejected_without_negotiated_snap() {
1985 let mut builder = SessionBuilder::default();
1987 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1988 let local_addr = listener.local_addr().unwrap();
1989 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1990 let _client_stream = client_stream;
1991 tokio::time::sleep(Duration::from_secs(60)).await;
1992 });
1993 tokio::task::spawn(fut);
1994 let (incoming, _) = listener.accept().await.unwrap();
1995 let mut session = builder.connect_incoming(incoming).await;
1996 assert!(!session.conn.supports_snap());
1997
1998 let (response, rx) = oneshot::channel();
1999 let request = SnapProtocolMessage::GetBlockAccessLists(GetBlockAccessListsMessage {
2000 request_id: 0,
2001 block_hashes: Vec::new(),
2002 response_bytes: 0,
2003 });
2004 let deadline = session.request_deadline();
2005 session.on_internal_peer_request(PeerRequest::GetSnap { request, response }, deadline);
2006
2007 assert!(session.inflight_requests.is_empty());
2009 assert!(session.queued_outgoing.pop_front().is_none());
2010 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::UnsupportedCapability);
2011 }
2012
2013 #[tokio::test(flavor = "multi_thread")]
2014 async fn inbound_snap_request_round_trips_to_a_response() {
2015 let mut builder = snap_session_builder();
2016 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
2017 let local_addr = listener.local_addr().unwrap();
2018 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
2019 let _client_stream = client_stream;
2020 tokio::time::sleep(Duration::from_secs(60)).await;
2021 });
2022 tokio::task::spawn(fut);
2023 let (incoming, _) = listener.accept().await.unwrap();
2024 let mut session = builder.connect_incoming(incoming).await;
2025
2026 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::GetAccountRange(
2028 GetAccountRangeMessage {
2029 request_id: 7,
2030 root_hash: B256::ZERO,
2031 starting_hash: B256::ZERO,
2032 limit_hash: B256::ZERO,
2033 response_bytes: 1024,
2034 },
2035 ));
2036 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
2037 assert_eq!(session.received_requests_from_remote.len(), 1);
2038
2039 let Some(ActiveSessionMessage::ValidMessage {
2041 message: PeerMessage::EthRequest(PeerRequest::GetSnap { request, response }),
2042 ..
2043 }) = builder.active_session_rx.next().await
2044 else {
2045 panic!("expected an outbound GetSnap request")
2046 };
2047 assert!(matches!(request, SnapProtocolMessage::GetAccountRange(_)));
2048
2049 let _ = response.send(Ok(SnapResponse::AccountRange(AccountRangeMessage {
2051 request_id: 7,
2052 accounts: Vec::new(),
2053 proof: Vec::new(),
2054 })));
2055
2056 let mut req = session.received_requests_from_remote.pop().unwrap();
2058 let waker = noop_waker();
2059 let mut cx = Context::from_waker(&waker);
2060 let Poll::Ready(resp) = req.rx.poll(&mut cx) else { panic!("response should be ready") };
2061 session.handle_outgoing_response(req.request_id, resp);
2062
2063 let msg = session.queued_outgoing.pop_front().expect("response queued for send");
2066 assert!(matches!(
2067 msg,
2068 OutgoingMessage::Snap(SnapProtocolMessage::AccountRange(AccountRangeMessage {
2069 request_id: 7,
2070 ..
2071 }))
2072 ));
2073 }
2074
2075 #[test]
2076 fn eth72_coalescing_preserves_cell_masks() {
2077 let masks =
2078 [None, Some(B128::repeat_byte(0xff)), Some(B128::from(1u128)), Some(B128::from(2u128))];
2079 for existing_mask in masks {
2080 for incoming_mask in masks {
2081 let announcement = |mask: Option<B128>, byte| NewPooledTransactionHashes72 {
2082 types: vec![if mask.is_some() { 3 } else { 2 }],
2083 sizes: vec![100],
2084 hashes: vec![B256::repeat_byte(byte)],
2085 cell_mask: mask,
2086 };
2087 let existing = announcement(existing_mask, 1);
2088 let incoming = announcement(incoming_mask, 2);
2089 let mut message: OutgoingMessage<EthNetworkPrimitives> =
2090 EthMessage::NewPooledTransactionHashes72(existing.clone()).into();
2091
2092 let remainder = message.try_merge_hashes(incoming.clone().into());
2093
2094 let OutgoingMessage::Eth(EthMessage::NewPooledTransactionHashes72(merged)) =
2095 message
2096 else {
2097 panic!("expected eth72 announcement");
2098 };
2099 if existing_mask == incoming_mask {
2100 assert!(remainder.is_none());
2101 assert_eq!(merged.cell_mask, existing_mask);
2102 assert_eq!(merged.hashes, vec![B256::repeat_byte(1), B256::repeat_byte(2)]);
2103 assert_eq!(merged.types, [existing.types, incoming.types].concat());
2104 assert_eq!(merged.sizes, vec![100, 100]);
2105 } else {
2106 assert_eq!(remainder, Some(incoming.into()));
2107 assert_eq!(merged, existing);
2108 }
2109 }
2110 }
2111 }
2112
2113 #[test]
2114 fn eth72_pooled_hashes_count_broadcast_items() {
2115 let hashes =
2116 vec![alloy_primitives::B256::repeat_byte(1), alloy_primitives::B256::repeat_byte(2)];
2117 let msg: OutgoingMessage<EthNetworkPrimitives> =
2118 EthMessage::NewPooledTransactionHashes72(NewPooledTransactionHashes72 {
2119 types: vec![0; hashes.len()],
2120 sizes: vec![1; hashes.len()],
2121 hashes,
2122 cell_mask: None,
2123 })
2124 .into();
2125
2126 assert_eq!(2, msg.broadcast_item_count());
2127 }
2128
2129 #[test]
2130 fn test_reject_bal_request_for_eth70() {
2131 let (tx, _rx) = oneshot::channel();
2132 let request: PeerRequest<EthNetworkPrimitives> =
2133 PeerRequest::GetBlockAccessLists { request: GetBlockAccessLists(vec![]), response: tx };
2134
2135 assert!(!ActiveSession::<EthNetworkPrimitives>::is_request_supported_for_version(
2136 &request,
2137 EthVersion::Eth70
2138 ));
2139 assert!(ActiveSession::<EthNetworkPrimitives>::is_request_supported_for_version(
2140 &request,
2141 EthVersion::Eth71
2142 ));
2143 }
2144
2145 #[tokio::test(flavor = "multi_thread")]
2146 async fn test_keep_alive() {
2147 let mut builder = SessionBuilder::default();
2148
2149 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
2150 let local_addr = listener.local_addr().unwrap();
2151
2152 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
2153 let _ = tokio::time::timeout(Duration::from_secs(1), client_stream.next()).await;
2154 client_stream.into_inner().disconnect(DisconnectReason::UselessPeer).await.unwrap();
2155 });
2156
2157 let (tx, rx) = oneshot::channel();
2158
2159 tokio::task::spawn(async move {
2160 let (incoming, _) = listener.accept().await.unwrap();
2161 let session = builder.connect_incoming(incoming).await;
2162 session.await;
2163
2164 tx.send(()).unwrap();
2165 });
2166
2167 tokio::task::spawn(fut);
2168
2169 rx.await.unwrap();
2170 }
2171
2172 #[tokio::test(flavor = "multi_thread")]
2174 async fn test_send_at_capacity() {
2175 let mut builder = SessionBuilder::default();
2176
2177 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
2178 let local_addr = listener.local_addr().unwrap();
2179
2180 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
2181 client_stream
2182 .send(EthMessage::NewPooledTransactionHashes68(Default::default()))
2183 .await
2184 .unwrap();
2185 let _ = tokio::time::timeout(Duration::from_secs(100), client_stream.next()).await;
2186 });
2187 tokio::task::spawn(fut);
2188
2189 let (incoming, _) = listener.accept().await.unwrap();
2190 let session = builder.connect_incoming(incoming).await;
2191
2192 let mut num_fill_messages = 0;
2194 loop {
2195 if builder
2196 .active_session_tx
2197 .try_send(ActiveSessionMessage::ProtocolBreach { peer_id: PeerId::random() })
2198 .is_err()
2199 {
2200 break
2201 }
2202 num_fill_messages += 1;
2203 }
2204
2205 tokio::task::spawn(async move {
2206 session.await;
2207 });
2208
2209 tokio::time::sleep(Duration::from_millis(100)).await;
2210
2211 for _ in 0..num_fill_messages {
2212 let message = builder.active_session_rx.next().await.unwrap();
2213 match message {
2214 ActiveSessionMessage::ProtocolBreach { .. } => {}
2215 ev => unreachable!("{ev:?}"),
2216 }
2217 }
2218
2219 let message = builder.active_session_rx.next().await.unwrap();
2220 match message {
2221 ActiveSessionMessage::ValidMessage {
2222 message: PeerMessage::PooledTransactions(_),
2223 ..
2224 } => {}
2225 _ => unreachable!(),
2226 }
2227 }
2228
2229 #[test]
2230 fn timeout_calculation_sanity_tests() {
2231 let rtt = Duration::from_secs(5);
2232 let timeout = rtt * TIMEOUT_SCALING;
2234
2235 assert_eq!(calculate_new_timeout(timeout, rtt), timeout);
2237
2238 assert!(calculate_new_timeout(timeout, rtt / 2) < timeout);
2240 assert!(calculate_new_timeout(timeout, rtt / 2) > timeout / 2);
2241 assert!(calculate_new_timeout(timeout, rtt * 2) > timeout);
2242 assert!(calculate_new_timeout(timeout, rtt * 2) < timeout * 2);
2243 }
2244}