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