1use crate::{
69 blobstore::{BlobStore, PooledBlobSidecar},
70 error::{PoolError, PoolErrorKind, PoolResult},
71 identifier::{SenderId, SenderIdentifiers, TransactionId},
72 metrics::BlobStoreMetrics,
73 pool::{
74 listener::{
75 BlobTransactionSidecarListener, PendingTransactionHashListener, PoolEventBroadcast,
76 TransactionListener,
77 },
78 state::SubPool,
79 txpool::{SenderInfo, TxPool},
80 update::UpdateOutcome,
81 },
82 traits::{
83 AllPoolTransactions, BestTransactionsAttributes, BlockInfo, GetPooledTransactionLimit,
84 NewBlobSidecar, PoolSize, PoolTransaction, PropagatedTransactions, TransactionOrigin,
85 },
86 validate::{TransactionValidationOutcome, ValidPoolTransaction, ValidTransaction},
87 CanonicalStateUpdate, EthPoolTransaction, PoolConfig, TransactionOrdering,
88 TransactionValidator,
89};
90
91use alloy_primitives::{
92 map::{AddressSet, HashSet},
93 Address, TxHash, B256,
94};
95use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
96use reth_eth_wire_types::HandleMempoolData;
97use reth_execution_types::ChangedAccount;
98
99use alloy_eips::{eip7594::BlobTransactionSidecarVariant, Typed2718};
100use reth_primitives_traits::Recovered;
101use rustc_hash::FxHashMap;
102use std::{
103 fmt,
104 sync::{
105 atomic::{AtomicBool, Ordering},
106 Arc,
107 },
108 time::Instant,
109};
110use tokio::sync::mpsc;
111use tracing::{debug, trace, warn};
112mod events;
113pub use best::{BestTransactionFilter, BestTransactionsWithPrioritizedSenders};
114pub use blob::{blob_tx_priority, fee_delta, BlobOrd, BlobTransactions};
115pub use events::{FullTransactionEvent, NewTransactionEvent, TransactionEvent};
116pub use listener::{AllTransactionsEvents, TransactionEvents, TransactionListenerKind};
117pub use parked::{BasefeeOrd, ParkedOrd, ParkedPool, QueuedOrd};
118pub use pending::PendingPool;
119
120mod best;
121pub use best::BestTransactions;
122
123mod blob;
124pub mod listener;
125mod parked;
126pub mod pending;
127pub mod size;
128pub(crate) mod state;
129pub mod txpool;
130mod update;
131
132pub const PENDING_TX_LISTENER_BUFFER_SIZE: usize = 2048;
134pub const NEW_TX_LISTENER_BUFFER_SIZE: usize = 1024;
136
137const BLOB_SIDECAR_LISTENER_BUFFER_SIZE: usize = 512;
138
139pub struct PoolInner<V, T, S>
141where
142 T: TransactionOrdering,
143{
144 identifiers: RwLock<SenderIdentifiers>,
146 validator: V,
148 blob_store: S,
150 pool: RwLock<TxPool<T>>,
152 config: PoolConfig,
154 event_listener: RwLock<PoolEventBroadcast<T::Transaction>>,
156 has_event_listeners: AtomicBool,
158 pending_transaction_listener: RwLock<Vec<PendingTransactionHashListener>>,
160 transaction_listener: RwLock<Vec<TransactionListener<T::Transaction>>>,
162 blob_transaction_sidecar_listener: Mutex<Vec<BlobTransactionSidecarListener>>,
164 blob_store_metrics: BlobStoreMetrics,
166}
167
168impl<V, T, S> PoolInner<V, T, S>
171where
172 V: TransactionValidator,
173 T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction>,
174 S: BlobStore,
175{
176 pub fn new(validator: V, ordering: T, blob_store: S, config: PoolConfig) -> Self {
178 Self {
179 identifiers: Default::default(),
180 validator,
181 event_listener: Default::default(),
182 has_event_listeners: AtomicBool::new(false),
183 pool: RwLock::new(TxPool::new(ordering, config.clone())),
184 pending_transaction_listener: Default::default(),
185 transaction_listener: Default::default(),
186 blob_transaction_sidecar_listener: Default::default(),
187 config,
188 blob_store,
189 blob_store_metrics: Default::default(),
190 }
191 }
192
193 pub const fn blob_store(&self) -> &S {
195 &self.blob_store
196 }
197
198 pub fn size(&self) -> PoolSize {
200 self.get_pool_data().size()
201 }
202
203 pub fn block_info(&self) -> BlockInfo {
205 self.get_pool_data().block_info()
206 }
207 pub fn set_block_info(&self, info: BlockInfo) {
212 let outcome = self.pool.write().set_block_info(info);
213
214 self.notify_on_transaction_updates(outcome.promoted, outcome.discarded);
216 }
217
218 pub fn get_sender_id(&self, addr: Address) -> SenderId {
225 self.identifiers.write().sender_id_or_create(addr)
226 }
227
228 pub fn sender_id(&self, addr: &Address) -> Option<SenderId> {
233 self.identifiers.read().sender_id(addr)
234 }
235
236 pub fn get_sender_ids(&self, addrs: impl IntoIterator<Item = Address>) -> Vec<SenderId> {
238 self.identifiers.write().sender_ids_or_create(addrs)
239 }
240
241 pub fn unique_senders(&self) -> AddressSet {
243 self.get_pool_data().unique_senders()
244 }
245
246 fn changed_senders(
249 &self,
250 accs: impl Iterator<Item = ChangedAccount>,
251 ) -> FxHashMap<SenderId, SenderInfo> {
252 let identifiers = self.identifiers.read();
253 accs.into_iter()
254 .filter_map(|acc| {
255 let ChangedAccount { address, nonce, balance } = acc;
256 let sender_id = identifiers.sender_id(&address)?;
257 Some((sender_id, SenderInfo { state_nonce: nonce, balance }))
258 })
259 .collect()
260 }
261
262 pub const fn config(&self) -> &PoolConfig {
264 &self.config
265 }
266
267 pub const fn validator(&self) -> &V {
269 &self.validator
270 }
271
272 pub fn add_pending_listener(&self, kind: TransactionListenerKind) -> mpsc::Receiver<TxHash> {
275 let (sender, rx) = mpsc::channel(self.config.pending_tx_listener_buffer_size);
276 let listener = PendingTransactionHashListener { sender, kind };
277
278 let mut listeners = self.pending_transaction_listener.write();
279 listeners.retain(|l| !l.sender.is_closed());
281 listeners.push(listener);
282
283 rx
284 }
285
286 pub fn add_new_transaction_listener(
288 &self,
289 kind: TransactionListenerKind,
290 ) -> mpsc::Receiver<NewTransactionEvent<T::Transaction>> {
291 let (sender, rx) = mpsc::channel(self.config.new_tx_listener_buffer_size);
292 let listener = TransactionListener { sender, kind };
293
294 let mut listeners = self.transaction_listener.write();
295 listeners.retain(|l| !l.sender.is_closed());
297 listeners.push(listener);
298
299 rx
300 }
301 pub fn add_blob_sidecar_listener(&self) -> mpsc::Receiver<NewBlobSidecar> {
304 let (sender, rx) = mpsc::channel(BLOB_SIDECAR_LISTENER_BUFFER_SIZE);
305 let listener = BlobTransactionSidecarListener { sender };
306 self.blob_transaction_sidecar_listener.lock().push(listener);
307 rx
308 }
309
310 pub fn add_transaction_event_listener(&self, tx_hash: TxHash) -> Option<TransactionEvents> {
313 if !self.get_pool_data().contains(&tx_hash) {
314 return None
315 }
316 let mut listener = self.event_listener.write();
317 let events = listener.subscribe(tx_hash);
318 self.mark_event_listener_installed();
319 Some(events)
320 }
321
322 pub fn add_all_transactions_event_listener(&self) -> AllTransactionsEvents<T::Transaction> {
324 let mut listener = self.event_listener.write();
325 let events = listener.subscribe_all();
326 self.mark_event_listener_installed();
327 events
328 }
329
330 #[inline]
331 fn has_event_listeners(&self) -> bool {
332 self.has_event_listeners.load(Ordering::Relaxed)
333 }
334
335 #[inline]
336 fn mark_event_listener_installed(&self) {
337 self.has_event_listeners.store(true, Ordering::Relaxed);
338 }
339
340 #[inline]
341 fn update_event_listener_state(&self, listener: &PoolEventBroadcast<T::Transaction>) {
342 if listener.is_empty() {
343 self.has_event_listeners.store(false, Ordering::Relaxed);
344 }
345 }
346
347 #[inline]
348 fn with_event_listener<F>(&self, emit: F)
349 where
350 F: FnOnce(&mut PoolEventBroadcast<T::Transaction>),
351 {
352 if !self.has_event_listeners() {
353 return
354 }
355 let mut listener = self.event_listener.write();
356 if !listener.is_empty() {
357 emit(&mut listener);
358 }
359 self.update_event_listener_state(&listener);
360 }
361
362 pub fn get_pool_data(&self) -> RwLockReadGuard<'_, TxPool<T>> {
364 self.pool.read()
365 }
366
367 pub fn pooled_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
369 let mut out = Vec::new();
370 self.append_pooled_transactions(&mut out);
371 out
372 }
373
374 pub fn pooled_transactions_hashes(&self) -> Vec<TxHash> {
376 let mut out = Vec::new();
377 self.append_pooled_transactions_hashes(&mut out);
378 out
379 }
380
381 pub fn pooled_transactions_max(
383 &self,
384 max: usize,
385 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
386 if max == 0 {
387 return Vec::new()
388 }
389
390 let pool = self.get_pool_data();
391 let mut out = Vec::with_capacity(max.min(pool.all().len()));
392 out.extend(pool.all().transactions_iter().filter(|tx| tx.propagate).take(max).cloned());
393 out
394 }
395
396 pub fn append_pooled_transactions(
398 &self,
399 out: &mut Vec<Arc<ValidPoolTransaction<T::Transaction>>>,
400 ) {
401 out.extend(
402 self.get_pool_data().all().transactions_iter().filter(|tx| tx.propagate).cloned(),
403 );
404 }
405
406 pub fn append_pooled_transaction_elements(
409 &self,
410 tx_hashes: &[TxHash],
411 limit: GetPooledTransactionLimit,
412 out: &mut Vec<<<V as TransactionValidator>::Transaction as PoolTransaction>::Pooled>,
413 ) where
414 <V as TransactionValidator>::Transaction: EthPoolTransaction,
415 {
416 let transactions = self.get_all_propagatable(tx_hashes);
417 let mut size = 0;
418 for transaction in transactions {
419 let encoded_len = transaction.encoded_length();
420 let Some(pooled) = self.to_pooled_transaction(transaction) else {
421 continue;
422 };
423
424 size += encoded_len;
425 out.push(pooled.into_inner());
426
427 if limit.exceeds(size) {
428 break
429 }
430 }
431 }
432
433 pub fn append_pooled_transactions_hashes(&self, out: &mut Vec<TxHash>) {
436 out.extend(
437 self.get_pool_data()
438 .all()
439 .transactions_iter()
440 .filter(|tx| tx.propagate)
441 .map(|tx| *tx.hash()),
442 );
443 }
444
445 pub fn append_pooled_transactions_max(
448 &self,
449 max: usize,
450 out: &mut Vec<Arc<ValidPoolTransaction<T::Transaction>>>,
451 ) {
452 out.extend(
453 self.get_pool_data()
454 .all()
455 .transactions_iter()
456 .filter(|tx| tx.propagate)
457 .take(max)
458 .cloned(),
459 );
460 }
461
462 pub fn pooled_transactions_hashes_max(&self, max: usize) -> Vec<TxHash> {
464 if max == 0 {
465 return Vec::new();
466 }
467
468 let pool = self.get_pool_data();
469 let mut out = Vec::with_capacity(max.min(pool.all().len()));
470 out.extend(
471 pool.all().transactions_iter().filter(|tx| tx.propagate).take(max).map(|tx| *tx.hash()),
472 );
473 out
474 }
475
476 fn to_pooled_transaction(
481 &self,
482 transaction: Arc<ValidPoolTransaction<T::Transaction>>,
483 ) -> Option<Recovered<<<V as TransactionValidator>::Transaction as PoolTransaction>::Pooled>>
484 where
485 <V as TransactionValidator>::Transaction: EthPoolTransaction,
486 {
487 if transaction.is_eip4844() {
488 let sidecar = self.blob_store.get(*transaction.hash()).ok()??;
489 transaction.transaction.clone().try_into_pooled_eip4844(sidecar)
490 } else {
491 transaction
492 .transaction
493 .clone_into_pooled()
494 .inspect_err(|err| {
495 debug!(
496 target: "txpool", %err,
497 "failed to convert transaction to pooled element; skipping",
498 );
499 })
500 .ok()
501 }
502 }
503
504 pub fn get_pooled_transaction_elements(
507 &self,
508 tx_hashes: Vec<TxHash>,
509 limit: GetPooledTransactionLimit,
510 ) -> Vec<<<V as TransactionValidator>::Transaction as PoolTransaction>::Pooled>
511 where
512 <V as TransactionValidator>::Transaction: EthPoolTransaction,
513 {
514 let mut elements = Vec::new();
515 self.append_pooled_transaction_elements(&tx_hashes, limit, &mut elements);
516 elements.shrink_to_fit();
517 elements
518 }
519
520 pub fn get_pooled_transaction_element(
522 &self,
523 tx_hash: TxHash,
524 ) -> Option<Recovered<<<V as TransactionValidator>::Transaction as PoolTransaction>::Pooled>>
525 where
526 <V as TransactionValidator>::Transaction: EthPoolTransaction,
527 {
528 self.get(&tx_hash).and_then(|tx| self.to_pooled_transaction(tx))
529 }
530
531 pub fn on_canonical_state_change(&self, update: CanonicalStateUpdate<'_, V::Block>) {
533 trace!(target: "txpool", ?update, "updating pool on canonical state change");
534
535 let block_info = update.block_info();
536 let CanonicalStateUpdate {
537 new_tip, changed_accounts, mined_transactions, update_kind, ..
538 } = update;
539 self.validator.on_new_head_block(new_tip);
540
541 let changed_senders = self.changed_senders(changed_accounts.into_iter());
542
543 let outcome = self.pool.write().on_canonical_state_change(
545 block_info,
546 mined_transactions,
547 changed_senders,
548 update_kind,
549 );
550
551 self.delete_discarded_blobs(outcome.discarded.iter());
553
554 self.notify_on_new_state(outcome);
556 }
557
558 pub fn update_accounts(&self, accounts: Vec<ChangedAccount>) {
564 let changed_senders = self.changed_senders(accounts.into_iter());
565 let UpdateOutcome { promoted, discarded } =
566 self.pool.write().update_accounts(changed_senders);
567
568 self.notify_on_transaction_updates(promoted, discarded);
569 }
570
571 fn add_transaction(
579 &self,
580 pool: &mut RwLockWriteGuard<'_, TxPool<T>>,
581 origin: TransactionOrigin,
582 tx: TransactionValidationOutcome<T::Transaction>,
583 timestamp: Instant,
584 ) -> (PoolResult<AddedTransactionOutcome>, Option<AddedTransactionMeta<T::Transaction>>) {
585 match tx {
586 TransactionValidationOutcome::Valid {
587 balance,
588 state_nonce,
589 transaction,
590 propagate,
591 bytecode_hash,
592 authorities,
593 } => {
594 let sender_id = self.get_sender_id(transaction.sender());
595 let transaction_id = TransactionId::new(sender_id, transaction.nonce());
596
597 let (transaction, blob_sidecar) = match transaction {
599 ValidTransaction::Valid(tx) => (tx, None),
600 ValidTransaction::ValidWithSidecar { transaction, sidecar } => {
601 debug_assert!(
602 transaction.is_eip4844(),
603 "validator returned sidecar for non EIP-4844 transaction"
604 );
605 (transaction, Some(sidecar))
606 }
607 };
608
609 let tx = ValidPoolTransaction {
610 transaction,
611 transaction_id,
612 propagate,
613 timestamp,
614 origin,
615 authority_ids: authorities.map(|auths| self.get_sender_ids(auths)),
616 };
617
618 let added = match pool.add_transaction(tx, balance, state_nonce, bytecode_hash) {
619 Ok(added) => added,
620 Err(err) => return (Err(err), None),
621 };
622 let hash = *added.hash();
623 let state = added.transaction_state();
624
625 let meta = AddedTransactionMeta { added, blob_sidecar };
626
627 (Ok(AddedTransactionOutcome { hash, state }), Some(meta))
628 }
629 TransactionValidationOutcome::Invalid(tx, err) => {
630 self.with_event_listener(|listener| listener.invalid(tx.hash()));
631 (Err(PoolError::new(*tx.hash(), err)), None)
632 }
633 TransactionValidationOutcome::Error(tx_hash, err) => {
634 self.with_event_listener(|listener| listener.discarded(&tx_hash));
635 (Err(PoolError::other(tx_hash, err)), None)
636 }
637 }
638 }
639
640 pub fn add_transaction_and_subscribe(
642 &self,
643 origin: TransactionOrigin,
644 tx: TransactionValidationOutcome<T::Transaction>,
645 ) -> PoolResult<TransactionEvents> {
646 let listener = {
647 let mut listener = self.event_listener.write();
648 let events = listener.subscribe(tx.tx_hash());
649 self.mark_event_listener_installed();
650 events
651 };
652 let mut results = self.add_transactions(origin, std::iter::once(tx));
653 results.pop().expect("result length is the same as the input")?;
654 Ok(listener)
655 }
656
657 pub fn add_transactions(
662 &self,
663 origin: TransactionOrigin,
664 transactions: impl IntoIterator<Item = TransactionValidationOutcome<T::Transaction>>,
665 ) -> Vec<PoolResult<AddedTransactionOutcome>> {
666 self.add_transactions_with_origins(transactions.into_iter().map(|tx| (origin, tx)))
667 }
668
669 pub fn add_transactions_with_origins(
672 &self,
673 transactions: impl IntoIterator<
674 Item = (TransactionOrigin, TransactionValidationOutcome<T::Transaction>),
675 >,
676 ) -> Vec<PoolResult<AddedTransactionOutcome>> {
677 let transactions = transactions.into_iter();
678 let mut added_metas = Vec::with_capacity(transactions.size_hint().0);
679
680 let (mut results, added_metas, discarded) = {
682 let mut pool = self.pool.write();
683 let timestamp = Instant::now();
684
685 let results = transactions
686 .map(|(origin, tx)| {
687 let (result, meta) = self.add_transaction(&mut pool, origin, tx, timestamp);
688
689 if result.is_ok() &&
691 let Some(meta) = meta
692 {
693 added_metas.push(meta);
694 }
695
696 result
697 })
698 .collect::<Vec<_>>();
699
700 let discarded = if results.iter().any(Result::is_ok) {
702 let discarded = pool.discard_worst();
703 pool.update_size_metrics();
704 discarded
705 } else {
706 Default::default()
707 };
708
709 (results, added_metas, discarded)
710 };
711
712 for meta in added_metas {
713 self.on_added_transaction(meta);
714 }
715
716 if !discarded.is_empty() {
717 self.delete_discarded_blobs(discarded.iter());
719 self.with_event_listener(|listener| listener.discarded_many(&discarded));
720
721 const MAX_LINEAR_SEARCH_DISCARDS: usize = 4;
723 let discarded_hashes = (discarded.len() > MAX_LINEAR_SEARCH_DISCARDS)
724 .then(|| discarded.iter().map(|tx| *tx.hash()).collect::<HashSet<_>>());
725 let is_discarded = |hash: &TxHash| match &discarded_hashes {
726 Some(hashes) => hashes.contains(hash),
727 None => discarded.iter().any(|tx| tx.hash() == hash),
728 };
729
730 for res in &mut results {
733 if let Ok(AddedTransactionOutcome { hash, .. }) = res &&
734 is_discarded(hash)
735 {
736 *res = Err(PoolError::new(*hash, PoolErrorKind::DiscardedOnInsert))
737 }
738 }
739 };
740
741 results
742 }
743
744 fn on_added_transaction(&self, mut meta: AddedTransactionMeta<T::Transaction>) {
749 if let Some(sidecar) = meta.blob_sidecar {
751 let hash = *meta.added.hash();
752 self.on_new_blob_sidecar(&hash, &sidecar);
753 self.insert_blob(hash, sidecar);
754 }
755
756 if let Some(replaced) = meta.added.replaced_blob_transaction() {
758 debug!(target: "txpool", "[{:?}] delete replaced blob sidecar", replaced);
759 self.delete_blob(replaced);
760 }
761
762 if let Some(discarded) = meta.added.discarded_transactions() {
764 self.delete_discarded_blobs(discarded.iter());
765 }
766
767 if let Some(pending) = meta.added.as_pending() {
769 self.on_new_pending_transaction(pending);
770 }
771
772 let promoted = meta.added.take_parked_promoted();
775 if !promoted.is_empty() {
776 self.notify_on_transaction_updates(promoted, Vec::new());
777 }
778
779 self.notify_event_listeners(&meta.added);
781
782 self.on_new_transaction(meta.added.into_new_transaction_event());
784 }
785
786 pub fn on_new_pending_transaction(&self, pending: &AddedPendingTransaction<T::Transaction>) {
795 let mut needs_cleanup = false;
796
797 {
798 let listeners = self.pending_transaction_listener.read();
799 for listener in listeners.iter() {
800 if !listener.send_all(pending.pending_transactions(listener.kind)) {
801 needs_cleanup = true;
802 }
803 }
804 }
805
806 if needs_cleanup {
808 self.pending_transaction_listener
809 .write()
810 .retain(|listener| !listener.sender.is_closed());
811 }
812 }
813
814 pub fn on_new_transaction(&self, event: NewTransactionEvent<T::Transaction>) {
823 let mut needs_cleanup = false;
824
825 {
826 let listeners = self.transaction_listener.read();
827 for listener in listeners.iter() {
828 if listener.kind.is_propagate_only() && !event.transaction.propagate {
829 if listener.sender.is_closed() {
830 needs_cleanup = true;
831 }
832 continue
834 }
835
836 if !listener.send(event.clone()) {
837 needs_cleanup = true;
838 }
839 }
840 }
841
842 if needs_cleanup {
844 self.transaction_listener.write().retain(|listener| !listener.sender.is_closed());
845 }
846 }
847
848 fn on_new_blob_sidecar(&self, tx_hash: &TxHash, sidecar: &BlobTransactionSidecarVariant) {
850 let mut sidecar_listeners = self.blob_transaction_sidecar_listener.lock();
851 if sidecar_listeners.is_empty() {
852 return
853 }
854 let sidecar = Arc::new(sidecar.clone());
855 sidecar_listeners.retain_mut(|listener| {
856 let new_blob_event = NewBlobSidecar { tx_hash: *tx_hash, sidecar: sidecar.clone() };
857 match listener.sender.try_send(new_blob_event) {
858 Ok(()) => true,
859 Err(err) => {
860 if matches!(err, mpsc::error::TrySendError::Full(_)) {
861 debug!(
862 target: "txpool",
863 "[{:?}] failed to send blob sidecar; channel full",
864 sidecar,
865 );
866 true
867 } else {
868 false
869 }
870 }
871 }
872 })
873 }
874
875 fn notify_on_new_state(&self, outcome: OnNewCanonicalStateOutcome<T::Transaction>) {
877 trace!(target: "txpool", promoted=outcome.promoted.len(), discarded= outcome.discarded.len() ,"notifying listeners on state change");
878
879 let mut needs_pending_cleanup = false;
881 {
882 let listeners = self.pending_transaction_listener.read();
883 for listener in listeners.iter() {
884 if !listener.send_all(outcome.pending_transactions(listener.kind)) {
885 needs_pending_cleanup = true;
886 }
887 }
888 }
889 if needs_pending_cleanup {
890 self.pending_transaction_listener.write().retain(|l| !l.sender.is_closed());
891 }
892
893 let mut needs_tx_cleanup = false;
895 {
896 let listeners = self.transaction_listener.read();
897 for listener in listeners.iter() {
898 if !listener.send_all(outcome.full_pending_transactions(listener.kind)) {
899 needs_tx_cleanup = true;
900 }
901 }
902 }
903 if needs_tx_cleanup {
904 self.transaction_listener.write().retain(|l| !l.sender.is_closed());
905 }
906
907 let OnNewCanonicalStateOutcome { mined, promoted, discarded, block_hash } = outcome;
908
909 self.with_event_listener(|listener| {
911 for tx in &mined {
912 listener.mined(tx, block_hash);
913 }
914 for tx in &promoted {
915 listener.pending(tx.hash(), None);
916 }
917 for tx in &discarded {
918 listener.discarded(tx.hash());
919 }
920 })
921 }
922
923 pub fn notify_on_transaction_updates(
932 &self,
933 promoted: Vec<Arc<ValidPoolTransaction<T::Transaction>>>,
934 discarded: Vec<Arc<ValidPoolTransaction<T::Transaction>>>,
935 ) {
936 if !promoted.is_empty() {
938 let mut needs_pending_cleanup = false;
939 {
940 let listeners = self.pending_transaction_listener.read();
941 for listener in listeners.iter() {
942 let promoted_hashes = promoted.iter().filter_map(|tx| {
943 if listener.kind.is_propagate_only() && !tx.propagate {
944 None
945 } else {
946 Some(*tx.hash())
947 }
948 });
949 if !listener.send_all(promoted_hashes) {
950 needs_pending_cleanup = true;
951 }
952 }
953 }
954 if needs_pending_cleanup {
955 self.pending_transaction_listener.write().retain(|l| !l.sender.is_closed());
956 }
957
958 let mut needs_tx_cleanup = false;
960 {
961 let listeners = self.transaction_listener.read();
962 for listener in listeners.iter() {
963 let promoted_txs = promoted.iter().filter_map(|tx| {
964 if listener.kind.is_propagate_only() && !tx.propagate {
965 None
966 } else {
967 Some(NewTransactionEvent::pending(tx.clone()))
968 }
969 });
970 if !listener.send_all(promoted_txs) {
971 needs_tx_cleanup = true;
972 }
973 }
974 }
975 if needs_tx_cleanup {
976 self.transaction_listener.write().retain(|l| !l.sender.is_closed());
977 }
978 }
979
980 self.with_event_listener(|listener| {
981 for tx in &promoted {
982 listener.pending(tx.hash(), None);
983 }
984 for tx in &discarded {
985 listener.discarded(tx.hash());
986 }
987 });
988
989 if !discarded.is_empty() {
990 self.delete_discarded_blobs(discarded.iter());
993 }
994 }
995
996 pub fn notify_event_listeners(&self, tx: &AddedTransaction<T::Transaction>) {
1005 self.with_event_listener(|listener| match tx {
1006 AddedTransaction::Pending(tx) => {
1007 let AddedPendingTransaction { transaction, promoted, discarded, replaced } = tx;
1008
1009 listener.pending(transaction.hash(), replaced.clone());
1010 for tx in promoted {
1011 listener.pending(tx.hash(), None);
1012 }
1013 for tx in discarded {
1014 listener.discarded(tx.hash());
1015 }
1016 }
1017 AddedTransaction::Parked { transaction, replaced, queued_reason, .. } => {
1018 listener.queued(transaction.hash(), queued_reason.clone());
1019 if let Some(replaced) = replaced {
1020 listener.replaced(replaced.clone(), *transaction.hash());
1021 }
1022 }
1023 });
1024 }
1025
1026 pub fn best_transactions(&self) -> BestTransactions<T> {
1028 self.get_pool_data().best_transactions()
1029 }
1030
1031 pub fn best_transactions_with_attributes(
1034 &self,
1035 best_transactions_attributes: BestTransactionsAttributes,
1036 ) -> Box<dyn crate::traits::BestTransactions<Item = Arc<ValidPoolTransaction<T::Transaction>>>>
1037 {
1038 self.get_pool_data().best_transactions_with_attributes(best_transactions_attributes)
1039 }
1040
1041 pub fn pending_transactions_max(
1043 &self,
1044 max: usize,
1045 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1046 self.get_pool_data().pending_transactions_iter().take(max).collect()
1047 }
1048
1049 pub fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1051 self.get_pool_data().pending_transactions()
1052 }
1053
1054 pub fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1056 self.get_pool_data().queued_transactions()
1057 }
1058
1059 pub fn all_transactions(&self) -> AllPoolTransactions<T::Transaction> {
1061 let pool = self.get_pool_data();
1062 AllPoolTransactions {
1063 pending: pool.pending_transactions(),
1064 queued: pool.queued_transactions(),
1065 }
1066 }
1067
1068 pub fn all_transactions_by_sender(
1071 &self,
1072 sender: Address,
1073 ) -> AllPoolTransactions<T::Transaction> {
1074 let Some(sender_id) = self.sender_id(&sender) else { return Default::default() };
1075 let pool = self.get_pool_data();
1076 AllPoolTransactions {
1077 pending: pool.pending_txs_by_sender(sender_id),
1078 queued: pool.queued_txs_by_sender(sender_id),
1079 }
1080 }
1081
1082 pub fn all_transaction_hashes(&self) -> Vec<TxHash> {
1084 self.get_pool_data().all().transactions_iter().map(|tx| *tx.hash()).collect()
1085 }
1086
1087 pub fn remove_transactions(
1092 &self,
1093 hashes: Vec<TxHash>,
1094 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1095 if hashes.is_empty() {
1096 return Vec::new()
1097 }
1098 let removed = self.pool.write().remove_transactions(hashes);
1099
1100 self.with_event_listener(|listener| listener.discarded_many(&removed));
1101
1102 removed
1103 }
1104
1105 pub fn remove_transactions_and_descendants(
1108 &self,
1109 hashes: Vec<TxHash>,
1110 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1111 if hashes.is_empty() {
1112 return Vec::new()
1113 }
1114 let removed = self.pool.write().remove_transactions_and_descendants(hashes);
1115
1116 self.with_event_listener(|listener| {
1117 for tx in &removed {
1118 listener.discarded(tx.hash());
1119 }
1120 });
1121
1122 removed
1123 }
1124
1125 pub fn remove_transactions_by_sender(
1127 &self,
1128 sender: Address,
1129 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1130 let Some(sender_id) = self.sender_id(&sender) else { return Vec::new() };
1131 let removed = self.pool.write().remove_transactions_by_sender(sender_id);
1132
1133 self.with_event_listener(|listener| listener.discarded_many(&removed));
1134
1135 removed
1136 }
1137
1138 pub fn prune_transactions(
1143 &self,
1144 hashes: Vec<TxHash>,
1145 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1146 if hashes.is_empty() {
1147 return Vec::new()
1148 }
1149
1150 self.pool.write().prune_transactions(hashes)
1151 }
1152
1153 pub fn retain_unknown<A>(&self, announcement: &mut A)
1155 where
1156 A: HandleMempoolData,
1157 {
1158 if announcement.is_empty() {
1159 return
1160 }
1161 let pool = self.get_pool_data();
1162 announcement.retain_by_hash(|tx| !pool.contains(tx))
1163 }
1164
1165 pub fn retain_contains<A>(&self, announcement: &mut A)
1167 where
1168 A: HandleMempoolData,
1169 {
1170 if announcement.is_empty() {
1171 return
1172 }
1173 let pool = self.get_pool_data();
1174 announcement.retain_by_hash(|tx| pool.contains(tx))
1175 }
1176
1177 pub fn get(&self, tx_hash: &TxHash) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
1179 self.get_pool_data().get(tx_hash)
1180 }
1181
1182 pub fn get_transactions_by_sender(
1184 &self,
1185 sender: Address,
1186 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1187 let Some(sender_id) = self.sender_id(&sender) else { return Vec::new() };
1188 self.get_pool_data().get_transactions_by_sender(sender_id)
1189 }
1190
1191 pub fn get_pending_transaction_by_sender_and_nonce(
1193 &self,
1194 sender: Address,
1195 nonce: u64,
1196 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
1197 let sender_id = self.sender_id(&sender)?;
1198 self.get_pool_data().get_pending_transaction_by_sender_and_nonce(sender_id, nonce)
1199 }
1200
1201 pub fn get_queued_transactions_by_sender(
1203 &self,
1204 sender: Address,
1205 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1206 let Some(sender_id) = self.sender_id(&sender) else { return Vec::new() };
1207 self.get_pool_data().queued_txs_by_sender(sender_id)
1208 }
1209
1210 pub fn pending_transactions_with_predicate(
1212 &self,
1213 predicate: impl FnMut(&ValidPoolTransaction<T::Transaction>) -> bool,
1214 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1215 self.get_pool_data().pending_transactions_with_predicate(predicate)
1216 }
1217
1218 pub fn get_pending_transactions_by_sender(
1220 &self,
1221 sender: Address,
1222 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1223 let Some(sender_id) = self.sender_id(&sender) else { return Vec::new() };
1224 self.get_pending_transactions_by_sender_id(sender_id)
1225 }
1226
1227 pub fn get_pending_transactions_by_sender_id(
1229 &self,
1230 sender_id: SenderId,
1231 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1232 self.get_pool_data().pending_txs_by_sender(sender_id)
1233 }
1234
1235 pub fn get_highest_transaction_by_sender(
1237 &self,
1238 sender: Address,
1239 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
1240 let sender_id = self.sender_id(&sender)?;
1241 self.get_highest_transaction_by_sender_id(sender_id)
1242 }
1243
1244 pub fn get_highest_transaction_by_sender_id(
1246 &self,
1247 sender_id: SenderId,
1248 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
1249 self.get_pool_data().get_highest_transaction_by_sender(sender_id)
1250 }
1251
1252 pub fn get_highest_consecutive_transaction_by_sender(
1254 &self,
1255 sender: Address,
1256 on_chain_nonce: u64,
1257 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
1258 let sender_id = self.sender_id(&sender)?;
1259 self.get_highest_consecutive_transaction_by_sender_id(sender_id, on_chain_nonce)
1260 }
1261
1262 pub fn get_highest_consecutive_transaction_by_sender_id(
1264 &self,
1265 sender_id: SenderId,
1266 on_chain_nonce: u64,
1267 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
1268 self.get_pool_data().get_highest_consecutive_transaction_by_sender(
1269 sender_id.into_transaction_id(on_chain_nonce),
1270 )
1271 }
1272
1273 pub fn get_transaction_by_transaction_id(
1275 &self,
1276 transaction_id: &TransactionId,
1277 ) -> Option<Arc<ValidPoolTransaction<T::Transaction>>> {
1278 self.get_pool_data().all().get(transaction_id).map(|tx| tx.transaction.clone())
1279 }
1280
1281 pub fn get_transactions_by_origin(
1283 &self,
1284 origin: TransactionOrigin,
1285 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1286 self.get_pool_data()
1287 .all()
1288 .transactions_iter()
1289 .filter(|tx| tx.origin == origin)
1290 .cloned()
1291 .collect()
1292 }
1293
1294 pub fn get_pending_transactions_by_origin(
1296 &self,
1297 origin: TransactionOrigin,
1298 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1299 self.get_pool_data().pending_transactions_iter().filter(|tx| tx.origin == origin).collect()
1300 }
1301
1302 pub fn get_all(&self, txs: Vec<TxHash>) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1306 if txs.is_empty() {
1307 return Vec::new()
1308 }
1309 self.get_pool_data().get_all(txs).collect()
1310 }
1311
1312 fn get_all_propagatable(
1316 &self,
1317 txs: &[TxHash],
1318 ) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
1319 if txs.is_empty() {
1320 return Vec::new()
1321 }
1322 let pool = self.get_pool_data();
1323 txs.iter().filter_map(|tx| pool.get(tx).filter(|tx| tx.propagate)).collect()
1324 }
1325
1326 pub fn on_propagated(&self, txs: PropagatedTransactions) {
1328 if txs.is_empty() {
1329 return
1330 }
1331 self.with_event_listener(|listener| {
1332 txs.into_iter().for_each(|(hash, peers)| listener.propagated(&hash, peers));
1333 });
1334 }
1335
1336 pub fn len(&self) -> usize {
1338 self.get_pool_data().len()
1339 }
1340
1341 pub fn is_empty(&self) -> bool {
1343 self.get_pool_data().is_empty()
1344 }
1345
1346 pub fn is_exceeded(&self) -> bool {
1348 self.pool.read().is_exceeded()
1349 }
1350
1351 fn insert_blob(&self, hash: TxHash, blob: PooledBlobSidecar) {
1353 debug!(target: "txpool", "[{:?}] storing blob sidecar", hash);
1354 if let Err(err) = self.blob_store.insert(hash, blob) {
1355 warn!(target: "txpool", %err, "[{:?}] failed to insert blob", hash);
1356 self.blob_store_metrics.blobstore_failed_inserts.increment(1);
1357 }
1358 self.update_blob_store_metrics();
1359 }
1360
1361 pub fn delete_blob(&self, blob: TxHash) {
1363 let _ = self.blob_store.delete(blob);
1364 }
1365
1366 pub fn delete_blobs(&self, txs: Vec<TxHash>) {
1368 let _ = self.blob_store.delete_all(txs);
1369 }
1370
1371 pub fn cleanup_blobs(&self) {
1373 let stat = self.blob_store.cleanup();
1374 self.blob_store_metrics.blobstore_failed_deletes.increment(stat.delete_failed as u64);
1375 self.update_blob_store_metrics();
1376 }
1377
1378 fn update_blob_store_metrics(&self) {
1379 if let Some(data_size) = self.blob_store.data_size_hint() {
1380 self.blob_store_metrics.blobstore_byte_size.set(data_size as f64);
1381 }
1382 self.blob_store_metrics.blobstore_entries.set(self.blob_store.blobs_len() as f64);
1383 }
1384
1385 fn delete_discarded_blobs<'a>(
1387 &'a self,
1388 transactions: impl IntoIterator<Item = &'a Arc<ValidPoolTransaction<T::Transaction>>>,
1389 ) {
1390 let blob_txs = transactions
1391 .into_iter()
1392 .filter(|tx| tx.transaction.is_eip4844())
1393 .map(|tx| *tx.hash())
1394 .collect();
1395 self.delete_blobs(blob_txs);
1396 }
1397}
1398
1399impl<V, T: TransactionOrdering, S> fmt::Debug for PoolInner<V, T, S> {
1400 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1401 f.debug_struct("PoolInner").field("config", &self.config).finish_non_exhaustive()
1402 }
1403}
1404
1405#[derive(Debug)]
1410struct AddedTransactionMeta<T: PoolTransaction> {
1411 added: AddedTransaction<T>,
1413 blob_sidecar: Option<PooledBlobSidecar>,
1415}
1416
1417#[derive(Debug, Clone)]
1419pub struct AddedPendingTransaction<T: PoolTransaction> {
1420 pub transaction: Arc<ValidPoolTransaction<T>>,
1422 pub replaced: Option<Arc<ValidPoolTransaction<T>>>,
1424 pub promoted: Vec<Arc<ValidPoolTransaction<T>>>,
1426 pub discarded: Vec<Arc<ValidPoolTransaction<T>>>,
1428}
1429
1430impl<T: PoolTransaction> AddedPendingTransaction<T> {
1431 pub(crate) fn pending_transactions(
1437 &self,
1438 kind: TransactionListenerKind,
1439 ) -> impl Iterator<Item = B256> + '_ {
1440 let iter = std::iter::once(&self.transaction).chain(self.promoted.iter());
1441 PendingTransactionIter { kind, iter }
1442 }
1443}
1444
1445pub(crate) struct PendingTransactionIter<Iter> {
1446 kind: TransactionListenerKind,
1447 iter: Iter,
1448}
1449
1450impl<'a, Iter, T> Iterator for PendingTransactionIter<Iter>
1451where
1452 Iter: Iterator<Item = &'a Arc<ValidPoolTransaction<T>>>,
1453 T: PoolTransaction + 'a,
1454{
1455 type Item = B256;
1456
1457 fn next(&mut self) -> Option<Self::Item> {
1458 loop {
1459 let next = self.iter.next()?;
1460 if self.kind.is_propagate_only() && !next.propagate {
1461 continue
1462 }
1463 return Some(*next.hash())
1464 }
1465 }
1466}
1467
1468pub(crate) struct FullPendingTransactionIter<Iter> {
1470 kind: TransactionListenerKind,
1471 iter: Iter,
1472}
1473
1474impl<'a, Iter, T> Iterator for FullPendingTransactionIter<Iter>
1475where
1476 Iter: Iterator<Item = &'a Arc<ValidPoolTransaction<T>>>,
1477 T: PoolTransaction + 'a,
1478{
1479 type Item = NewTransactionEvent<T>;
1480
1481 fn next(&mut self) -> Option<Self::Item> {
1482 loop {
1483 let next = self.iter.next()?;
1484 if self.kind.is_propagate_only() && !next.propagate {
1485 continue
1486 }
1487 return Some(NewTransactionEvent {
1488 subpool: SubPool::Pending,
1489 transaction: next.clone(),
1490 })
1491 }
1492 }
1493}
1494
1495#[derive(Debug, Clone)]
1497pub enum AddedTransaction<T: PoolTransaction> {
1498 Pending(AddedPendingTransaction<T>),
1500 Parked {
1503 transaction: Arc<ValidPoolTransaction<T>>,
1505 replaced: Option<Arc<ValidPoolTransaction<T>>>,
1507 subpool: SubPool,
1509 queued_reason: Option<QueuedReason>,
1511 promoted: Vec<Arc<ValidPoolTransaction<T>>>,
1517 },
1518}
1519
1520impl<T: PoolTransaction> AddedTransaction<T> {
1521 pub const fn as_pending(&self) -> Option<&AddedPendingTransaction<T>> {
1523 match self {
1524 Self::Pending(tx) => Some(tx),
1525 _ => None,
1526 }
1527 }
1528
1529 pub const fn replaced(&self) -> Option<&Arc<ValidPoolTransaction<T>>> {
1531 match self {
1532 Self::Pending(tx) => tx.replaced.as_ref(),
1533 Self::Parked { replaced, .. } => replaced.as_ref(),
1534 }
1535 }
1536
1537 pub(crate) fn take_parked_promoted(&mut self) -> Vec<Arc<ValidPoolTransaction<T>>> {
1542 match self {
1543 Self::Parked { promoted, .. } => std::mem::take(promoted),
1544 Self::Pending(_) => Vec::new(),
1545 }
1546 }
1547
1548 pub(crate) fn discarded_transactions(&self) -> Option<&[Arc<ValidPoolTransaction<T>>]> {
1550 match self {
1551 Self::Pending(tx) => Some(&tx.discarded),
1552 Self::Parked { .. } => None,
1553 }
1554 }
1555
1556 pub(crate) fn replaced_blob_transaction(&self) -> Option<B256> {
1558 self.replaced().filter(|tx| tx.transaction.is_eip4844()).map(|tx| *tx.transaction.hash())
1559 }
1560
1561 pub fn hash(&self) -> &TxHash {
1563 match self {
1564 Self::Pending(tx) => tx.transaction.hash(),
1565 Self::Parked { transaction, .. } => transaction.hash(),
1566 }
1567 }
1568
1569 pub fn into_new_transaction_event(self) -> NewTransactionEvent<T> {
1571 match self {
1572 Self::Pending(tx) => {
1573 NewTransactionEvent { subpool: SubPool::Pending, transaction: tx.transaction }
1574 }
1575 Self::Parked { transaction, subpool, .. } => {
1576 NewTransactionEvent { transaction, subpool }
1577 }
1578 }
1579 }
1580
1581 pub(crate) const fn subpool(&self) -> SubPool {
1583 match self {
1584 Self::Pending(_) => SubPool::Pending,
1585 Self::Parked { subpool, .. } => *subpool,
1586 }
1587 }
1588
1589 #[cfg(test)]
1591 pub(crate) fn id(&self) -> &TransactionId {
1592 match self {
1593 Self::Pending(added) => added.transaction.id(),
1594 Self::Parked { transaction, .. } => transaction.id(),
1595 }
1596 }
1597
1598 pub const fn queued_reason(&self) -> Option<&QueuedReason> {
1600 match self {
1601 Self::Pending(_) => None,
1602 Self::Parked { queued_reason, .. } => queued_reason.as_ref(),
1603 }
1604 }
1605
1606 pub fn transaction_state(&self) -> AddedTransactionState {
1608 match self.subpool() {
1609 SubPool::Pending => AddedTransactionState::Pending,
1610 _ => {
1611 if let Some(reason) = self.queued_reason() {
1614 AddedTransactionState::Queued(reason.clone())
1615 } else {
1616 AddedTransactionState::Queued(QueuedReason::NonceGap)
1618 }
1619 }
1620 }
1621 }
1622}
1623
1624#[derive(Debug, Clone, PartialEq, Eq)]
1626pub enum QueuedReason {
1627 NonceGap,
1629 ParkedAncestors,
1631 InsufficientBalance,
1633 TooMuchGas,
1635 InsufficientBaseFee,
1637 InsufficientBlobFee,
1639}
1640
1641#[derive(Debug, Clone, PartialEq, Eq)]
1643pub enum AddedTransactionState {
1644 Pending,
1646 Queued(QueuedReason),
1648}
1649
1650impl AddedTransactionState {
1651 pub const fn is_queued(&self) -> bool {
1653 matches!(self, Self::Queued(_))
1654 }
1655
1656 pub const fn is_pending(&self) -> bool {
1658 matches!(self, Self::Pending)
1659 }
1660
1661 pub const fn queued_reason(&self) -> Option<&QueuedReason> {
1663 match self {
1664 Self::Queued(reason) => Some(reason),
1665 Self::Pending => None,
1666 }
1667 }
1668}
1669
1670#[derive(Debug, Clone, PartialEq, Eq)]
1672pub struct AddedTransactionOutcome {
1673 pub hash: TxHash,
1675 pub state: AddedTransactionState,
1677}
1678
1679impl AddedTransactionOutcome {
1680 pub const fn is_queued(&self) -> bool {
1682 self.state.is_queued()
1683 }
1684
1685 pub const fn is_pending(&self) -> bool {
1687 self.state.is_pending()
1688 }
1689}
1690
1691#[derive(Debug)]
1693pub(crate) struct OnNewCanonicalStateOutcome<T: PoolTransaction> {
1694 pub(crate) block_hash: B256,
1696 pub(crate) mined: Vec<TxHash>,
1698 pub(crate) promoted: Vec<Arc<ValidPoolTransaction<T>>>,
1700 pub(crate) discarded: Vec<Arc<ValidPoolTransaction<T>>>,
1702}
1703
1704impl<T: PoolTransaction> OnNewCanonicalStateOutcome<T> {
1705 pub(crate) fn pending_transactions(
1711 &self,
1712 kind: TransactionListenerKind,
1713 ) -> impl Iterator<Item = B256> + '_ {
1714 let iter = self.promoted.iter();
1715 PendingTransactionIter { kind, iter }
1716 }
1717
1718 pub(crate) fn full_pending_transactions(
1724 &self,
1725 kind: TransactionListenerKind,
1726 ) -> impl Iterator<Item = NewTransactionEvent<T>> + '_ {
1727 let iter = self.promoted.iter();
1728 FullPendingTransactionIter { kind, iter }
1729 }
1730}
1731
1732#[cfg(test)]
1733mod tests {
1734 use crate::{
1735 blobstore::{BlobStore, InMemoryBlobStore, PooledBlobSidecar},
1736 identifier::SenderId,
1737 test_utils::{testing_pool, MockTransaction, TestPool, TestPoolBuilder},
1738 validate::ValidTransaction,
1739 BlockInfo, FullTransactionEvent, PoolConfig, SubPool, SubPoolLimit,
1740 TransactionListenerKind, TransactionOrigin, TransactionPool, TransactionPoolExt,
1741 TransactionValidationOutcome, ValidPoolTransaction, U256,
1742 };
1743 use alloy_consensus::Transaction;
1744 use alloy_eips::{eip4844::BlobTransactionSidecar, eip7594::BlobTransactionSidecarVariant};
1745 use alloy_primitives::{Address, B256};
1746 use futures_util::{FutureExt, StreamExt};
1747 use std::{fs, path::PathBuf, sync::Arc};
1748 use tokio::sync::mpsc::error::TryRecvError;
1749
1750 fn insert_with_state_nonce(pool: &TestPool, nonce: u64, state_nonce: u64, propagate: bool) {
1752 let transaction = MockTransaction::eip1559()
1753 .with_sender(Address::with_last_byte(1))
1754 .with_nonce(nonce)
1755 .with_hash(B256::from([nonce as u8; 32]));
1756 pool.pool
1757 .add_transactions(
1758 TransactionOrigin::External,
1759 [TransactionValidationOutcome::Valid {
1760 balance: U256::MAX,
1761 state_nonce,
1762 bytecode_hash: None,
1763 transaction: ValidTransaction::Valid(transaction),
1764 propagate,
1765 authorities: None,
1766 }],
1767 )
1768 .pop()
1769 .unwrap()
1770 .unwrap();
1771 }
1772
1773 fn transaction_nonces(txs: &[Arc<ValidPoolTransaction<MockTransaction>>]) -> Vec<u64> {
1774 let mut nonces: Vec<_> = txs.iter().map(|tx| tx.transaction.nonce()).collect();
1775 nonces.sort_unstable();
1776 nonces
1777 }
1778
1779 #[tokio::test]
1780 async fn all_transactions_by_sender_across_reclassification() {
1781 let pool = testing_pool();
1782 let sender = Address::with_last_byte(1);
1783 for nonce in [0, 1, 9] {
1785 let tx =
1786 MockTransaction::legacy().with_sender(sender).with_nonce(nonce).with_gas_price(100);
1787 pool.add_transaction(TransactionOrigin::External, tx).await.unwrap();
1788 }
1789 let nonces = |txs: &[Arc<ValidPoolTransaction<MockTransaction>>]| {
1790 let mut nonces: Vec<_> = txs.iter().map(|tx| tx.transaction.nonce()).collect();
1791 nonces.sort_unstable();
1792 nonces
1793 };
1794
1795 let txs = pool.all_transactions_by_sender(sender);
1796 assert_eq!(nonces(&txs.pending), [0, 1]);
1797 assert_eq!(nonces(&txs.queued), [9]);
1798
1799 let sender_id = pool.inner().sender_id(&sender).unwrap();
1800 assert_eq!(nonces(&pool.inner().get_pending_transactions_by_sender_id(sender_id)), [0, 1]);
1801 assert_eq!(
1802 pool.inner().get_highest_transaction_by_sender_id(sender_id).unwrap().nonce(),
1803 9
1804 );
1805 assert_eq!(
1806 pool.inner()
1807 .get_highest_consecutive_transaction_by_sender_id(sender_id, 0)
1808 .unwrap()
1809 .nonce(),
1810 1
1811 );
1812
1813 pool.set_block_info(BlockInfo {
1816 pending_basefee: 200,
1817 block_gas_limit: 30_000_000,
1818 ..Default::default()
1819 });
1820 let txs = pool.all_transactions_by_sender(sender);
1821 assert!(txs.pending.is_empty());
1822 assert_eq!(nonces(&txs.queued), [0, 1, 9]);
1823 assert_eq!(nonces(&pool.get_transactions_by_sender(sender)), [0, 1, 9]);
1824 }
1825
1826 #[test]
1827 fn queued_insertion_notifies_older_promotions() {
1828 let test_pool = testing_pool();
1829 let pool = &test_pool.pool;
1830 let mut network = pool.add_pending_listener(TransactionListenerKind::PropagateOnly);
1831 let mut all = pool.add_pending_listener(TransactionListenerKind::All);
1832 insert_with_state_nonce(&test_pool, 1, 0, true);
1834 insert_with_state_nonce(&test_pool, 2, 0, true);
1835 let txs = test_pool.all_transactions_by_sender(Address::with_last_byte(1));
1836 assert!(txs.pending.is_empty());
1837 assert_eq!(transaction_nonces(&txs.queued), [1, 2]);
1838 assert_eq!(network.try_recv(), Err(TryRecvError::Empty));
1839 assert_eq!(all.try_recv(), Err(TryRecvError::Empty));
1840
1841 let mut full_network =
1842 pool.add_new_transaction_listener(TransactionListenerKind::PropagateOnly);
1843 let mut full_all = pool.add_new_transaction_listener(TransactionListenerKind::All);
1844 let mut events = pool.add_all_transactions_event_listener();
1845
1846 insert_with_state_nonce(&test_pool, 4, 1, true);
1849 let txs = test_pool.all_transactions_by_sender(Address::with_last_byte(1));
1850 assert_eq!(transaction_nonces(&txs.pending), [1, 2]);
1851 assert_eq!(transaction_nonces(&txs.queued), [4]);
1852
1853 let expected = vec![B256::from([1; 32]), B256::from([2; 32])];
1854 for (kind, listener) in [("network", &mut network), ("all", &mut all)] {
1855 let mut received = Vec::new();
1856 while let Ok(hash) = listener.try_recv() {
1857 received.push(hash);
1858 }
1859 received.sort_unstable();
1860 assert_eq!(received, expected, "{kind} pending notifications");
1861 }
1862
1863 for (kind, listener) in [("network", &mut full_network), ("all", &mut full_all)] {
1866 let mut received = Vec::new();
1867 while let Ok(event) = listener.try_recv() {
1868 received.push((*event.transaction.hash(), event.subpool));
1869 }
1870 received.sort_unstable_by_key(|(hash, _)| *hash);
1871 let expected = vec![
1872 (B256::from([1; 32]), SubPool::Pending),
1873 (B256::from([2; 32]), SubPool::Pending),
1874 (B256::from([4; 32]), SubPool::Queued),
1875 ];
1876 assert_eq!(received, expected, "{kind} full transaction notifications");
1877 }
1878
1879 let mut pending_events = Vec::new();
1880 let mut queued_events = Vec::new();
1881 while let Some(Some(event)) = events.next().now_or_never() {
1882 match event {
1883 FullTransactionEvent::Pending(hash) => pending_events.push(hash),
1884 FullTransactionEvent::Queued(hash, _) => queued_events.push(hash),
1885 other => panic!("unexpected event: {other:?}"),
1886 }
1887 }
1888 pending_events.sort_unstable();
1889 assert_eq!(pending_events, expected);
1890 assert_eq!(queued_events, vec![B256::from([4; 32])]);
1891
1892 insert_with_state_nonce(&test_pool, 5, 1, true);
1894 assert_eq!(network.try_recv(), Err(TryRecvError::Empty));
1895 assert_eq!(all.try_recv(), Err(TryRecvError::Empty));
1896 for listener in [&mut full_network, &mut full_all] {
1897 let event = listener.try_recv().unwrap();
1898 assert_eq!(*event.transaction.hash(), B256::from([5; 32]));
1899 assert_eq!(event.subpool, SubPool::Queued);
1900 assert!(matches!(listener.try_recv(), Err(TryRecvError::Empty)));
1901 }
1902 assert!(matches!(
1903 events.next().now_or_never(),
1904 Some(Some(FullTransactionEvent::Queued(hash, _))) if hash == B256::from([5; 32])
1905 ));
1906 assert!(events.next().now_or_never().is_none());
1907 }
1908
1909 #[test]
1910 fn queued_insertion_promotions_respect_propagation_filter() {
1911 let test_pool = testing_pool();
1912 let pool = &test_pool.pool;
1913 insert_with_state_nonce(&test_pool, 1, 0, false);
1914 insert_with_state_nonce(&test_pool, 2, 0, true);
1915
1916 let mut network = pool.add_pending_listener(TransactionListenerKind::PropagateOnly);
1917 let mut all = pool.add_pending_listener(TransactionListenerKind::All);
1918 let mut full_network =
1919 pool.add_new_transaction_listener(TransactionListenerKind::PropagateOnly);
1920 let mut full_all = pool.add_new_transaction_listener(TransactionListenerKind::All);
1921 insert_with_state_nonce(&test_pool, 4, 1, true);
1922
1923 assert_eq!(network.try_recv().unwrap(), B256::from([2; 32]));
1924 assert_eq!(network.try_recv(), Err(TryRecvError::Empty));
1925 let mut received = Vec::new();
1926 while let Ok(hash) = all.try_recv() {
1927 received.push(hash);
1928 }
1929 received.sort_unstable();
1930 assert_eq!(received, [B256::from([1; 32]), B256::from([2; 32])]);
1931
1932 for (listener, expected) in [
1933 (
1934 &mut full_network,
1935 vec![
1936 (B256::from([2; 32]), SubPool::Pending),
1937 (B256::from([4; 32]), SubPool::Queued),
1938 ],
1939 ),
1940 (
1941 &mut full_all,
1942 vec![
1943 (B256::from([1; 32]), SubPool::Pending),
1944 (B256::from([2; 32]), SubPool::Pending),
1945 (B256::from([4; 32]), SubPool::Queued),
1946 ],
1947 ),
1948 ] {
1949 let mut received = Vec::new();
1950 while let Ok(event) = listener.try_recv() {
1951 received.push((*event.transaction.hash(), event.subpool));
1952 }
1953 received.sort_unstable_by_key(|(hash, _)| *hash);
1954 assert_eq!(received, expected);
1955 }
1956 }
1957
1958 #[test]
1959 fn pending_insertion_notifies_older_promotions() {
1960 let test_pool = testing_pool();
1961 let pool = &test_pool.pool;
1962 insert_with_state_nonce(&test_pool, 1, 0, true);
1963 insert_with_state_nonce(&test_pool, 2, 0, true);
1964 let mut network = pool.add_pending_listener(TransactionListenerKind::PropagateOnly);
1965 let mut all = pool.add_pending_listener(TransactionListenerKind::All);
1966
1967 insert_with_state_nonce(&test_pool, 3, 1, true);
1969 let txs = test_pool.all_transactions_by_sender(Address::with_last_byte(1));
1970 assert_eq!(transaction_nonces(&txs.pending), [1, 2, 3]);
1971 assert!(txs.queued.is_empty());
1972 for listener in [&mut network, &mut all] {
1973 let mut received = Vec::new();
1974 while let Ok(hash) = listener.try_recv() {
1975 received.push(hash);
1976 }
1977 received.sort_unstable();
1978 assert_eq!(received, [B256::from([1; 32]), B256::from([2; 32]), B256::from([3; 32])]);
1979 }
1980 }
1981
1982 #[test]
1983 fn test_discard_blobs_on_blob_tx_eviction() {
1984 let blobs = {
1985 let json_content = fs::read_to_string(
1987 PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test_data/blob1.json"),
1988 )
1989 .expect("Failed to read the blob data file");
1990
1991 let json_value: serde_json::Value =
1993 serde_json::from_str(&json_content).expect("Failed to deserialize JSON");
1994
1995 vec![
1997 json_value
1999 .get("data")
2000 .unwrap()
2001 .as_str()
2002 .expect("Data is not a valid string")
2003 .to_string(),
2004 ]
2005 };
2006
2007 let sidecar = BlobTransactionSidecarVariant::Eip4844(
2009 BlobTransactionSidecar::try_from_blobs_hex(blobs).unwrap(),
2010 );
2011
2012 let blob_limit = SubPoolLimit::new(1000, usize::MAX);
2014
2015 let test_pool = &TestPoolBuilder::default()
2017 .with_config(PoolConfig { blob_limit, ..Default::default() })
2018 .pool;
2019
2020 test_pool
2022 .set_block_info(BlockInfo { pending_blob_fee: Some(10_000_000), ..Default::default() });
2023
2024 let blob_store = InMemoryBlobStore::default();
2026
2027 for n in 0..blob_limit.max_txs + 10 {
2029 let mut tx = MockTransaction::eip4844_with_sidecar(sidecar.clone());
2031
2032 tx.set_size(1844674407370951);
2034
2035 if n < blob_limit.max_txs {
2037 blob_store.insert(*tx.get_hash(), sidecar.clone().into()).unwrap();
2038 }
2039
2040 test_pool.add_transactions(
2042 TransactionOrigin::External,
2043 [TransactionValidationOutcome::Valid {
2044 balance: U256::from(1_000),
2045 state_nonce: 0,
2046 bytecode_hash: None,
2047 transaction: ValidTransaction::ValidWithSidecar {
2048 transaction: tx,
2049 sidecar: PooledBlobSidecar::from(sidecar.clone()),
2050 },
2051 propagate: true,
2052 authorities: None,
2053 }],
2054 );
2055 }
2056
2057 assert_eq!(test_pool.size().blob, blob_limit.max_txs);
2059
2060 assert_eq!(test_pool.size().blob_size, 1844674407370951000);
2062
2063 assert_eq!(*test_pool.blob_store(), blob_store);
2065 }
2066
2067 #[test]
2068 fn test_auths_stored_in_identifiers() {
2069 let test_pool = &TestPoolBuilder::default().with_config(Default::default()).pool;
2071
2072 let auth = Address::new([1; 20]);
2073 let tx = MockTransaction::eip7702();
2074
2075 test_pool.add_transactions(
2076 TransactionOrigin::Local,
2077 [TransactionValidationOutcome::Valid {
2078 balance: U256::from(1_000),
2079 state_nonce: 0,
2080 bytecode_hash: None,
2081 transaction: ValidTransaction::Valid(tx),
2082 propagate: true,
2083 authorities: Some(vec![auth]),
2084 }],
2085 );
2086
2087 let identifiers = test_pool.identifiers.read();
2088 assert_eq!(identifiers.sender_id(&auth), Some(SenderId::from(1)));
2089 }
2090
2091 #[test]
2092 fn sender_queries_do_not_allocate_ids_for_unknown_addresses() {
2093 let test_pool = &TestPoolBuilder::default().with_config(Default::default()).pool;
2094 let sender = Address::new([9; 20]);
2095
2096 assert_eq!(test_pool.sender_id(&sender), None);
2097 assert!(test_pool.get_transactions_by_sender(sender).is_empty());
2098 assert!(test_pool.get_pending_transaction_by_sender_and_nonce(sender, 0).is_none());
2099 assert!(test_pool.get_queued_transactions_by_sender(sender).is_empty());
2100 assert!(test_pool.get_pending_transactions_by_sender(sender).is_empty());
2101 assert!(test_pool.get_highest_transaction_by_sender(sender).is_none());
2102 assert!(test_pool.get_highest_consecutive_transaction_by_sender(sender, 0).is_none());
2103 assert!(test_pool.remove_transactions_by_sender(sender).is_empty());
2104 assert_eq!(test_pool.sender_id(&sender), None);
2105 }
2106}