1use crate::{
7 blobstore::BlobStoreError,
8 error::{InvalidPoolTransactionError, PoolError},
9 pool::TransactionListenerKind,
10 traits::{BestTransactionsAttributes, GetPooledTransactionLimit, NewBlobSidecar},
11 validate::ValidTransaction,
12 AllPoolTransactions, AllTransactionsEvents, BestTransactions, BlockInfo, EthPoolTransaction,
13 EthPooledTransaction, NewTransactionEvent, PoolResult, PoolSize, PoolTransaction,
14 PropagatedTransactions, TransactionEvents, TransactionOrigin, TransactionPool,
15 TransactionValidationOutcome, TransactionValidator, ValidPoolTransaction,
16};
17use alloy_eips::{
18 eip1559::ETHEREUM_BLOCK_GAS_LIMIT_30M,
19 eip4844::{BlobAndProofV1, BlobTransactionSidecar},
20};
21use alloy_primitives::{Address, TxHash, B256, U256};
22use reth_eth_wire_types::HandleMempoolData;
23use reth_primitives_traits::Recovered;
24use std::{collections::HashSet, marker::PhantomData, sync::Arc};
25use tokio::sync::{mpsc, mpsc::Receiver};
26
27#[derive(Debug, Clone)]
32#[non_exhaustive]
33pub struct NoopTransactionPool<T: EthPoolTransaction = EthPooledTransaction> {
34 _marker: PhantomData<T>,
36}
37
38impl<T: EthPoolTransaction> NoopTransactionPool<T> {
39 pub fn new() -> Self {
41 Self { _marker: Default::default() }
42 }
43}
44
45impl Default for NoopTransactionPool<EthPooledTransaction> {
46 fn default() -> Self {
47 Self { _marker: Default::default() }
48 }
49}
50
51impl<T: EthPoolTransaction> TransactionPool for NoopTransactionPool<T> {
52 type Transaction = T;
53
54 fn pool_size(&self) -> PoolSize {
55 Default::default()
56 }
57
58 fn block_info(&self) -> BlockInfo {
59 BlockInfo {
60 block_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT_30M,
61 last_seen_block_hash: Default::default(),
62 last_seen_block_number: 0,
63 pending_basefee: 0,
64 pending_blob_fee: None,
65 }
66 }
67
68 async fn add_transaction_and_subscribe(
69 &self,
70 _origin: TransactionOrigin,
71 transaction: Self::Transaction,
72 ) -> PoolResult<TransactionEvents> {
73 let hash = *transaction.hash();
74 Err(PoolError::other(hash, Box::new(NoopInsertError::new(transaction))))
75 }
76
77 async fn add_transaction(
78 &self,
79 _origin: TransactionOrigin,
80 transaction: Self::Transaction,
81 ) -> PoolResult<TxHash> {
82 let hash = *transaction.hash();
83 Err(PoolError::other(hash, Box::new(NoopInsertError::new(transaction))))
84 }
85
86 async fn add_transactions(
87 &self,
88 _origin: TransactionOrigin,
89 transactions: Vec<Self::Transaction>,
90 ) -> Vec<PoolResult<TxHash>> {
91 transactions
92 .into_iter()
93 .map(|transaction| {
94 let hash = *transaction.hash();
95 Err(PoolError::other(hash, Box::new(NoopInsertError::new(transaction))))
96 })
97 .collect()
98 }
99
100 fn transaction_event_listener(&self, _tx_hash: TxHash) -> Option<TransactionEvents> {
101 None
102 }
103
104 fn all_transactions_event_listener(&self) -> AllTransactionsEvents<Self::Transaction> {
105 AllTransactionsEvents::new(mpsc::channel(1).1)
106 }
107
108 fn pending_transactions_listener_for(
109 &self,
110 _kind: TransactionListenerKind,
111 ) -> Receiver<TxHash> {
112 mpsc::channel(1).1
113 }
114
115 fn new_transactions_listener(&self) -> Receiver<NewTransactionEvent<Self::Transaction>> {
116 mpsc::channel(1).1
117 }
118
119 fn blob_transaction_sidecars_listener(&self) -> Receiver<NewBlobSidecar> {
120 mpsc::channel(1).1
121 }
122
123 fn new_transactions_listener_for(
124 &self,
125 _kind: TransactionListenerKind,
126 ) -> Receiver<NewTransactionEvent<Self::Transaction>> {
127 mpsc::channel(1).1
128 }
129
130 fn pooled_transaction_hashes(&self) -> Vec<TxHash> {
131 vec![]
132 }
133
134 fn pooled_transaction_hashes_max(&self, _max: usize) -> Vec<TxHash> {
135 vec![]
136 }
137
138 fn pooled_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
139 vec![]
140 }
141
142 fn pooled_transactions_max(
143 &self,
144 _max: usize,
145 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
146 vec![]
147 }
148
149 fn get_pooled_transaction_elements(
150 &self,
151 _tx_hashes: Vec<TxHash>,
152 _limit: GetPooledTransactionLimit,
153 ) -> Vec<<Self::Transaction as PoolTransaction>::Pooled> {
154 vec![]
155 }
156
157 fn get_pooled_transaction_element(
158 &self,
159 _tx_hash: TxHash,
160 ) -> Option<Recovered<<Self::Transaction as PoolTransaction>::Pooled>> {
161 None
162 }
163
164 fn best_transactions(
165 &self,
166 ) -> Box<dyn BestTransactions<Item = Arc<ValidPoolTransaction<Self::Transaction>>>> {
167 Box::new(std::iter::empty())
168 }
169
170 fn best_transactions_with_attributes(
171 &self,
172 _: BestTransactionsAttributes,
173 ) -> Box<dyn BestTransactions<Item = Arc<ValidPoolTransaction<Self::Transaction>>>> {
174 Box::new(std::iter::empty())
175 }
176
177 fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
178 vec![]
179 }
180
181 fn pending_transactions_max(
182 &self,
183 _max: usize,
184 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
185 vec![]
186 }
187
188 fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
189 vec![]
190 }
191
192 fn all_transactions(&self) -> AllPoolTransactions<Self::Transaction> {
193 AllPoolTransactions::default()
194 }
195
196 fn remove_transactions(
197 &self,
198 _hashes: Vec<TxHash>,
199 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
200 vec![]
201 }
202
203 fn remove_transactions_and_descendants(
204 &self,
205 _hashes: Vec<TxHash>,
206 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
207 vec![]
208 }
209
210 fn remove_transactions_by_sender(
211 &self,
212 _sender: Address,
213 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
214 vec![]
215 }
216
217 fn retain_unknown<A>(&self, _announcement: &mut A)
218 where
219 A: HandleMempoolData,
220 {
221 }
222
223 fn get(&self, _tx_hash: &TxHash) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
224 None
225 }
226
227 fn get_all(&self, _txs: Vec<TxHash>) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
228 vec![]
229 }
230
231 fn on_propagated(&self, _txs: PropagatedTransactions) {}
232
233 fn get_transactions_by_sender(
234 &self,
235 _sender: Address,
236 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
237 vec![]
238 }
239
240 fn get_pending_transactions_with_predicate(
241 &self,
242 _predicate: impl FnMut(&ValidPoolTransaction<Self::Transaction>) -> bool,
243 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
244 vec![]
245 }
246
247 fn get_pending_transactions_by_sender(
248 &self,
249 _sender: Address,
250 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
251 vec![]
252 }
253
254 fn get_queued_transactions_by_sender(
255 &self,
256 _sender: Address,
257 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
258 vec![]
259 }
260
261 fn get_highest_transaction_by_sender(
262 &self,
263 _sender: Address,
264 ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
265 None
266 }
267
268 fn get_highest_consecutive_transaction_by_sender(
269 &self,
270 _sender: Address,
271 _on_chain_nonce: u64,
272 ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
273 None
274 }
275
276 fn get_transaction_by_sender_and_nonce(
277 &self,
278 _sender: Address,
279 _nonce: u64,
280 ) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
281 None
282 }
283
284 fn get_transactions_by_origin(
285 &self,
286 _origin: TransactionOrigin,
287 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
288 vec![]
289 }
290
291 fn get_pending_transactions_by_origin(
292 &self,
293 _origin: TransactionOrigin,
294 ) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
295 vec![]
296 }
297
298 fn unique_senders(&self) -> HashSet<Address> {
299 Default::default()
300 }
301
302 fn get_blob(
303 &self,
304 _tx_hash: TxHash,
305 ) -> Result<Option<Arc<BlobTransactionSidecar>>, BlobStoreError> {
306 Ok(None)
307 }
308
309 fn get_all_blobs(
310 &self,
311 _tx_hashes: Vec<TxHash>,
312 ) -> Result<Vec<(TxHash, Arc<BlobTransactionSidecar>)>, BlobStoreError> {
313 Ok(vec![])
314 }
315
316 fn get_all_blobs_exact(
317 &self,
318 tx_hashes: Vec<TxHash>,
319 ) -> Result<Vec<Arc<BlobTransactionSidecar>>, BlobStoreError> {
320 if tx_hashes.is_empty() {
321 return Ok(vec![])
322 }
323 Err(BlobStoreError::MissingSidecar(tx_hashes[0]))
324 }
325
326 fn get_blobs_for_versioned_hashes(
327 &self,
328 versioned_hashes: &[B256],
329 ) -> Result<Vec<Option<BlobAndProofV1>>, BlobStoreError> {
330 Ok(vec![None; versioned_hashes.len()])
331 }
332}
333
334#[derive(Debug, Clone)]
336#[non_exhaustive]
337pub struct MockTransactionValidator<T> {
338 propagate_local: bool,
339 return_invalid: bool,
340 _marker: PhantomData<T>,
341}
342
343impl<T: EthPoolTransaction> TransactionValidator for MockTransactionValidator<T> {
344 type Transaction = T;
345
346 async fn validate_transaction(
347 &self,
348 origin: TransactionOrigin,
349 mut transaction: Self::Transaction,
350 ) -> TransactionValidationOutcome<Self::Transaction> {
351 if self.return_invalid {
352 return TransactionValidationOutcome::Invalid(
353 transaction,
354 InvalidPoolTransactionError::Underpriced,
355 );
356 }
357 let maybe_sidecar = transaction.take_blob().maybe_sidecar().cloned();
358 TransactionValidationOutcome::Valid {
361 balance: U256::MAX,
362 state_nonce: 0,
363 transaction: ValidTransaction::new(transaction, maybe_sidecar),
364 propagate: match origin {
365 TransactionOrigin::External => true,
366 TransactionOrigin::Local => self.propagate_local,
367 TransactionOrigin::Private => false,
368 },
369 }
370 }
371}
372
373impl<T> MockTransactionValidator<T> {
374 pub fn no_propagate_local() -> Self {
377 Self { propagate_local: false, return_invalid: false, _marker: Default::default() }
378 }
379 pub fn return_invalid() -> Self {
381 Self { propagate_local: false, return_invalid: true, _marker: Default::default() }
382 }
383}
384
385impl<T> Default for MockTransactionValidator<T> {
386 fn default() -> Self {
387 Self { propagate_local: true, return_invalid: false, _marker: Default::default() }
388 }
389}
390
391#[derive(Debug, Clone, thiserror::Error)]
393#[error("can't insert transaction into the noop pool that does nothing")]
394pub struct NoopInsertError<T: EthPoolTransaction = EthPooledTransaction> {
395 tx: T,
396}
397
398impl<T: EthPoolTransaction> NoopInsertError<T> {
399 const fn new(tx: T) -> Self {
400 Self { tx }
401 }
402
403 pub fn into_inner(self) -> T {
405 self.tx
406 }
407}