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