1use futures::{Sink, SinkExt, Stream, StreamExt};
4use reth_ecies::stream::ECIESStream;
5use reth_eth_wire::{
6 errors::{EthStreamError, P2PStreamError},
7 message::EthBroadcastMessage,
8 multiplex::{ProtocolProxy, RlpxSatelliteStream},
9 snap::SnapProtocolMessage,
10 EthMessage, EthNetworkPrimitives, EthSnapMessage, EthSnapStream, EthStream, EthVersion,
11 NetworkPrimitives, P2PStream,
12};
13use reth_eth_wire_types::RawCapabilityMessage;
14use std::{
15 pin::Pin,
16 task::{Context, Poll},
17};
18use tokio::net::TcpStream;
19
20pub type EthPeerConnection<N> = EthStream<P2PStream<ECIESStream<TcpStream>>, N>;
22
23pub type EthSatelliteConnection<N = EthNetworkPrimitives> =
25 RlpxSatelliteStream<ECIESStream<TcpStream>, EthStream<ProtocolProxy, N>>;
26
27pub type EthSnapConnection<N = EthNetworkPrimitives> = EthSnapStream<ECIESStream<TcpStream>, N>;
29
30#[derive(Debug)]
39pub enum EthRlpxConnection<N: NetworkPrimitives = EthNetworkPrimitives> {
40 EthOnly(Box<EthPeerConnection<N>>),
42 EthSnap(Box<EthSnapConnection<N>>),
44 Satellite(Box<EthSatelliteConnection<N>>),
46}
47
48impl<N: NetworkPrimitives> EthRlpxConnection<N> {
49 #[inline]
51 pub(crate) const fn version(&self) -> EthVersion {
52 match self {
53 Self::EthOnly(conn) => conn.version(),
54 Self::EthSnap(conn) => conn.version(),
55 Self::Satellite(conn) => conn.primary().version(),
56 }
57 }
58
59 #[inline]
61 pub(crate) const fn supports_snap(&self) -> bool {
62 matches!(self, Self::EthSnap(_))
63 }
64
65 #[inline]
67 pub(crate) fn into_inner(self) -> P2PStream<ECIESStream<TcpStream>> {
68 match self {
69 Self::EthOnly(conn) => conn.into_inner(),
70 Self::EthSnap(conn) => conn.into_inner(),
71 Self::Satellite(conn) => conn.into_inner(),
72 }
73 }
74
75 #[inline]
77 pub(crate) fn inner_mut(&mut self) -> &mut P2PStream<ECIESStream<TcpStream>> {
78 match self {
79 Self::EthOnly(conn) => conn.inner_mut(),
80 Self::EthSnap(conn) => conn.inner_mut(),
81 Self::Satellite(conn) => conn.inner_mut(),
82 }
83 }
84
85 #[inline]
87 pub(crate) const fn inner(&self) -> &P2PStream<ECIESStream<TcpStream>> {
88 match self {
89 Self::EthOnly(conn) => conn.inner(),
90 Self::EthSnap(conn) => conn.inner(),
91 Self::Satellite(conn) => conn.inner(),
92 }
93 }
94
95 #[inline]
97 pub fn start_send_broadcast(
98 &mut self,
99 item: EthBroadcastMessage<N>,
100 ) -> Result<(), EthStreamError> {
101 match self {
102 Self::EthOnly(conn) => conn.start_send_broadcast(item),
103 Self::EthSnap(conn) => conn.start_send_broadcast(item),
104 Self::Satellite(conn) => conn.primary_mut().start_send_broadcast(item),
105 }
106 }
107
108 pub fn start_send_raw(&mut self, msg: RawCapabilityMessage) -> Result<(), EthStreamError> {
110 match self {
111 Self::EthOnly(conn) => conn.start_send_raw(msg),
112 Self::EthSnap(conn) => conn.start_send_raw(msg),
113 Self::Satellite(conn) => conn.primary_mut().start_send_raw(msg),
114 }
115 }
116
117 pub fn start_send_snap(&mut self, msg: SnapProtocolMessage) -> Result<(), EthStreamError> {
122 match self {
123 Self::EthSnap(conn) => conn.start_send_unpin(EthSnapMessage::Snap(msg)),
124 Self::EthOnly(_) | Self::Satellite(_) => {
125 Err(P2PStreamError::CapabilityNotShared.into())
126 }
127 }
128 }
129
130 pub fn set_reject_block_announcements(&mut self, reject: bool) {
133 match self {
134 Self::EthOnly(conn) => conn.set_reject_block_announcements(reject),
135 Self::EthSnap(conn) => conn.set_reject_block_announcements(reject),
136 Self::Satellite(conn) => conn.primary_mut().set_reject_block_announcements(reject),
137 }
138 }
139}
140
141impl<N: NetworkPrimitives> From<EthPeerConnection<N>> for EthRlpxConnection<N> {
142 #[inline]
143 fn from(conn: EthPeerConnection<N>) -> Self {
144 Self::EthOnly(Box::new(conn))
145 }
146}
147
148impl<N: NetworkPrimitives> From<EthSnapConnection<N>> for EthRlpxConnection<N> {
149 #[inline]
150 fn from(conn: EthSnapConnection<N>) -> Self {
151 Self::EthSnap(Box::new(conn))
152 }
153}
154
155impl<N: NetworkPrimitives> From<EthSatelliteConnection<N>> for EthRlpxConnection<N> {
156 #[inline]
157 fn from(conn: EthSatelliteConnection<N>) -> Self {
158 Self::Satellite(Box::new(conn))
159 }
160}
161
162macro_rules! delegate_call {
167 ($self:ident.$method:ident($($args:ident),+)) => {
168 match $self.get_mut() {
169 Self::EthOnly(l) => l.$method($($args),+),
170 Self::EthSnap(s) => s.$method($($args),+),
171 Self::Satellite(r) => r.$method($($args),+),
172 }
173 };
174 ($self:ident.$method:ident($($args:ident),+) => $adapt:expr) => {
175 match $self.get_mut() {
176 Self::EthOnly(l) => $adapt(l.$method($($args),+)),
177 Self::Satellite(r) => $adapt(r.$method($($args),+)),
178 Self::EthSnap(s) => s.$method($($args),+),
179 }
180 };
181}
182
183impl<N: NetworkPrimitives> Stream for EthRlpxConnection<N> {
184 type Item = Result<EthSnapMessage<N>, EthStreamError>;
185
186 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
187 delegate_call!(self.poll_next_unpin(cx) => lift_eth)
188 }
189}
190
191impl<N: NetworkPrimitives> Sink<EthMessage<N>> for EthRlpxConnection<N> {
192 type Error = EthStreamError;
193
194 fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
195 delegate_call!(self.poll_ready_unpin(cx))
196 }
197
198 fn start_send(self: Pin<&mut Self>, item: EthMessage<N>) -> Result<(), Self::Error> {
199 match self.get_mut() {
200 Self::EthOnly(l) => l.start_send_unpin(item),
201 Self::Satellite(r) => r.start_send_unpin(item),
202 Self::EthSnap(s) => s.start_send_unpin(EthSnapMessage::Eth(item)),
203 }
204 }
205
206 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
207 delegate_call!(self.poll_flush_unpin(cx))
208 }
209
210 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
211 delegate_call!(self.poll_close_unpin(cx))
212 }
213}
214
215#[inline]
217fn lift_eth<N: NetworkPrimitives>(
218 poll: Poll<Option<Result<EthMessage<N>, EthStreamError>>>,
219) -> Poll<Option<Result<EthSnapMessage<N>, EthStreamError>>> {
220 poll.map(|opt| opt.map(|res| res.map(EthSnapMessage::Eth)))
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 const fn assert_eth_stream<N, St>()
228 where
229 N: NetworkPrimitives,
230 St: Stream<Item = Result<EthMessage<N>, EthStreamError>> + Sink<EthMessage<N>>,
231 {
232 }
233
234 const fn assert_eth_snap_stream<N, St>()
235 where
236 N: NetworkPrimitives,
237 St: Stream<Item = Result<EthSnapMessage<N>, EthStreamError>> + Sink<EthMessage<N>>,
238 {
239 }
240
241 #[test]
242 const fn test_eth_stream_variants() {
243 assert_eth_stream::<EthNetworkPrimitives, EthSatelliteConnection<EthNetworkPrimitives>>();
244 assert_eth_snap_stream::<EthNetworkPrimitives, EthRlpxConnection<EthNetworkPrimitives>>();
245 }
246}