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 if existing.cell_mask != inc.cell_mask {
1196 return Some(inc.into())
1197 }
1198 existing.hashes.extend(inc.hashes);
1199 existing.sizes.extend(inc.sizes);
1200 existing.types.extend(inc.types);
1201 None
1202 }
1203 (_, incoming) => Some(incoming),
1204 }
1205 }
1206}
1207
1208impl<N: NetworkPrimitives> From<EthMessage<N>> for OutgoingMessage<N> {
1209 fn from(value: EthMessage<N>) -> Self {
1210 Self::Eth(value)
1211 }
1212}
1213
1214impl<N: NetworkPrimitives> From<EthBroadcastMessage<N>> for OutgoingMessage<N> {
1215 fn from(value: EthBroadcastMessage<N>) -> Self {
1216 Self::Broadcast(value)
1217 }
1218}
1219
1220pub(super) fn request_timeout_interval(timeout: Duration) -> Interval {
1225 let mut interval = tokio::time::interval(timeout);
1226 interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1227 interval
1228}
1229
1230#[inline]
1232fn calculate_new_timeout(current_timeout: Duration, estimated_rtt: Duration) -> Duration {
1233 let new_timeout = estimated_rtt.mul_f64(SAMPLE_IMPACT) * TIMEOUT_SCALING;
1234
1235 let smoothened_timeout = current_timeout.mul_f64(1.0 - SAMPLE_IMPACT) + new_timeout;
1237
1238 smoothened_timeout.clamp(MINIMUM_TIMEOUT, MAXIMUM_TIMEOUT)
1239}
1240
1241pub(crate) struct QueuedOutgoingMessages<N: NetworkPrimitives> {
1248 messages: VecDeque<OutgoingMessage<N>>,
1249 queued_responses: usize,
1252 count: Gauge,
1253 broadcast_items: BroadcastItemCounter,
1255}
1256
1257impl<N: NetworkPrimitives> QueuedOutgoingMessages<N> {
1258 pub(crate) const fn new(metric: Gauge, broadcast_items: BroadcastItemCounter) -> Self {
1259 Self { messages: VecDeque::new(), queued_responses: 0, count: metric, broadcast_items }
1260 }
1261
1262 pub(crate) const fn response_count(&self) -> usize {
1264 self.queued_responses
1265 }
1266
1267 pub(crate) fn is_empty(&self) -> bool {
1268 self.messages.is_empty()
1269 }
1270
1271 pub(crate) fn push_back(&mut self, message: OutgoingMessage<N>) {
1272 self.queued_responses += message.is_response() as usize;
1273 self.messages.push_back(message);
1274 self.count.increment(1);
1275 }
1276
1277 pub(crate) fn pop_front(&mut self) -> Option<OutgoingMessage<N>> {
1278 self.messages.pop_front().inspect(|msg| {
1279 self.count.decrement(1);
1280 self.queued_responses -= msg.is_response() as usize;
1281 let items = msg.broadcast_item_count();
1282 if items > 0 {
1283 self.broadcast_items.sub(items);
1284 }
1285 })
1286 }
1287
1288 pub(crate) fn push_pooled_hashes(&mut self, msg: NewPooledTransactionHashes) {
1291 let msg = if let Some(last) = self.messages.back_mut() {
1292 match last.try_merge_hashes(msg) {
1293 None => return,
1294 Some(msg) => msg,
1295 }
1296 } else {
1297 msg
1298 };
1299 self.messages.push_back(EthMessage::from(msg).into());
1300 self.count.increment(1);
1301 }
1302
1303 pub(crate) fn shrink_to_fit(&mut self) {
1307 if self.messages.is_empty() && self.messages.capacity() > SHRINK_CAPACITY_THRESHOLD {
1308 self.messages.shrink_to(MAX_QUEUED_OUTGOING_RESPONSES);
1309 }
1310 }
1311}
1312
1313impl<N: NetworkPrimitives> Drop for QueuedOutgoingMessages<N> {
1314 fn drop(&mut self) {
1315 let remaining = self.messages.len();
1317 if remaining > 0 {
1318 self.count.decrement(remaining as f64);
1319 }
1320 }
1321}
1322
1323#[cfg(test)]
1324mod tests {
1325 use super::*;
1326 use crate::session::{handle::PendingSessionEvent, start_pending_incoming_session};
1327 use alloy_eips::eip2124::ForkFilter;
1328 use alloy_primitives::B256;
1329 use futures::task::noop_waker;
1330 use reth_chainspec::MAINNET;
1331 use reth_ecies::stream::ECIESStream;
1332 use reth_eth_wire::{
1333 handshake::EthHandshake, protocol::Protocol, BlockBodies, BlockHeaders,
1334 EthNetworkPrimitives, EthStream, GetBlockAccessLists, GetBlockBodies,
1335 HelloMessageWithProtocols, P2PStream, StatusBuilder, UnauthedEthStream, UnauthedP2PStream,
1336 UnifiedStatus,
1337 };
1338 use reth_eth_wire_types::{
1339 message::MAX_MESSAGE_SIZE,
1340 snap::{
1341 AccountRangeMessage, BlockAccessListsMessage, GetAccountRangeMessage,
1342 GetBlockAccessListsMessage,
1343 },
1344 BlockAccessLists, EthMessageID, NewPooledTransactionHashes72,
1345 };
1346 use reth_ethereum_forks::EthereumHardfork;
1347 use reth_network_p2p::error::RequestResult;
1348 use reth_network_peers::pk2id;
1349 use reth_network_types::session::config::PROTOCOL_BREACH_REQUEST_TIMEOUT;
1350 use secp256k1::{SecretKey, SECP256K1};
1351 use tokio::{
1352 net::{TcpListener, TcpStream},
1353 sync::mpsc,
1354 };
1355
1356 fn eth_hello(server_key: &SecretKey) -> HelloMessageWithProtocols {
1358 HelloMessageWithProtocols::builder(pk2id(&server_key.public_key(SECP256K1))).build()
1359 }
1360
1361 struct SessionBuilder<N: NetworkPrimitives = EthNetworkPrimitives> {
1362 _remote_capabilities: Arc<Capabilities>,
1363 active_session_tx: mpsc::Sender<ActiveSessionMessage<N>>,
1364 active_session_rx: ReceiverStream<ActiveSessionMessage<N>>,
1365 to_sessions: Vec<mpsc::Sender<SessionCommand<N>>>,
1366 secret_key: SecretKey,
1367 local_peer_id: PeerId,
1368 hello: HelloMessageWithProtocols,
1369 status: UnifiedStatus,
1370 fork_filter: ForkFilter,
1371 next_id: usize,
1372 }
1373
1374 impl<N: NetworkPrimitives> SessionBuilder<N> {
1375 fn next_id(&mut self) -> SessionId {
1376 let id = self.next_id;
1377 self.next_id += 1;
1378 SessionId(id)
1379 }
1380
1381 fn with_client_stream<F, O>(
1383 &self,
1384 local_addr: SocketAddr,
1385 f: F,
1386 ) -> Pin<Box<dyn Future<Output = ()> + Send>>
1387 where
1388 F: FnOnce(EthStream<P2PStream<ECIESStream<TcpStream>>, N>) -> O + Send + 'static,
1389 O: Future<Output = ()> + Send + Sync,
1390 {
1391 let mut status = self.status;
1392 let fork_filter = self.fork_filter.clone();
1393 let local_peer_id = self.local_peer_id;
1394 let mut hello = self.hello.clone();
1395 let key = SecretKey::new(&mut rand_08::thread_rng());
1396 hello.id = pk2id(&key.public_key(SECP256K1));
1397 Box::pin(async move {
1398 let outgoing = TcpStream::connect(local_addr).await.unwrap();
1399 let sink = ECIESStream::connect(outgoing, key, local_peer_id).await.unwrap();
1400
1401 let (p2p_stream, _) = UnauthedP2PStream::new(sink).handshake(hello).await.unwrap();
1402
1403 let eth_version = p2p_stream.shared_capabilities().eth_version().unwrap();
1404 status.set_eth_version(eth_version);
1405
1406 let (client_stream, _) = UnauthedEthStream::new(p2p_stream)
1407 .handshake(status, fork_filter)
1408 .await
1409 .unwrap();
1410 f(client_stream).await
1411 })
1412 }
1413
1414 async fn connect_incoming(&mut self, stream: TcpStream) -> ActiveSession<N> {
1415 let remote_addr = stream.local_addr().unwrap();
1416 let session_id = self.next_id();
1417 let (_disconnect_tx, disconnect_rx) = oneshot::channel();
1418 let (pending_sessions_tx, pending_sessions_rx) = mpsc::channel(1);
1419
1420 tokio::task::spawn(start_pending_incoming_session(
1421 Arc::new(EthHandshake::default()),
1422 MAX_MESSAGE_SIZE,
1423 disconnect_rx,
1424 session_id,
1425 stream,
1426 pending_sessions_tx,
1427 remote_addr,
1428 self.secret_key,
1429 self.hello.clone(),
1430 self.status,
1431 self.fork_filter.clone(),
1432 Default::default(),
1433 ));
1434
1435 let mut stream = ReceiverStream::new(pending_sessions_rx);
1436
1437 match stream.next().await.unwrap() {
1438 PendingSessionEvent::Established {
1439 session_id,
1440 remote_addr,
1441 peer_id,
1442 capabilities,
1443 conn,
1444 ..
1445 } => {
1446 let (_to_session_tx, messages_rx) = mpsc::channel(10);
1447 let (commands_to_session, commands_rx) = mpsc::channel(10);
1448 let (_unbounded_tx, unbounded_rx) = mpsc::unbounded_channel();
1449 let poll_sender = PollSender::new(self.active_session_tx.clone());
1450
1451 self.to_sessions.push(commands_to_session);
1452
1453 ActiveSession {
1454 next_id: 0,
1455 remote_peer_id: peer_id,
1456 remote_addr,
1457 remote_capabilities: Arc::clone(&capabilities),
1458 session_id,
1459 commands_rx: ReceiverStream::new(commands_rx),
1460 unbounded_rx,
1461 unbounded_broadcast_msgs: Counter::noop(),
1462 to_session_manager: MeteredPollSender::new(
1463 poll_sender,
1464 "network_active_session",
1465 ),
1466 pending_message_to_session: None,
1467 internal_request_rx: ReceiverStream::new(messages_rx).fuse(),
1468 inflight_requests: Default::default(),
1469 conn,
1470 queued_outgoing: QueuedOutgoingMessages::new(
1471 Gauge::noop(),
1472 BroadcastItemCounter::new(),
1473 ),
1474 received_requests_from_remote: Default::default(),
1475 internal_request_timeout_interval: request_timeout_interval(
1476 INITIAL_REQUEST_TIMEOUT,
1477 ),
1478 internal_request_timeout: Arc::new(AtomicU64::new(
1479 INITIAL_REQUEST_TIMEOUT.as_millis() as u64,
1480 )),
1481 protocol_breach_request_timeout: PROTOCOL_BREACH_REQUEST_TIMEOUT,
1482 terminate_message: None,
1483 range_info: None,
1484 local_range_info: BlockRangeInfo::new(
1485 0,
1486 1000,
1487 alloy_primitives::B256::ZERO,
1488 ),
1489 range_update_interval: None,
1490 last_sent_latest_block: None,
1491 }
1492 }
1493 ev => {
1494 panic!("unexpected message {ev:?}")
1495 }
1496 }
1497 }
1498 }
1499
1500 impl Default for SessionBuilder {
1501 fn default() -> Self {
1502 let (active_session_tx, active_session_rx) = mpsc::channel(100);
1503
1504 let (secret_key, pk) = SECP256K1.generate_keypair(&mut rand_08::thread_rng());
1505 let local_peer_id = pk2id(&pk);
1506
1507 Self {
1508 next_id: 0,
1509 _remote_capabilities: Arc::new(Capabilities::from(vec![])),
1510 active_session_tx,
1511 active_session_rx: ReceiverStream::new(active_session_rx),
1512 to_sessions: vec![],
1513 hello: eth_hello(&secret_key),
1514 secret_key,
1515 local_peer_id,
1516 status: StatusBuilder::default().build(),
1517 fork_filter: MAINNET
1518 .hardfork_fork_filter(EthereumHardfork::Frontier)
1519 .expect("The Frontier fork filter should exist on mainnet"),
1520 }
1521 }
1522 }
1523
1524 fn snap_session_builder() -> SessionBuilder {
1528 let mut builder = SessionBuilder::default();
1529 builder.hello.try_add_protocol(Protocol::snap_2()).unwrap();
1530 builder
1531 }
1532
1533 fn dispatch_snap_request(
1536 session: &mut ActiveSession<EthNetworkPrimitives>,
1537 caller_request_id: u64,
1538 ) -> (u64, oneshot::Receiver<RequestResult<SnapResponse>>) {
1539 let (response, rx) = oneshot::channel();
1540 let request = SnapProtocolMessage::GetBlockAccessLists(GetBlockAccessListsMessage {
1541 request_id: caller_request_id,
1542 block_hashes: Vec::new(),
1543 response_bytes: 0,
1544 });
1545 let deadline = session.request_deadline();
1546 session.on_internal_peer_request(PeerRequest::GetSnap { request, response }, deadline);
1547 let id = *session.inflight_requests.keys().next().expect("snap request tracked");
1548 (id, rx)
1549 }
1550
1551 fn dispatch_block_bodies_request(
1555 session: &mut ActiveSession<EthNetworkPrimitives>,
1556 ) -> (u64, oneshot::Receiver<RequestResult<BlockBodies>>) {
1557 let (response, rx) = oneshot::channel();
1558 let deadline = session.request_deadline();
1559 session.on_internal_peer_request(
1560 PeerRequest::GetBlockBodies { request: GetBlockBodies(Vec::new()), response },
1561 deadline,
1562 );
1563 let id = *session.inflight_requests.keys().next().expect("eth request tracked");
1564 (id, rx)
1565 }
1566
1567 #[tokio::test(flavor = "multi_thread")]
1568 async fn test_disconnect() {
1569 let mut builder = SessionBuilder::default();
1570
1571 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1572 let local_addr = listener.local_addr().unwrap();
1573
1574 let expected_disconnect = DisconnectReason::UselessPeer;
1575
1576 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
1577 let msg = client_stream.next().await.unwrap().unwrap_err();
1578 assert_eq!(msg.as_disconnected().unwrap(), expected_disconnect);
1579 });
1580
1581 tokio::task::spawn(async move {
1582 let (incoming, _) = listener.accept().await.unwrap();
1583 let mut session = builder.connect_incoming(incoming).await;
1584
1585 session.start_disconnect(expected_disconnect).unwrap();
1586 session.await
1587 });
1588
1589 fut.await;
1590 }
1591
1592 #[tokio::test(flavor = "multi_thread")]
1593 async fn test_invalid_message_disconnects_with_protocol_breach() {
1594 let mut builder = SessionBuilder::default();
1595
1596 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1597 let local_addr = listener.local_addr().unwrap();
1598
1599 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
1600 client_stream
1601 .start_send_raw(RawCapabilityMessage::eth(
1602 EthMessageID::PooledTransactions,
1603 vec![0xc0].into(),
1604 ))
1605 .unwrap();
1606 client_stream.flush().await.unwrap();
1607
1608 let msg = client_stream.next().await.unwrap().unwrap_err();
1609 assert_eq!(msg.as_disconnected(), Some(DisconnectReason::ProtocolBreach));
1610 });
1611
1612 let (tx, rx) = oneshot::channel();
1613
1614 tokio::task::spawn(async move {
1615 let (incoming, _) = listener.accept().await.unwrap();
1616 let session = builder.connect_incoming(incoming).await;
1617 session.await;
1618
1619 tx.send(()).unwrap();
1620 });
1621
1622 fut.await;
1623 rx.await.unwrap();
1624 }
1625
1626 #[tokio::test(flavor = "multi_thread")]
1627 async fn handle_dropped_stream() {
1628 let mut builder = SessionBuilder::default();
1629
1630 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1631 let local_addr = listener.local_addr().unwrap();
1632
1633 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1634 drop(client_stream);
1635 tokio::time::sleep(Duration::from_secs(1)).await
1636 });
1637
1638 let (tx, rx) = oneshot::channel();
1639
1640 tokio::task::spawn(async move {
1641 let (incoming, _) = listener.accept().await.unwrap();
1642 let session = builder.connect_incoming(incoming).await;
1643 session.await;
1644
1645 tx.send(()).unwrap();
1646 });
1647
1648 tokio::task::spawn(fut);
1649
1650 rx.await.unwrap();
1651 }
1652
1653 #[tokio::test(flavor = "multi_thread")]
1654 async fn test_send_many_messages() {
1655 reth_tracing::init_test_tracing();
1656 let mut builder = SessionBuilder::default();
1657
1658 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1659 let local_addr = listener.local_addr().unwrap();
1660
1661 let num_messages = 100;
1662
1663 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
1664 for _ in 0..num_messages {
1665 client_stream
1666 .send(EthMessage::NewPooledTransactionHashes66(Vec::new().into()))
1667 .await
1668 .unwrap();
1669 }
1670 });
1671
1672 let (tx, rx) = oneshot::channel();
1673
1674 tokio::task::spawn(async move {
1675 let (incoming, _) = listener.accept().await.unwrap();
1676 let session = builder.connect_incoming(incoming).await;
1677 session.await;
1678
1679 tx.send(()).unwrap();
1680 });
1681
1682 tokio::task::spawn(fut);
1683
1684 rx.await.unwrap();
1685 }
1686
1687 #[tokio::test(flavor = "multi_thread")]
1688 async fn test_request_timeout() {
1689 reth_tracing::init_test_tracing();
1690
1691 let mut builder = SessionBuilder::default();
1692
1693 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1694 let local_addr = listener.local_addr().unwrap();
1695
1696 let request_timeout = Duration::from_millis(100);
1697 let drop_timeout = Duration::from_millis(1500);
1698
1699 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1700 let _client_stream = client_stream;
1701 tokio::time::sleep(drop_timeout * 60).await;
1702 });
1703 tokio::task::spawn(fut);
1704
1705 let (incoming, _) = listener.accept().await.unwrap();
1706 let mut session = builder.connect_incoming(incoming).await;
1707 session
1708 .internal_request_timeout
1709 .store(request_timeout.as_millis() as u64, Ordering::Relaxed);
1710 session.protocol_breach_request_timeout = drop_timeout;
1711 session.internal_request_timeout_interval =
1712 tokio::time::interval_at(tokio::time::Instant::now(), request_timeout);
1713 session
1714 .internal_request_timeout_interval
1715 .set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1716 let (tx, rx) = oneshot::channel();
1717 let req = PeerRequest::GetBlockBodies { request: GetBlockBodies(vec![]), response: tx };
1718 session.on_internal_peer_request(req, Instant::now());
1719 tokio::spawn(session);
1720
1721 let err = rx.await.unwrap().unwrap_err();
1722 assert_eq!(err, RequestError::Timeout);
1723
1724 let msg = builder.active_session_rx.next().await.unwrap();
1726 match msg {
1727 ActiveSessionMessage::ProtocolBreach { .. } => {}
1728 ev => unreachable!("{ev:?}"),
1729 }
1730 }
1731
1732 #[tokio::test(flavor = "multi_thread")]
1733 async fn snap_request_is_assigned_unique_id_and_response_correlated() {
1734 let mut builder = snap_session_builder();
1735 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1736 let local_addr = listener.local_addr().unwrap();
1737 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1738 let _client_stream = client_stream;
1739 tokio::time::sleep(Duration::from_secs(60)).await;
1740 });
1741 tokio::task::spawn(fut);
1742 let (incoming, _) = listener.accept().await.unwrap();
1743 let mut session = builder.connect_incoming(incoming).await;
1744
1745 let (id, rx) = dispatch_snap_request(&mut session, u64::MAX);
1747 assert_ne!(id, u64::MAX, "session must assign its own request id");
1748
1749 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::BlockAccessLists(
1751 BlockAccessListsMessage {
1752 request_id: id,
1753 block_access_lists: BlockAccessLists(Vec::new()),
1754 },
1755 ));
1756 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1757 assert!(!session.inflight_requests.contains_key(&id));
1758
1759 let response = rx.await.unwrap().unwrap();
1761 assert!(matches!(
1762 response,
1763 SnapResponse::BlockAccessLists(m) if m.request_id == u64::MAX
1764 ));
1765 }
1766
1767 #[tokio::test(flavor = "multi_thread")]
1768 async fn wrong_type_snap_response_is_rejected() {
1769 let mut builder = snap_session_builder();
1770 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1771 let local_addr = listener.local_addr().unwrap();
1772 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1773 let _client_stream = client_stream;
1774 tokio::time::sleep(Duration::from_secs(60)).await;
1775 });
1776 tokio::task::spawn(fut);
1777 let (incoming, _) = listener.accept().await.unwrap();
1778 let mut session = builder.connect_incoming(incoming).await;
1779
1780 let (id, rx) = dispatch_snap_request(&mut session, 0);
1781
1782 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::AccountRange(
1784 AccountRangeMessage { request_id: id, accounts: Vec::new(), proof: Vec::new() },
1785 ));
1786 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1787 assert!(!session.inflight_requests.contains_key(&id));
1788 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::BadResponse);
1789 assert!(matches!(
1790 builder.active_session_rx.next().await,
1791 Some(ActiveSessionMessage::BadMessage { .. })
1792 ));
1793 }
1794
1795 #[tokio::test(flavor = "multi_thread")]
1796 async fn snap_request_times_out() {
1797 let mut builder = snap_session_builder();
1798 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1799 let local_addr = listener.local_addr().unwrap();
1800 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1801 let _client_stream = client_stream;
1802 tokio::time::sleep(Duration::from_secs(60)).await;
1803 });
1804 tokio::task::spawn(fut);
1805 let (incoming, _) = listener.accept().await.unwrap();
1806 let mut session = builder.connect_incoming(incoming).await;
1807
1808 session.internal_request_timeout.store(1, Ordering::Relaxed);
1810 let (id, rx) = dispatch_snap_request(&mut session, 0);
1811
1812 tokio::time::sleep(Duration::from_millis(20)).await;
1815 assert!(!session.check_timed_out_requests(Instant::now()));
1816 assert!(session.inflight_requests.contains_key(&id));
1817 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::Timeout);
1818
1819 session.protocol_breach_request_timeout = Duration::from_millis(1);
1821 assert!(session.check_timed_out_requests(Instant::now()));
1822 }
1823
1824 #[tokio::test(flavor = "multi_thread")]
1825 async fn late_snap_response_is_consumed_without_penalty() {
1826 let mut builder = snap_session_builder();
1827 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1828 let local_addr = listener.local_addr().unwrap();
1829 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1830 let _client_stream = client_stream;
1831 tokio::time::sleep(Duration::from_secs(60)).await;
1832 });
1833 tokio::task::spawn(fut);
1834 let (incoming, _) = listener.accept().await.unwrap();
1835 let mut session = builder.connect_incoming(incoming).await;
1836
1837 session.internal_request_timeout.store(1, Ordering::Relaxed);
1838 let (id, _rx) = dispatch_snap_request(&mut session, 0);
1839 tokio::time::sleep(Duration::from_millis(20)).await;
1840 assert!(!session.check_timed_out_requests(Instant::now()));
1841
1842 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::BlockAccessLists(
1844 BlockAccessListsMessage {
1845 request_id: id,
1846 block_access_lists: BlockAccessLists(Vec::new()),
1847 },
1848 ));
1849 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1850 assert!(!session.inflight_requests.contains_key(&id));
1851 assert!(futures::FutureExt::now_or_never(builder.active_session_rx.next())
1852 .flatten()
1853 .is_none());
1854 }
1855
1856 #[tokio::test(flavor = "multi_thread")]
1857 async fn unknown_snap_response_is_penalized() {
1858 let mut builder = snap_session_builder();
1859 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1860 let local_addr = listener.local_addr().unwrap();
1861 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1862 let _client_stream = client_stream;
1863 tokio::time::sleep(Duration::from_secs(60)).await;
1864 });
1865 tokio::task::spawn(fut);
1866 let (incoming, _) = listener.accept().await.unwrap();
1867 let mut session = builder.connect_incoming(incoming).await;
1868
1869 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::BlockAccessLists(
1871 BlockAccessListsMessage {
1872 request_id: 999,
1873 block_access_lists: BlockAccessLists(Vec::new()),
1874 },
1875 ));
1876 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1877 assert!(session.inflight_requests.is_empty());
1878 assert!(session.queued_outgoing.pop_front().is_none());
1879 assert!(matches!(
1880 builder.active_session_rx.next().await,
1881 Some(ActiveSessionMessage::BadMessage { .. })
1882 ));
1883 }
1884
1885 #[tokio::test(flavor = "multi_thread")]
1886 async fn wrong_type_eth_response_is_penalized() {
1887 let mut builder = SessionBuilder::default();
1888 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1889 let local_addr = listener.local_addr().unwrap();
1890 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1891 let _client_stream = client_stream;
1892 tokio::time::sleep(Duration::from_secs(60)).await;
1893 });
1894 tokio::task::spawn(fut);
1895 let (incoming, _) = listener.accept().await.unwrap();
1896 let mut session = builder.connect_incoming(incoming).await;
1897
1898 let (id, rx) = dispatch_block_bodies_request(&mut session);
1899
1900 let outcome = session.on_incoming_message(EthMessage::BlockHeaders(RequestPair {
1904 request_id: id,
1905 message: BlockHeaders(Vec::new()),
1906 }));
1907 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1908 assert!(!session.inflight_requests.contains_key(&id));
1909 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::BadResponse);
1910 assert!(matches!(
1911 futures::FutureExt::now_or_never(builder.active_session_rx.next()).flatten(),
1912 Some(ActiveSessionMessage::BadMessage { .. })
1913 ));
1914 }
1915
1916 #[tokio::test(flavor = "multi_thread")]
1917 async fn matching_eth_response_is_not_penalized() {
1918 let mut builder = SessionBuilder::default();
1919 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1920 let local_addr = listener.local_addr().unwrap();
1921 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1922 let _client_stream = client_stream;
1923 tokio::time::sleep(Duration::from_secs(60)).await;
1924 });
1925 tokio::task::spawn(fut);
1926 let (incoming, _) = listener.accept().await.unwrap();
1927 let mut session = builder.connect_incoming(incoming).await;
1928
1929 let (id, rx) = dispatch_block_bodies_request(&mut session);
1930
1931 let outcome = session.on_incoming_message(EthMessage::BlockBodies(RequestPair {
1932 request_id: id,
1933 message: BlockBodies(Vec::new()),
1934 }));
1935 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1936 assert!(!session.inflight_requests.contains_key(&id));
1937 assert!(rx.await.unwrap().is_ok());
1938 assert!(futures::FutureExt::now_or_never(builder.active_session_rx.next())
1939 .flatten()
1940 .is_none());
1941 }
1942
1943 #[tokio::test(flavor = "multi_thread")]
1944 async fn snap_response_to_eth_request_is_penalized() {
1945 let mut builder = snap_session_builder();
1946 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1947 let local_addr = listener.local_addr().unwrap();
1948 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1949 let _client_stream = client_stream;
1950 tokio::time::sleep(Duration::from_secs(60)).await;
1951 });
1952 tokio::task::spawn(fut);
1953 let (incoming, _) = listener.accept().await.unwrap();
1954 let mut session = builder.connect_incoming(incoming).await;
1955
1956 let (id, rx) = dispatch_block_bodies_request(&mut session);
1959
1960 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::AccountRange(
1961 AccountRangeMessage { request_id: id, accounts: Vec::new(), proof: Vec::new() },
1962 ));
1963 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
1964 assert!(!session.inflight_requests.contains_key(&id));
1965 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::BadResponse);
1966 assert!(matches!(
1967 futures::FutureExt::now_or_never(builder.active_session_rx.next()).flatten(),
1968 Some(ActiveSessionMessage::BadMessage { .. })
1969 ));
1970 }
1971
1972 #[tokio::test(flavor = "multi_thread")]
1973 async fn get_snap_request_rejected_without_negotiated_snap() {
1974 let mut builder = SessionBuilder::default();
1976 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1977 let local_addr = listener.local_addr().unwrap();
1978 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
1979 let _client_stream = client_stream;
1980 tokio::time::sleep(Duration::from_secs(60)).await;
1981 });
1982 tokio::task::spawn(fut);
1983 let (incoming, _) = listener.accept().await.unwrap();
1984 let mut session = builder.connect_incoming(incoming).await;
1985 assert!(!session.conn.supports_snap());
1986
1987 let (response, rx) = oneshot::channel();
1988 let request = SnapProtocolMessage::GetBlockAccessLists(GetBlockAccessListsMessage {
1989 request_id: 0,
1990 block_hashes: Vec::new(),
1991 response_bytes: 0,
1992 });
1993 let deadline = session.request_deadline();
1994 session.on_internal_peer_request(PeerRequest::GetSnap { request, response }, deadline);
1995
1996 assert!(session.inflight_requests.is_empty());
1998 assert!(session.queued_outgoing.pop_front().is_none());
1999 assert_eq!(rx.await.unwrap().unwrap_err(), RequestError::UnsupportedCapability);
2000 }
2001
2002 #[tokio::test(flavor = "multi_thread")]
2003 async fn inbound_snap_request_round_trips_to_a_response() {
2004 let mut builder = snap_session_builder();
2005 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
2006 let local_addr = listener.local_addr().unwrap();
2007 let fut = builder.with_client_stream(local_addr, async move |client_stream| {
2008 let _client_stream = client_stream;
2009 tokio::time::sleep(Duration::from_secs(60)).await;
2010 });
2011 tokio::task::spawn(fut);
2012 let (incoming, _) = listener.accept().await.unwrap();
2013 let mut session = builder.connect_incoming(incoming).await;
2014
2015 let outcome = session.on_incoming_snap_message(SnapProtocolMessage::GetAccountRange(
2017 GetAccountRangeMessage {
2018 request_id: 7,
2019 root_hash: B256::ZERO,
2020 starting_hash: B256::ZERO,
2021 limit_hash: B256::ZERO,
2022 response_bytes: 1024,
2023 },
2024 ));
2025 assert!(matches!(outcome, OnIncomingMessageOutcome::Ok));
2026 assert_eq!(session.received_requests_from_remote.len(), 1);
2027
2028 let Some(ActiveSessionMessage::ValidMessage {
2030 message: PeerMessage::EthRequest(PeerRequest::GetSnap { request, response }),
2031 ..
2032 }) = builder.active_session_rx.next().await
2033 else {
2034 panic!("expected an outbound GetSnap request")
2035 };
2036 assert!(matches!(request, SnapProtocolMessage::GetAccountRange(_)));
2037
2038 let _ = response.send(Ok(SnapResponse::AccountRange(AccountRangeMessage {
2040 request_id: 7,
2041 accounts: Vec::new(),
2042 proof: Vec::new(),
2043 })));
2044
2045 let mut req = session.received_requests_from_remote.pop().unwrap();
2047 let waker = noop_waker();
2048 let mut cx = Context::from_waker(&waker);
2049 let Poll::Ready(resp) = req.rx.poll(&mut cx) else { panic!("response should be ready") };
2050 session.handle_outgoing_response(req.request_id, resp);
2051
2052 let msg = session.queued_outgoing.pop_front().expect("response queued for send");
2055 assert!(matches!(
2056 msg,
2057 OutgoingMessage::Snap(SnapProtocolMessage::AccountRange(AccountRangeMessage {
2058 request_id: 7,
2059 ..
2060 }))
2061 ));
2062 }
2063
2064 #[test]
2065 fn eth72_coalescing_preserves_cell_masks() {
2066 use alloy_primitives::B128;
2067
2068 let masks =
2069 [None, Some(B128::repeat_byte(0xff)), Some(B128::from(1u128)), Some(B128::from(2u128))];
2070 for existing_mask in masks {
2071 for incoming_mask in masks {
2072 let announcement = |mask: Option<B128>, byte| NewPooledTransactionHashes72 {
2073 types: vec![if mask.is_some() { 3 } else { 2 }],
2074 sizes: vec![100],
2075 hashes: vec![B256::repeat_byte(byte)],
2076 cell_mask: mask,
2077 };
2078 let existing = announcement(existing_mask, 1);
2079 let incoming = announcement(incoming_mask, 2);
2080 let mut message: OutgoingMessage<EthNetworkPrimitives> =
2081 EthMessage::NewPooledTransactionHashes72(existing.clone()).into();
2082
2083 let remainder = message.try_merge_hashes(incoming.clone().into());
2084
2085 let OutgoingMessage::Eth(EthMessage::NewPooledTransactionHashes72(merged)) =
2086 message
2087 else {
2088 panic!("expected eth72 announcement");
2089 };
2090 if existing_mask == incoming_mask {
2091 assert!(remainder.is_none());
2092 assert_eq!(merged.cell_mask, existing_mask);
2093 assert_eq!(merged.hashes, vec![B256::repeat_byte(1), B256::repeat_byte(2)]);
2094 assert_eq!(merged.types, [existing.types, incoming.types].concat());
2095 assert_eq!(merged.sizes, vec![100, 100]);
2096 } else {
2097 assert_eq!(remainder, Some(incoming.into()));
2098 assert_eq!(merged, existing);
2099 }
2100 }
2101 }
2102 }
2103
2104 #[test]
2105 fn eth72_pooled_hashes_count_broadcast_items() {
2106 let hashes =
2107 vec![alloy_primitives::B256::repeat_byte(1), alloy_primitives::B256::repeat_byte(2)];
2108 let msg: OutgoingMessage<EthNetworkPrimitives> =
2109 EthMessage::NewPooledTransactionHashes72(NewPooledTransactionHashes72 {
2110 types: vec![0; hashes.len()],
2111 sizes: vec![1; hashes.len()],
2112 hashes,
2113 cell_mask: None,
2114 })
2115 .into();
2116
2117 assert_eq!(2, msg.broadcast_item_count());
2118 }
2119
2120 #[test]
2121 fn test_reject_bal_request_for_eth70() {
2122 let (tx, _rx) = oneshot::channel();
2123 let request: PeerRequest<EthNetworkPrimitives> =
2124 PeerRequest::GetBlockAccessLists { request: GetBlockAccessLists(vec![]), response: tx };
2125
2126 assert!(!ActiveSession::<EthNetworkPrimitives>::is_request_supported_for_version(
2127 &request,
2128 EthVersion::Eth70
2129 ));
2130 assert!(ActiveSession::<EthNetworkPrimitives>::is_request_supported_for_version(
2131 &request,
2132 EthVersion::Eth71
2133 ));
2134 }
2135
2136 #[tokio::test(flavor = "multi_thread")]
2137 async fn test_keep_alive() {
2138 let mut builder = SessionBuilder::default();
2139
2140 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
2141 let local_addr = listener.local_addr().unwrap();
2142
2143 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
2144 let _ = tokio::time::timeout(Duration::from_secs(5), client_stream.next()).await;
2145 client_stream.into_inner().disconnect(DisconnectReason::UselessPeer).await.unwrap();
2146 });
2147
2148 let (tx, rx) = oneshot::channel();
2149
2150 tokio::task::spawn(async move {
2151 let (incoming, _) = listener.accept().await.unwrap();
2152 let session = builder.connect_incoming(incoming).await;
2153 session.await;
2154
2155 tx.send(()).unwrap();
2156 });
2157
2158 tokio::task::spawn(fut);
2159
2160 rx.await.unwrap();
2161 }
2162
2163 #[tokio::test(flavor = "multi_thread")]
2165 async fn test_send_at_capacity() {
2166 let mut builder = SessionBuilder::default();
2167
2168 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
2169 let local_addr = listener.local_addr().unwrap();
2170
2171 let fut = builder.with_client_stream(local_addr, async move |mut client_stream| {
2172 client_stream
2173 .send(EthMessage::NewPooledTransactionHashes68(Default::default()))
2174 .await
2175 .unwrap();
2176 let _ = tokio::time::timeout(Duration::from_secs(100), client_stream.next()).await;
2177 });
2178 tokio::task::spawn(fut);
2179
2180 let (incoming, _) = listener.accept().await.unwrap();
2181 let session = builder.connect_incoming(incoming).await;
2182
2183 let mut num_fill_messages = 0;
2185 loop {
2186 if builder
2187 .active_session_tx
2188 .try_send(ActiveSessionMessage::ProtocolBreach { peer_id: PeerId::random() })
2189 .is_err()
2190 {
2191 break
2192 }
2193 num_fill_messages += 1;
2194 }
2195
2196 tokio::task::spawn(async move {
2197 session.await;
2198 });
2199
2200 tokio::time::sleep(Duration::from_millis(100)).await;
2201
2202 for _ in 0..num_fill_messages {
2203 let message = builder.active_session_rx.next().await.unwrap();
2204 match message {
2205 ActiveSessionMessage::ProtocolBreach { .. } => {}
2206 ev => unreachable!("{ev:?}"),
2207 }
2208 }
2209
2210 let message = builder.active_session_rx.next().await.unwrap();
2211 match message {
2212 ActiveSessionMessage::ValidMessage {
2213 message: PeerMessage::PooledTransactions(_),
2214 ..
2215 } => {}
2216 _ => unreachable!(),
2217 }
2218 }
2219
2220 #[test]
2221 fn timeout_calculation_sanity_tests() {
2222 let rtt = Duration::from_secs(5);
2223 let timeout = rtt * TIMEOUT_SCALING;
2225
2226 assert_eq!(calculate_new_timeout(timeout, rtt), timeout);
2228
2229 assert!(calculate_new_timeout(timeout, rtt / 2) < timeout);
2231 assert!(calculate_new_timeout(timeout, rtt / 2) > timeout / 2);
2232 assert!(calculate_new_timeout(timeout, rtt * 2) > timeout);
2233 assert!(calculate_new_timeout(timeout, rtt * 2) < timeout * 2);
2234 }
2235}