1use std::{
11 collections::VecDeque,
12 fmt,
13 future::Future,
14 io,
15 pin::{pin, Pin},
16 sync::{
17 atomic::{AtomicUsize, Ordering},
18 Arc,
19 },
20 task::{ready, Context, Poll},
21};
22
23use crate::{
24 capability::{SharedCapabilities, SharedCapability, UnsupportedCapabilityError},
25 errors::{EthStreamError, P2PStreamError},
26 handshake::EthRlpxHandshake,
27 p2pstream::DisconnectP2P,
28 protocol::ProtocolIngressLimits,
29 CanDisconnect, Capability, DisconnectReason, EthStream, P2PStream, UnifiedStatus,
30 HANDSHAKE_TIMEOUT,
31};
32use bytes::{Bytes, BytesMut};
33use futures::{Sink, SinkExt, Stream, StreamExt, TryStream, TryStreamExt};
34use reth_eth_wire_types::NetworkPrimitives;
35use reth_ethereum_forks::ForkFilter;
36use reth_metrics::metrics::counter;
37use tokio::sync::{mpsc, mpsc::UnboundedSender};
38use tokio_stream::wrappers::{ReceiverStream, UnboundedReceiverStream};
39
40#[derive(Debug)]
43pub struct RlpxProtocolMultiplexer<St> {
44 inner: MultiplexInner<St>,
45}
46
47impl<St> RlpxProtocolMultiplexer<St> {
48 pub fn new(conn: P2PStream<St>) -> Self {
50 Self {
51 inner: MultiplexInner {
52 conn,
53 protocols: Default::default(),
54 out_buffer: Default::default(),
55 inbound_budget: Arc::new(InboundBudget::new(MAX_MUX_IN_BUFFER_BYTES)),
56 },
57 }
58 }
59
60 pub fn install_protocol<F, Proto>(
65 &mut self,
66 cap: &Capability,
67 f: F,
68 ) -> Result<(), UnsupportedCapabilityError>
69 where
70 F: FnOnce(ProtocolConnection) -> Proto,
71 Proto: Stream<Item = BytesMut> + Send + 'static,
72 {
73 self.inner.install_protocol(cap, ProtocolIngressLimits::default(), f)
74 }
75
76 pub fn install_protocol_with_limits<F, Proto>(
78 &mut self,
79 cap: &Capability,
80 limits: ProtocolIngressLimits,
81 f: F,
82 ) -> Result<(), UnsupportedCapabilityError>
83 where
84 F: FnOnce(ProtocolConnection) -> Proto,
85 Proto: Stream<Item = BytesMut> + Send + 'static,
86 {
87 self.inner.install_protocol(cap, limits, f)
88 }
89
90 pub const fn shared_capabilities(&self) -> &SharedCapabilities {
92 self.inner.shared_capabilities()
93 }
94
95 pub fn into_satellite_stream<F, Primary>(
97 self,
98 cap: &Capability,
99 primary: F,
100 ) -> Result<RlpxSatelliteStream<St, Primary>, P2PStreamError>
101 where
102 F: FnOnce(ProtocolProxy) -> Primary,
103 {
104 let Ok(shared_cap) = self.shared_capabilities().ensure_matching_capability(cap).cloned()
105 else {
106 return Err(P2PStreamError::CapabilityNotShared)
107 };
108
109 let (to_primary, from_wire) =
110 self.inner.inbound_channel(&shared_cap, ProtocolIngressLimits::default());
111 let (to_wire, from_primary) = mpsc::unbounded_channel();
112 let proxy = ProtocolProxy { shared_cap: shared_cap.clone(), from_wire, to_wire };
113
114 let st = primary(proxy);
115 Ok(RlpxSatelliteStream {
116 inner: self.inner,
117 primary: PrimaryProtocol {
118 to_primary,
119 from_primary: UnboundedReceiverStream::new(from_primary),
120 st,
121 shared_cap,
122 },
123 next_outbound: 0,
124 producer_polls_since_inbound: 0,
125 })
126 }
127
128 pub async fn into_satellite_stream_with_handshake<F, Fut, Err, Primary>(
133 self,
134 cap: &Capability,
135 handshake: F,
136 ) -> Result<RlpxSatelliteStream<St, Primary>, Err>
137 where
138 F: FnOnce(ProtocolProxy) -> Fut,
139 Fut: Future<Output = Result<Primary, Err>>,
140 St: Stream<Item = io::Result<BytesMut>> + Sink<Bytes, Error = io::Error> + Unpin,
141 P2PStreamError: Into<Err>,
142 {
143 self.into_satellite_stream_with_tuple_handshake(cap, async move |proxy| {
144 let st = handshake(proxy).await?;
145 Ok((st, ()))
146 })
147 .await
148 .map(|(st, _)| st)
149 }
150
151 pub async fn into_satellite_stream_with_tuple_handshake<F, Fut, Err, Primary, Extra>(
161 mut self,
162 cap: &Capability,
163 handshake: F,
164 ) -> Result<(RlpxSatelliteStream<St, Primary>, Extra), Err>
165 where
166 F: FnOnce(ProtocolProxy) -> Fut,
167 Fut: Future<Output = Result<(Primary, Extra), Err>>,
168 St: Stream<Item = io::Result<BytesMut>> + Sink<Bytes, Error = io::Error> + Unpin,
169 P2PStreamError: Into<Err>,
170 {
171 let Ok(shared_cap) = self.shared_capabilities().ensure_matching_capability(cap).cloned()
172 else {
173 return Err(P2PStreamError::CapabilityNotShared.into())
174 };
175
176 let (to_primary, from_wire) =
177 self.inner.inbound_channel(&shared_cap, ProtocolIngressLimits::default());
178 let (to_wire, mut from_primary) = mpsc::unbounded_channel();
179 let proxy = ProtocolProxy { shared_cap: shared_cap.clone(), from_wire, to_wire };
180
181 let f = handshake(proxy);
182 let mut f = pin!(f);
183 let mut inbound_messages = 0;
184 let mut handshake_satellite_bytes = 0usize;
185 let mut handshake_satellite_messages = 0usize;
186
187 loop {
190 tokio::select! {
191 biased;
192 res = &mut f => {
193 let (st, extra) = res?;
194 return Ok((
195 RlpxSatelliteStream {
196 inner: self.inner,
197 primary: PrimaryProtocol {
198 to_primary,
199 from_primary: UnboundedReceiverStream::new(from_primary),
200 st,
201 shared_cap,
202 },
203 next_outbound: 0,
204 producer_polls_since_inbound: 0,
205 },
206 extra,
207 ))
208 }
209 Some(msg) = from_primary.recv() => {
210 self.inner.conn.send(msg).await.map_err(Into::into)?;
211 }
212 msg = ProtocolsPoller::new(&mut self.inner.protocols) => {
215 self.inner.conn.send(msg.map_err(Into::into)?).await.map_err(Into::into)?;
216 }
217 incoming = self.inner.conn.next() => {
218 let msg = match incoming {
219 Some(Ok(msg)) => msg,
220 Some(Err(err)) => return Err(err.into()),
221 None => {
222 return Err(P2PStreamError::Io(io::ErrorKind::UnexpectedEof.into()).into())
223 }
224 };
225 let Some(offset) = msg.first().copied()
227 else {
228 return Err(P2PStreamError::EmptyProtocolMessage.into())
229 };
230 if let Some(cap) = self.shared_capabilities().find_by_relative_offset(offset).cloned() {
231 if cap == shared_cap {
232 to_primary.try_send(msg).map_err(Into::into)?;
234 } else {
235 handshake_satellite_bytes = handshake_satellite_bytes
238 .saturating_add(msg.capacity().max(msg.len()));
239 handshake_satellite_messages += 1;
240 if handshake_satellite_bytes > MAX_HANDSHAKE_SATELLITE_BYTES ||
241 handshake_satellite_messages > MAX_HANDSHAKE_SATELLITE_MESSAGES
242 {
243 counter!("p2pstream.subprotocol_inbound_buffer_full").increment(1);
244 return Err(P2PStreamError::SubprotocolInboundBufferFull {
245 capability: cap.capability().into_owned(),
246 }.into())
247 }
248 self.inner.delegate_message(&cap, msg).map_err(Into::into)?;
249 }
250 } else {
251 return Err(P2PStreamError::UnknownReservedMessageId(offset).into())
252 }
253
254 inbound_messages += 1;
255 if inbound_messages == MAX_INBOUND_MESSAGES_PER_POLL {
256 inbound_messages = 0;
257 yield_once().await;
258 }
259 }
260 }
261 }
262 }
263
264 pub async fn into_eth_satellite_stream<N: NetworkPrimitives>(
267 self,
268 status: UnifiedStatus,
269 fork_filter: ForkFilter,
270 handshake: Arc<dyn EthRlpxHandshake>,
271 eth_max_message_size: usize,
272 ) -> Result<(RlpxSatelliteStream<St, EthStream<ProtocolProxy, N>>, UnifiedStatus), EthStreamError>
273 where
274 St: Stream<Item = io::Result<BytesMut>> + Sink<Bytes, Error = io::Error> + Unpin,
275 {
276 let eth_cap = self.inner.conn.shared_capabilities().eth_version()?;
277 self.into_satellite_stream_with_tuple_handshake(
278 &Capability::eth(eth_cap),
279 async move |proxy| {
280 let handshake = handshake.clone();
281 let mut unauth = UnauthProxy { inner: proxy };
282 let their_status = handshake
283 .handshake(&mut unauth, status, fork_filter, HANDSHAKE_TIMEOUT)
284 .await?;
285 let eth_stream = EthStream::with_max_message_size(
286 eth_cap,
287 unauth.into_inner(),
288 eth_max_message_size,
289 );
290 Ok((eth_stream, their_status))
291 },
292 )
293 .await
294 }
295}
296
297#[derive(Debug)]
298struct MultiplexInner<St> {
299 conn: P2PStream<St>,
301 protocols: VecDeque<ProtocolStream>,
303 out_buffer: OutBuffer,
305 inbound_budget: Arc<InboundBudget>,
307}
308
309impl<St> MultiplexInner<St> {
310 const fn shared_capabilities(&self) -> &SharedCapabilities {
311 self.conn.shared_capabilities()
312 }
313
314 fn delegate_message(
316 &self,
317 cap: &SharedCapability,
318 msg: BytesMut,
319 ) -> Result<bool, P2PStreamError> {
320 for proto in &self.protocols {
321 if proto.shared_cap == *cap {
322 proto.send_raw(msg)?;
323 return Ok(true)
324 }
325 }
326 Ok(false)
327 }
328
329 fn install_protocol<F, Proto>(
330 &mut self,
331 cap: &Capability,
332 limits: ProtocolIngressLimits,
333 f: F,
334 ) -> Result<(), UnsupportedCapabilityError>
335 where
336 F: FnOnce(ProtocolConnection) -> Proto,
337 Proto: Stream<Item = BytesMut> + Send + 'static,
338 {
339 let shared_cap =
340 self.conn.shared_capabilities().ensure_matching_capability(cap).cloned()?;
341 self.conn.set_protocol_ingress_limits(&shared_cap, limits);
342 let (to_satellite, from_wire) = self.inbound_channel(&shared_cap, limits);
343 let proto_conn = ProtocolConnection { from_wire };
344 let st = f(proto_conn);
345 let st = ProtocolStream { shared_cap, to_satellite, satellite_st: Box::pin(st) };
346 self.protocols.push_back(st);
347 Ok(())
348 }
349
350 fn inbound_channel(
351 &self,
352 capability: &SharedCapability,
353 limits: ProtocolIngressLimits,
354 ) -> (InboundSender, InboundReceiver) {
355 inbound_channel(capability, limits, Arc::clone(&self.inbound_budget))
356 }
357}
358
359#[derive(Debug)]
361struct PrimaryProtocol<Primary> {
362 to_primary: InboundSender,
364 from_primary: UnboundedReceiverStream<Bytes>,
366 shared_cap: SharedCapability,
368 st: Primary,
370}
371
372#[derive(Debug)]
376pub struct ProtocolProxy {
377 shared_cap: SharedCapability,
378 from_wire: InboundReceiver,
380 to_wire: UnboundedSender<Bytes>,
382}
383
384impl ProtocolProxy {
385 fn try_send(&self, msg: Bytes) -> Result<(), io::Error> {
387 if msg.is_empty() {
388 return Err(io::ErrorKind::InvalidInput.into())
390 }
391 self.to_wire.send(self.mask_msg_id(msg)?).map_err(|_| io::ErrorKind::BrokenPipe.into())
392 }
393
394 #[inline]
396 fn mask_msg_id(&self, msg: Bytes) -> Result<Bytes, io::Error> {
397 if msg.is_empty() {
398 return Err(io::ErrorKind::InvalidInput.into())
400 }
401
402 let offset = self.shared_cap.relative_message_id_offset();
403 if offset == 0 {
404 return Ok(msg);
405 }
406
407 let mut masked: BytesMut = msg.into();
408 masked[0] = masked[0].checked_add(offset).ok_or(io::ErrorKind::InvalidInput)?;
409 Ok(masked.freeze())
410 }
411
412 #[inline]
414 fn unmask_id(&self, mut msg: BytesMut) -> Result<BytesMut, io::Error> {
415 if msg.is_empty() {
416 return Err(io::ErrorKind::InvalidInput.into())
418 }
419 msg[0] = msg[0]
420 .checked_sub(self.shared_cap.relative_message_id_offset())
421 .ok_or(io::ErrorKind::InvalidInput)?;
422 Ok(msg)
423 }
424}
425
426impl Stream for ProtocolProxy {
427 type Item = Result<BytesMut, io::Error>;
428
429 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
430 let msg = ready!(self.from_wire.poll_next_unpin(cx));
431 Poll::Ready(msg.map(|msg| self.get_mut().unmask_id(msg)))
432 }
433}
434
435impl Sink<Bytes> for ProtocolProxy {
436 type Error = io::Error;
437
438 fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
439 Poll::Ready(Ok(()))
440 }
441
442 fn start_send(self: Pin<&mut Self>, item: Bytes) -> Result<(), Self::Error> {
443 self.get_mut().try_send(item)
444 }
445
446 fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
447 Poll::Ready(Ok(()))
448 }
449
450 fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
451 Poll::Ready(Ok(()))
452 }
453}
454
455impl CanDisconnect<Bytes> for ProtocolProxy {
456 fn disconnect(
457 &mut self,
458 _reason: DisconnectReason,
459 ) -> Pin<Box<dyn Future<Output = Result<(), <Self as Sink<Bytes>>::Error>> + Send + '_>> {
460 Box::pin(async move { Ok(()) })
461 }
462}
463
464#[derive(Debug)]
467struct UnauthProxy {
468 inner: ProtocolProxy,
469}
470
471impl UnauthProxy {
472 fn into_inner(self) -> ProtocolProxy {
473 self.inner
474 }
475}
476
477impl Stream for UnauthProxy {
478 type Item = Result<BytesMut, P2PStreamError>;
479
480 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
481 self.inner.poll_next_unpin(cx).map(|opt| opt.map(|res| res.map_err(P2PStreamError::from)))
482 }
483}
484
485impl Sink<Bytes> for UnauthProxy {
486 type Error = P2PStreamError;
487
488 fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
489 self.inner.poll_ready_unpin(cx).map_err(P2PStreamError::from)
490 }
491
492 fn start_send(mut self: Pin<&mut Self>, item: Bytes) -> Result<(), Self::Error> {
493 self.inner.start_send_unpin(item).map_err(P2PStreamError::from)
494 }
495
496 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
497 self.inner.poll_flush_unpin(cx).map_err(P2PStreamError::from)
498 }
499
500 fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
501 self.inner.poll_close_unpin(cx).map_err(P2PStreamError::from)
502 }
503}
504
505impl CanDisconnect<Bytes> for UnauthProxy {
506 fn disconnect(
507 &mut self,
508 reason: DisconnectReason,
509 ) -> Pin<Box<dyn Future<Output = Result<(), <Self as Sink<Bytes>>::Error>> + Send + '_>> {
510 let fut = self.inner.disconnect(reason);
511 Box::pin(async move { fut.await.map_err(P2PStreamError::from) })
512 }
513}
514
515#[derive(Debug)]
516struct InboundSender {
517 inner: mpsc::Sender<BudgetedInbound>,
518 connection_budget: Arc<InboundBudget>,
519 protocol_budget: Arc<InboundBudget>,
520 capability: Capability,
521}
522
523impl InboundSender {
524 fn try_send(&self, frame: BytesMut) -> Result<(), P2PStreamError> {
525 let size = frame.capacity().max(frame.len());
526 let Some(connection_guard) = InboundBudget::try_reserve(&self.connection_budget, size)
527 else {
528 return Err(self.buffer_full())
529 };
530 let Some(protocol_guard) = InboundBudget::try_reserve(&self.protocol_budget, size) else {
531 return Err(self.buffer_full())
532 };
533
534 let frame = BudgetedInbound {
535 frame,
536 _connection_guard: connection_guard,
537 _protocol_guard: protocol_guard,
538 };
539 self.inner.try_send(frame).map_err(|err| match err {
540 mpsc::error::TrySendError::Full(_) => self.buffer_full(),
541 mpsc::error::TrySendError::Closed(_) => {
542 P2PStreamError::Io(io::ErrorKind::BrokenPipe.into())
543 }
544 })
545 }
546
547 fn buffer_full(&self) -> P2PStreamError {
548 counter!("p2pstream.subprotocol_inbound_buffer_full").increment(1);
549 P2PStreamError::SubprotocolInboundBufferFull { capability: self.capability.clone() }
550 }
551}
552
553#[derive(Debug)]
554struct InboundReceiver {
555 inner: ReceiverStream<BudgetedInbound>,
556}
557
558impl Stream for InboundReceiver {
559 type Item = BytesMut;
560
561 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
562 self.inner.poll_next_unpin(cx).map(|frame| frame.map(BudgetedInbound::into_frame))
563 }
564}
565
566#[derive(Debug)]
567struct BudgetedInbound {
568 frame: BytesMut,
569 _connection_guard: InboundBudgetGuard,
570 _protocol_guard: InboundBudgetGuard,
571}
572
573impl BudgetedInbound {
574 fn into_frame(self) -> BytesMut {
575 let Self { frame, _connection_guard, _protocol_guard } = self;
576 frame
577 }
578}
579
580#[derive(Debug)]
581struct InboundBudget {
582 used: AtomicUsize,
583 max: usize,
584}
585
586impl InboundBudget {
587 const fn new(max: usize) -> Self {
588 Self { used: AtomicUsize::new(0), max }
589 }
590
591 fn try_reserve(budget: &Arc<Self>, size: usize) -> Option<InboundBudgetGuard> {
592 budget
593 .used
594 .try_update(Ordering::Relaxed, Ordering::Relaxed, |used| {
595 used.checked_add(size).filter(|next| *next <= budget.max)
596 })
597 .ok()
598 .map(|_| InboundBudgetGuard { size, budget: Arc::clone(budget) })
599 }
600}
601
602#[derive(Debug)]
603struct InboundBudgetGuard {
604 size: usize,
605 budget: Arc<InboundBudget>,
606}
607
608impl Drop for InboundBudgetGuard {
609 fn drop(&mut self) {
610 self.budget.used.fetch_sub(self.size, Ordering::Relaxed);
611 }
612}
613
614fn inbound_channel(
615 capability: &SharedCapability,
616 limits: ProtocolIngressLimits,
617 connection_budget: Arc<InboundBudget>,
618) -> (InboundSender, InboundReceiver) {
619 let (tx, rx) = mpsc::channel(limits.max_buffered_messages());
620 let sender = InboundSender {
621 inner: tx,
622 connection_budget,
623 protocol_budget: Arc::new(InboundBudget::new(limits.max_buffered_bytes())),
624 capability: capability.capability().into_owned(),
625 };
626 let receiver = InboundReceiver { inner: ReceiverStream::new(rx) };
627 (sender, receiver)
628}
629
630#[derive(Debug)]
634pub struct ProtocolConnection {
635 from_wire: InboundReceiver,
636}
637
638impl Stream for ProtocolConnection {
639 type Item = BytesMut;
640
641 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
642 self.from_wire.poll_next_unpin(cx)
643 }
644}
645
646#[derive(Debug)]
649pub struct RlpxSatelliteStream<St, Primary> {
650 inner: MultiplexInner<St>,
651 primary: PrimaryProtocol<Primary>,
652 next_outbound: usize,
654 producer_polls_since_inbound: usize,
656}
657
658impl<St, Primary> RlpxSatelliteStream<St, Primary> {
659 pub fn install_protocol<F, Proto>(
664 &mut self,
665 cap: &Capability,
666 f: F,
667 ) -> Result<(), UnsupportedCapabilityError>
668 where
669 F: FnOnce(ProtocolConnection) -> Proto,
670 Proto: Stream<Item = BytesMut> + Send + 'static,
671 {
672 let result = self.inner.install_protocol(cap, ProtocolIngressLimits::default(), f);
673 if result.is_ok() {
674 self.producer_polls_since_inbound = 0;
675 }
676 result
677 }
678
679 pub fn install_protocol_with_limits<F, Proto>(
681 &mut self,
682 cap: &Capability,
683 limits: ProtocolIngressLimits,
684 f: F,
685 ) -> Result<(), UnsupportedCapabilityError>
686 where
687 F: FnOnce(ProtocolConnection) -> Proto,
688 Proto: Stream<Item = BytesMut> + Send + 'static,
689 {
690 let result = self.inner.install_protocol(cap, limits, f);
691 if result.is_ok() {
692 self.producer_polls_since_inbound = 0;
693 }
694 result
695 }
696
697 #[inline]
699 pub const fn primary(&self) -> &Primary {
700 &self.primary.st
701 }
702
703 #[inline]
705 pub const fn primary_mut(&mut self) -> &mut Primary {
706 &mut self.primary.st
707 }
708
709 #[inline]
711 pub const fn inner(&self) -> &P2PStream<St> {
712 &self.inner.conn
713 }
714
715 #[inline]
717 pub const fn inner_mut(&mut self) -> &mut P2PStream<St> {
718 &mut self.inner.conn
719 }
720
721 #[inline]
723 pub fn into_inner(self) -> P2PStream<St> {
724 self.inner.conn
725 }
726
727 fn poll_outbound_producers(&mut self, cx: &mut Context<'_>) -> Result<ProducerPoll, io::Error> {
733 let producers = self.inner.protocols.len() + 1;
734 let mut pending = 0;
735
736 while pending < producers {
737 if self.inner.out_buffer.is_full() {
738 return Ok(ProducerPoll::Full)
739 }
740
741 if self.next_outbound >= producers {
742 self.next_outbound = 0;
743 }
744
745 let producer = self.next_outbound;
746 self.next_outbound = (self.next_outbound + 1) % producers;
747 if self.producer_polls_since_inbound < producers {
748 self.producer_polls_since_inbound += 1;
749 }
750
751 let msg = if producer == 0 {
752 match self.primary.from_primary.poll_next_unpin(cx) {
753 Poll::Ready(Some(msg)) => msg,
754 Poll::Ready(None) => return Ok(ProducerPoll::Closed),
755 Poll::Pending => {
756 pending += 1;
757 continue
758 }
759 }
760 } else {
761 let proto = self
762 .inner
763 .protocols
764 .get_mut(producer - 1)
765 .expect("outbound producer index checked against protocol count");
766 match proto.poll_next_unpin(cx) {
767 Poll::Ready(Some(msg)) => msg?,
768 Poll::Ready(None) => return Ok(ProducerPoll::Closed),
769 Poll::Pending => {
770 pending += 1;
771 continue
772 }
773 }
774 };
775
776 pending = 0;
777 self.inner.out_buffer.push_back(msg);
778 }
779
780 Ok(ProducerPoll::Pending)
781 }
782}
783
784impl<St, Primary, PrimaryErr> Stream for RlpxSatelliteStream<St, Primary>
785where
786 St: Stream<Item = io::Result<BytesMut>> + Sink<Bytes, Error = io::Error> + Unpin,
787 Primary: TryStream<Error = PrimaryErr> + Unpin,
788 P2PStreamError: Into<PrimaryErr>,
789{
790 type Item = Result<Primary::Ok, Primary::Error>;
791
792 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
793 let this = self.get_mut();
794 let mut inbound_messages = 0;
795
796 loop {
797 if let Poll::Ready(Some(msg)) = this.primary.st.try_poll_next_unpin(cx) {
799 return Poll::Ready(Some(msg))
800 }
801
802 let mut conn_ready = true;
803 loop {
804 match this.inner.conn.poll_ready_unpin(cx) {
805 Poll::Ready(Ok(())) => {
806 if let Some(msg) = this.inner.out_buffer.pop_front() {
807 if let Err(err) = this.inner.conn.start_send_unpin(msg) {
808 return Poll::Ready(Some(Err(err.into())))
809 }
810 } else {
811 break
812 }
813 }
814 Poll::Ready(Err(err)) => {
815 if let Err(disconnect_err) =
816 this.inner.conn.start_disconnect(DisconnectReason::DisconnectRequested)
817 {
818 return Poll::Ready(Some(Err(disconnect_err.into())))
819 }
820 return Poll::Ready(Some(Err(err.into())))
821 }
822 Poll::Pending => {
823 conn_ready = false;
824 break
825 }
826 }
827 }
828 match this.inner.conn.poll_flush_unpin(cx) {
833 Poll::Ready(Ok(())) => {}
834 Poll::Ready(Err(err)) => return Poll::Ready(Some(Err(err.into()))),
835 Poll::Pending => {
836 conn_ready = false;
837 }
838 }
839
840 match this.poll_outbound_producers(cx) {
841 Ok(ProducerPoll::Full)
842 if this.producer_polls_since_inbound < this.inner.protocols.len() + 1 =>
843 {
844 if conn_ready {
847 cx.waker().wake_by_ref();
848 }
849 return Poll::Pending
850 }
851 Ok(ProducerPoll::Pending | ProducerPoll::Full) => {}
852 Ok(ProducerPoll::Closed) => return Poll::Ready(None),
853 Err(err) => return Poll::Ready(Some(Err(P2PStreamError::Io(err).into()))),
854 }
855
856 let mut delegated = false;
857 match this.inner.conn.poll_next_unpin(cx) {
860 Poll::Ready(Some(Ok(msg))) => {
861 delegated = true;
862 let Some(offset) = msg.first().copied() else {
863 return Poll::Ready(Some(Err(P2PStreamError::EmptyProtocolMessage.into())))
864 };
865 let Some(cap) = this
866 .inner
867 .conn
868 .shared_capabilities()
869 .find_by_relative_offset(offset)
870 .cloned()
871 else {
872 return Poll::Ready(Some(Err(P2PStreamError::UnknownReservedMessageId(
873 offset,
874 )
875 .into())))
876 };
877
878 let result = if cap == this.primary.shared_cap {
879 this.primary.to_primary.try_send(msg)
880 } else {
881 this.inner.delegate_message(&cap, msg).map(|_| ())
882 };
883 if let Err(err) = result {
884 return Poll::Ready(Some(Err(err.into())))
885 }
886 this.producer_polls_since_inbound = 0;
887
888 inbound_messages += 1;
889 if inbound_messages == MAX_INBOUND_MESSAGES_PER_POLL {
890 cx.waker().wake_by_ref();
891 return Poll::Pending
892 }
893 }
894 Poll::Ready(Some(Err(err))) => return Poll::Ready(Some(Err(err.into()))),
895 Poll::Ready(None) => return Poll::Ready(None),
896 Poll::Pending => {}
897 }
898
899 if !conn_ready || (!delegated && this.inner.out_buffer.is_empty()) {
900 return Poll::Pending
901 }
902 }
903 }
904}
905
906impl<St, Primary, T> Sink<T> for RlpxSatelliteStream<St, Primary>
907where
908 St: Stream<Item = io::Result<BytesMut>> + Sink<Bytes, Error = io::Error> + Unpin,
909 Primary: Sink<T> + Unpin,
910 P2PStreamError: Into<<Primary as Sink<T>>::Error>,
911{
912 type Error = <Primary as Sink<T>>::Error;
913
914 fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
915 let this = self.get_mut();
916 if let Err(err) = ready!(this.inner.conn.poll_ready_unpin(cx)) {
917 return Poll::Ready(Err(err.into()))
918 }
919 if let Err(err) = ready!(this.primary.st.poll_ready_unpin(cx)) {
920 return Poll::Ready(Err(err))
921 }
922 Poll::Ready(Ok(()))
923 }
924
925 fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> {
926 self.get_mut().primary.st.start_send_unpin(item)
927 }
928
929 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
930 self.get_mut().inner.conn.poll_flush_unpin(cx).map_err(Into::into)
931 }
932
933 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
934 self.get_mut().inner.conn.poll_close_unpin(cx).map_err(Into::into)
935 }
936}
937
938struct ProtocolStream {
940 shared_cap: SharedCapability,
941 to_satellite: InboundSender,
943 satellite_st: Pin<Box<dyn Stream<Item = BytesMut> + Send>>,
944}
945
946impl ProtocolStream {
947 #[inline]
949 fn mask_msg_id(&self, mut msg: BytesMut) -> Result<Bytes, io::Error> {
950 if msg.is_empty() {
951 return Err(io::ErrorKind::InvalidInput.into())
953 }
954 msg[0] = msg[0]
955 .checked_add(self.shared_cap.relative_message_id_offset())
956 .ok_or(io::ErrorKind::InvalidInput)?;
957 Ok(msg.freeze())
958 }
959
960 #[inline]
962 fn unmask_id(&self, mut msg: BytesMut) -> Result<BytesMut, io::Error> {
963 if msg.is_empty() {
964 return Err(io::ErrorKind::InvalidInput.into())
966 }
967 msg[0] = msg[0]
968 .checked_sub(self.shared_cap.relative_message_id_offset())
969 .ok_or(io::ErrorKind::InvalidInput)?;
970 Ok(msg)
971 }
972
973 fn send_raw(&self, msg: BytesMut) -> Result<(), P2PStreamError> {
975 let msg = self.unmask_id(msg).map_err(P2PStreamError::from)?;
976 self.to_satellite.try_send(msg)
977 }
978}
979
980impl Stream for ProtocolStream {
981 type Item = Result<Bytes, io::Error>;
982
983 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
984 let this = self.get_mut();
985 let msg = ready!(this.satellite_st.as_mut().poll_next(cx));
986 Poll::Ready(msg.map(|msg| this.mask_msg_id(msg)))
987 }
988}
989
990impl fmt::Debug for ProtocolStream {
991 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
992 f.debug_struct("ProtocolStream").field("cap", &self.shared_cap).finish_non_exhaustive()
993 }
994}
995
996struct ProtocolsPoller<'a> {
998 protocols: &'a mut VecDeque<ProtocolStream>,
999}
1000
1001impl<'a> ProtocolsPoller<'a> {
1002 const fn new(protocols: &'a mut VecDeque<ProtocolStream>) -> Self {
1003 Self { protocols }
1004 }
1005}
1006
1007impl<'a> Future for ProtocolsPoller<'a> {
1008 type Output = Result<Bytes, P2PStreamError>;
1009
1010 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1011 let protocols = self.protocols.len();
1012 for _ in 0..protocols {
1013 let mut proto = self.protocols.pop_front().expect("protocol count checked");
1014 match proto.poll_next_unpin(cx) {
1015 Poll::Ready(Some(Err(err))) => {
1016 self.protocols.push_back(proto);
1017 return Poll::Ready(Err(P2PStreamError::from(err)))
1018 }
1019 Poll::Ready(Some(Ok(msg))) => {
1020 self.protocols.push_back(proto);
1022 return Poll::Ready(Ok(msg));
1023 }
1024 _ => {
1025 self.protocols.push_back(proto);
1027 }
1028 }
1029 }
1030
1031 Poll::Pending
1033 }
1034}
1035
1036fn yield_once() -> impl Future<Output = ()> {
1037 let mut yielded = false;
1038 std::future::poll_fn(move |cx| {
1039 if yielded {
1040 Poll::Ready(())
1041 } else {
1042 yielded = true;
1043 cx.waker().wake_by_ref();
1044 Poll::Pending
1045 }
1046 })
1047}
1048
1049const MAX_MUX_IN_BUFFER_BYTES: usize = 32 * 1024 * 1024;
1051
1052const MAX_HANDSHAKE_SATELLITE_BYTES: usize = 256 * 1024;
1055const MAX_HANDSHAKE_SATELLITE_MESSAGES: usize = 64;
1056
1057const MAX_INBOUND_MESSAGES_PER_POLL: usize = 32;
1059
1060const MAX_MUX_OUT_BUFFER_BYTES: usize = 32 * 1024 * 1024;
1069
1070#[derive(Debug)]
1071struct OutBuffer {
1072 messages: VecDeque<Bytes>,
1073 bytes: usize,
1074 max_bytes: usize,
1075}
1076
1077impl Default for OutBuffer {
1078 fn default() -> Self {
1079 Self { messages: Default::default(), bytes: 0, max_bytes: MAX_MUX_OUT_BUFFER_BYTES }
1080 }
1081}
1082
1083impl OutBuffer {
1084 fn push_back(&mut self, msg: Bytes) {
1085 self.bytes += msg.len();
1086 self.messages.push_back(msg);
1087 }
1088
1089 fn pop_front(&mut self) -> Option<Bytes> {
1090 let msg = self.messages.pop_front()?;
1091 self.bytes -= msg.len();
1092 Some(msg)
1093 }
1094
1095 fn is_empty(&self) -> bool {
1096 self.messages.is_empty()
1097 }
1098
1099 const fn is_full(&self) -> bool {
1100 self.bytes >= self.max_bytes
1101 }
1102}
1103
1104#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1106enum ProducerPoll {
1107 Pending,
1109 Full,
1111 Closed,
1113}
1114
1115#[cfg(test)]
1116mod tests {
1117 use super::*;
1118 use crate::{
1119 handshake::EthHandshake,
1120 message::MAX_MESSAGE_SIZE,
1121 protocol::Protocol,
1122 test_utils::{
1123 connect_passthrough, eth_handshake, eth_hello,
1124 proto::{test_hello, TestProtoMessage},
1125 },
1126 UnauthedEthStream, UnauthedP2PStream,
1127 };
1128 use futures::{stream, task::noop_waker_ref};
1129 use reth_eth_wire_types::EthNetworkPrimitives;
1130 use std::{sync::atomic::AtomicBool, task::Poll};
1131 use tokio::{net::TcpListener, sync::oneshot};
1132 use tokio_util::codec::Decoder;
1133
1134 #[derive(Debug)]
1135 struct PendingPrimary {
1136 _proxy: ProtocolProxy,
1137 }
1138
1139 impl Stream for PendingPrimary {
1140 type Item = Result<(), P2PStreamError>;
1141
1142 fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1143 Poll::Pending
1144 }
1145 }
1146
1147 #[derive(Debug)]
1148 struct BurstingPrimary {
1149 proxy: ProtocolProxy,
1150 remaining: usize,
1151 }
1152
1153 impl Stream for BurstingPrimary {
1154 type Item = Result<(), P2PStreamError>;
1155
1156 fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1157 if self.remaining > 0 {
1158 self.remaining -= 1;
1159 self.proxy.try_send(Bytes::from_static(&[0, 0])).unwrap();
1160 }
1161 Poll::Pending
1162 }
1163 }
1164
1165 #[derive(Debug)]
1166 struct StalledTransport;
1167
1168 impl Stream for StalledTransport {
1169 type Item = io::Result<BytesMut>;
1170
1171 fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1172 Poll::Pending
1173 }
1174 }
1175
1176 impl Sink<Bytes> for StalledTransport {
1177 type Error = io::Error;
1178
1179 fn poll_ready(
1180 self: Pin<&mut Self>,
1181 _cx: &mut Context<'_>,
1182 ) -> Poll<Result<(), Self::Error>> {
1183 Poll::Pending
1184 }
1185
1186 fn start_send(self: Pin<&mut Self>, _item: Bytes) -> Result<(), Self::Error> {
1187 Ok(())
1188 }
1189
1190 fn poll_flush(
1191 self: Pin<&mut Self>,
1192 _cx: &mut Context<'_>,
1193 ) -> Poll<Result<(), Self::Error>> {
1194 Poll::Pending
1195 }
1196
1197 fn poll_close(
1198 self: Pin<&mut Self>,
1199 _cx: &mut Context<'_>,
1200 ) -> Poll<Result<(), Self::Error>> {
1201 Poll::Pending
1202 }
1203 }
1204
1205 #[derive(Debug)]
1206 struct InboundFramesTransport {
1207 frames: VecDeque<BytesMut>,
1208 writable: AtomicBool,
1209 }
1210
1211 impl Stream for InboundFramesTransport {
1212 type Item = io::Result<BytesMut>;
1213
1214 fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1215 Poll::Ready(self.frames.pop_front().map(Ok))
1216 }
1217 }
1218
1219 impl Sink<Bytes> for InboundFramesTransport {
1220 type Error = io::Error;
1221
1222 fn poll_ready(
1223 self: Pin<&mut Self>,
1224 _cx: &mut Context<'_>,
1225 ) -> Poll<Result<(), Self::Error>> {
1226 if self.writable.load(Ordering::Relaxed) {
1227 Poll::Ready(Ok(()))
1228 } else {
1229 Poll::Pending
1230 }
1231 }
1232
1233 fn start_send(self: Pin<&mut Self>, _item: Bytes) -> Result<(), Self::Error> {
1234 Ok(())
1235 }
1236
1237 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
1238 self.poll_ready(cx)
1239 }
1240
1241 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
1242 self.poll_ready(cx)
1243 }
1244 }
1245
1246 #[derive(Debug)]
1247 struct HoldingProtocol {
1248 _conn: ProtocolConnection,
1249 }
1250
1251 impl Stream for HoldingProtocol {
1252 type Item = BytesMut;
1253
1254 fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1255 Poll::Pending
1256 }
1257 }
1258
1259 #[derive(Debug)]
1260 struct DrainingProtocol {
1261 conn: ProtocolConnection,
1262 }
1263
1264 impl Stream for DrainingProtocol {
1265 type Item = BytesMut;
1266
1267 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1268 while matches!(self.conn.poll_next_unpin(cx), Poll::Ready(Some(_))) {}
1269 Poll::Pending
1270 }
1271 }
1272
1273 #[derive(Debug)]
1274 struct SignalingDrainingProtocol {
1275 conn: ProtocolConnection,
1276 drained: Option<oneshot::Sender<()>>,
1277 }
1278
1279 impl Stream for SignalingDrainingProtocol {
1280 type Item = BytesMut;
1281
1282 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1283 if matches!(self.conn.poll_next_unpin(cx), Poll::Ready(Some(_))) &&
1284 let Some(drained) = self.drained.take()
1285 {
1286 let _ = drained.send(());
1287 }
1288 Poll::Pending
1289 }
1290 }
1291
1292 fn compressed_frame(message_id: u8, payload: &[u8]) -> BytesMut {
1293 let mut encoded = vec![0; snap::raw::max_compress_len(payload.len()) + 1];
1294 encoded[0] = message_id;
1295 let len = snap::raw::Encoder::new().compress(payload, &mut encoded[1..]).unwrap();
1296 encoded.truncate(len + 1);
1297 BytesMut::from(encoded.as_slice())
1298 }
1299
1300 fn test_multiplexer(
1301 frame_count: usize,
1302 ) -> (RlpxProtocolMultiplexer<InboundFramesTransport>, SharedCapability, SharedCapability) {
1303 let (hello, _) = test_hello();
1304 let shared_capabilities =
1305 SharedCapabilities::try_new(hello.protocols.clone(), hello.message().capabilities)
1306 .unwrap();
1307 let eth = shared_capabilities.eth().unwrap().clone();
1308 let test = shared_capabilities.find(&TestProtoMessage::capability()).unwrap().clone();
1309 let frames =
1310 (0..frame_count).map(|_| compressed_frame(test.message_id_offset(), &[0])).collect();
1311 let conn = P2PStream::new(
1312 InboundFramesTransport { frames, writable: AtomicBool::new(true) },
1313 shared_capabilities,
1314 );
1315 (RlpxProtocolMultiplexer::new(conn), eth, test)
1316 }
1317
1318 fn shared_test_capability(name: &'static str, offset: u8) -> SharedCapability {
1319 SharedCapability::UnknownCapability {
1320 cap: Capability::new_static(name, 1),
1321 offset,
1322 messages: 1,
1323 }
1324 }
1325
1326 #[tokio::test]
1327 async fn inbound_channel_enforces_and_releases_protocol_limits() {
1328 let capability = shared_test_capability("test", 0x10);
1329 let limits =
1330 ProtocolIngressLimits::new(16).with_max_buffered_bytes(4).with_max_buffered_messages(1);
1331 let aggregate = Arc::new(InboundBudget::new(16));
1332 let (sender, mut receiver) = inbound_channel(&capability, limits, aggregate);
1333
1334 sender.try_send(BytesMut::zeroed(4)).unwrap();
1335 assert!(matches!(
1336 sender.try_send(BytesMut::zeroed(1)),
1337 Err(P2PStreamError::SubprotocolInboundBufferFull { .. })
1338 ));
1339
1340 assert_eq!(receiver.next().await.unwrap().len(), 4);
1341 sender.try_send(BytesMut::zeroed(1)).unwrap();
1342 }
1343
1344 #[tokio::test]
1345 async fn inbound_channels_share_connection_byte_budget() {
1346 let aggregate = Arc::new(InboundBudget::new(6));
1347 let limits = ProtocolIngressLimits::new(16)
1348 .with_max_buffered_bytes(16)
1349 .with_max_buffered_messages(2);
1350 let (first, mut first_receiver) =
1351 inbound_channel(&shared_test_capability("aaa", 0x10), limits, Arc::clone(&aggregate));
1352 let (second, _second_receiver) =
1353 inbound_channel(&shared_test_capability("bbb", 0x11), limits, aggregate);
1354
1355 first.try_send(BytesMut::zeroed(4)).unwrap();
1356 assert!(matches!(
1357 second.try_send(BytesMut::zeroed(4)),
1358 Err(P2PStreamError::SubprotocolInboundBufferFull { .. })
1359 ));
1360
1361 let _ = first_receiver.next().await.unwrap();
1362 second.try_send(BytesMut::zeroed(4)).unwrap();
1363 }
1364
1365 #[tokio::test]
1366 async fn stalled_satellite_fails_when_its_inbound_queue_is_full() {
1367 let (mut mux, eth, test) = test_multiplexer(2);
1368 let limits =
1369 ProtocolIngressLimits::new(2).with_max_buffered_bytes(2).with_max_buffered_messages(1);
1370 mux.install_protocol_with_limits(&TestProtoMessage::capability(), limits, |conn| {
1371 HoldingProtocol { _conn: conn }
1372 })
1373 .unwrap();
1374 let mut stream = mux
1375 .into_satellite_stream(eth.capability().as_ref(), |proxy| PendingPrimary {
1376 _proxy: proxy,
1377 })
1378 .unwrap();
1379
1380 let mut cx = Context::from_waker(noop_waker_ref());
1381 assert!(matches!(
1382 Pin::new(&mut stream).poll_next(&mut cx),
1383 Poll::Ready(Some(Err(P2PStreamError::SubprotocolInboundBufferFull {
1384 capability,
1385 }))) if capability == test.capability().into_owned()
1386 ));
1387 }
1388
1389 #[tokio::test]
1390 async fn satellite_is_polled_between_inbound_frames() {
1391 let (mut mux, eth, _) = test_multiplexer(2 * MAX_INBOUND_MESSAGES_PER_POLL);
1392 let limits =
1393 ProtocolIngressLimits::new(2).with_max_buffered_bytes(2).with_max_buffered_messages(1);
1394 mux.install_protocol_with_limits(&TestProtoMessage::capability(), limits, |conn| {
1395 DrainingProtocol { conn }
1396 })
1397 .unwrap();
1398 let mut stream = mux
1399 .into_satellite_stream(eth.capability().as_ref(), |proxy| PendingPrimary {
1400 _proxy: proxy,
1401 })
1402 .unwrap();
1403
1404 let mut cx = Context::from_waker(noop_waker_ref());
1405 assert!(Pin::new(&mut stream).poll_next(&mut cx).is_pending());
1406 assert_eq!(stream.inner.conn.inner().frames.len(), MAX_INBOUND_MESSAGES_PER_POLL);
1407 }
1408
1409 #[tokio::test]
1410 async fn outbound_backpressure_preserves_inbound_fairness() {
1411 let (hello, _) = test_hello();
1412 let shared_capabilities =
1413 SharedCapabilities::try_new(hello.protocols.clone(), hello.message().capabilities)
1414 .unwrap();
1415 let eth = shared_capabilities.eth().unwrap().clone();
1416 let test = shared_capabilities.find(&TestProtoMessage::capability()).unwrap().clone();
1417 let frames = (0..2)
1418 .map(|_| compressed_frame(test.message_id_offset(), &[0]))
1419 .collect::<VecDeque<_>>();
1420 let conn = P2PStream::new(
1421 InboundFramesTransport { frames, writable: AtomicBool::new(false) },
1422 shared_capabilities,
1423 );
1424 let mut mux = RlpxProtocolMultiplexer::new(conn);
1425 let limits =
1426 ProtocolIngressLimits::new(2).with_max_buffered_bytes(2).with_max_buffered_messages(1);
1427 mux.install_protocol_with_limits(&TestProtoMessage::capability(), limits, |conn| {
1428 DrainingProtocol { conn }
1429 })
1430 .unwrap();
1431 let mut stream = mux
1432 .into_satellite_stream(eth.capability().as_ref(), |proxy| BurstingPrimary {
1433 proxy,
1434 remaining: 3,
1435 })
1436 .unwrap();
1437 stream.inner.conn.start_send_unpin(Bytes::from_static(&[0, 0])).unwrap();
1438 stream.inner.conn.start_send_unpin(Bytes::from_static(&[0, 0])).unwrap();
1439 stream.inner.out_buffer.max_bytes = 1;
1440 stream.inner.out_buffer.push_back(Bytes::from_static(&[0, 0]));
1441
1442 let mut cx = Context::from_waker(noop_waker_ref());
1443 assert!(Pin::new(&mut stream).poll_next(&mut cx).is_pending());
1444 assert_eq!(stream.inner.conn.inner().frames.len(), 2);
1445
1446 assert!(Pin::new(&mut stream).poll_next(&mut cx).is_pending());
1447 assert_eq!(stream.inner.conn.inner().frames.len(), 2);
1448
1449 stream.inner.conn.inner().writable.store(true, Ordering::Relaxed);
1450 assert!(Pin::new(&mut stream).poll_next(&mut cx).is_pending());
1451 assert_eq!(stream.inner.conn.inner().frames.len(), 2);
1452
1453 assert!(matches!(Pin::new(&mut stream).poll_next(&mut cx), Poll::Ready(None)));
1454 assert_eq!(stream.inner.conn.inner().frames.len(), 0);
1455 }
1456
1457 #[tokio::test]
1458 async fn satellite_is_polled_between_frames_during_primary_handshake() {
1459 let (mut mux, eth, _) = test_multiplexer(2);
1460 let limits =
1461 ProtocolIngressLimits::new(2).with_max_buffered_bytes(2).with_max_buffered_messages(1);
1462 let (drained_tx, drained_rx) = oneshot::channel();
1463 mux.install_protocol_with_limits(&TestProtoMessage::capability(), limits, |conn| {
1464 SignalingDrainingProtocol { conn, drained: Some(drained_tx) }
1465 })
1466 .unwrap();
1467
1468 let stream = mux
1469 .into_satellite_stream_with_handshake(eth.capability().as_ref(), async move |proxy| {
1470 drained_rx.await.unwrap();
1471 Ok::<_, P2PStreamError>(PendingPrimary { _proxy: proxy })
1472 })
1473 .await;
1474
1475 assert!(stream.is_ok());
1476 }
1477
1478 #[tokio::test]
1479 async fn satellite_mux_stops_polling_protocols_when_out_buffer_is_full() {
1480 let (hello, _) = test_hello();
1481 let shared_capabilities =
1482 SharedCapabilities::try_new(hello.protocols.clone(), hello.message().capabilities)
1483 .unwrap();
1484 let conn = P2PStream::new(StalledTransport, shared_capabilities);
1485 let eth = conn.shared_capabilities().eth().unwrap().clone();
1486
1487 let mut st = RlpxProtocolMultiplexer::new(conn)
1488 .into_satellite_stream(eth.capability().as_ref(), |proxy| PendingPrimary {
1489 _proxy: proxy,
1490 })
1491 .unwrap();
1492 const MESSAGE_COUNT: usize = 4096;
1493 const MESSAGE_BYTES: usize = 1024;
1494 st.inner.out_buffer.max_bytes = 4 * MESSAGE_BYTES + 1;
1495 st.install_protocol(&TestProtoMessage::capability(), |_conn| {
1496 stream::iter((0..MESSAGE_COUNT).map(|_| {
1497 let mut msg = BytesMut::zeroed(MESSAGE_BYTES);
1498 msg[0] = TestProtoMessage::ping().message_type as u8;
1499 msg
1500 }))
1501 })
1502 .unwrap();
1503
1504 let mut cx = Context::from_waker(noop_waker_ref());
1505 assert!(Pin::new(&mut st).poll_next(&mut cx).is_pending());
1506
1507 assert!(st.inner.out_buffer.bytes > st.inner.out_buffer.max_bytes);
1508 assert!(st.inner.out_buffer.bytes <= st.inner.out_buffer.max_bytes + MESSAGE_BYTES);
1509 assert!(st.inner.out_buffer.messages.len() < MESSAGE_COUNT);
1510 }
1511
1512 #[tokio::test]
1513 async fn satellite_mux_round_robins_ready_protocols_when_out_buffer_fills() {
1514 let (mut hello, _) = eth_hello();
1515 let cap_a = Capability::new_static("aaa", 1);
1516 let cap_b = Capability::new_static("bbb", 1);
1517 hello.protocols.push(Protocol::new(cap_a.clone(), 1));
1518 hello.protocols.push(Protocol::new(cap_b.clone(), 1));
1519
1520 let shared_capabilities =
1521 SharedCapabilities::try_new(hello.protocols.clone(), hello.message().capabilities)
1522 .unwrap();
1523 let conn = P2PStream::new(StalledTransport, shared_capabilities);
1524 let eth = conn.shared_capabilities().eth().unwrap().clone();
1525 let cap_a_offset =
1526 conn.shared_capabilities().find(&cap_a).unwrap().relative_message_id_offset();
1527 let cap_b_offset =
1528 conn.shared_capabilities().find(&cap_b).unwrap().relative_message_id_offset();
1529
1530 let mut st = RlpxProtocolMultiplexer::new(conn)
1531 .into_satellite_stream(eth.capability().as_ref(), |proxy| PendingPrimary {
1532 _proxy: proxy,
1533 })
1534 .unwrap();
1535 st.inner.out_buffer.max_bytes = 5;
1536 st.install_protocol(&cap_a, |_conn| {
1537 stream::iter((0..16).map(|_| BytesMut::from(&[0, b'a'][..])))
1538 })
1539 .unwrap();
1540 st.install_protocol(&cap_b, |_conn| {
1541 stream::iter((0..16).map(|_| BytesMut::from(&[0, b'b'][..])))
1542 })
1543 .unwrap();
1544
1545 let mut cx = Context::from_waker(noop_waker_ref());
1546 assert!(Pin::new(&mut st).poll_next(&mut cx).is_pending());
1547
1548 let message_ids =
1549 st.inner.out_buffer.messages.iter().take(2).map(|msg| msg[0]).collect::<Vec<_>>();
1550 assert_eq!(message_ids.len(), 2);
1551 assert_ne!(message_ids[0], message_ids[1]);
1552 assert!(message_ids.contains(&cap_a_offset));
1553 assert!(message_ids.contains(&cap_b_offset));
1554 }
1555
1556 #[tokio::test]
1557 async fn eth_satellite() {
1558 reth_tracing::init_test_tracing();
1559 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1560 let local_addr = listener.local_addr().unwrap();
1561 let (status, fork_filter) = eth_handshake();
1562 let other_status = status;
1563 let other_fork_filter = fork_filter.clone();
1564 let _handle = tokio::spawn(async move {
1565 let (incoming, _) = listener.accept().await.unwrap();
1566 let stream = crate::PassthroughCodec::default().framed(incoming);
1567 let (server_hello, _) = eth_hello();
1568 let (p2p_stream, _) =
1569 UnauthedP2PStream::new(stream).handshake(server_hello).await.unwrap();
1570
1571 let (_eth_stream, _) = UnauthedEthStream::new(p2p_stream)
1572 .handshake::<EthNetworkPrimitives>(other_status, other_fork_filter)
1573 .await
1574 .unwrap();
1575
1576 tokio::time::sleep(std::time::Duration::from_millis(100)).await;
1577 });
1578
1579 let conn = connect_passthrough(local_addr, eth_hello().0).await;
1580 let eth = conn.shared_capabilities().eth().unwrap().clone();
1581
1582 let multiplexer = RlpxProtocolMultiplexer::new(conn);
1583 let _satellite = multiplexer
1584 .into_satellite_stream_with_handshake(eth.capability().as_ref(), async move |proxy| {
1585 UnauthedEthStream::new(proxy)
1586 .handshake::<EthNetworkPrimitives>(status, fork_filter)
1587 .await
1588 })
1589 .await
1590 .unwrap();
1591 }
1592
1593 #[tokio::test(flavor = "multi_thread")]
1595 async fn eth_test_protocol_satellite() {
1596 reth_tracing::init_test_tracing();
1597 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1598 let local_addr = listener.local_addr().unwrap();
1599 let (status, fork_filter) = eth_handshake();
1600 let other_status = status;
1601 let other_fork_filter = fork_filter.clone();
1602 let _handle = tokio::spawn(async move {
1603 let (incoming, _) = listener.accept().await.unwrap();
1604 let stream = crate::PassthroughCodec::default().framed(incoming);
1605 let (server_hello, _) = test_hello();
1606 let (conn, _) = UnauthedP2PStream::new(stream).handshake(server_hello).await.unwrap();
1607
1608 let (mut st, _their_status) = RlpxProtocolMultiplexer::new(conn)
1609 .into_eth_satellite_stream::<EthNetworkPrimitives>(
1610 other_status,
1611 other_fork_filter,
1612 Arc::new(EthHandshake::default()),
1613 MAX_MESSAGE_SIZE,
1614 )
1615 .await
1616 .unwrap();
1617
1618 st.install_protocol(&TestProtoMessage::capability(), |mut conn| {
1619 async_stream::stream! {
1620 yield TestProtoMessage::ping().encoded();
1621 let msg = conn.next().await.unwrap();
1622 let msg = TestProtoMessage::decode_message(&mut &msg[..]).unwrap();
1623 assert_eq!(msg, TestProtoMessage::pong());
1624
1625 yield TestProtoMessage::message("hello").encoded();
1626 let msg = conn.next().await.unwrap();
1627 let msg = TestProtoMessage::decode_message(&mut &msg[..]).unwrap();
1628 assert_eq!(msg, TestProtoMessage::message("good bye!"));
1629
1630 yield TestProtoMessage::message("good bye!").encoded();
1631
1632 futures::future::pending::<()>().await;
1633 unreachable!()
1634 }
1635 })
1636 .unwrap();
1637
1638 loop {
1639 let _ = st.next().await;
1640 }
1641 });
1642
1643 let conn = connect_passthrough(local_addr, test_hello().0).await;
1644 let (mut st, _their_status) = RlpxProtocolMultiplexer::new(conn)
1645 .into_eth_satellite_stream::<EthNetworkPrimitives>(
1646 status,
1647 fork_filter,
1648 Arc::new(EthHandshake::default()),
1649 MAX_MESSAGE_SIZE,
1650 )
1651 .await
1652 .unwrap();
1653
1654 let (tx, mut rx) = oneshot::channel();
1655
1656 st.install_protocol(&TestProtoMessage::capability(), |mut conn| {
1657 async_stream::stream! {
1658 let msg = conn.next().await.unwrap();
1659 let msg = TestProtoMessage::decode_message(&mut &msg[..]).unwrap();
1660 assert_eq!(msg, TestProtoMessage::ping());
1661
1662 yield TestProtoMessage::pong().encoded();
1663
1664 let msg = conn.next().await.unwrap();
1665 let msg = TestProtoMessage::decode_message(&mut &msg[..]).unwrap();
1666 assert_eq!(msg, TestProtoMessage::message("hello"));
1667
1668 yield TestProtoMessage::message("good bye!").encoded();
1669
1670 let msg = conn.next().await.unwrap();
1671 let msg = TestProtoMessage::decode_message(&mut &msg[..]).unwrap();
1672 assert_eq!(msg, TestProtoMessage::message("good bye!"));
1673
1674 tx.send(()).unwrap();
1675
1676 futures::future::pending::<()>().await;
1677 unreachable!()
1678 }
1679 })
1680 .unwrap();
1681
1682 loop {
1683 tokio::select! {
1684 _ = &mut rx => {
1685 break
1686 }
1687 _ = st.next() => {
1688 }
1689 }
1690 }
1691 }
1692}