1use crate::eth::{error::PoolError, util::hex_fmt_many};
2use alloy_consensus::{
3 Transaction, Typed2718,
4 crypto::RecoveryError,
5 transaction::{SignerRecoverable, TxHashRef},
6};
7use alloy_network::AnyRpcTransaction;
8use alloy_primitives::{
9 Address, TxHash,
10 map::{HashMap, HashSet},
11};
12use alloy_rlp::Encodable;
13use anvil_core::eth::transaction::PendingTransaction;
14use parking_lot::RwLock;
15use std::{cmp::Ordering, collections::BTreeSet, fmt, str::FromStr, sync::Arc, time::Instant};
16
17pub type TxMarker = Vec<u8>;
19
20type ReplacedTransactions<T> = (Vec<Arc<PoolTransaction<T>>>, Vec<TxHash>);
23
24pub fn to_marker(nonce: u64, from: Address) -> TxMarker {
26 let mut data = [0u8; 28];
27 data[..8].copy_from_slice(&nonce.to_le_bytes()[..]);
28 data[8..].copy_from_slice(&from.0[..]);
29 data.to_vec()
30}
31
32#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
36pub enum TransactionOrder {
37 Fifo,
42 #[default]
44 Fees,
45}
46
47impl TransactionOrder {
48 pub fn priority<T: Transaction>(&self, tx: &T) -> TransactionPriority {
50 match self {
51 Self::Fifo => TransactionPriority::default(),
52 Self::Fees => TransactionPriority(tx.max_fee_per_gas()),
53 }
54 }
55}
56
57impl FromStr for TransactionOrder {
58 type Err = String;
59
60 fn from_str(s: &str) -> Result<Self, Self::Err> {
61 let s = s.to_lowercase();
62 let order = match s.as_str() {
63 "fees" => Self::Fees,
64 "fifo" => Self::Fifo,
65 _ => return Err(format!("Unknown TransactionOrder: `{s}`")),
66 };
67 Ok(order)
68 }
69}
70
71#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
76pub struct TransactionPriority(pub u128);
77
78#[derive(Clone, PartialEq, Eq)]
80pub struct PoolTransaction<T> {
81 pub pending_transaction: PendingTransaction<T>,
83 pub requires: Vec<TxMarker>,
85 pub provides: Vec<TxMarker>,
87 pub priority: TransactionPriority,
89 pub is_replay: bool,
91}
92
93impl<T> PoolTransaction<T> {
96 pub const fn new(transaction: PendingTransaction<T>) -> Self {
97 Self {
98 pending_transaction: transaction,
99 requires: vec![],
100 provides: vec![],
101 priority: TransactionPriority(0),
102 is_replay: false,
103 }
104 }
105
106 pub const fn with_replay(mut self) -> Self {
108 self.is_replay = true;
109 self
110 }
111
112 pub const fn hash(&self) -> TxHash {
114 *self.pending_transaction.hash()
115 }
116}
117
118impl<T: Transaction> PoolTransaction<T> {
119 pub fn max_fee_per_gas(&self) -> u128 {
121 self.pending_transaction.transaction.max_fee_per_gas()
122 }
123}
124
125impl<T: Typed2718> PoolTransaction<T> {
126 pub fn tx_type(&self) -> u8 {
128 self.pending_transaction.transaction.ty()
129 }
130}
131
132impl<T: fmt::Debug> fmt::Debug for PoolTransaction<T> {
133 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
134 write!(fmt, "Transaction {{ ")?;
135 write!(fmt, "hash: {:?}, ", self.pending_transaction.hash())?;
136 write!(fmt, "requires: [{}], ", hex_fmt_many(self.requires.iter()))?;
137 write!(fmt, "provides: [{}], ", hex_fmt_many(self.provides.iter()))?;
138 write!(fmt, "raw tx: {:?}", self.pending_transaction)?;
139 write!(fmt, "}}")?;
140 Ok(())
141 }
142}
143
144impl<T> TryFrom<AnyRpcTransaction> for PoolTransaction<T>
145where
146 T: SignerRecoverable + TxHashRef + Encodable + TryFrom<AnyRpcTransaction>,
147 <T as TryFrom<AnyRpcTransaction>>::Error: Into<eyre::Error>,
148 RecoveryError: Into<eyre::Error>,
149{
150 type Error = eyre::Error;
151 fn try_from(value: AnyRpcTransaction) -> Result<Self, Self::Error> {
152 let typed_transaction = T::try_from(value).map_err(Into::into)?;
153 let pending_transaction = PendingTransaction::new(typed_transaction)?;
154 Ok(Self {
155 pending_transaction,
156 requires: vec![],
157 provides: vec![],
158 priority: TransactionPriority(0),
159 is_replay: false,
160 })
161 }
162}
163
164#[derive(Clone, Debug)]
168pub struct PendingTransactions<T> {
169 required_markers: HashMap<TxMarker, HashSet<TxHash>>,
171 waiting_markers: HashMap<Vec<TxMarker>, TxHash>,
173 waiting_queue: HashMap<TxHash, PendingPoolTransaction<T>>,
175}
176
177impl<T> Default for PendingTransactions<T> {
178 fn default() -> Self {
179 Self {
180 required_markers: Default::default(),
181 waiting_markers: Default::default(),
182 waiting_queue: Default::default(),
183 }
184 }
185}
186
187impl<T> PendingTransactions<T> {
188 pub fn len(&self) -> usize {
190 self.waiting_queue.len()
191 }
192
193 pub fn is_empty(&self) -> bool {
194 self.waiting_queue.is_empty()
195 }
196
197 pub fn clear(&mut self) {
199 self.required_markers.clear();
200 self.waiting_markers.clear();
201 self.waiting_queue.clear();
202 }
203
204 pub fn transactions(&self) -> impl Iterator<Item = Arc<PoolTransaction<T>>> + '_ {
206 self.waiting_queue.values().map(|tx| tx.transaction.clone())
207 }
208
209 pub fn contains(&self, hash: &TxHash) -> bool {
211 self.waiting_queue.contains_key(hash)
212 }
213
214 pub fn get(&self, hash: &TxHash) -> Option<&PendingPoolTransaction<T>> {
216 self.waiting_queue.get(hash)
217 }
218
219 pub fn mark_and_unlock(
224 &mut self,
225 markers: impl IntoIterator<Item = impl AsRef<TxMarker>>,
226 ) -> Vec<PendingPoolTransaction<T>> {
227 let mut unlocked_ready = Vec::new();
228 for mark in markers {
229 let mark = mark.as_ref();
230 if let Some(tx_hashes) = self.required_markers.remove(mark) {
231 for hash in tx_hashes {
232 let tx = self.waiting_queue.get_mut(&hash).expect("tx is included;");
233 tx.mark(mark);
234
235 if tx.is_ready() {
236 let tx = self.waiting_queue.remove(&hash).expect("tx is included;");
237 self.waiting_markers.remove(&tx.transaction.provides);
238
239 unlocked_ready.push(tx);
240 }
241 }
242 }
243 }
244
245 unlocked_ready
246 }
247
248 pub fn remove(&mut self, hashes: Vec<TxHash>) -> Vec<Arc<PoolTransaction<T>>> {
252 let mut removed = vec![];
253 for hash in hashes {
254 if let Some(waiting_tx) = self.waiting_queue.remove(&hash) {
255 self.waiting_markers.remove(&waiting_tx.transaction.provides);
256 for marker in waiting_tx.missing_markers {
257 let remove = if let Some(required) = self.required_markers.get_mut(&marker) {
258 required.remove(&hash);
259 required.is_empty()
260 } else {
261 false
262 };
263 if remove {
264 self.required_markers.remove(&marker);
265 }
266 }
267 removed.push(waiting_tx.transaction)
268 }
269 }
270 removed
271 }
272}
273
274impl<T: Transaction> PendingTransactions<T> {
275 pub fn add_transaction(&mut self, tx: PendingPoolTransaction<T>) -> Result<(), PoolError> {
277 assert!(!tx.is_ready(), "transaction must not be ready");
278 assert!(
279 !self.waiting_queue.contains_key(&tx.transaction.hash()),
280 "transaction is already added"
281 );
282
283 if let Some(replace) = self
284 .waiting_markers
285 .get(&tx.transaction.provides)
286 .and_then(|hash| self.waiting_queue.get(hash))
287 {
288 if tx.transaction.max_fee_per_gas() <= replace.transaction.max_fee_per_gas() {
290 warn!(target: "txpool", "pending replacement transaction underpriced [{:?}]", tx.transaction.hash());
291 return Err(PoolError::ReplacementUnderpriced(tx.transaction.hash()));
292 }
293 }
294
295 for marker in &tx.missing_markers {
297 self.required_markers.entry(marker.clone()).or_default().insert(tx.transaction.hash());
298 }
299
300 self.waiting_markers.insert(tx.transaction.provides.clone(), tx.transaction.hash());
302 self.waiting_queue.insert(tx.transaction.hash(), tx);
304
305 Ok(())
306 }
307}
308
309#[derive(Clone)]
311pub struct PendingPoolTransaction<T> {
312 pub transaction: Arc<PoolTransaction<T>>,
313 pub missing_markers: HashSet<TxMarker>,
315 pub added_at: Instant,
317}
318
319impl<T> PendingPoolTransaction<T> {
320 pub fn new(transaction: PoolTransaction<T>, provided: &HashMap<TxMarker, TxHash>) -> Self {
325 let missing_markers = transaction
326 .requires
327 .iter()
328 .filter(|marker| {
329 !provided.contains_key(&**marker)
331 })
332 .cloned()
333 .collect();
334
335 Self { transaction: Arc::new(transaction), missing_markers, added_at: Instant::now() }
336 }
337
338 pub fn mark(&mut self, marker: &TxMarker) {
340 self.missing_markers.remove(marker);
341 }
342
343 pub fn is_ready(&self) -> bool {
345 self.missing_markers.is_empty()
346 }
347}
348
349impl<T: fmt::Debug> fmt::Debug for PendingPoolTransaction<T> {
350 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
351 write!(fmt, "PendingTransaction {{ ")?;
352 write!(fmt, "added_at: {:?}, ", self.added_at)?;
353 write!(fmt, "tx: {:?}, ", self.transaction)?;
354 write!(fmt, "missing_markers: {{{}}}", hex_fmt_many(self.missing_markers.iter()))?;
355 write!(fmt, "}}")
356 }
357}
358
359pub struct TransactionsIterator<T> {
360 all: HashMap<TxHash, ReadyTransaction<T>>,
361 awaiting: HashMap<TxHash, (usize, PoolTransactionRef<T>)>,
362 independent: BTreeSet<PoolTransactionRef<T>>,
363 _invalid: HashSet<TxHash>,
364}
365
366impl<T> TransactionsIterator<T> {
367 fn independent_or_awaiting(&mut self, satisfied: usize, tx_ref: PoolTransactionRef<T>) {
370 if satisfied >= tx_ref.transaction.requires.len() {
371 self.independent.insert(tx_ref);
373 } else {
374 self.awaiting.insert(tx_ref.transaction.hash(), (satisfied, tx_ref));
376 }
377 }
378}
379
380impl<T> Iterator for TransactionsIterator<T> {
381 type Item = Arc<PoolTransaction<T>>;
382
383 fn next(&mut self) -> Option<Self::Item> {
384 loop {
385 let best = self.independent.iter().next_back()?.clone();
386 let best = self.independent.take(&best)?;
387 let hash = best.transaction.hash();
388
389 let ready =
390 if let Some(ready) = self.all.get(&hash).cloned() { ready } else { continue };
391
392 for hash in &ready.unlocks {
394 let res = if let Some((mut satisfied, tx_ref)) = self.awaiting.remove(hash) {
396 satisfied += 1;
397 Some((satisfied, tx_ref))
398 } else {
400 self.all
401 .get(hash)
402 .map(|next| (next.requires_offset + 1, next.transaction.clone()))
403 };
404 if let Some((satisfied, tx_ref)) = res {
405 self.independent_or_awaiting(satisfied, tx_ref)
406 }
407 }
408
409 return Some(best.transaction);
410 }
411 }
412}
413
414#[derive(Clone, Debug)]
416pub struct ReadyTransactions<T> {
417 id: u64,
421 provided_markers: HashMap<TxMarker, TxHash>,
423 ready_tx: Arc<RwLock<HashMap<TxHash, ReadyTransaction<T>>>>,
425 independent_transactions: BTreeSet<PoolTransactionRef<T>>,
428}
429
430impl<T> Default for ReadyTransactions<T> {
431 fn default() -> Self {
432 Self {
433 id: 0,
434 provided_markers: Default::default(),
435 ready_tx: Default::default(),
436 independent_transactions: Default::default(),
437 }
438 }
439}
440
441impl<T> ReadyTransactions<T> {
442 pub fn get_transactions(&self) -> TransactionsIterator<T> {
444 TransactionsIterator {
445 all: self.ready_tx.read().clone(),
446 independent: self.independent_transactions.clone(),
447 awaiting: Default::default(),
448 _invalid: Default::default(),
449 }
450 }
451
452 pub fn clear(&mut self) {
454 self.provided_markers.clear();
455 self.ready_tx.write().clear();
456 self.independent_transactions.clear();
457 }
458
459 pub fn contains(&self, hash: &TxHash) -> bool {
461 self.ready_tx.read().contains_key(hash)
462 }
463
464 pub fn len(&self) -> usize {
466 self.ready_tx.read().len()
467 }
468
469 pub fn is_empty(&self) -> bool {
471 self.ready_tx.read().is_empty()
472 }
473
474 pub fn get(&self, hash: &TxHash) -> Option<ReadyTransaction<T>> {
476 self.ready_tx.read().get(hash).cloned()
477 }
478
479 pub const fn provided_markers(&self) -> &HashMap<TxMarker, TxHash> {
480 &self.provided_markers
481 }
482
483 const fn next_id(&mut self) -> u64 {
484 let id = self.id;
485 self.id = self.id.wrapping_add(1);
486 id
487 }
488
489 pub fn clear_transactions(&mut self, tx_hashes: &[TxHash]) -> Vec<Arc<PoolTransaction<T>>> {
492 self.remove_with_markers(tx_hashes.to_vec(), None)
493 }
494
495 pub fn prune_tags(&mut self, marker: TxMarker) -> Vec<Arc<PoolTransaction<T>>> {
500 let mut removed_tx = vec![];
501
502 let mut remove = vec![marker];
504
505 while let Some(marker) = remove.pop() {
506 let res = self
507 .provided_markers
508 .remove(&marker)
509 .and_then(|hash| self.ready_tx.write().remove(&hash));
510
511 if let Some(tx) = res {
512 let unlocks = tx.unlocks;
513 self.independent_transactions.remove(&tx.transaction);
514 let tx = tx.transaction.transaction;
515
516 {
518 let hash = tx.hash();
519 let mut ready = self.ready_tx.write();
520
521 let mut previous_markers = |marker| -> Option<Vec<TxMarker>> {
522 let prev_hash = self.provided_markers.get(marker)?;
523 let tx2 = ready.get_mut(prev_hash)?;
524 if let Some(idx) = tx2.unlocks.iter().position(|i| i == &hash) {
526 tx2.unlocks.swap_remove(idx);
527 }
528 tx2.unlocks.is_empty().then(|| tx2.transaction.transaction.provides.clone())
529 };
530
531 for marker in &tx.requires {
533 if let Some(mut tags_to_remove) = previous_markers(marker) {
534 remove.append(&mut tags_to_remove);
535 }
536 }
537 }
538
539 for hash in unlocks {
541 if let Some(tx) = self.ready_tx.write().get_mut(&hash) {
542 tx.requires_offset += 1;
543 if tx.requires_offset == tx.transaction.transaction.requires.len() {
544 self.independent_transactions.insert(tx.transaction.clone());
545 }
546 }
547 }
548 let current_marker = ▮
550 for marker in &tx.provides {
551 let removed = self.provided_markers.remove(marker);
552 assert_eq!(
553 removed,
554 if current_marker == marker { None } else { Some(tx.hash()) },
555 "The pool contains exactly one transaction providing given tag; the removed transaction
556 claims to provide that tag, so it has to be mapped to it's hash; qed"
557 );
558 }
559 removed_tx.push(tx);
560 }
561 }
562
563 removed_tx
564 }
565
566 pub fn remove_with_markers(
569 &mut self,
570 mut tx_hashes: Vec<TxHash>,
571 marker_filter: Option<HashSet<TxMarker>>,
572 ) -> Vec<Arc<PoolTransaction<T>>> {
573 let mut removed = Vec::new();
574 let mut ready = self.ready_tx.write();
575
576 while let Some(hash) = tx_hashes.pop() {
577 if let Some(mut tx) = ready.remove(&hash) {
578 let invalidated = tx.transaction.transaction.provides.iter().filter(|mark| {
579 marker_filter.as_ref().map(|filter| !filter.contains(&**mark)).unwrap_or(true)
580 });
581
582 let mut removed_some_marks = false;
583 for mark in invalidated {
585 removed_some_marks = true;
586 self.provided_markers.remove(mark);
587 }
588
589 for mark in &tx.transaction.transaction.requires {
591 if let Some(provider_hash) = self.provided_markers.get(mark)
592 && let Some(provider_tx) = ready.get_mut(provider_hash)
593 && let Some(idx) = provider_tx.unlocks.iter().position(|i| i == &hash)
594 {
595 provider_tx.unlocks.swap_remove(idx);
596 }
597 }
598
599 self.independent_transactions.remove(&tx.transaction);
601
602 if removed_some_marks {
603 tx_hashes.append(&mut tx.unlocks);
605 }
606
607 removed.push(tx.transaction.transaction);
609 }
610 }
611
612 removed
613 }
614}
615
616impl<T: Transaction> ReadyTransactions<T> {
617 pub fn add_transaction(
624 &mut self,
625 tx: PendingPoolTransaction<T>,
626 ) -> Result<Vec<Arc<PoolTransaction<T>>>, PoolError> {
627 assert!(tx.is_ready(), "transaction must be ready",);
628 assert!(
629 !self.ready_tx.read().contains_key(&tx.transaction.hash()),
630 "transaction already included"
631 );
632
633 let (replaced_tx, unlocks) = self.replaced_transactions(&tx.transaction)?;
634
635 let id = self.next_id();
636 let hash = tx.transaction.hash();
637
638 let mut independent = true;
639 let mut requires_offset = 0;
640 let mut ready = self.ready_tx.write();
641 for mark in &tx.transaction.requires {
643 if let Some(other) = self.provided_markers.get(mark) {
645 let tx = ready.get_mut(other).expect("hash included;");
646 tx.unlocks.push(hash);
647 independent = false;
649 } else {
650 requires_offset += 1;
651 }
652 }
653
654 for mark in tx.transaction.provides.iter().cloned() {
656 self.provided_markers.insert(mark, hash);
657 }
658
659 let transaction = PoolTransactionRef { id, transaction: tx.transaction };
660
661 if independent {
663 self.independent_transactions.insert(transaction.clone());
664 }
665
666 ready.insert(hash, ReadyTransaction { transaction, unlocks, requires_offset });
668
669 Ok(replaced_tx)
670 }
671
672 fn replaced_transactions(
674 &mut self,
675 tx: &PoolTransaction<T>,
676 ) -> Result<ReplacedTransactions<T>, PoolError> {
677 let remove_hashes: HashSet<_> =
679 tx.provides.iter().filter_map(|mark| self.provided_markers.get(mark)).collect();
680
681 if remove_hashes.is_empty() {
683 return Ok((Vec::new(), Vec::new()));
684 }
685
686 let mut unlocked_tx = Vec::new();
688 {
689 let ready = self.ready_tx.read();
692 for to_remove in remove_hashes.iter().filter_map(|hash| ready.get(*hash)) {
693 if to_remove.provides() == tx.provides {
696 if tx.pending_transaction.transaction.max_fee_per_gas()
698 <= to_remove.max_fee_per_gas()
699 {
700 warn!(target: "txpool", "ready replacement transaction underpriced [{:?}]", tx.hash());
701 return Err(PoolError::ReplacementUnderpriced(tx.hash()));
702 }
703 trace!(target: "txpool", "replacing ready transaction [{:?}] with higher gas price [{:?}]", to_remove.transaction.transaction.hash(), tx.hash());
704 }
705
706 unlocked_tx.extend(to_remove.unlocks.iter().copied())
707 }
708 }
709
710 let remove_hashes = remove_hashes.into_iter().copied().collect::<Vec<_>>();
711
712 let new_provides = tx.provides.iter().cloned().collect::<HashSet<_>>();
713 let removed_tx = self.remove_with_markers(remove_hashes, Some(new_provides));
714
715 Ok((removed_tx, unlocked_tx))
716 }
717}
718
719#[derive(Debug)]
721pub struct PoolTransactionRef<T> {
722 pub transaction: Arc<PoolTransaction<T>>,
724 pub id: u64,
726}
727
728impl<T> Clone for PoolTransactionRef<T> {
729 fn clone(&self) -> Self {
730 Self { transaction: Arc::clone(&self.transaction), id: self.id }
731 }
732}
733
734impl<T> Eq for PoolTransactionRef<T> {}
735
736impl<T> PartialEq<Self> for PoolTransactionRef<T> {
737 fn eq(&self, other: &Self) -> bool {
738 self.cmp(other) == Ordering::Equal
739 }
740}
741
742impl<T> PartialOrd<Self> for PoolTransactionRef<T> {
743 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
744 Some(self.cmp(other))
745 }
746}
747
748impl<T> Ord for PoolTransactionRef<T> {
749 fn cmp(&self, other: &Self) -> Ordering {
750 self.transaction
751 .priority
752 .cmp(&other.transaction.priority)
753 .then_with(|| other.id.cmp(&self.id))
754 }
755}
756
757#[derive(Debug)]
758pub struct ReadyTransaction<T> {
759 pub transaction: PoolTransactionRef<T>,
761 pub unlocks: Vec<TxHash>,
763 pub requires_offset: usize,
765}
766
767impl<T> Clone for ReadyTransaction<T> {
768 fn clone(&self) -> Self {
769 Self {
770 transaction: self.transaction.clone(),
771 unlocks: self.unlocks.clone(),
772 requires_offset: self.requires_offset,
773 }
774 }
775}
776
777impl<T> ReadyTransaction<T> {
778 pub fn provides(&self) -> &[TxMarker] {
779 &self.transaction.transaction.provides
780 }
781}
782
783impl<T: Transaction> ReadyTransaction<T> {
784 pub fn max_fee_per_gas(&self) -> u128 {
785 self.transaction.transaction.max_fee_per_gas()
786 }
787}
788
789#[cfg(test)]
790mod tests {
791 use super::*;
792
793 #[test]
794 fn can_id_txs() {
795 let addr = Address::random();
796 assert_eq!(to_marker(1, addr), to_marker(1, addr));
797 assert_ne!(to_marker(2, addr), to_marker(1, addr));
798 }
799}