reth_network_p2p/test_utils/
full_block.rs1use crate::{
2 block_access_lists::client::{BalRequirement, BlockAccessListsClient},
3 bodies::client::BodiesClient,
4 download::DownloadClient,
5 error::PeerRequestResult,
6 headers::client::{HeadersClient, HeadersRequest},
7 priority::Priority,
8 BlockClient,
9};
10use alloy_consensus::Header;
11use alloy_eips::{BlockHashOrNumber, BlockNumHash};
12use alloy_primitives::{map::B256Map, Bytes, B256};
13use parking_lot::Mutex;
14use reth_eth_wire_types::{BlockAccessLists, HeadersDirection};
15use reth_ethereum_primitives::{Block, BlockBody};
16use reth_network_peers::{PeerId, WithPeerId};
17use reth_primitives_traits::{SealedBlock, SealedHeader};
18use std::{ops::RangeInclusive, sync::Arc};
19
20#[derive(Clone, Debug)]
25pub struct TestFullBlockClient {
26 headers: Arc<Mutex<B256Map<Header>>>,
27 bodies: Arc<Mutex<B256Map<BlockBody>>>,
28 access_lists: Arc<Mutex<B256Map<Bytes>>>,
29 soft_limit: usize,
31}
32
33impl Default for TestFullBlockClient {
34 fn default() -> Self {
35 Self {
36 headers: Arc::new(Mutex::new(B256Map::default())),
37 bodies: Arc::new(Mutex::new(B256Map::default())),
38 access_lists: Arc::new(Mutex::new(B256Map::default())),
39 soft_limit: 20,
40 }
41 }
42}
43
44impl TestFullBlockClient {
45 pub fn insert(&self, header: SealedHeader, body: BlockBody) {
47 let hash = header.hash();
48 self.headers.lock().insert(hash, header.unseal());
49 self.bodies.lock().insert(hash, body);
50 }
51
52 pub fn insert_access_list(&self, hash: B256, access_list: Bytes) {
54 self.access_lists.lock().insert(hash, access_list);
55 }
56
57 pub const fn set_soft_limit(&mut self, limit: usize) {
59 self.soft_limit = limit;
60 }
61
62 pub fn highest_block(&self) -> Option<SealedBlock<Block>> {
64 self.headers.lock().iter().max_by_key(|(_, header)| header.number).and_then(
65 |(hash, header)| {
66 self.bodies.lock().get(hash).map(|body| {
67 SealedBlock::from_parts_unchecked(header.clone(), body.clone(), *hash)
68 })
69 },
70 )
71 }
72}
73
74impl DownloadClient for TestFullBlockClient {
75 fn report_bad_message(&self, _peer_id: PeerId) {}
77
78 fn num_connected_peers(&self) -> usize {
82 1
83 }
84}
85
86impl HeadersClient for TestFullBlockClient {
88 type Header = Header;
89 type Output = futures::future::Ready<PeerRequestResult<Vec<Header>>>;
91
92 fn get_headers_with_priority(
103 &self,
104 request: HeadersRequest,
105 _priority: Priority,
106 ) -> Self::Output {
107 let headers = self.headers.lock();
108
109 let mut block: BlockHashOrNumber = match request.start {
111 BlockHashOrNumber::Hash(hash) => headers.get(&hash).cloned(),
112 BlockHashOrNumber::Number(num) => headers.values().find(|h| h.number == num).cloned(),
113 }
114 .map(|h| h.number.into())
115 .unwrap();
116
117 let resp = (0..request.limit)
119 .filter_map(|_| {
120 headers.iter().find_map(|(hash, header)| {
121 BlockNumHash::new(header.number, *hash).matches_block_or_num(&block).then(
123 || {
124 match request.direction {
125 HeadersDirection::Falling => block = header.parent_hash.into(),
126 HeadersDirection::Rising => block = (header.number + 1).into(),
127 }
128 header.clone()
129 },
130 )
131 })
132 })
133 .collect::<Vec<_>>();
134
135 futures::future::ready(Ok(WithPeerId::new(PeerId::random(), resp)))
137 }
138}
139
140impl BodiesClient for TestFullBlockClient {
142 type Body = BlockBody;
143 type Output = futures::future::Ready<PeerRequestResult<Vec<BlockBody>>>;
145
146 fn get_block_bodies_with_priority_and_range_hint(
157 &self,
158 hashes: Vec<B256>,
159 _priority: Priority,
160 _range_hint: Option<RangeInclusive<u64>>,
161 ) -> Self::Output {
162 let bodies = self.bodies.lock();
164
165 futures::future::ready(Ok(WithPeerId::new(
168 PeerId::random(),
169 hashes
170 .iter()
171 .filter_map(|hash| bodies.get(hash).cloned())
172 .take(self.soft_limit)
173 .collect(),
174 )))
175 }
176}
177
178impl BlockClient for TestFullBlockClient {
179 type Block = reth_ethereum_primitives::Block;
180}
181
182impl BlockAccessListsClient for TestFullBlockClient {
183 type Output = futures::future::Ready<PeerRequestResult<BlockAccessLists>>;
184
185 fn get_block_access_lists_with_priority_and_requirement(
186 &self,
187 hashes: Vec<B256>,
188 _priority: Priority,
189 _requirement: BalRequirement,
190 ) -> Self::Output {
191 let access_lists = self.access_lists.lock();
192 futures::future::ready(Ok(WithPeerId::new(
193 PeerId::random(),
194 BlockAccessLists(hashes.iter().map(|hash| access_lists.get(hash).cloned()).collect()),
195 )))
196 }
197}