1use crate::{
30 eth::{
31 error::PoolError,
32 pool::transactions::{
33 PendingPoolTransaction, PendingTransactions, PoolTransaction, ReadyTransactions,
34 TransactionsIterator, TxMarker,
35 },
36 },
37 mem::storage::MinedBlockOutcome,
38};
39use alloy_consensus::Transaction;
40use alloy_primitives::{Address, TxHash};
41use alloy_rpc_types::txpool::TxpoolStatus;
42use anvil_core::eth::transaction::PendingTransaction;
43use futures::channel::mpsc::{Receiver, Sender, channel};
44use parking_lot::{Mutex, RwLock};
45use std::{collections::VecDeque, fmt, sync::Arc};
46
47pub mod transactions;
48
49pub struct Pool<T> {
51 inner: RwLock<PoolInner<T>>,
53 transaction_listener: Mutex<Vec<Sender<TxHash>>>,
55}
56
57impl<T> Default for Pool<T> {
58 fn default() -> Self {
59 Self { inner: RwLock::new(PoolInner::default()), transaction_listener: Default::default() }
60 }
61}
62
63impl<T> Pool<T> {
66 pub fn ready_transactions(&self) -> TransactionsIterator<T> {
68 self.inner.read().ready_transactions()
69 }
70
71 pub fn pending_transactions(&self) -> Vec<Arc<PoolTransaction<T>>> {
73 self.inner.read().pending_transactions.transactions().collect()
74 }
75
76 pub fn txpool_status(&self) -> TxpoolStatus {
78 let pending: u64 = self.inner.read().ready_transactions.len().try_into().unwrap_or(0);
80 let queued: u64 = self.inner.read().pending_transactions.len().try_into().unwrap_or(0);
81 TxpoolStatus { pending, queued }
82 }
83
84 pub fn add_ready_listener(&self) -> Receiver<TxHash> {
87 const TX_LISTENER_BUFFER_SIZE: usize = 2048;
88 let (tx, rx) = channel(TX_LISTENER_BUFFER_SIZE);
89 self.transaction_listener.lock().push(tx);
90 rx
91 }
92
93 pub fn contains(&self, tx_hash: &TxHash) -> bool {
95 self.inner.read().contains(tx_hash)
96 }
97
98 pub fn contains_sender_nonce(&self, sender: Address, nonce: u64) -> bool
100 where
101 T: Transaction,
102 {
103 self.inner
104 .read()
105 .transactions_by_sender(sender)
106 .any(|tx| tx.pending_transaction.nonce() == nonce)
107 }
108
109 pub fn clear(&self) {
111 let mut pool = self.inner.write();
112 pool.clear();
113 }
114
115 pub fn remove_invalid(&self, tx_hashes: Vec<TxHash>) -> Vec<Arc<PoolTransaction<T>>> {
117 self.inner.write().remove_invalid(tx_hashes)
118 }
119
120 pub fn remove_transactions_by_address(&self, sender: Address) -> Vec<Arc<PoolTransaction<T>>> {
122 self.inner.write().remove_transactions_by_address(sender)
123 }
124
125 pub fn drop_transaction(&self, tx: TxHash) -> Option<Arc<PoolTransaction<T>>> {
131 trace!(target: "txpool", "Dropping transaction: [{:?}]", tx);
132 let removed = {
133 let mut pool = self.inner.write();
134 pool.ready_transactions.remove_with_markers(vec![tx], None)
135 };
136 trace!(target: "txpool", "Dropped transactions: {:?}", removed.iter().map(|tx| tx.hash()).collect::<Vec<_>>());
137
138 if removed.is_empty() {
139 None
140 } else {
141 removed.into_iter().find(|t| *t.pending_transaction.hash() == tx)
142 }
143 }
144
145 fn notify_ready(&self, tx: &AddedTransaction<T>) {
147 if let AddedTransaction::Ready(ready) = tx {
148 self.notify_listener(ready.hash);
149 for promoted in ready.promoted.iter().copied() {
150 self.notify_listener(promoted);
151 }
152 }
153 }
154
155 fn notify_listener(&self, hash: TxHash) {
157 let mut listener = self.transaction_listener.lock();
158 for n in (0..listener.len()).rev() {
160 let mut listener_tx = listener.swap_remove(n);
161 let retain = match listener_tx.try_send(hash) {
162 Ok(()) => true,
163 Err(e) => {
164 if e.is_full() {
165 warn!(
166 target: "txpool",
167 "[{:?}] Failed to send tx notification because channel is full",
168 hash,
169 );
170 true
171 } else {
172 false
173 }
174 }
175 };
176 if retain {
177 listener.push(listener_tx)
178 }
179 }
180 }
181}
182
183impl<T: Clone> Pool<T> {
184 pub fn get_transaction(&self, hash: TxHash) -> Option<PendingTransaction<T>> {
186 self.inner.read().get_transaction(hash)
187 }
188}
189
190impl<T: Transaction> Pool<T> {
191 pub fn on_mined_block(self: &Arc<Self>, outcome: MinedBlockOutcome<T>) -> PruneResult<T> {
195 let MinedBlockOutcome { block_number, included, invalid, not_yet_valid } = outcome;
196
197 self.remove_invalid(invalid.into_iter().map(|tx| tx.hash()).collect());
199
200 let res = self
202 .prune_markers(block_number, included.into_iter().flat_map(|tx| tx.provides.clone()));
203 trace!(target: "txpool", "pruned transaction markers {:?}", res);
204
205 if !not_yet_valid.is_empty() {
208 let tx_hashes: Vec<_> = not_yet_valid.iter().map(|tx| tx.hash()).collect();
209 let pool = Arc::clone(self);
210 tokio::spawn(async move {
211 tokio::time::sleep(std::time::Duration::from_secs(1)).await;
212 for hash in tx_hashes {
213 trace!(target: "txpool", "re-notifying for not-yet-valid tx: {:?}", hash);
214 pool.notify_listener(hash);
215 }
216 });
217 }
218
219 res
220 }
221
222 pub fn prune_markers(
227 &self,
228 block_number: u64,
229 markers: impl IntoIterator<Item = TxMarker>,
230 ) -> PruneResult<T> {
231 debug!(target: "txpool", ?block_number, "pruning transactions");
232 let res = self.inner.write().prune_markers(markers);
233 for tx in &res.promoted {
234 self.notify_ready(tx);
235 }
236 res
237 }
238
239 pub fn add_transaction(
241 &self,
242 tx: PoolTransaction<T>,
243 ) -> Result<AddedTransaction<T>, PoolError> {
244 let added = self.inner.write().add_transaction(tx)?;
245 self.notify_ready(&added);
246 Ok(added)
247 }
248}
249
250#[derive(Debug)]
254struct PoolInner<T> {
255 ready_transactions: ReadyTransactions<T>,
256 pending_transactions: PendingTransactions<T>,
257}
258
259impl<T> Default for PoolInner<T> {
260 fn default() -> Self {
261 Self { ready_transactions: Default::default(), pending_transactions: Default::default() }
262 }
263}
264
265impl<T> PoolInner<T> {
268 fn ready_transactions(&self) -> TransactionsIterator<T> {
270 self.ready_transactions.get_transactions()
271 }
272
273 fn clear(&mut self) {
275 self.ready_transactions.clear();
276 self.pending_transactions.clear();
277 }
278
279 pub fn transactions_by_sender(
281 &self,
282 sender: Address,
283 ) -> impl Iterator<Item = Arc<PoolTransaction<T>>> + '_ {
284 let pending_txs = self
285 .pending_transactions
286 .transactions()
287 .filter(move |tx| tx.pending_transaction.sender().eq(&sender));
288
289 let ready_txs = self
290 .ready_transactions
291 .get_transactions()
292 .filter(move |tx| tx.pending_transaction.sender().eq(&sender));
293
294 pending_txs.chain(ready_txs)
295 }
296
297 fn contains(&self, tx_hash: &TxHash) -> bool {
299 self.pending_transactions.contains(tx_hash) || self.ready_transactions.contains(tx_hash)
300 }
301
302 fn remove_invalid(&mut self, tx_hashes: Vec<TxHash>) -> Vec<Arc<PoolTransaction<T>>> {
304 if tx_hashes.is_empty() {
306 return vec![];
307 }
308 trace!(target: "txpool", "Removing invalid transactions: {:?}", tx_hashes);
309
310 let mut removed = self.ready_transactions.remove_with_markers(tx_hashes.clone(), None);
311 removed.extend(self.pending_transactions.remove(tx_hashes));
312
313 trace!(target: "txpool", "Removed invalid transactions: {:?}", removed.iter().map(|tx| tx.hash()).collect::<Vec<_>>());
314
315 removed
316 }
317
318 fn remove_transactions_by_address(&mut self, sender: Address) -> Vec<Arc<PoolTransaction<T>>> {
320 let tx_hashes =
321 self.transactions_by_sender(sender).map(move |tx| tx.hash()).collect::<Vec<TxHash>>();
322
323 if tx_hashes.is_empty() {
324 return vec![];
325 }
326
327 trace!(target: "txpool", "Removing transactions: {:?}", tx_hashes);
328
329 let mut removed = self.ready_transactions.remove_with_markers(tx_hashes.clone(), None);
330 removed.extend(self.pending_transactions.remove(tx_hashes));
331
332 trace!(target: "txpool", "Removed transactions: {:?}", removed.iter().map(|tx| tx.hash()).collect::<Vec<_>>());
333
334 removed
335 }
336}
337
338impl<T: Clone> PoolInner<T> {
339 fn get_transaction(&self, hash: TxHash) -> Option<PendingTransaction<T>> {
343 if let Some(pending) = self.pending_transactions.get(&hash) {
344 return Some(pending.transaction.pending_transaction.clone());
345 }
346 Some(
347 self.ready_transactions.get(&hash)?.transaction.transaction.pending_transaction.clone(),
348 )
349 }
350}
351
352impl<T: Transaction> PoolInner<T> {
353 fn add_transaction(
354 &mut self,
355 tx: PoolTransaction<T>,
356 ) -> Result<AddedTransaction<T>, PoolError> {
357 if self.contains(&tx.hash()) {
358 debug!(target: "txpool", "[{:?}] Already imported", tx.hash());
359 return Err(PoolError::AlreadyImported(tx.hash()));
360 }
361
362 let tx = PendingPoolTransaction::new(tx, self.ready_transactions.provided_markers());
363 trace!(target: "txpool", "[{:?}] ready={}", tx.transaction.hash(), tx.is_ready());
364
365 if !tx.is_ready() {
367 let hash = tx.transaction.hash();
368 self.pending_transactions.add_transaction(tx)?;
369 return Ok(AddedTransaction::Pending { hash });
370 }
371 self.add_ready_transaction(tx)
372 }
373
374 fn add_ready_transaction(
376 &mut self,
377 tx: PendingPoolTransaction<T>,
378 ) -> Result<AddedTransaction<T>, PoolError> {
379 let hash = tx.transaction.hash();
380 trace!(target: "txpool", "adding ready transaction [{:?}]", hash);
381 let mut ready = ReadyTransaction::new(hash);
382
383 let mut tx_queue = VecDeque::from([tx]);
384 let mut is_new_tx = true;
386
387 while let Some(current_tx) = tx_queue.pop_front() {
389 tx_queue.extend(
391 self.pending_transactions.mark_and_unlock(¤t_tx.transaction.provides),
392 );
393
394 let current_hash = current_tx.transaction.hash();
395 match self.ready_transactions.add_transaction(current_tx) {
397 Ok(replaced_transactions) => {
398 if !is_new_tx {
399 ready.promoted.push(current_hash);
400 }
401 ready.removed.extend(replaced_transactions);
403 }
404 Err(err) => {
405 if is_new_tx {
407 debug!(target: "txpool", "[{:?}] Failed to add tx: {:?}", current_hash,
408 err);
409 return Err(err);
410 }
411 ready.discarded.push(current_hash);
412 }
413 }
414 is_new_tx = false;
415 }
416
417 if ready.removed.iter().any(|tx| *tx.hash() == hash) {
421 self.ready_transactions.clear_transactions(&ready.promoted);
422 return Err(PoolError::CyclicTransaction);
423 }
424
425 Ok(AddedTransaction::Ready(ready))
426 }
427
428 pub fn prune_markers(&mut self, markers: impl IntoIterator<Item = TxMarker>) -> PruneResult<T> {
433 let mut imports = vec![];
434 let mut pruned = vec![];
435
436 for marker in markers {
437 imports.extend(self.pending_transactions.mark_and_unlock(Some(&marker)));
439 pruned.extend(self.ready_transactions.prune_tags(marker.clone()));
441 }
442
443 let mut promoted = vec![];
444 let mut failed = vec![];
445 for tx in imports {
446 let hash = tx.transaction.hash();
447 match self.add_ready_transaction(tx) {
448 Ok(res) => promoted.push(res),
449 Err(e) => {
450 warn!(target: "txpool", "Failed to promote tx [{:?}] : {:?}", hash, e);
451 failed.push(hash)
452 }
453 }
454 }
455
456 PruneResult { pruned, failed, promoted }
457 }
458}
459
460pub struct PruneResult<T> {
462 pub promoted: Vec<AddedTransaction<T>>,
464 pub failed: Vec<TxHash>,
466 pub pruned: Vec<Arc<PoolTransaction<T>>>,
468}
469
470impl<T> fmt::Debug for PruneResult<T> {
471 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
472 write!(fmt, "PruneResult {{ ")?;
473 write!(
474 fmt,
475 "promoted: {:?}, ",
476 self.promoted.iter().map(|tx| *tx.hash()).collect::<Vec<_>>()
477 )?;
478 write!(fmt, "failed: {:?}, ", self.failed)?;
479 write!(
480 fmt,
481 "pruned: {:?}, ",
482 self.pruned.iter().map(|tx| *tx.pending_transaction.hash()).collect::<Vec<_>>()
483 )?;
484 write!(fmt, "}}")?;
485 Ok(())
486 }
487}
488
489#[derive(Clone, Debug)]
490pub struct ReadyTransaction<T> {
491 hash: TxHash,
493 promoted: Vec<TxHash>,
495 discarded: Vec<TxHash>,
497 removed: Vec<Arc<PoolTransaction<T>>>,
499}
500
501impl<T> ReadyTransaction<T> {
502 pub fn new(hash: TxHash) -> Self {
503 Self {
504 hash,
505 promoted: Default::default(),
506 discarded: Default::default(),
507 removed: Default::default(),
508 }
509 }
510}
511
512#[derive(Clone, Debug)]
513pub enum AddedTransaction<T> {
514 Ready(ReadyTransaction<T>),
516 Pending {
518 hash: TxHash,
520 },
521}
522
523impl<T> AddedTransaction<T> {
524 pub const fn hash(&self) -> &TxHash {
525 match self {
526 Self::Ready(tx) => &tx.hash,
527 Self::Pending { hash } => hash,
528 }
529 }
530}