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_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 = Duration::from_secs(EPOCH_SLOTS * 12);
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> {
241 let mut progress = false;
242 while self.conn.poll_ready_unpin(cx).is_ready() {
243 let Some(msg) = self.queued_outgoing.pop_front() else { break };
244 progress = true;
245 let res = match msg {
246 OutgoingMessage::Snap(msg) => self.conn.start_send_snap(msg),
247 OutgoingMessage::Eth(msg) => self.conn.start_send_unpin(msg),
248 OutgoingMessage::Broadcast(msg) => self.conn.start_send_broadcast(msg),
249 OutgoingMessage::Raw(msg) => self.conn.start_send_raw(msg),
250 };
251 res?;
252 }
253 Ok(progress)
254 }
255
256 fn on_incoming_message(&mut self, msg: EthMessage<N>) -> OnIncomingMessageOutcome<N> {
260 macro_rules! on_request {
264 ($req:ident, $resp_item:ident, $req_item:ident) => {{
265 let RequestPair { request_id, message: request } = $req;
266 let (tx, response) = oneshot::channel();
267 let received = ReceivedRequest {
268 request_id,
269 rx: PeerResponse::$resp_item { response },
270 received: Instant::now(),
271 };
272 self.received_requests_from_remote.push(received);
273 self.try_emit_request(PeerMessage::EthRequest(PeerRequest::$req_item {
274 request,
275 response: tx,
276 }))
277 .into()
278 }};
279 }
280
281 macro_rules! on_response {
283 ($resp:ident, $item:ident) => {{
284 let RequestPair { request_id, message } = $resp;
285 if let Some(req) = self.inflight_requests.remove(&request_id) {
286 match req.request {
287 RequestState::Waiting(PeerRequest::$item { response, .. }) => {
288 trace!(peer_id=?self.remote_peer_id, ?request_id, "received response from peer");
289 let _ = response.send(Ok(message));
290 self.update_request_timeout(req.timestamp, Instant::now());
291 }
292 RequestState::Waiting(request) => {
293 debug!(target: "net::session", ?request_id, remote_peer_id=?self.remote_peer_id, "received response of wrong type");
298 self.on_bad_message();
299 request.send_bad_response();
300 }
301 RequestState::TimedOut => {
302 self.update_request_timeout(req.timestamp, Instant::now());
304 }
305 }
306 } else {
307 trace!(peer_id=?self.remote_peer_id, ?request_id, "received response to unknown request");
308 self.on_bad_message();
310 }
311
312 OnIncomingMessageOutcome::Ok
313 }};
314 }
315
316 match msg {
317 message @ EthMessage::Status(_) => OnIncomingMessageOutcome::BadMessage {
318 error: EthStreamError::EthHandshakeError(EthHandshakeError::StatusNotInHandshake),
319 message,
320 },
321 EthMessage::NewBlockHashes(msg) => {
322 self.try_emit_broadcast(PeerMessage::NewBlockHashes(msg)).into()
323 }
324 EthMessage::NewBlock(msg) => {
325 let block = NewBlockMessage {
326 hash: msg.block().header().hash_slow(),
327 block: Arc::new(*msg),
328 };
329 self.try_emit_broadcast(PeerMessage::NewBlock(block)).into()
330 }
331 EthMessage::Transactions(msg) => {
332 self.try_emit_broadcast(PeerMessage::ReceivedTransaction(msg)).into()
333 }
334 EthMessage::NewPooledTransactionHashes66(msg) => {
335 self.try_emit_broadcast(PeerMessage::PooledTransactions(msg.into())).into()
336 }
337 EthMessage::NewPooledTransactionHashes68(msg) => {
338 self.try_emit_broadcast(PeerMessage::PooledTransactions(msg.into())).into()
339 }
340 EthMessage::NewPooledTransactionHashes72(msg) => {
341 self.try_emit_broadcast(PeerMessage::PooledTransactions(msg.into())).into()
342 }
343 EthMessage::GetBlockHeaders(req) => {
344 on_request!(req, BlockHeaders, GetBlockHeaders)
345 }
346 EthMessage::BlockHeaders(resp) => {
347 on_response!(resp, GetBlockHeaders)
348 }
349 EthMessage::GetBlockBodies(req) => {
350 on_request!(req, BlockBodies, GetBlockBodies)
351 }
352 EthMessage::BlockBodies(resp) => {
353 on_response!(resp, GetBlockBodies)
354 }
355 EthMessage::GetPooledTransactions(req) => {
356 on_request!(req, PooledTransactions, GetPooledTransactions)
357 }
358 EthMessage::PooledTransactions(resp) => {
359 on_response!(resp, GetPooledTransactions)
360 }
361 EthMessage::GetNodeData(req) => {
362 on_request!(req, NodeData, GetNodeData)
363 }
364 EthMessage::NodeData(resp) => {
365 on_response!(resp, GetNodeData)
366 }
367 EthMessage::GetReceipts(req) => {
368 if self.conn.version() >= EthVersion::Eth69 {
369 on_request!(req, Receipts69, GetReceipts69)
370 } else {
371 on_request!(req, Receipts, GetReceipts)
372 }
373 }
374 EthMessage::GetReceipts70(req) => {
375 on_request!(req, Receipts70, GetReceipts70)
376 }
377 EthMessage::Receipts(resp) => {
378 on_response!(resp, GetReceipts)
379 }
380 EthMessage::Receipts69(resp) => {
381 on_response!(resp, GetReceipts69)
382 }
383 EthMessage::Receipts70(resp) => {
384 on_response!(resp, GetReceipts70)
385 }
386 EthMessage::GetBlockAccessLists(req) => {
387 on_request!(req, BlockAccessLists, GetBlockAccessLists)
388 }
389 EthMessage::BlockAccessLists(resp) => {
390 on_response!(resp, GetBlockAccessLists)
391 }
392 EthMessage::Cells(resp) => {
393 on_response!(resp, GetCells)
394 }
395 EthMessage::BlockRangeUpdate(msg) => {
396 if msg.earliest > msg.latest {
398 return OnIncomingMessageOutcome::BadMessage {
399 error: EthStreamError::InvalidMessage(MessageError::Other(format!(
400 "invalid block range: earliest ({}) > latest ({})",
401 msg.earliest, msg.latest
402 ))),
403 message: EthMessage::BlockRangeUpdate(msg),
404 };
405 }
406
407 if msg.latest_hash.is_zero() {
409 return OnIncomingMessageOutcome::BadMessage {
410 error: EthStreamError::InvalidMessage(MessageError::Other(
411 "invalid block range: latest_hash cannot be zero".to_string(),
412 )),
413 message: EthMessage::BlockRangeUpdate(msg),
414 };
415 }
416
417 if let Some(range_info) = self.range_info.as_ref() {
418 range_info.update(msg.earliest, msg.latest, msg.latest_hash);
419 }
420
421 OnIncomingMessageOutcome::Ok
422 }
423 EthMessage::GetCells(resp) => {
424 on_request!(resp, Cells, GetCells)
425 }
426 EthMessage::Other(bytes) => self.try_emit_broadcast(PeerMessage::Other(bytes)).into(),
427 }
428 }
429
430 fn on_incoming_snap_message(
437 &mut self,
438 mut msg: SnapProtocolMessage,
439 ) -> OnIncomingMessageOutcome<N> {
440 let request_id = msg.request_id();
441 if !msg.is_response() {
442 let (tx, response) = oneshot::channel();
443 self.received_requests_from_remote.push(ReceivedRequest {
444 request_id,
445 rx: PeerResponse::Snap { response },
446 received: Instant::now(),
447 });
448 return self
449 .try_emit_request(PeerMessage::EthRequest(PeerRequest::GetSnap {
450 request: msg,
451 response: tx,
452 }))
453 .into()
454 }
455
456 let Some(req) = self.inflight_requests.remove(&request_id) else {
457 trace!(target: "net::session", ?request_id, remote_peer_id=?self.remote_peer_id, "received snap response to unknown request");
458 self.on_bad_message();
459 return OnIncomingMessageOutcome::Ok
460 };
461
462 match req.request {
463 RequestState::Waiting(PeerRequest::GetSnap { request, response }) => {
464 if Some(msg.message_id()) != request.message_id().response() {
465 debug!(target: "net::session", ?request_id, msg_id=?msg.message_id(), remote_peer_id=?self.remote_peer_id, "received snap response of wrong type");
466 self.on_bad_message();
467 let _ = response.send(Err(RequestError::BadResponse));
468 return OnIncomingMessageOutcome::Ok
469 }
470 msg.set_request_id(request.request_id());
472 match SnapResponse::try_from(msg) {
473 Ok(snap_response) => {
474 trace!(target: "net::session", ?request_id, remote_peer_id=?self.remote_peer_id, "received snap response from peer");
475 let _ = response.send(Ok(snap_response));
476 self.update_request_timeout(req.timestamp, Instant::now());
477 }
478 Err(_) => {
479 let _ = response.send(Err(RequestError::BadResponse));
480 }
481 }
482 }
483 RequestState::Waiting(request) => {
484 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");
488 self.on_bad_message();
489 request.send_bad_response();
490 }
491 RequestState::TimedOut => {
492 self.update_request_timeout(req.timestamp, Instant::now());
493 }
494 }
495 OnIncomingMessageOutcome::Ok
496 }
497
498 fn on_internal_peer_request(&mut self, request: PeerRequest<N>, deadline: Instant) {
500 let version = self.conn.version();
501 if !Self::is_request_supported_for_version(&request, version) {
502 debug!(
503 target: "net",
504 ?request,
505 peer_id=?self.remote_peer_id,
506 ?version,
507 "Request not supported for negotiated eth version",
508 );
509 request.send_err_response(RequestError::UnsupportedCapability);
510 return;
511 }
512
513 if matches!(request, PeerRequest::GetSnap { .. }) && !self.conn.supports_snap() {
516 request.send_err_response(RequestError::UnsupportedCapability);
517 return;
518 }
519
520 let request_id = self.next_id();
521 trace!(?request, peer_id=?self.remote_peer_id, ?request_id, "sending request to peer");
522 let msg = match request.create_request_message(request_id) {
523 RequestMessage::Eth(msg) => msg.map_versioned(version).into(),
524 RequestMessage::Snap(msg) => OutgoingMessage::Snap(msg),
525 };
526
527 self.queued_outgoing.push_back(msg);
528 let req = InflightRequest {
529 request: RequestState::Waiting(request),
530 timestamp: Instant::now(),
531 deadline,
532 };
533 self.inflight_requests.insert(request_id, req);
534 }
535
536 #[inline]
537 fn is_request_supported_for_version(request: &PeerRequest<N>, version: EthVersion) -> bool {
538 request.is_supported_by_eth_version(version)
539 }
540
541 fn on_internal_peer_message(&mut self, msg: PeerMessage<N>) {
543 match msg {
544 PeerMessage::NewBlockHashes(msg) => {
545 self.queued_outgoing.push_back(EthMessage::NewBlockHashes(msg).into());
546 }
547 PeerMessage::NewBlock(msg) => {
548 self.queued_outgoing.push_back(EthBroadcastMessage::NewBlock(msg.block).into());
549 }
550 PeerMessage::PooledTransactions(msg) => {
551 if msg.is_valid_for_version(self.conn.version()) {
552 self.queued_outgoing.push_pooled_hashes(msg);
553 } else {
554 self.queued_outgoing.broadcast_items.sub(msg.len());
555 debug!(target: "net", ?msg, version=?self.conn.version(), "Message is invalid for connection version, skipping");
556 }
557 }
558 PeerMessage::EthRequest(req) => {
559 let deadline = self.request_deadline();
560 self.on_internal_peer_request(req, deadline);
561 }
562 PeerMessage::SendTransactions(msg) => {
563 self.queued_outgoing.push_back(EthBroadcastMessage::Transactions(msg).into());
564 }
565 PeerMessage::SendBroadcastPoolTransactions(msg) => {
566 self.queued_outgoing
567 .push_back(EthBroadcastMessage::BroadcastPoolTransactions(msg).into());
568 }
569 PeerMessage::BlockRangeUpdated(_) => {}
570 PeerMessage::ReceivedTransaction(_) => {
571 unreachable!("Not emitted by network")
572 }
573 PeerMessage::Other(other) => {
574 self.queued_outgoing.push_back(OutgoingMessage::Raw(other));
575 }
576 }
577 }
578
579 fn request_deadline(&self) -> Instant {
581 Instant::now() +
582 Duration::from_millis(self.internal_request_timeout.load(Ordering::Relaxed))
583 }
584
585 fn handle_outgoing_response(&mut self, id: u64, resp: PeerResponseResult<N>) {
589 match resp.try_into_message(id) {
590 Ok(RequestMessage::Eth(msg)) => {
591 self.queued_outgoing.push_back(msg.into());
592 }
593 Ok(RequestMessage::Snap(msg)) => {
594 self.queued_outgoing.push_back(OutgoingMessage::Snap(msg));
595 }
596 Err(err) => {
597 debug!(target: "net", %err, "Failed to respond to received request");
598 }
599 }
600 }
601
602 #[expect(clippy::result_large_err)]
606 fn try_emit_broadcast(&self, message: PeerMessage<N>) -> Result<(), ActiveSessionMessage<N>> {
607 let Some(sender) = self.to_session_manager.inner().get_ref() else { return Ok(()) };
608
609 match sender
610 .try_send(ActiveSessionMessage::ValidMessage { peer_id: self.remote_peer_id, message })
611 {
612 Ok(_) => Ok(()),
613 Err(err) => {
614 trace!(
615 target: "net",
616 %err,
617 "no capacity for incoming broadcast",
618 );
619 match err {
620 TrySendError::Full(msg) => Err(msg),
621 TrySendError::Closed(_) => Ok(()),
622 }
623 }
624 }
625 }
626
627 #[expect(clippy::result_large_err)]
632 fn try_emit_request(&self, message: PeerMessage<N>) -> Result<(), ActiveSessionMessage<N>> {
633 let Some(sender) = self.to_session_manager.inner().get_ref() else { return Ok(()) };
634
635 match sender
636 .try_send(ActiveSessionMessage::ValidMessage { peer_id: self.remote_peer_id, message })
637 {
638 Ok(_) => Ok(()),
639 Err(err) => {
640 trace!(
641 target: "net",
642 %err,
643 "no capacity for incoming request",
644 );
645 match err {
646 TrySendError::Full(msg) => Err(msg),
647 TrySendError::Closed(_) => {
648 Ok(())
651 }
652 }
653 }
654 }
655 }
656
657 fn on_bad_message(&self) {
659 let Some(sender) = self.to_session_manager.inner().get_ref() else { return };
660 let _ = sender.try_send(ActiveSessionMessage::BadMessage { peer_id: self.remote_peer_id });
661 }
662
663 fn emit_disconnect(&mut self, cx: &mut Context<'_>) -> Poll<()> {
665 trace!(target: "net::session", remote_peer_id=?self.remote_peer_id, "emitting disconnect");
666 let msg = ActiveSessionMessage::Disconnected {
667 peer_id: self.remote_peer_id,
668 remote_addr: self.remote_addr,
669 };
670
671 self.terminate_message = Some((self.to_session_manager.inner().clone(), msg));
672 self.poll_terminate_message(cx).expect("message is set")
673 }
674
675 fn close_on_error(&mut self, error: EthStreamError, cx: &mut Context<'_>) -> Poll<()> {
677 let msg = ActiveSessionMessage::ClosedOnConnectionError {
678 peer_id: self.remote_peer_id,
679 remote_addr: self.remote_addr,
680 error,
681 };
682 self.terminate_message = Some((self.to_session_manager.inner().clone(), msg));
683 self.poll_terminate_message(cx).expect("message is set")
684 }
685
686 fn start_disconnect(&mut self, reason: DisconnectReason) -> Result<(), EthStreamError> {
688 Ok(self.conn.inner_mut().start_disconnect(reason)?)
689 }
690
691 fn poll_disconnect(&mut self, cx: &mut Context<'_>) -> Poll<()> {
693 debug_assert!(self.is_disconnecting(), "not disconnecting");
694
695 let _ = ready!(self.conn.poll_close_unpin(cx));
697 self.emit_disconnect(cx)
698 }
699
700 fn try_disconnect(&mut self, reason: DisconnectReason, cx: &mut Context<'_>) -> Poll<()> {
702 match self.start_disconnect(reason) {
703 Ok(()) => {
704 self.poll_disconnect(cx)
706 }
707 Err(err) => {
708 debug!(target: "net::session", %err, remote_peer_id=?self.remote_peer_id, "could not send disconnect");
709 self.close_on_error(err, cx)
710 }
711 }
712 }
713
714 #[must_use]
723 fn check_timed_out_requests(&mut self, now: Instant) -> bool {
724 for (id, req) in &mut self.inflight_requests {
725 if req.is_timed_out(now) {
726 if req.is_waiting() {
727 debug!(target: "net::session", ?id, remote_peer_id=?self.remote_peer_id, "timed out outgoing request");
728 req.timeout();
729 } else if now - req.timestamp > self.protocol_breach_request_timeout {
730 return true
731 }
732 }
733 }
734
735 false
736 }
737
738 fn update_request_timeout(&mut self, sent: Instant, received: Instant) {
740 let elapsed = received.saturating_duration_since(sent);
741
742 let current = Duration::from_millis(self.internal_request_timeout.load(Ordering::Relaxed));
743 let request_timeout = calculate_new_timeout(current, elapsed);
744 self.internal_request_timeout.store(request_timeout.as_millis() as u64, Ordering::Relaxed);
745 self.internal_request_timeout_interval = request_timeout_interval(request_timeout);
746 }
747
748 fn poll_terminate_message(&mut self, cx: &mut Context<'_>) -> Option<Poll<()>> {
750 let (mut tx, msg) = self.terminate_message.take()?;
751 match tx.poll_reserve(cx) {
752 Poll::Pending => {
753 self.terminate_message = Some((tx, msg));
754 return Some(Poll::Pending)
755 }
756 Poll::Ready(Ok(())) => {
757 let _ = tx.send_item(msg);
758 }
759 Poll::Ready(Err(_)) => {
760 }
762 }
763 Some(Poll::Ready(()))
765 }
766}
767
768impl<N: NetworkPrimitives> Future for ActiveSession<N> {
769 type Output = ();
770
771 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
772 let this = self.get_mut();
773
774 if let Some(terminate) = this.poll_terminate_message(cx) {
776 return terminate
777 }
778
779 if this.is_disconnecting() {
780 return this.poll_disconnect(cx)
781 }
782
783 let mut budget = RECEIVE_MESSAGE_BUDGET;
789
790 'main: loop {
792 let mut progress = false;
793 let mut receive_pending = false;
794
795 loop {
797 match this.commands_rx.poll_next_unpin(cx) {
798 Poll::Pending => break,
799 Poll::Ready(None) => {
800 return Poll::Ready(())
803 }
804 Poll::Ready(Some(cmd)) => {
805 progress = true;
806 match cmd {
807 SessionCommand::Disconnect { reason } => {
808 debug!(
809 target: "net::session",
810 ?reason,
811 remote_peer_id=?this.remote_peer_id,
812 "Received disconnect command for session"
813 );
814 let reason =
815 reason.unwrap_or(DisconnectReason::DisconnectRequested);
816
817 return this.try_disconnect(reason, cx)
818 }
819 SessionCommand::Message(msg) => {
820 this.on_internal_peer_message(msg);
821 }
822 }
823 }
824 }
825 }
826
827 while let Poll::Ready(Some(cmd)) = this.unbounded_rx.poll_recv(cx) {
829 progress = true;
830 match cmd {
831 SessionCommand::Message(msg) => {
832 this.unbounded_broadcast_msgs.increment(1);
833 this.on_internal_peer_message(msg);
834 }
835 SessionCommand::Disconnect { reason } => {
836 let reason = reason.unwrap_or(DisconnectReason::DisconnectRequested);
837 return this.try_disconnect(reason, cx);
838 }
839 }
840 }
841
842 let deadline = this.request_deadline();
843
844 while let Poll::Ready(Some(req)) = this.internal_request_rx.poll_next_unpin(cx) {
845 progress = true;
846 this.on_internal_peer_request(req, deadline);
847 }
848
849 for idx in (0..this.received_requests_from_remote.len()).rev() {
852 let mut req = this.received_requests_from_remote.swap_remove(idx);
853 match req.rx.poll(cx) {
854 Poll::Pending => {
855 this.received_requests_from_remote.push(req);
857 }
858 Poll::Ready(resp) => {
859 this.handle_outgoing_response(req.request_id, resp);
860 }
861 }
862 }
863
864 match this.poll_send_queued(cx) {
869 Ok(sent) => progress |= sent,
870 Err(err) => {
871 debug!(target: "net::session", %err, remote_peer_id=?this.remote_peer_id, "failed to send message");
872 return this.close_on_error(err, cx)
874 }
875 }
876
877 'receive: loop {
879 budget -= 1;
881 if budget == 0 {
882 cx.waker().wake_by_ref();
884 break 'main
885 }
886
887 if let Some(msg) = this.pending_message_to_session.take() {
891 match this.to_session_manager.poll_reserve(cx) {
892 Poll::Ready(Ok(_)) => {
893 let _ = this.to_session_manager.send_item(msg);
894 }
895 Poll::Ready(Err(_)) => return Poll::Ready(()),
896 Poll::Pending => {
897 this.pending_message_to_session = Some(msg);
898 break 'receive
899 }
900 };
901 }
902
903 if this.received_requests_from_remote.len() > MAX_QUEUED_OUTGOING_RESPONSES {
905 break 'receive
911 }
912
913 if this.queued_outgoing.response_count() > MAX_QUEUED_OUTGOING_RESPONSES {
915 break 'receive
922 }
923
924 match this.conn.poll_next_unpin(cx) {
925 Poll::Pending => {
926 receive_pending = true;
927 break
928 }
929 Poll::Ready(None) => {
930 if this.is_disconnecting() {
931 break
932 }
933 debug!(target: "net::session", remote_peer_id=?this.remote_peer_id, "eth stream completed");
934 return this.emit_disconnect(cx)
935 }
936 Poll::Ready(Some(res)) => {
937 match res {
938 Ok(msg) => {
939 let outcome = match msg {
940 EthSnapMessage::Eth(msg) => {
941 trace!(target: "net::session", msg_id=?msg.message_id(), remote_peer_id=?this.remote_peer_id, "received eth message");
942 this.on_incoming_message(msg)
944 }
945 EthSnapMessage::Snap(msg) => this.on_incoming_snap_message(msg),
946 };
947 match outcome {
948 OnIncomingMessageOutcome::Ok => {
949 progress = true;
951 }
952 OnIncomingMessageOutcome::BadMessage { error, message } => {
953 debug!(target: "net::session", %error, msg=?message, remote_peer_id=?this.remote_peer_id, "received invalid protocol message");
954 this.on_bad_message();
955 return this
956 .try_disconnect(DisconnectReason::ProtocolBreach, cx)
957 }
958 OnIncomingMessageOutcome::NoCapacity(msg) => {
959 this.pending_message_to_session = Some(msg);
961 }
962 }
963 }
964 Err(err) => {
965 debug!(target: "net::session", %err, remote_peer_id=?this.remote_peer_id, "failed to receive message");
966 if err.is_protocol_breach() {
967 this.on_bad_message();
968 return this.try_disconnect(DisconnectReason::ProtocolBreach, cx)
969 }
970 return this.close_on_error(err, cx)
971 }
972 }
973 }
974 }
975 }
976
977 if receive_pending &&
980 this.queued_outgoing.is_empty() &&
981 this.pending_message_to_session.is_none() &&
982 this.received_requests_from_remote.is_empty()
983 {
984 break 'main
985 }
986
987 if !progress {
988 break 'main
989 }
990 }
991
992 if let Some(interval) = &mut this.range_update_interval {
993 while interval.poll_tick(cx).is_ready() {
995 let current_latest = this.local_range_info.latest();
996 let should_send = if let Some(last_sent) = this.last_sent_latest_block {
997 current_latest.saturating_sub(last_sent) >= EPOCH_SLOTS
999 } else {
1000 true };
1002
1003 if should_send {
1004 this.queued_outgoing.push_back(
1005 EthMessage::BlockRangeUpdate(this.local_range_info.to_message()).into(),
1006 );
1007 this.last_sent_latest_block = Some(current_latest);
1008 }
1009 }
1010 }
1011
1012 if !this.inflight_requests.is_empty() {
1013 while this.internal_request_timeout_interval.poll_tick(cx).is_ready() {
1014 if this.check_timed_out_requests(Instant::now()) &&
1016 let Poll::Ready(Ok(_)) = this.to_session_manager.poll_reserve(cx)
1017 {
1018 let msg = ActiveSessionMessage::ProtocolBreach { peer_id: this.remote_peer_id };
1019 this.pending_message_to_session = Some(msg);
1020 }
1021 }
1022 }
1023
1024 if let Err(err) = this.poll_send_queued(cx) {
1028 debug!(target: "net::session", %err, remote_peer_id=?this.remote_peer_id, "failed to send message");
1029 return this.close_on_error(err, cx)
1030 }
1031 match this.conn.poll_flush_unpin(cx) {
1032 Poll::Pending | Poll::Ready(Ok(())) => {}
1033 Poll::Ready(Err(err)) => {
1034 debug!(target: "net::session", %err, remote_peer_id=?this.remote_peer_id, "failed to flush connection");
1035 return this.close_on_error(err, cx)
1036 }
1037 }
1038
1039 this.shrink_to_fit();
1040
1041 Poll::Pending
1042 }
1043}
1044
1045pub(crate) struct ReceivedRequest<N: NetworkPrimitives> {
1047 request_id: u64,
1049 rx: PeerResponse<N>,
1051 #[expect(dead_code)]
1053 received: Instant,
1054}
1055
1056pub(crate) struct InflightRequest<R> {
1058 request: RequestState<R>,
1060 timestamp: Instant,
1062 deadline: Instant,
1064}
1065
1066impl<N: NetworkPrimitives> InflightRequest<PeerRequest<N>> {
1067 #[inline]
1069 fn is_timed_out(&self, now: Instant) -> bool {
1070 now > self.deadline
1071 }
1072
1073 #[inline]
1075 const fn is_waiting(&self) -> bool {
1076 matches!(self.request, RequestState::Waiting(_))
1077 }
1078
1079 fn timeout(&mut self) {
1081 let mut req = RequestState::TimedOut;
1082 std::mem::swap(&mut self.request, &mut req);
1083
1084 if let RequestState::Waiting(req) = req {
1085 req.send_err_response(RequestError::Timeout);
1086 }
1087 }
1088}
1089
1090enum OnIncomingMessageOutcome<N: NetworkPrimitives> {
1092 Ok,
1094 BadMessage { error: EthStreamError, message: EthMessage<N> },
1096 NoCapacity(ActiveSessionMessage<N>),
1098}
1099
1100impl<N: NetworkPrimitives> From<Result<(), ActiveSessionMessage<N>>>
1101 for OnIncomingMessageOutcome<N>
1102{
1103 fn from(res: Result<(), ActiveSessionMessage<N>>) -> Self {
1104 match res {
1105 Ok(_) => Self::Ok,
1106 Err(msg) => Self::NoCapacity(msg),
1107 }
1108 }
1109}
1110
1111enum RequestState<R> {
1112 Waiting(R),
1114 TimedOut,
1116}
1117
1118#[derive(Debug)]
1120pub(crate) enum OutgoingMessage<N: NetworkPrimitives> {
1121 Eth(EthMessage<N>),
1123 Broadcast(EthBroadcastMessage<N>),
1125 Raw(RawCapabilityMessage),
1127 Snap(SnapProtocolMessage),
1129}
1130
1131impl<N: NetworkPrimitives> OutgoingMessage<N> {
1132 const fn is_response(&self) -> bool {
1134 match self {
1135 Self::Eth(msg) => msg.is_response(),
1136 Self::Snap(msg) => msg.is_response(),
1139 Self::Broadcast(_) | Self::Raw(_) => false,
1140 }
1141 }
1142
1143 fn broadcast_item_count(&self) -> usize {
1149 match self {
1150 Self::Eth(msg) => match msg {
1151 EthMessage::NewBlockHashes(h) => h.len(),
1152 EthMessage::NewPooledTransactionHashes66(h) => h.len(),
1153 EthMessage::NewPooledTransactionHashes68(h) => h.hashes.len(),
1154 EthMessage::NewPooledTransactionHashes72(h) => h.hashes.len(),
1155 _ => 0,
1156 },
1157 Self::Broadcast(msg) => match msg {
1158 EthBroadcastMessage::NewBlock(_) => 1,
1159 EthBroadcastMessage::Transactions(txs) => txs.len(),
1160 EthBroadcastMessage::BroadcastPoolTransactions(txs) => txs.len(),
1161 },
1162 Self::Raw(_) | Self::Snap(_) => 0,
1163 }
1164 }
1165
1166 fn try_merge_hashes(
1169 &mut self,
1170 incoming: NewPooledTransactionHashes,
1171 ) -> Option<NewPooledTransactionHashes> {
1172 let Self::Eth(eth) = self else { return Some(incoming) };
1173 match (eth, incoming) {
1174 (
1175 EthMessage::NewPooledTransactionHashes66(existing),
1176 NewPooledTransactionHashes::Eth66(inc),
1177 ) => {
1178 existing.extend(inc);
1179 None
1180 }
1181 (
1182 EthMessage::NewPooledTransactionHashes68(existing),
1183 NewPooledTransactionHashes::Eth68(inc),
1184 ) => {
1185 existing.hashes.extend(inc.hashes);
1186 existing.sizes.extend(inc.sizes);
1187 existing.types.extend(inc.types);
1188 None
1189 }
1190 (
1191 EthMessage::NewPooledTransactionHashes72(existing),
1192 NewPooledTransactionHashes::Eth72(inc),
1193 ) => {
1194 existing.hashes.extend(inc.hashes);
1195 existing.sizes.extend(inc.sizes);
1196 existing.types.extend(inc.types);
1197 None
1198 }
1199 (_, incoming) => Some(incoming),
1200 }
1201 }
1202}
1203
1204impl<N: NetworkPrimitives> From<EthMessage<N>> for OutgoingMessage<N> {
1205 fn from(value: EthMessage<N>) -> Self {
1206 Self::Eth(value)
1207 }
1208}
1209
1210impl<N: NetworkPrimitives> From<EthBroadcastMessage<N>> for OutgoingMessage<N> {
1211 fn from(value: EthBroadcastMessage<N>) -> Self {
1212 Self::Broadcast(value)
1213 }
1214}
1215
1216pub(super) fn request_timeout_interval(timeout: Duration) -> Interval {
1221 let mut interval = tokio::time::interval(timeout);
1222 interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1223 interval
1224}
1225
1226#[inline]
1228fn calculate_new_timeout(current_timeout: Duration, estimated_rtt: Duration) -> Duration {
1229 let new_timeout = estimated_rtt.mul_f64(SAMPLE_IMPACT) * TIMEOUT_SCALING;
1230
1231 let smoothened_timeout = current_timeout.mul_f64(1.0 - SAMPLE_IMPACT) + new_timeout;
1233
1234 smoothened_timeout.clamp(MINIMUM_TIMEOUT, MAXIMUM_TIMEOUT)
1235}
1236
1237pub(crate) struct QueuedOutgoingMessages<N: NetworkPrimitives> {
1244 messages: VecDeque<OutgoingMessage<N>>,
1245 queued_responses: usize,
1248 count: Gauge,
1249 broadcast_items: BroadcastItemCounter,
1251}
1252
1253impl<N: NetworkPrimitives> QueuedOutgoingMessages<N> {
1254 pub(crate) const fn new(metric: Gauge, broadcast_items: BroadcastItemCounter) -> Self {
1255 Self { messages: VecDeque::new(), queued_responses: 0, count: metric, broadcast_items }
1256 }
1257
1258 pub(crate) const fn response_count(&self) -> usize {
1260 self.queued_responses
1261 }
1262
1263 pub(crate) fn is_empty(&self) -> bool {
1264 self.messages.is_empty()
1265 }
1266
1267 pub(crate) fn push_back(&mut self, message: OutgoingMessage<N>) {
1268 self.queued_responses += message.is_response() as usize;
1269 self.messages.push_back(message);
1270 self.count.increment(1);
1271 }
1272
1273 pub(crate) fn pop_front(&mut self) -> Option<OutgoingMessage<N>> {
1274 self.messages.pop_front().inspect(|msg| {
1275 self.count.decrement(1);
1276 self.queued_responses -= msg.is_response() as usize;
1277 let items = msg.broadcast_item_count();
1278 if items > 0 {
1279 self.broadcast_items.sub(items);
1280 }
1281 })
1282 }
1283
1284 pub(crate) fn push_pooled_hashes(&mut self, msg: NewPooledTransactionHashes) {
1287 let msg = if let Some(last) = self.messages.back_mut() {
1288 match last.try_merge_hashes(msg) {
1289 None => return,
1290 Some(msg) => msg,
1291 }
1292 } else {
1293 msg
1294 };
1295 self.messages.push_back(EthMessage::from(msg).into());
1296 self.count.increment(1);
1297 }
1298
1299 pub(crate) fn shrink_to_fit(&mut self) {
1303 if self.messages.is_empty() && self.messages.capacity() > SHRINK_CAPACITY_THRESHOLD {
1304 self.messages.shrink_to(MAX_QUEUED_OUTGOING_RESPONSES);
1305 }
1306 }
1307}
1308
1309impl<N: NetworkPrimitives> Drop for QueuedOutgoingMessages<N> {
1310 fn drop(&mut self) {
1311 let remaining = self.messages.len();
1313 if remaining > 0 {
1314 self.count.decrement(remaining as f64);
1315 }
1316 }
1317}
1318
1319#[cfg(test)]
1320mod tests {
1321 use super::*;
1322 use crate::session::{handle::PendingSessionEvent, start_pending_incoming_session};
1323 use alloy_eips::eip2124::ForkFilter;
1324 use alloy_primitives::B256;
1325 use futures::task::noop_waker;
1326 use reth_chainspec::MAINNET;
1327 use reth_ecies::stream::ECIESStream;
1328 use reth_eth_wire::{
1329 handshake::EthHandshake, protocol::Protocol, BlockBodies, BlockHeaders,
1330 EthNetworkPrimitives, EthStream, GetBlockAccessLists, GetBlockBodies,
1331 HelloMessageWithProtocols, P2PStream, StatusBuilder, UnauthedEthStream, UnauthedP2PStream,
1332 UnifiedStatus,
1333 };
1334 use reth_eth_wire_types::{
1335 message::MAX_MESSAGE_SIZE,
1336 snap::{
1337 AccountRangeMessage, BlockAccessListsMessage, GetAccountRangeMessage,
1338 GetBlockAccessListsMessage,
1339 },
1340 BlockAccessLists, EthMessageID, NewPooledTransactionHashes72,
1341 };
1342 use reth_ethereum_forks::EthereumHardfork;
1343 use reth_network_p2p::error::RequestResult;
1344 use reth_network_peers::pk2id;
1345 use reth_network_types::session::config::PROTOCOL_BREACH_REQUEST_TIMEOUT;
1346 use secp256k1::{SecretKey, SECP256K1};
1347 use tokio::{
1348 net::{TcpListener, TcpStream},
1349 sync::mpsc,
1350 };
1351
1352 fn eth_hello(server_key: &SecretKey) -> HelloMessageWithProtocols {
1354 HelloMessageWithProtocols::builder(pk2id(&server_key.public_key(SECP256K1))).build()
1355 }
1356
1357 struct SessionBuilder<N: NetworkPrimitives = EthNetworkPrimitives> {
1358 _remote_capabilities: Arc<Capabilities>,
1359 active_session_tx: mpsc::Sender<ActiveSessionMessage<N>>,
1360 active_session_rx: ReceiverStream<ActiveSessionMessage<N>>,
1361 to_sessions: Vec<mpsc::Sender<SessionCommand<N>>>,
1362 secret_key: SecretKey,
1363 local_peer_id: PeerId,
1364 hello: HelloMessageWithProtocols,
1365 status: UnifiedStatus,
1366 fork_filter: ForkFilter,
1367 next_id: usize,
1368 }
1369
1370 impl<N: NetworkPrimitives> SessionBuilder<N> {
1371 fn next_id(&mut self) -> SessionId {
1372 let id = self.next_id;
1373 self.next_id += 1;
1374 SessionId(id)
1375 }
1376
1377 fn with_client_stream<F, O>(
1379 &self,
1380 local_addr: SocketAddr,
1381 f: F,
1382 ) -> Pin<Box<dyn Future<Output = ()> + Send>>
1383 where
1384 F: FnOnce(EthStream<P2PStream<ECIESStream<TcpStream>>, N>) -> O + Send + 'static,
1385 O: Future<Output = ()> + Send + Sync,
1386 {
1387 let mut status = self.status;
1388 let fork_filter = self.fork_filter.clone();
1389 let local_peer_id = self.local_peer_id;
1390 let mut hello = self.hello.clone();
1391 let key = SecretKey::new(&mut rand_08::thread_rng());
1392 hello.id = pk2id(&key.public_key(SECP256K1));
1393 Box::pin(async move {
1394 let outgoing = TcpStream::connect(local_addr).await.unwrap();
1395 let sink = ECIESStream::connect(outgoing, key, local_peer_id).await.unwrap();
1396
1397 let (p2p_stream, _) = UnauthedP2PStream::new(sink).handshake(hello).await.unwrap();
1398
1399 let eth_version = p2p_stream.shared_capabilities().eth_version().unwrap();
1400 status.set_eth_version(eth_version);
1401
1402 let (client_stream, _) = UnauthedEthStream::new(p2p_stream)
1403 .handshake(status, fork_filter)
1404 .await
1405 .unwrap();
1406 f(client_stream).await
1407 })
1408 }
1409
1410 async fn connect_incoming(&mut self, stream: TcpStream) -> ActiveSession<N> {
1411 let remote_addr = stream.local_addr().unwrap();
1412 let session_id = self.next_id();
1413 let (_disconnect_tx, disconnect_rx) = oneshot::channel();
1414 let (pending_sessions_tx, pending_sessions_rx) = mpsc::channel(1);
1415
1416 tokio::task::spawn(start_pending_incoming_session(
1417 Arc::new(EthHandshake::default()),
1418 MAX_MESSAGE_SIZE,
1419 disconnect_rx,
1420 session_id,
1421 stream,
1422 pending_sessions_tx,
1423 remote_addr,
1424 self.secret_key,
1425 self.hello.clone(),
1426 self.status,
1427 self.fork_filter.clone(),
1428 Default::default(),
1429 ));
1430
1431 let mut stream = ReceiverStream::new(pending_sessions_rx);
1432
1433 match stream.next().await.unwrap() {
1434 PendingSessionEvent::Established {
1435 session_id,
1436 remote_addr,
1437 peer_id,
1438 capabilities,
1439 conn,
1440 ..
1441 } => {
1442 let (_to_session_tx, messages_rx) = mpsc::channel(10);
1443 let (commands_to_session, commands_rx) = mpsc::channel(10);
1444 let (_unbounded_tx, unbounded_rx) = mpsc::unbounded_channel();
1445 let poll_sender = PollSender::new(self.active_session_tx.clone());
1446
1447 self.to_sessions.push(commands_to_session);
1448
1449 ActiveSession {
1450 next_id: 0,
1451 remote_peer_id: peer_id,
1452 remote_addr,
1453 remote_capabilities: Arc::clone(&capabilities),
1454 session_id,
1455 commands_rx: ReceiverStream::new(commands_rx),
1456 unbounded_rx,
1457 unbounded_broadcast_msgs: Counter::noop(),
1458 to_session_manager: MeteredPollSender::new(
1459 poll_sender,
1460 "network_active_session",
1461 ),
1462 pending_message_to_session: None,
1463 internal_request_rx: ReceiverStream::new(messages_rx).fuse(),
1464 inflight_requests: Default::default(),
1465 conn,
1466 queued_outgoing: QueuedOutgoingMessages::new(
1467 Gauge::noop(),
1468 BroadcastItemCounter::new(),
1469 ),
1470 received_requests_from_remote: Default::default(),
1471 internal_request_timeout_interval: request_timeout_interval(
1472 INITIAL_REQUEST_TIMEOUT,
1473 ),
1474 internal_request_timeout: Arc::new(AtomicU64::new(
1475 INITIAL_REQUEST_TIMEOUT.as_millis() as u64,
1476 )),
1477 protocol_breach_request_timeout: PROTOCOL_BREACH_REQUEST_TIMEOUT,
1478 terminate_message: None,
1479 range_info: None,
1480 local_range_info: BlockRangeInfo::new(
1481 0,
1482 1000,
1483 alloy_primitives::B256::ZERO,
1484 ),
1485 range_update_interval: None,
1486 last_sent_latest_block: None,
1487 }
1488 }
1489 ev => {
1490 panic!("unexpected message {ev:?}")
1491 }
1492 }
1493 }
1494 }
1495
1496 impl Default for SessionBuilder {
1497 fn default() -> Self {
1498 let (active_session_tx, active_session_rx) = mpsc::channel(100);
1499
1500 let (secret_key, pk) = SECP256K1.generate_keypair(&mut rand_08::thread_rng());
1501 let local_peer_id = pk2id(&pk);
1502
1503 Self {
1504 next_id: 0,
1505 _remote_capabilities: Arc::new(Capabilities::from(vec![])),
1506 active_session_tx,
1507 active_session_rx: ReceiverStream::new(active_session_rx),
1508 to_sessions: vec![],
1509 hello: eth_hello(&secret_key),
1510 secret_key,
1511 local_peer_id,
1512 status: StatusBuilder::default().build(),
1513 fork_filter: MAINNET
1514 .hardfork_fork_filter(EthereumHardfork::Frontier)
1515 .expect("The Frontier fork filter should exist on mainnet"),
1516 }
1517 }
1518 }
1519
1520 fn snap_session_builder() -> SessionBuilder {
1524 let mut builder = SessionBuilder::default();
1525 builder.hello.try_add_protocol(Protocol::snap_2()).unwrap();
1526 builder
1527 }
1528
1529 fn dispatch_snap_request(
1532 session: &mut ActiveSession<EthNetworkPrimitives>,
1533 caller_request_id: u64,
1534 ) -> (u64, oneshot::Receiver<RequestResult<SnapResponse>>) {
1535 let (response, rx) = oneshot::channel();
1536 let request = SnapProtocolMessage::GetBlockAccessLists(GetBlockAccessListsMessage {
1537 request_id: caller_request_id,
1538 block_hashes: Vec::new(),
1539 response_bytes: 0,
1540 });
1541 let deadline = session.request_deadline();
1542 session.on_internal_peer_request(PeerRequest::GetSnap { request, response }, deadline);
1543 let id = *session.inflight_requests.keys().next().expect("snap request tracked");
1544 (id, rx)
1545 }
1546
1547 fn dispatch_block_bodies_request(
1551 session: &mut ActiveSession<EthNetworkPrimitives>,
1552 ) -> (u64, oneshot::Receiver<RequestResult<BlockBodies>>) {
1553 let (response, rx) = oneshot::channel();
1554 let deadline = session.request_deadline();
1555 session.on_internal_peer_request(
1556 PeerRequest::GetBlockBodies { request: GetBlockBodies(Vec::new()), response },
1557 deadline,
1558 );
1559 let id = *session.inflight_requests.keys().next().expect("eth request tracked");
1560 (id, rx)
1561 }
1562
1563 #[tokio::test(flavor = "multi_thread")]
1564 async fn test_disconnect() {
1565 let mut builder = SessionBuilder::default();
1566
1567 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1568 let local_addr = listener.local_addr().unwrap();
1569
1570 let expected_disconnect = DisconnectReason::UselessPeer;
1571
1572 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
1573 let msg = client_stream.next().await.unwrap().unwrap_err();
1574 assert_eq!(msg.as_disconnected().unwrap(), expected_disconnect);
1575 });
1576
1577 tokio::task::spawn(async move {
1578 let (incoming, _) = listener.accept().await.unwrap();
1579 let mut session = builder.connect_incoming(incoming).await;
1580
1581 session.start_disconnect(expected_disconnect).unwrap();
1582 session.await
1583 });
1584
1585 fut.await;
1586 }
1587
1588 #[tokio::test(flavor = "multi_thread")]
1589 async fn test_invalid_message_disconnects_with_protocol_breach() {
1590 let mut builder = SessionBuilder::default();
1591
1592 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1593 let local_addr = listener.local_addr().unwrap();
1594
1595 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
1596 client_stream
1597 .start_send_raw(RawCapabilityMessage::eth(
1598 EthMessageID::PooledTransactions,
1599 vec![0xc0].into(),
1600 ))
1601 .unwrap();
1602 client_stream.flush().await.unwrap();
1603
1604 let msg = client_stream.next().await.unwrap().unwrap_err();
1605 assert_eq!(msg.as_disconnected(), Some(DisconnectReason::ProtocolBreach));
1606 });
1607
1608 let (tx, rx) = oneshot::channel();
1609
1610 tokio::task::spawn(async move {
1611 let (incoming, _) = listener.accept().await.unwrap();
1612 let session = builder.connect_incoming(incoming).await;
1613 session.await;
1614
1615 tx.send(()).unwrap();
1616 });
1617
1618 fut.await;
1619 rx.await.unwrap();
1620 }
1621
1622 #[tokio::test(flavor = "multi_thread")]
1623 async fn handle_dropped_stream() {
1624 let mut builder = SessionBuilder::default();
1625
1626 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1627 let local_addr = listener.local_addr().unwrap();
1628
1629 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1630 drop(client_stream);
1631 tokio::time::sleep(Duration::from_secs(1)).await
1632 });
1633
1634 let (tx, rx) = oneshot::channel();
1635
1636 tokio::task::spawn(async move {
1637 let (incoming, _) = listener.accept().await.unwrap();
1638 let session = builder.connect_incoming(incoming).await;
1639 session.await;
1640
1641 tx.send(()).unwrap();
1642 });
1643
1644 tokio::task::spawn(fut);
1645
1646 rx.await.unwrap();
1647 }
1648
1649 #[tokio::test(flavor = "multi_thread")]
1650 async fn test_send_many_messages() {
1651 reth_tracing::init_test_tracing();
1652 let mut builder = SessionBuilder::default();
1653
1654 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1655 let local_addr = listener.local_addr().unwrap();
1656
1657 let num_messages = 100;
1658
1659 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
1660 for _ in 0..num_messages {
1661 client_stream
1662 .send(EthMessage::NewPooledTransactionHashes66(Vec::new().into()))
1663 .await
1664 .unwrap();
1665 }
1666 });
1667
1668 let (tx, rx) = oneshot::channel();
1669
1670 tokio::task::spawn(async move {
1671 let (incoming, _) = listener.accept().await.unwrap();
1672 let session = builder.connect_incoming(incoming).await;
1673 session.await;
1674
1675 tx.send(()).unwrap();
1676 });
1677
1678 tokio::task::spawn(fut);
1679
1680 rx.await.unwrap();
1681 }
1682
1683 #[tokio::test(flavor = "multi_thread")]
1684 async fn test_request_timeout() {
1685 reth_tracing::init_test_tracing();
1686
1687 let mut builder = SessionBuilder::default();
1688
1689 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1690 let local_addr = listener.local_addr().unwrap();
1691
1692 let request_timeout = Duration::from_millis(100);
1693 let drop_timeout = Duration::from_millis(1500);
1694
1695 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1696 let _client_stream = client_stream;
1697 tokio::time::sleep(drop_timeout * 60).await;
1698 });
1699 tokio::task::spawn(fut);
1700
1701 let (incoming, _) = listener.accept().await.unwrap();
1702 let mut session = builder.connect_incoming(incoming).await;
1703 session
1704 .internal_request_timeout
1705 .store(request_timeout.as_millis() as u64, Ordering::Relaxed);
1706 session.protocol_breach_request_timeout = drop_timeout;
1707 session.internal_request_timeout_interval =
1708 tokio::time::interval_at(tokio::time::Instant::now(), request_timeout);
1709 session
1710 .internal_request_timeout_interval
1711 .set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1712 let (tx, rx) = oneshot::channel();
1713 let req = PeerRequest::GetBlockBodies { request: GetBlockBodies(vec![]), response: tx };
1714 session.on_internal_peer_request(req, Instant::now());
1715 tokio::spawn(session);
1716
1717 let err = rx.await.unwrap().unwrap_err();
1718 assert_eq!(err, RequestError::Timeout);
1719
1720 let msg = builder.active_session_rx.next().await.unwrap();
1722 match msg {
1723 ActiveSessionMessage::ProtocolBreach { .. } => {}
1724 ev => unreachable!("{ev:?}"),
1725 }
1726 }
1727
1728 #[tokio::test(flavor = "multi_thread")]
1729 async fn snap_request_is_assigned_unique_id_and_response_correlated() {
1730 let mut builder = snap_session_builder();
1731 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1732 let local_addr = listener.local_addr().unwrap();
1733 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1734 let _client_stream = client_stream;
1735 tokio::time::sleep(Duration::from_secs(60)).await;
1736 });
1737 tokio::task::spawn(fut);
1738 let (incoming, _) = listener.accept().await.unwrap();
1739 let mut session = builder.connect_incoming(incoming).await;
1740
1741 let (id, rx) = dispatch_snap_request(&mut session, u64::MAX);
1743 assert_ne!(id, u64::MAX, "session must assign its own request id");
1744
1745 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::BlockAccessLists(
1747 BlockAccessListsMessage {
1748 request_id: id,
1749 block_access_lists: BlockAccessLists(Vec::new()),
1750 },
1751 ));
1752 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1753 assert!(!session.inflight_requests.contains_key(&id));
1754
1755 let response = rx.await.unwrap().unwrap();
1757 assert!(matches!(
1758 response,
1759 SnapResponse::BlockAccessLists(m) if m.request_id == u64::MAX
1760 ));
1761 }
1762
1763 #[tokio::test(flavor = "multi_thread")]
1764 async fn wrong_type_snap_response_is_rejected() {
1765 let mut builder = snap_session_builder();
1766 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1767 let local_addr = listener.local_addr().unwrap();
1768 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1769 let _client_stream = client_stream;
1770 tokio::time::sleep(Duration::from_secs(60)).await;
1771 });
1772 tokio::task::spawn(fut);
1773 let (incoming, _) = listener.accept().await.unwrap();
1774 let mut session = builder.connect_incoming(incoming).await;
1775
1776 let (id, rx) = dispatch_snap_request(&mut session, 0);
1777
1778 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::AccountRange(
1780 AccountRangeMessage { request_id: id, accounts: Vec::new(), proof: Vec::new() },
1781 ));
1782 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1783 assert!(!session.inflight_requests.contains_key(&id));
1784 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::BadResponse);
1785 assert!(matches!(
1786 builder.active_session_rx.next().await,
1787 Some(ActiveSessionMessage::BadMessage { .. })
1788 ));
1789 }
1790
1791 #[tokio::test(flavor = "multi_thread")]
1792 async fn snap_request_times_out() {
1793 let mut builder = snap_session_builder();
1794 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1795 let local_addr = listener.local_addr().unwrap();
1796 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1797 let _client_stream = client_stream;
1798 tokio::time::sleep(Duration::from_secs(60)).await;
1799 });
1800 tokio::task::spawn(fut);
1801 let (incoming, _) = listener.accept().await.unwrap();
1802 let mut session = builder.connect_incoming(incoming).await;
1803
1804 session.internal_request_timeout.store(1, Ordering::Relaxed);
1806 let (id, rx) = dispatch_snap_request(&mut session, 0);
1807
1808 tokio::time::sleep(Duration::from_millis(20)).await;
1811 assert!(!session.check_timed_out_requests(Instant::now()));
1812 assert!(session.inflight_requests.contains_key(&id));
1813 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::Timeout);
1814
1815 session.protocol_breach_request_timeout = Duration::from_millis(1);
1817 assert!(session.check_timed_out_requests(Instant::now()));
1818 }
1819
1820 #[tokio::test(flavor = "multi_thread")]
1821 async fn late_snap_response_is_consumed_without_penalty() {
1822 let mut builder = snap_session_builder();
1823 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1824 let local_addr = listener.local_addr().unwrap();
1825 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1826 let _client_stream = client_stream;
1827 tokio::time::sleep(Duration::from_secs(60)).await;
1828 });
1829 tokio::task::spawn(fut);
1830 let (incoming, _) = listener.accept().await.unwrap();
1831 let mut session = builder.connect_incoming(incoming).await;
1832
1833 session.internal_request_timeout.store(1, Ordering::Relaxed);
1834 let (id, _rx) = dispatch_snap_request(&mut session, 0);
1835 tokio::time::sleep(Duration::from_millis(20)).await;
1836 assert!(!session.check_timed_out_requests(Instant::now()));
1837
1838 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::BlockAccessLists(
1840 BlockAccessListsMessage {
1841 request_id: id,
1842 block_access_lists: BlockAccessLists(Vec::new()),
1843 },
1844 ));
1845 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1846 assert!(!session.inflight_requests.contains_key(&id));
1847 assert!(futures::FutureExt::now_or_never(builder.active_session_rx.next())
1848 .flatten()
1849 .is_none());
1850 }
1851
1852 #[tokio::test(flavor = "multi_thread")]
1853 async fn unknown_snap_response_is_penalized() {
1854 let mut builder = snap_session_builder();
1855 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1856 let local_addr = listener.local_addr().unwrap();
1857 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1858 let _client_stream = client_stream;
1859 tokio::time::sleep(Duration::from_secs(60)).await;
1860 });
1861 tokio::task::spawn(fut);
1862 let (incoming, _) = listener.accept().await.unwrap();
1863 let mut session = builder.connect_incoming(incoming).await;
1864
1865 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::BlockAccessLists(
1867 BlockAccessListsMessage {
1868 request_id: 999,
1869 block_access_lists: BlockAccessLists(Vec::new()),
1870 },
1871 ));
1872 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1873 assert!(session.inflight_requests.is_empty());
1874 assert!(session.queued_outgoing.pop_front().is_none());
1875 assert!(matches!(
1876 builder.active_session_rx.next().await,
1877 Some(ActiveSessionMessage::BadMessage { .. })
1878 ));
1879 }
1880
1881 #[tokio::test(flavor = "multi_thread")]
1882 async fn wrong_type_eth_response_is_penalized() {
1883 let mut builder = SessionBuilder::default();
1884 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1885 let local_addr = listener.local_addr().unwrap();
1886 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1887 let _client_stream = client_stream;
1888 tokio::time::sleep(Duration::from_secs(60)).await;
1889 });
1890 tokio::task::spawn(fut);
1891 let (incoming, _) = listener.accept().await.unwrap();
1892 let mut session = builder.connect_incoming(incoming).await;
1893
1894 let (id, rx) = dispatch_block_bodies_request(&mut session);
1895
1896 let outcome = session.on_incoming_message(EthMessage::BlockHeaders(RequestPair {
1900 request_id: id,
1901 message: BlockHeaders(Vec::new()),
1902 }));
1903 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1904 assert!(!session.inflight_requests.contains_key(&id));
1905 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::BadResponse);
1906 assert!(matches!(
1907 futures::FutureExt::now_or_never(builder.active_session_rx.next()).flatten(),
1908 Some(ActiveSessionMessage::BadMessage { .. })
1909 ));
1910 }
1911
1912 #[tokio::test(flavor = "multi_thread")]
1913 async fn matching_eth_response_is_not_penalized() {
1914 let mut builder = SessionBuilder::default();
1915 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1916 let local_addr = listener.local_addr().unwrap();
1917 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1918 let _client_stream = client_stream;
1919 tokio::time::sleep(Duration::from_secs(60)).await;
1920 });
1921 tokio::task::spawn(fut);
1922 let (incoming, _) = listener.accept().await.unwrap();
1923 let mut session = builder.connect_incoming(incoming).await;
1924
1925 let (id, rx) = dispatch_block_bodies_request(&mut session);
1926
1927 let outcome = session.on_incoming_message(EthMessage::BlockBodies(RequestPair {
1928 request_id: id,
1929 message: BlockBodies(Vec::new()),
1930 }));
1931 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1932 assert!(!session.inflight_requests.contains_key(&id));
1933 assert!(rx.await.unwrap().is_ok());
1934 assert!(futures::FutureExt::now_or_never(builder.active_session_rx.next())
1935 .flatten()
1936 .is_none());
1937 }
1938
1939 #[tokio::test(flavor = "multi_thread")]
1940 async fn snap_response_to_eth_request_is_penalized() {
1941 let mut builder = snap_session_builder();
1942 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1943 let local_addr = listener.local_addr().unwrap();
1944 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1945 let _client_stream = client_stream;
1946 tokio::time::sleep(Duration::from_secs(60)).await;
1947 });
1948 tokio::task::spawn(fut);
1949 let (incoming, _) = listener.accept().await.unwrap();
1950 let mut session = builder.connect_incoming(incoming).await;
1951
1952 let (id, rx) = dispatch_block_bodies_request(&mut session);
1955
1956 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::AccountRange(
1957 AccountRangeMessage { request_id: id, accounts: Vec::new(), proof: Vec::new() },
1958 ));
1959 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1960 assert!(!session.inflight_requests.contains_key(&id));
1961 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::BadResponse);
1962 assert!(matches!(
1963 futures::FutureExt::now_or_never(builder.active_session_rx.next()).flatten(),
1964 Some(ActiveSessionMessage::BadMessage { .. })
1965 ));
1966 }
1967
1968 #[tokio::test(flavor = "multi_thread")]
1969 async fn get_snap_request_rejected_without_negotiated_snap() {
1970 let mut builder = SessionBuilder::default();
1972 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1973 let local_addr = listener.local_addr().unwrap();
1974 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1975 let _client_stream = client_stream;
1976 tokio::time::sleep(Duration::from_secs(60)).await;
1977 });
1978 tokio::task::spawn(fut);
1979 let (incoming, _) = listener.accept().await.unwrap();
1980 let mut session = builder.connect_incoming(incoming).await;
1981 assert!(!session.conn.supports_snap());
1982
1983 let (response, rx) = oneshot::channel();
1984 let request = SnapProtocolMessage::GetBlockAccessLists(GetBlockAccessListsMessage {
1985 request_id: 0,
1986 block_hashes: Vec::new(),
1987 response_bytes: 0,
1988 });
1989 let deadline = session.request_deadline();
1990 session.on_internal_peer_request(PeerRequest::GetSnap { request, response }, deadline);
1991
1992 assert!(session.inflight_requests.is_empty());
1994 assert!(session.queued_outgoing.pop_front().is_none());
1995 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::UnsupportedCapability);
1996 }
1997
1998 #[tokio::test(flavor = "multi_thread")]
1999 async fn inbound_snap_request_round_trips_to_a_response() {
2000 let mut builder = snap_session_builder();
2001 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
2002 let local_addr = listener.local_addr().unwrap();
2003 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
2004 let _client_stream = client_stream;
2005 tokio::time::sleep(Duration::from_secs(60)).await;
2006 });
2007 tokio::task::spawn(fut);
2008 let (incoming, _) = listener.accept().await.unwrap();
2009 let mut session = builder.connect_incoming(incoming).await;
2010
2011 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::GetAccountRange(
2013 GetAccountRangeMessage {
2014 request_id: 7,
2015 root_hash: B256::ZERO,
2016 starting_hash: B256::ZERO,
2017 limit_hash: B256::ZERO,
2018 response_bytes: 1024,
2019 },
2020 ));
2021 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
2022 assert_eq!(session.received_requests_from_remote.len(), 1);
2023
2024 let Some(ActiveSessionMessage::ValidMessage {
2026 message: PeerMessage::EthRequest(PeerRequest::GetSnap { request, response }),
2027 ..
2028 }) = builder.active_session_rx.next().await
2029 else {
2030 panic!("expected an outbound GetSnap request")
2031 };
2032 assert!(matches!(request, SnapProtocolMessage::GetAccountRange(_)));
2033
2034 let _ = response.send(Ok(SnapResponse::AccountRange(AccountRangeMessage {
2036 request_id: 7,
2037 accounts: Vec::new(),
2038 proof: Vec::new(),
2039 })));
2040
2041 let mut req = session.received_requests_from_remote.pop().unwrap();
2043 let waker = noop_waker();
2044 let mut cx = Context::from_waker(&waker);
2045 let Poll::Ready(resp) = req.rx.poll(&mut cx) else { panic!("response should be ready") };
2046 session.handle_outgoing_response(req.request_id, resp);
2047
2048 let msg = session.queued_outgoing.pop_front().expect("response queued for send");
2051 assert!(matches!(
2052 msg,
2053 OutgoingMessage::Snap(SnapProtocolMessage::AccountRange(AccountRangeMessage {
2054 request_id: 7,
2055 ..
2056 }))
2057 ));
2058 }
2059
2060 #[test]
2061 fn eth72_pooled_hashes_count_broadcast_items() {
2062 let hashes =
2063 vec![alloy_primitives::B256::repeat_byte(1), alloy_primitives::B256::repeat_byte(2)];
2064 let msg: OutgoingMessage<EthNetworkPrimitives> =
2065 EthMessage::NewPooledTransactionHashes72(NewPooledTransactionHashes72 {
2066 types: vec![0; hashes.len()],
2067 sizes: vec![1; hashes.len()],
2068 hashes,
2069 cell_mask: None,
2070 })
2071 .into();
2072
2073 assert_eq!(2, msg.broadcast_item_count());
2074 }
2075
2076 #[test]
2077 fn test_reject_bal_request_for_eth70() {
2078 let (tx, _rx) = oneshot::channel();
2079 let request: PeerRequest<EthNetworkPrimitives> =
2080 PeerRequest::GetBlockAccessLists { request: GetBlockAccessLists(vec![]), response: tx };
2081
2082 assert!(!ActiveSession::<EthNetworkPrimitives>::is_request_supported_for_version(
2083 &request,
2084 EthVersion::Eth70
2085 ));
2086 assert!(ActiveSession::<EthNetworkPrimitives>::is_request_supported_for_version(
2087 &request,
2088 EthVersion::Eth71
2089 ));
2090 }
2091
2092 #[tokio::test(flavor = "multi_thread")]
2093 async fn test_keep_alive() {
2094 let mut builder = SessionBuilder::default();
2095
2096 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
2097 let local_addr = listener.local_addr().unwrap();
2098
2099 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
2100 let _ = tokio::time::timeout(Duration::from_secs(5), client_stream.next()).await;
2101 client_stream.into_inner().disconnect(DisconnectReason::UselessPeer).await.unwrap();
2102 });
2103
2104 let (tx, rx) = oneshot::channel();
2105
2106 tokio::task::spawn(async move {
2107 let (incoming, _) = listener.accept().await.unwrap();
2108 let session = builder.connect_incoming(incoming).await;
2109 session.await;
2110
2111 tx.send(()).unwrap();
2112 });
2113
2114 tokio::task::spawn(fut);
2115
2116 rx.await.unwrap();
2117 }
2118
2119 #[tokio::test(flavor = "multi_thread")]
2121 async fn test_send_at_capacity() {
2122 let mut builder = SessionBuilder::default();
2123
2124 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
2125 let local_addr = listener.local_addr().unwrap();
2126
2127 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
2128 client_stream
2129 .send(EthMessage::NewPooledTransactionHashes68(Default::default()))
2130 .await
2131 .unwrap();
2132 let _ = tokio::time::timeout(Duration::from_secs(100), client_stream.next()).await;
2133 });
2134 tokio::task::spawn(fut);
2135
2136 let (incoming, _) = listener.accept().await.unwrap();
2137 let session = builder.connect_incoming(incoming).await;
2138
2139 let mut num_fill_messages = 0;
2141 loop {
2142 if builder
2143 .active_session_tx
2144 .try_send(ActiveSessionMessage::ProtocolBreach { peer_id: PeerId::random() })
2145 .is_err()
2146 {
2147 break
2148 }
2149 num_fill_messages += 1;
2150 }
2151
2152 tokio::task::spawn(async move {
2153 session.await;
2154 });
2155
2156 tokio::time::sleep(Duration::from_millis(100)).await;
2157
2158 for _ in 0..num_fill_messages {
2159 let message = builder.active_session_rx.next().await.unwrap();
2160 match message {
2161 ActiveSessionMessage::ProtocolBreach { .. } => {}
2162 ev => unreachable!("{ev:?}"),
2163 }
2164 }
2165
2166 let message = builder.active_session_rx.next().await.unwrap();
2167 match message {
2168 ActiveSessionMessage::ValidMessage {
2169 message: PeerMessage::PooledTransactions(_),
2170 ..
2171 } => {}
2172 _ => unreachable!(),
2173 }
2174 }
2175
2176 #[test]
2177 fn timeout_calculation_sanity_tests() {
2178 let rtt = Duration::from_secs(5);
2179 let timeout = rtt * TIMEOUT_SCALING;
2181
2182 assert_eq!(calculate_new_timeout(timeout, rtt), timeout);
2184
2185 assert!(calculate_new_timeout(timeout, rtt / 2) < timeout);
2187 assert!(calculate_new_timeout(timeout, rtt / 2) > timeout / 2);
2188 assert!(calculate_new_timeout(timeout, rtt * 2) > timeout);
2189 assert!(calculate_new_timeout(timeout, rtt * 2) < timeout * 2);
2190 }
2191}