1use crate::{
30 eth::{
31 error::PoolError,
32 fees::FeeManager,
33 pool::transactions::{
34 PendingPoolTransaction, PendingTransactions, PoolTransaction, ReadyTransactions,
35 TransactionsIterator, TxMarker,
36 },
37 },
38 mem::storage::MinedBlockOutcome,
39};
40use alloy_consensus::Transaction;
41use alloy_primitives::{Address, TxHash};
42use alloy_rpc_types::txpool::TxpoolStatus;
43use anvil_core::eth::transaction::PendingTransaction;
44use futures::channel::mpsc::{Receiver, Sender, channel};
45use parking_lot::{Mutex, RwLock};
46use std::{collections::VecDeque, fmt, sync::Arc};
47
48#[cfg(feature = "base")]
49use alloy_consensus::Typed2718;
50
51pub mod transactions;
52
53pub struct Pool<T> {
55 inner: RwLock<PoolInner<T>>,
57 transaction_listener: Mutex<Vec<ReadyListener>>,
59 fees: Option<FeeManager>,
61}
62
63struct ReadyListener {
64 sender: Sender<TxHash>,
65 close_on_full: bool,
66}
67
68#[derive(Debug)]
70pub(crate) struct PoolSnapshot<T> {
71 inner: PoolInner<T>,
72}
73
74impl<T> Default for Pool<T> {
75 fn default() -> Self {
76 Self {
77 inner: RwLock::new(PoolInner::default()),
78 transaction_listener: Default::default(),
79 fees: None,
80 }
81 }
82}
83
84impl<T> Pool<T> {
87 pub fn new(fees: FeeManager) -> Self {
89 Self { fees: Some(fees), ..Default::default() }
90 }
91
92 fn base_fee(&self) -> u64 {
94 self.fees.as_ref().map_or(0, FeeManager::base_fee)
95 }
96
97 pub(crate) fn snapshot(&self) -> PoolSnapshot<T> {
99 let pool = self.inner.read();
100 PoolSnapshot {
101 inner: PoolInner {
102 ready_transactions: pool.ready_transactions.snapshot(),
103 pending_transactions: pool.pending_transactions.snapshot(),
104 },
105 }
106 }
107
108 pub(crate) fn restore(&self, snapshot: PoolSnapshot<T>) {
110 let ready = {
111 let mut pool = self.inner.write();
112 *pool = snapshot.inner;
113 pool.ready_transactions(self.base_fee()).map(|tx| tx.hash()).collect::<Vec<_>>()
114 };
115 for hash in ready {
116 self.notify_listener(hash);
117 }
118 }
119
120 pub fn ready_transactions(&self) -> TransactionsIterator<T> {
122 self.inner.read().ready_transactions(self.base_fee())
123 }
124
125 pub fn pending_transactions(&self) -> Vec<Arc<PoolTransaction<T>>> {
127 self.inner.read().pending_transactions.transactions().collect()
128 }
129
130 #[cfg(feature = "base")]
132 pub fn all_transactions(&self) -> Vec<Arc<PoolTransaction<T>>> {
133 let pool = self.inner.read();
134 pool.pending_transactions
135 .transactions()
136 .chain(pool.ready_transactions(self.base_fee()))
137 .collect()
138 }
139
140 pub fn txpool_status(&self) -> TxpoolStatus {
142 let pending: u64 = self.inner.read().ready_transactions.len().try_into().unwrap_or(0);
144 let queued: u64 = self.inner.read().pending_transactions.len().try_into().unwrap_or(0);
145 TxpoolStatus { pending, queued }
146 }
147
148 pub fn add_ready_listener(&self) -> Receiver<TxHash> {
151 self.add_ready_listener_with_policy(false)
152 }
153
154 pub(crate) fn add_ready_subscription_listener(&self) -> Receiver<TxHash> {
156 self.add_ready_listener_with_policy(true)
157 }
158
159 fn add_ready_listener_with_policy(&self, close_on_full: bool) -> Receiver<TxHash> {
160 const TX_LISTENER_BUFFER_SIZE: usize = 2048;
161 let (tx, rx) = channel(TX_LISTENER_BUFFER_SIZE);
162 self.transaction_listener.lock().push(ReadyListener { sender: tx, close_on_full });
163 rx
164 }
165
166 pub fn contains(&self, tx_hash: &TxHash) -> bool {
168 self.inner.read().contains(tx_hash)
169 }
170
171 pub fn contains_sender_nonce(&self, sender: Address, nonce: u64) -> bool
173 where
174 T: Transaction,
175 {
176 self.inner
177 .read()
178 .transactions_by_sender(sender)
179 .any(|tx| tx.pending_transaction.nonce() == nonce)
180 }
181
182 #[cfg(feature = "base")]
184 pub fn transaction_with_markers(
185 &self,
186 sender: Address,
187 markers: &[TxMarker],
188 ) -> Option<Arc<PoolTransaction<T>>> {
189 self.inner.read().transactions_by_sender(sender).find(|tx| tx.provides == markers)
190 }
191
192 pub fn clear(&self) {
194 let mut pool = self.inner.write();
195 pool.clear();
196 }
197
198 pub fn remove_invalid(&self, tx_hashes: Vec<TxHash>) -> Vec<Arc<PoolTransaction<T>>> {
200 self.inner.write().remove_invalid(tx_hashes)
201 }
202
203 pub fn remove_transactions_by_address(&self, sender: Address) -> Vec<Arc<PoolTransaction<T>>> {
205 self.inner.write().remove_transactions_by_address(sender)
206 }
207
208 pub fn drop_transaction(&self, tx: TxHash) -> Option<Arc<PoolTransaction<T>>> {
214 trace!(target: "txpool", "Dropping transaction: [{:?}]", tx);
215 let removed = {
216 let mut pool = self.inner.write();
217 let mut removed = pool.ready_transactions.remove_with_markers(vec![tx], None);
218 let invalidated = removed.iter().flat_map(|tx| tx.provides.iter().cloned());
219 removed.extend(pool.pending_transactions.remove_with_dependents(vec![tx], invalidated));
220 removed
221 };
222 trace!(target: "txpool", "Dropped transactions: {:?}", removed.iter().map(|tx| tx.hash()).collect::<Vec<_>>());
223
224 if removed.is_empty() {
225 None
226 } else {
227 removed.into_iter().find(|t| *t.pending_transaction.hash() == tx)
228 }
229 }
230
231 fn notify_ready(&self, tx: &AddedTransaction<T>) {
233 if let AddedTransaction::Ready(ready) = tx {
234 self.notify_listener(ready.hash);
235 for promoted in ready.promoted.iter().copied() {
236 self.notify_listener(promoted);
237 }
238 }
239 }
240
241 fn notify_listener(&self, hash: TxHash) {
243 let mut listener = self.transaction_listener.lock();
244 for n in (0..listener.len()).rev() {
246 let mut listener_tx = listener.swap_remove(n);
247 let retain = match listener_tx.sender.try_send(hash) {
248 Ok(()) => true,
249 Err(e) => {
250 if e.is_full() {
251 warn!(
252 target: "txpool",
253 "[{:?}] Failed to send tx notification because channel is full",
254 hash,
255 );
256 !listener_tx.close_on_full
257 } else {
258 false
259 }
260 }
261 };
262 if retain {
263 listener.push(listener_tx)
264 }
265 }
266 }
267}
268
269impl<T: Clone> Pool<T> {
270 pub fn get_transaction(&self, hash: TxHash) -> Option<PendingTransaction<T>> {
272 self.inner.read().get_transaction(hash)
273 }
274}
275
276impl<T: Transaction> Pool<T> {
277 pub fn on_mined_block(self: &Arc<Self>, outcome: MinedBlockOutcome<T>) -> bool {
284 let MinedBlockOutcome { block_number, included, stale, invalid, not_yet_valid } = outcome;
285 let made_progress = !included.is_empty() || !stale.is_empty() || !invalid.is_empty();
289 let retry_ready = made_progress && not_yet_valid.is_empty();
290
291 self.remove_invalid(invalid.into_iter().map(|tx| tx.hash()).collect());
293
294 let res = self.prune_markers(
296 block_number,
297 included.into_iter().chain(stale).flat_map(|tx| tx.provides.clone()),
298 );
299 trace!(target: "txpool", "pruned transaction markers {:?}", res);
300
301 if !not_yet_valid.is_empty() {
304 let tx_hashes: Vec<_> = not_yet_valid.iter().map(|tx| tx.hash()).collect();
305 let pool = Arc::clone(self);
306 tokio::spawn(async move {
307 tokio::time::sleep(std::time::Duration::from_secs(1)).await;
308 for hash in tx_hashes {
309 trace!(target: "txpool", "re-notifying for not-yet-valid tx: {:?}", hash);
310 pool.notify_listener(hash);
311 }
312 });
313 }
314
315 retry_ready && !self.inner.read().ready_transactions.is_empty()
316 }
317
318 pub fn prune_markers(
323 &self,
324 block_number: u64,
325 markers: impl IntoIterator<Item = TxMarker>,
326 ) -> PruneResult<T> {
327 debug!(target: "txpool", ?block_number, "pruning transactions");
328 let res = self.inner.write().prune_markers(markers);
329 for tx in &res.promoted {
330 self.notify_ready(tx);
331 }
332 res
333 }
334
335 pub fn add_transaction(
337 &self,
338 tx: PoolTransaction<T>,
339 ) -> Result<AddedTransaction<T>, PoolError> {
340 let added = self.inner.write().add_transaction(tx)?;
341 self.notify_ready(&added);
342 Ok(added)
343 }
344}
345
346#[cfg(feature = "base")]
347impl<T: Typed2718> Pool<T> {
348 pub fn clear_transaction_type(&self, tx_type: u8) -> Vec<Arc<PoolTransaction<T>>> {
350 let hashes = {
351 let pool = self.inner.read();
352 pool.pending_transactions
353 .transactions()
354 .chain(pool.ready_transactions(self.base_fee()))
355 .filter_map(|tx| {
356 (tx.pending_transaction.transaction.ty() == tx_type).then_some(tx.hash())
357 })
358 .collect()
359 };
360 self.remove_invalid(hashes)
361 }
362}
363
364#[derive(Debug)]
368struct PoolInner<T> {
369 ready_transactions: ReadyTransactions<T>,
370 pending_transactions: PendingTransactions<T>,
371}
372
373impl<T> Default for PoolInner<T> {
374 fn default() -> Self {
375 Self { ready_transactions: Default::default(), pending_transactions: Default::default() }
376 }
377}
378
379impl<T> PoolInner<T> {
382 fn ready_transactions(&self, base_fee: u64) -> TransactionsIterator<T> {
384 self.ready_transactions.get_transactions(base_fee)
385 }
386
387 fn clear(&mut self) {
389 self.ready_transactions.clear();
390 self.pending_transactions.clear();
391 }
392
393 pub fn transactions_by_sender(
395 &self,
396 sender: Address,
397 ) -> impl Iterator<Item = Arc<PoolTransaction<T>>> + '_ {
398 let pending_txs = self
399 .pending_transactions
400 .transactions()
401 .filter(move |tx| tx.pending_transaction.sender().eq(&sender));
402
403 let ready_txs = self
404 .ready_transactions
405 .get_transactions(0)
407 .filter(move |tx| tx.pending_transaction.sender().eq(&sender));
408
409 pending_txs.chain(ready_txs)
410 }
411
412 fn contains(&self, tx_hash: &TxHash) -> bool {
414 self.pending_transactions.contains(tx_hash) || self.ready_transactions.contains(tx_hash)
415 }
416
417 fn remove_invalid(&mut self, tx_hashes: Vec<TxHash>) -> Vec<Arc<PoolTransaction<T>>> {
419 if tx_hashes.is_empty() {
421 return vec![];
422 }
423 trace!(target: "txpool", "Removing invalid transactions: {:?}", tx_hashes);
424
425 let mut removed = self.ready_transactions.remove_with_markers(tx_hashes.clone(), None);
426 removed.extend(self.pending_transactions.remove(tx_hashes));
427
428 trace!(target: "txpool", "Removed invalid transactions: {:?}", removed.iter().map(|tx| tx.hash()).collect::<Vec<_>>());
429
430 removed
431 }
432
433 fn remove_transactions_by_address(&mut self, sender: Address) -> Vec<Arc<PoolTransaction<T>>> {
435 let tx_hashes =
436 self.transactions_by_sender(sender).map(move |tx| tx.hash()).collect::<Vec<TxHash>>();
437
438 if tx_hashes.is_empty() {
439 return vec![];
440 }
441
442 trace!(target: "txpool", "Removing transactions: {:?}", tx_hashes);
443
444 let mut removed = self.ready_transactions.remove_with_markers(tx_hashes.clone(), None);
445 removed.extend(self.pending_transactions.remove(tx_hashes));
446
447 trace!(target: "txpool", "Removed transactions: {:?}", removed.iter().map(|tx| tx.hash()).collect::<Vec<_>>());
448
449 removed
450 }
451}
452
453impl<T: Clone> PoolInner<T> {
454 fn get_transaction(&self, hash: TxHash) -> Option<PendingTransaction<T>> {
458 if let Some(pending) = self.pending_transactions.get(&hash) {
459 return Some(pending.transaction.pending_transaction.clone());
460 }
461 Some(
462 self.ready_transactions.get(&hash)?.transaction.transaction.pending_transaction.clone(),
463 )
464 }
465}
466
467impl<T: Transaction> PoolInner<T> {
468 fn add_transaction(
469 &mut self,
470 tx: PoolTransaction<T>,
471 ) -> Result<AddedTransaction<T>, PoolError> {
472 if self.contains(&tx.hash()) {
473 debug!(target: "txpool", "[{:?}] Already imported", tx.hash());
474 return Err(PoolError::AlreadyImported(tx.hash()));
475 }
476
477 let tx = PendingPoolTransaction::new(tx, self.ready_transactions.provided_markers());
478 trace!(target: "txpool", "[{:?}] ready={}", tx.transaction.hash(), tx.is_ready());
479
480 if !tx.is_ready() {
482 let hash = tx.transaction.hash();
483 self.pending_transactions.add_transaction(tx)?;
484 return Ok(AddedTransaction::Pending { hash });
485 }
486 self.add_ready_transaction(tx)
487 }
488
489 fn add_ready_transaction(
491 &mut self,
492 tx: PendingPoolTransaction<T>,
493 ) -> Result<AddedTransaction<T>, PoolError> {
494 let hash = tx.transaction.hash();
495 trace!(target: "txpool", "adding ready transaction [{:?}]", hash);
496 let mut ready = ReadyTransaction::new(hash);
497
498 let mut tx_queue = VecDeque::from([tx]);
499 let mut is_new_tx = true;
501
502 while let Some(current_tx) = tx_queue.pop_front() {
504 tx_queue.extend(
506 self.pending_transactions.mark_and_unlock(¤t_tx.transaction.provides),
507 );
508
509 let current_hash = current_tx.transaction.hash();
510 match self.ready_transactions.add_transaction(current_tx) {
512 Ok(replaced_transactions) => {
513 if !is_new_tx {
514 ready.promoted.push(current_hash);
515 }
516 ready.removed.extend(replaced_transactions);
518 }
519 Err(err) => {
520 if is_new_tx {
522 debug!(target: "txpool", "[{:?}] Failed to add tx: {:?}", current_hash,
523 err);
524 return Err(err);
525 }
526 ready.discarded.push(current_hash);
527 }
528 }
529 is_new_tx = false;
530 }
531
532 if ready.removed.iter().any(|tx| *tx.hash() == hash) {
536 self.ready_transactions.clear_transactions(&ready.promoted);
537 return Err(PoolError::CyclicTransaction);
538 }
539
540 Ok(AddedTransaction::Ready(ready))
541 }
542
543 pub fn prune_markers(&mut self, markers: impl IntoIterator<Item = TxMarker>) -> PruneResult<T> {
548 let mut imports = vec![];
549 let mut pruned = vec![];
550
551 for marker in markers {
552 imports.extend(self.pending_transactions.mark_and_unlock(Some(&marker)));
554 pruned.extend(self.ready_transactions.prune_tags(marker.clone()));
556 }
557
558 let mut promoted = vec![];
559 let mut failed = vec![];
560 for tx in imports {
561 let hash = tx.transaction.hash();
562 match self.add_ready_transaction(tx) {
563 Ok(res) => promoted.push(res),
564 Err(e) => {
565 warn!(target: "txpool", "Failed to promote tx [{:?}] : {:?}", hash, e);
566 failed.push(hash)
567 }
568 }
569 }
570
571 PruneResult { pruned, failed, promoted }
572 }
573}
574
575pub struct PruneResult<T> {
577 pub promoted: Vec<AddedTransaction<T>>,
579 pub failed: Vec<TxHash>,
581 pub pruned: Vec<Arc<PoolTransaction<T>>>,
583}
584
585impl<T> fmt::Debug for PruneResult<T> {
586 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
587 write!(fmt, "PruneResult {{ ")?;
588 write!(
589 fmt,
590 "promoted: {:?}, ",
591 self.promoted.iter().map(|tx| *tx.hash()).collect::<Vec<_>>()
592 )?;
593 write!(fmt, "failed: {:?}, ", self.failed)?;
594 write!(
595 fmt,
596 "pruned: {:?}, ",
597 self.pruned.iter().map(|tx| *tx.pending_transaction.hash()).collect::<Vec<_>>()
598 )?;
599 write!(fmt, "}}")?;
600 Ok(())
601 }
602}
603
604#[derive(Clone, Debug)]
605pub struct ReadyTransaction<T> {
606 hash: TxHash,
608 promoted: Vec<TxHash>,
610 discarded: Vec<TxHash>,
612 removed: Vec<Arc<PoolTransaction<T>>>,
614}
615
616impl<T> ReadyTransaction<T> {
617 pub fn new(hash: TxHash) -> Self {
618 Self {
619 hash,
620 promoted: Default::default(),
621 discarded: Default::default(),
622 removed: Default::default(),
623 }
624 }
625}
626
627#[derive(Clone, Debug)]
628pub enum AddedTransaction<T> {
629 Ready(ReadyTransaction<T>),
631 Pending {
633 hash: TxHash,
635 },
636}
637
638impl<T> AddedTransaction<T> {
639 pub const fn hash(&self) -> &TxHash {
640 match self {
641 Self::Ready(tx) => &tx.hash,
642 Self::Pending { hash } => hash,
643 }
644 }
645}
646
647#[cfg(test)]
648mod tests {
649 use super::*;
650 use alloy_primitives::U256;
651 use futures::StreamExt;
652 use std::task::{Context, Poll, Waker};
653
654 #[test]
655 fn subscription_listener_closes_on_overflow_without_closing_ordinary_listener() {
656 let pool = Pool::<()>::default();
657 let mut ordinary = pool.add_ready_listener();
658 let mut subscription = pool.add_ready_subscription_listener();
659 let hashes = (0..4_096).map(|index| TxHash::from(U256::from(index))).collect::<Vec<_>>();
660
661 for &hash in &hashes {
663 pool.notify_listener(hash);
664 }
665
666 let mut cx = Context::from_waker(Waker::noop());
667 let mut expected = Vec::new();
668 while let Poll::Ready(Some(hash)) = ordinary.poll_next_unpin(&mut cx) {
669 expected.push(hash);
670 }
671 assert!(!expected.is_empty());
672 assert!(expected.len() < hashes.len());
673 assert_eq!(expected, hashes[..expected.len()]);
674 assert_eq!(ordinary.poll_next_unpin(&mut cx), Poll::Pending);
675
676 let mut received = Vec::new();
677 while let Poll::Ready(Some(hash)) = subscription.poll_next_unpin(&mut cx) {
678 received.push(hash);
679 }
680 assert_eq!(received, expected);
681 assert_eq!(subscription.poll_next_unpin(&mut cx), Poll::Ready(None));
682
683 let hash = TxHash::from(U256::MAX);
684 pool.notify_listener(hash);
685 assert_eq!(ordinary.poll_next_unpin(&mut cx), Poll::Ready(Some(hash)));
686 }
687}