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