1use crate::{fetch::DownloadRequest, flattened_response::FlattenedResponse};
4use alloy_primitives::B256;
5use futures::{future, future::Either};
6use reth_eth_wire::{BlockAccessLists, EthNetworkPrimitives, NetworkPrimitives};
7use reth_eth_wire_types::snap::{
8 GetAccountRangeMessage, GetBlockAccessListsMessage, GetByteCodesMessage,
9 GetStorageRangesMessage, SnapProtocolMessage,
10};
11use reth_network_api::test_utils::PeersHandle;
12use reth_network_p2p::{
13 block_access_lists::client::{BalRequirement, BlockAccessListsClient},
14 bodies::client::{BodiesClient, BodiesFut},
15 download::DownloadClient,
16 error::{PeerRequestResult, RequestError},
17 headers::client::{HeadersClient, HeadersRequest},
18 priority::Priority,
19 receipts::client::{ReceiptsClient, ReceiptsFut},
20 snap::client::{SnapClient, SnapResponse},
21 BlockClient,
22};
23use reth_network_peers::PeerId;
24use reth_network_types::ReputationChangeKind;
25use std::{
26 ops::RangeInclusive,
27 sync::{
28 atomic::{AtomicUsize, Ordering},
29 Arc,
30 },
31};
32use tokio::sync::{mpsc::UnboundedSender, oneshot};
33
34#[cfg_attr(doc, aquamarine::aquamarine)]
35#[derive(Debug, Clone)]
42pub struct FetchClient<N: NetworkPrimitives = EthNetworkPrimitives> {
43 pub(crate) request_tx: UnboundedSender<DownloadRequest<N>>,
45 pub(crate) peers_handle: PeersHandle,
47 pub(crate) num_active_peers: Arc<AtomicUsize>,
49}
50
51impl<N: NetworkPrimitives> DownloadClient for FetchClient<N> {
52 fn report_bad_message(&self, peer_id: PeerId) {
53 self.peers_handle.reputation_change(peer_id, ReputationChangeKind::BadMessage);
54 }
55
56 fn num_connected_peers(&self) -> usize {
57 self.num_active_peers.load(Ordering::Relaxed)
58 }
59}
60
61impl<N: NetworkPrimitives> FetchClient<N> {
62 fn send_snap_request(
64 &self,
65 request: SnapProtocolMessage,
66 priority: Priority,
67 ) -> std::pin::Pin<Box<dyn Future<Output = PeerRequestResult<SnapResponse>> + Send + Sync>>
68 {
69 let (response, rx) = oneshot::channel();
70 if self.request_tx.send(DownloadRequest::GetSnap { request, response, priority }).is_ok() {
71 Box::pin(FlattenedResponse::from(rx))
72 } else {
73 Box::pin(future::err(RequestError::ChannelClosed))
74 }
75 }
76}
77
78type HeadersClientFuture<T> = Either<FlattenedResponse<T>, future::Ready<T>>;
81
82impl<N: NetworkPrimitives> HeadersClient for FetchClient<N> {
83 type Header = N::BlockHeader;
84 type Output = HeadersClientFuture<PeerRequestResult<Vec<N::BlockHeader>>>;
85
86 fn get_headers_with_priority(
88 &self,
89 request: HeadersRequest,
90 priority: Priority,
91 ) -> Self::Output {
92 let (response, rx) = oneshot::channel();
93 if self
94 .request_tx
95 .send(DownloadRequest::GetBlockHeaders { request, response, priority })
96 .is_ok()
97 {
98 Either::Left(FlattenedResponse::from(rx))
99 } else {
100 Either::Right(future::err(RequestError::ChannelClosed))
101 }
102 }
103}
104
105impl<N: NetworkPrimitives> BodiesClient for FetchClient<N> {
106 type Body = N::BlockBody;
107 type Output = BodiesFut<N::BlockBody>;
108
109 fn get_block_bodies_with_priority_and_range_hint(
111 &self,
112 request: Vec<B256>,
113 priority: Priority,
114 range_hint: Option<RangeInclusive<u64>>,
115 ) -> Self::Output {
116 let (response, rx) = oneshot::channel();
117 if self
118 .request_tx
119 .send(DownloadRequest::GetBlockBodies { request, response, priority, range_hint })
120 .is_ok()
121 {
122 Box::pin(FlattenedResponse::from(rx))
123 } else {
124 Box::pin(future::err(RequestError::ChannelClosed))
125 }
126 }
127}
128
129impl<N: NetworkPrimitives> ReceiptsClient for FetchClient<N> {
130 type Receipt = N::Receipt;
131 type Output = ReceiptsFut<N::Receipt>;
132
133 fn get_receipts_with_priority(&self, request: Vec<B256>, priority: Priority) -> Self::Output {
134 let (response, rx) = oneshot::channel();
135 if self
136 .request_tx
137 .send(DownloadRequest::GetReceipts { request, response, priority })
138 .is_ok()
139 {
140 Box::pin(FlattenedResponse::from(rx))
141 } else {
142 Box::pin(future::err(RequestError::ChannelClosed))
143 }
144 }
145}
146
147impl<N: NetworkPrimitives> BlockClient for FetchClient<N> {
148 type Block = N::Block;
149}
150
151impl<N: NetworkPrimitives> BlockAccessListsClient for FetchClient<N> {
152 type Output =
153 std::pin::Pin<Box<dyn Future<Output = PeerRequestResult<BlockAccessLists>> + Send + Sync>>;
154
155 fn get_block_access_lists_with_priority_and_requirement(
156 &self,
157 hashes: Vec<B256>,
158 priority: Priority,
159 requirement: BalRequirement,
160 ) -> Self::Output {
161 let (response, rx) = oneshot::channel();
162 if self
163 .request_tx
164 .send(DownloadRequest::GetBlockAccessLists {
165 request: hashes,
166 response,
167 priority,
168 requirement,
169 })
170 .is_ok()
171 {
172 Box::pin(FlattenedResponse::from(rx))
173 } else {
174 Box::pin(future::err(RequestError::ChannelClosed))
175 }
176 }
177}
178
179impl<N: NetworkPrimitives> SnapClient for FetchClient<N> {
180 type Output =
181 std::pin::Pin<Box<dyn Future<Output = PeerRequestResult<SnapResponse>> + Send + Sync>>;
182
183 fn get_account_range_with_priority(
185 &self,
186 request: GetAccountRangeMessage,
187 priority: Priority,
188 ) -> Self::Output {
189 self.send_snap_request(SnapProtocolMessage::GetAccountRange(request), priority)
190 }
191
192 fn get_storage_ranges(&self, request: GetStorageRangesMessage) -> Self::Output {
194 self.get_storage_ranges_with_priority(request, Priority::Normal)
195 }
196
197 fn get_storage_ranges_with_priority(
199 &self,
200 request: GetStorageRangesMessage,
201 priority: Priority,
202 ) -> Self::Output {
203 self.send_snap_request(SnapProtocolMessage::GetStorageRanges(request), priority)
204 }
205
206 fn get_byte_codes(&self, request: GetByteCodesMessage) -> Self::Output {
208 self.get_byte_codes_with_priority(request, Priority::Normal)
209 }
210
211 fn get_byte_codes_with_priority(
213 &self,
214 request: GetByteCodesMessage,
215 priority: Priority,
216 ) -> Self::Output {
217 self.send_snap_request(SnapProtocolMessage::GetByteCodes(request), priority)
218 }
219
220 fn get_block_access_lists_with_priority(
222 &self,
223 request: GetBlockAccessListsMessage,
224 priority: Priority,
225 ) -> Self::Output {
226 self.send_snap_request(SnapProtocolMessage::GetBlockAccessLists(request), priority)
227 }
228}