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,
15 download::DownloadClient,
16 error::{PeerRequestResult, RequestError},
17 headers::client::{HeadersClient, HeadersRequest},
18 priority::Priority,
19 receipts::client::{ReceiptsClient, ReceiptsResponse},
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 ) -> FetchClientFuture<PeerRequestResult<SnapResponse>> {
68 let (response, rx) = oneshot::channel();
69 if self.request_tx.send(DownloadRequest::GetSnap { request, response, priority }).is_ok() {
70 Either::Left(FlattenedResponse::from(rx))
71 } else {
72 Either::Right(future::err(RequestError::ChannelClosed))
73 }
74 }
75}
76
77type FetchClientFuture<T> = Either<FlattenedResponse<T>, future::Ready<T>>;
79
80impl<N: NetworkPrimitives> HeadersClient for FetchClient<N> {
81 type Header = N::BlockHeader;
82 type Output = FetchClientFuture<PeerRequestResult<Vec<N::BlockHeader>>>;
83
84 fn get_headers_with_priority(
86 &self,
87 request: HeadersRequest,
88 priority: Priority,
89 ) -> Self::Output {
90 let (response, rx) = oneshot::channel();
91 if self
92 .request_tx
93 .send(DownloadRequest::GetBlockHeaders { request, response, priority })
94 .is_ok()
95 {
96 Either::Left(FlattenedResponse::from(rx))
97 } else {
98 Either::Right(future::err(RequestError::ChannelClosed))
99 }
100 }
101}
102
103impl<N: NetworkPrimitives> BodiesClient for FetchClient<N> {
104 type Body = N::BlockBody;
105 type Output = FetchClientFuture<PeerRequestResult<Vec<N::BlockBody>>>;
106
107 fn get_block_bodies_with_priority_and_range_hint(
109 &self,
110 request: Vec<B256>,
111 priority: Priority,
112 range_hint: Option<RangeInclusive<u64>>,
113 ) -> Self::Output {
114 let (response, rx) = oneshot::channel();
115 if self
116 .request_tx
117 .send(DownloadRequest::GetBlockBodies { request, response, priority, range_hint })
118 .is_ok()
119 {
120 Either::Left(FlattenedResponse::from(rx))
121 } else {
122 Either::Right(future::err(RequestError::ChannelClosed))
123 }
124 }
125}
126
127impl<N: NetworkPrimitives> ReceiptsClient for FetchClient<N> {
128 type Receipt = N::Receipt;
129 type Output = FetchClientFuture<PeerRequestResult<ReceiptsResponse<N::Receipt>>>;
130
131 fn get_receipts_with_priority(&self, request: Vec<B256>, priority: Priority) -> Self::Output {
132 let (response, rx) = oneshot::channel();
133 if self
134 .request_tx
135 .send(DownloadRequest::GetReceipts { request, response, priority })
136 .is_ok()
137 {
138 Either::Left(FlattenedResponse::from(rx))
139 } else {
140 Either::Right(future::err(RequestError::ChannelClosed))
141 }
142 }
143}
144
145impl<N: NetworkPrimitives> BlockClient for FetchClient<N> {
146 type Block = N::Block;
147}
148
149impl<N: NetworkPrimitives> BlockAccessListsClient for FetchClient<N> {
150 type Output = FetchClientFuture<PeerRequestResult<BlockAccessLists>>;
151
152 fn get_block_access_lists_with_priority_and_requirement(
153 &self,
154 hashes: Vec<B256>,
155 priority: Priority,
156 requirement: BalRequirement,
157 ) -> Self::Output {
158 let (response, rx) = oneshot::channel();
159 if self
160 .request_tx
161 .send(DownloadRequest::GetBlockAccessLists {
162 request: hashes,
163 response,
164 priority,
165 requirement,
166 })
167 .is_ok()
168 {
169 Either::Left(FlattenedResponse::from(rx))
170 } else {
171 Either::Right(future::err(RequestError::ChannelClosed))
172 }
173 }
174}
175
176impl<N: NetworkPrimitives> SnapClient for FetchClient<N> {
177 type Output = FetchClientFuture<PeerRequestResult<SnapResponse>>;
178
179 fn get_account_range_with_priority(
181 &self,
182 request: GetAccountRangeMessage,
183 priority: Priority,
184 ) -> Self::Output {
185 self.send_snap_request(SnapProtocolMessage::GetAccountRange(request), priority)
186 }
187
188 fn get_storage_ranges(&self, request: GetStorageRangesMessage) -> Self::Output {
190 self.get_storage_ranges_with_priority(request, Priority::Normal)
191 }
192
193 fn get_storage_ranges_with_priority(
195 &self,
196 request: GetStorageRangesMessage,
197 priority: Priority,
198 ) -> Self::Output {
199 self.send_snap_request(SnapProtocolMessage::GetStorageRanges(request), priority)
200 }
201
202 fn get_byte_codes(&self, request: GetByteCodesMessage) -> Self::Output {
204 self.get_byte_codes_with_priority(request, Priority::Normal)
205 }
206
207 fn get_byte_codes_with_priority(
209 &self,
210 request: GetByteCodesMessage,
211 priority: Priority,
212 ) -> Self::Output {
213 self.send_snap_request(SnapProtocolMessage::GetByteCodes(request), priority)
214 }
215
216 fn get_block_access_lists_with_priority(
218 &self,
219 request: GetBlockAccessListsMessage,
220 priority: Priority,
221 ) -> Self::Output {
222 self.send_snap_request(SnapProtocolMessage::GetBlockAccessLists(request), priority)
223 }
224}