Skip to main content

anvil/eth/pool/
transactions.rs

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
17/// A unique identifying marker for a transaction
18pub type TxMarker = Vec<u8>;
19
20/// Result type for replaced transactions: the replaced pool transactions and the hashes they
21/// unlock.
22type ReplacedTransactions<T> = (Vec<Arc<PoolTransaction<T>>>, Vec<TxHash>);
23
24/// Modes that determine the transaction ordering of the mempool
25///
26/// This type controls the transaction order via the priority metric of a transaction
27#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
28pub enum TransactionOrder {
29    /// Keep the pool transaction transactions sorted in the order they arrive.
30    ///
31    /// This will essentially assign every transaction the exact priority so the order is
32    /// determined by their internal id
33    Fifo,
34    /// This means that it prioritizes transactions based on the fees paid to the miner.
35    #[default]
36    Fees,
37}
38
39impl TransactionOrder {
40    /// Returns the priority of the transactions
41    pub fn priority<T: Transaction>(&self, tx: &T) -> TransactionPriority {
42        match self {
43            Self::Fifo => TransactionPriority::default(),
44            Self::Fees => TransactionPriority(tx.max_fee_per_gas()),
45        }
46    }
47}
48
49impl FromStr for TransactionOrder {
50    type Err = String;
51
52    fn from_str(s: &str) -> Result<Self, Self::Err> {
53        let s = s.to_lowercase();
54        let order = match s.as_str() {
55            "fees" => Self::Fees,
56            "fifo" => Self::Fifo,
57            _ => return Err(format!("Unknown TransactionOrder: `{s}`")),
58        };
59        Ok(order)
60    }
61}
62
63/// Metric value for the priority of a transaction.
64///
65/// The `TransactionPriority` determines the ordering of two transactions that have all their
66/// markers satisfied.
67#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
68pub struct TransactionPriority(pub u128);
69
70/// Internal Transaction type
71#[derive(Clone, PartialEq, Eq)]
72pub struct PoolTransaction<T> {
73    /// the pending eth transaction
74    pub pending_transaction: PendingTransaction<T>,
75    /// Markers required by the transaction
76    pub requires: Vec<TxMarker>,
77    /// Markers that this transaction provides
78    pub provides: Vec<TxMarker>,
79    /// priority of the transaction
80    pub priority: TransactionPriority,
81    /// Whether this transaction is being replayed from chain history.
82    pub is_replay: bool,
83}
84
85// == impl PoolTransaction ==
86
87impl<T> PoolTransaction<T> {
88    pub const fn new(transaction: PendingTransaction<T>) -> Self {
89        Self {
90            pending_transaction: transaction,
91            requires: vec![],
92            provides: vec![],
93            priority: TransactionPriority(0),
94            is_replay: false,
95        }
96    }
97
98    /// Marks this transaction as a historical replay.
99    pub const fn with_replay(mut self) -> Self {
100        self.is_replay = true;
101        self
102    }
103
104    /// Returns the hash of this transaction
105    pub const fn hash(&self) -> TxHash {
106        *self.pending_transaction.hash()
107    }
108}
109
110impl<T: Transaction> PoolTransaction<T> {
111    /// Returns the max fee per gas of this transaction
112    pub fn max_fee_per_gas(&self) -> u128 {
113        self.pending_transaction.transaction.max_fee_per_gas()
114    }
115}
116
117impl<T: Typed2718> PoolTransaction<T> {
118    /// Returns the type of the transaction
119    pub fn tx_type(&self) -> u8 {
120        self.pending_transaction.transaction.ty()
121    }
122}
123
124impl<T: fmt::Debug> fmt::Debug for PoolTransaction<T> {
125    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
126        write!(fmt, "Transaction {{ ")?;
127        write!(fmt, "hash: {:?}, ", self.pending_transaction.hash())?;
128        write!(fmt, "requires: [{}], ", hex_fmt_many(self.requires.iter()))?;
129        write!(fmt, "provides: [{}], ", hex_fmt_many(self.provides.iter()))?;
130        write!(fmt, "raw tx: {:?}", self.pending_transaction)?;
131        write!(fmt, "}}")?;
132        Ok(())
133    }
134}
135
136impl<T> TryFrom<AnyRpcTransaction> for PoolTransaction<T>
137where
138    T: SignerRecoverable + TxHashRef + Encodable + TryFrom<AnyRpcTransaction>,
139    <T as TryFrom<AnyRpcTransaction>>::Error: Into<eyre::Error>,
140    RecoveryError: Into<eyre::Error>,
141{
142    type Error = eyre::Error;
143    fn try_from(value: AnyRpcTransaction) -> Result<Self, Self::Error> {
144        let typed_transaction = T::try_from(value).map_err(Into::into)?;
145        let pending_transaction = PendingTransaction::new(typed_transaction)?;
146        Ok(Self {
147            pending_transaction,
148            requires: vec![],
149            provides: vec![],
150            priority: TransactionPriority(0),
151            is_replay: false,
152        })
153    }
154}
155
156/// A waiting pool of transaction that are pending, but not yet ready to be included in a new block.
157///
158/// Keeps a set of transactions that are waiting for other transactions
159#[derive(Clone, Debug)]
160pub struct PendingTransactions<T> {
161    /// markers that aren't yet provided by any transaction
162    required_markers: HashMap<TxMarker, HashSet<TxHash>>,
163    /// mapping of the markers of a transaction to the hash of the transaction
164    waiting_markers: HashMap<Vec<TxMarker>, TxHash>,
165    /// the transactions that are not ready yet are waiting for another tx to finish
166    waiting_queue: HashMap<TxHash, PendingPoolTransaction<T>>,
167}
168
169impl<T> Default for PendingTransactions<T> {
170    fn default() -> Self {
171        Self {
172            required_markers: Default::default(),
173            waiting_markers: Default::default(),
174            waiting_queue: Default::default(),
175        }
176    }
177}
178
179impl<T> PendingTransactions<T> {
180    /// Returns the number of transactions that are currently waiting
181    pub fn len(&self) -> usize {
182        self.waiting_queue.len()
183    }
184
185    pub fn is_empty(&self) -> bool {
186        self.waiting_queue.is_empty()
187    }
188
189    /// Clears internal state
190    pub fn clear(&mut self) {
191        self.required_markers.clear();
192        self.waiting_markers.clear();
193        self.waiting_queue.clear();
194    }
195
196    /// Returns an iterator over all transactions in the waiting pool
197    pub fn transactions(&self) -> impl Iterator<Item = Arc<PoolTransaction<T>>> + '_ {
198        self.waiting_queue.values().map(|tx| tx.transaction.clone())
199    }
200
201    /// Returns true if given transaction is part of the queue
202    pub fn contains(&self, hash: &TxHash) -> bool {
203        self.waiting_queue.contains_key(hash)
204    }
205
206    /// Returns the transaction for the hash if it's pending
207    pub fn get(&self, hash: &TxHash) -> Option<&PendingPoolTransaction<T>> {
208        self.waiting_queue.get(hash)
209    }
210
211    /// This will check off the markers of pending transactions.
212    ///
213    /// Returns the those transactions that become unlocked (all markers checked) and can be moved
214    /// to the ready queue.
215    pub fn mark_and_unlock(
216        &mut self,
217        markers: impl IntoIterator<Item = impl AsRef<TxMarker>>,
218    ) -> Vec<PendingPoolTransaction<T>> {
219        let mut unlocked_ready = Vec::new();
220        for mark in markers {
221            let mark = mark.as_ref();
222            if let Some(tx_hashes) = self.required_markers.remove(mark) {
223                for hash in tx_hashes {
224                    let tx = self.waiting_queue.get_mut(&hash).expect("tx is included;");
225                    tx.mark(mark);
226
227                    if tx.is_ready() {
228                        let tx = self.waiting_queue.remove(&hash).expect("tx is included;");
229                        self.waiting_markers.remove(&tx.transaction.provides);
230
231                        unlocked_ready.push(tx);
232                    }
233                }
234            }
235        }
236
237        unlocked_ready
238    }
239
240    /// Removes the transactions associated with the given hashes
241    ///
242    /// Returns all removed transactions.
243    pub fn remove(&mut self, hashes: Vec<TxHash>) -> Vec<Arc<PoolTransaction<T>>> {
244        let mut removed = vec![];
245        for hash in hashes {
246            if let Some(waiting_tx) = self.waiting_queue.remove(&hash) {
247                self.waiting_markers.remove(&waiting_tx.transaction.provides);
248                for marker in waiting_tx.missing_markers {
249                    let remove = if let Some(required) = self.required_markers.get_mut(&marker) {
250                        required.remove(&hash);
251                        required.is_empty()
252                    } else {
253                        false
254                    };
255                    if remove {
256                        self.required_markers.remove(&marker);
257                    }
258                }
259                removed.push(waiting_tx.transaction)
260            }
261        }
262        removed
263    }
264}
265
266impl<T: Transaction> PendingTransactions<T> {
267    /// Adds a transaction to Pending queue of transactions
268    pub fn add_transaction(&mut self, tx: PendingPoolTransaction<T>) -> Result<(), PoolError> {
269        assert!(!tx.is_ready(), "transaction must not be ready");
270        assert!(
271            !self.waiting_queue.contains_key(&tx.transaction.hash()),
272            "transaction is already added"
273        );
274
275        if let Some(replace) = self
276            .waiting_markers
277            .get(&tx.transaction.provides)
278            .and_then(|hash| self.waiting_queue.get(hash))
279        {
280            // check if underpriced
281            if tx.transaction.max_fee_per_gas() <= replace.transaction.max_fee_per_gas() {
282                warn!(target: "txpool", "pending replacement transaction underpriced [{:?}]", tx.transaction.hash());
283                return Err(PoolError::ReplacementUnderpriced(tx.transaction.hash()));
284            }
285        }
286
287        // add all missing markers
288        for marker in &tx.missing_markers {
289            self.required_markers.entry(marker.clone()).or_default().insert(tx.transaction.hash());
290        }
291
292        // also track identifying markers
293        self.waiting_markers.insert(tx.transaction.provides.clone(), tx.transaction.hash());
294        // add tx to the queue
295        self.waiting_queue.insert(tx.transaction.hash(), tx);
296
297        Ok(())
298    }
299}
300
301/// A transaction in the pool
302#[derive(Clone)]
303pub struct PendingPoolTransaction<T> {
304    pub transaction: Arc<PoolTransaction<T>>,
305    /// markers required and have not been satisfied yet by other transactions in the pool
306    pub missing_markers: HashSet<TxMarker>,
307    /// timestamp when the tx was added
308    pub added_at: Instant,
309}
310
311impl<T> PendingPoolTransaction<T> {
312    /// Creates a new `PendingPoolTransaction`.
313    ///
314    /// Determines the markers that are still missing before this transaction can be moved to the
315    /// ready queue.
316    pub fn new(transaction: PoolTransaction<T>, provided: &HashMap<TxMarker, TxHash>) -> Self {
317        let missing_markers = transaction
318            .requires
319            .iter()
320            .filter(|marker| {
321                // is true if the marker is already satisfied either via transaction in the pool
322                !provided.contains_key(&**marker)
323            })
324            .cloned()
325            .collect();
326
327        Self { transaction: Arc::new(transaction), missing_markers, added_at: Instant::now() }
328    }
329
330    /// Removes the required marker
331    pub fn mark(&mut self, marker: &TxMarker) {
332        self.missing_markers.remove(marker);
333    }
334
335    /// Returns true if transaction has all requirements satisfied.
336    pub fn is_ready(&self) -> bool {
337        self.missing_markers.is_empty()
338    }
339}
340
341impl<T: fmt::Debug> fmt::Debug for PendingPoolTransaction<T> {
342    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
343        write!(fmt, "PendingTransaction {{ ")?;
344        write!(fmt, "added_at: {:?}, ", self.added_at)?;
345        write!(fmt, "tx: {:?}, ", self.transaction)?;
346        write!(fmt, "missing_markers: {{{}}}", hex_fmt_many(self.missing_markers.iter()))?;
347        write!(fmt, "}}")
348    }
349}
350
351pub struct TransactionsIterator<T> {
352    all: HashMap<TxHash, ReadyTransaction<T>>,
353    awaiting: HashMap<TxHash, (usize, PoolTransactionRef<T>)>,
354    independent: BTreeSet<PoolTransactionRef<T>>,
355    _invalid: HashSet<TxHash>,
356}
357
358impl<T> TransactionsIterator<T> {
359    /// Depending on number of satisfied requirements insert given ref
360    /// either to awaiting set or to best set.
361    fn independent_or_awaiting(&mut self, satisfied: usize, tx_ref: PoolTransactionRef<T>) {
362        if satisfied >= tx_ref.transaction.requires.len() {
363            // If we have satisfied all deps insert to best
364            self.independent.insert(tx_ref);
365        } else {
366            // otherwise we're still awaiting for some deps
367            self.awaiting.insert(tx_ref.transaction.hash(), (satisfied, tx_ref));
368        }
369    }
370}
371
372impl<T> Iterator for TransactionsIterator<T> {
373    type Item = Arc<PoolTransaction<T>>;
374
375    fn next(&mut self) -> Option<Self::Item> {
376        loop {
377            let best = self.independent.iter().next_back()?.clone();
378            let best = self.independent.take(&best)?;
379            let hash = best.transaction.hash();
380
381            let ready =
382                if let Some(ready) = self.all.get(&hash).cloned() { ready } else { continue };
383
384            // Insert transactions that just got unlocked.
385            for hash in &ready.unlocks {
386                // first check local awaiting transactions
387                let res = if let Some((mut satisfied, tx_ref)) = self.awaiting.remove(hash) {
388                    satisfied += 1;
389                    Some((satisfied, tx_ref))
390                    // then get from the pool
391                } else {
392                    self.all
393                        .get(hash)
394                        .map(|next| (next.requires_offset + 1, next.transaction.clone()))
395                };
396                if let Some((satisfied, tx_ref)) = res {
397                    self.independent_or_awaiting(satisfied, tx_ref)
398                }
399            }
400
401            return Some(best.transaction);
402        }
403    }
404}
405
406/// transactions that are ready to be included in a block.
407#[derive(Clone, Debug)]
408pub struct ReadyTransactions<T> {
409    /// keeps track of transactions inserted in the pool
410    ///
411    /// this way we can determine when transactions where submitted to the pool
412    id: u64,
413    /// markers that are provided by `ReadyTransaction`s
414    provided_markers: HashMap<TxMarker, TxHash>,
415    /// transactions that are ready
416    ready_tx: Arc<RwLock<HashMap<TxHash, ReadyTransaction<T>>>>,
417    /// independent transactions that can be included directly and don't require other transactions
418    /// Sorted by their id
419    independent_transactions: BTreeSet<PoolTransactionRef<T>>,
420}
421
422impl<T> Default for ReadyTransactions<T> {
423    fn default() -> Self {
424        Self {
425            id: 0,
426            provided_markers: Default::default(),
427            ready_tx: Default::default(),
428            independent_transactions: Default::default(),
429        }
430    }
431}
432
433impl<T> ReadyTransactions<T> {
434    /// Returns an iterator over all transactions
435    pub fn get_transactions(&self) -> TransactionsIterator<T> {
436        TransactionsIterator {
437            all: self.ready_tx.read().clone(),
438            independent: self.independent_transactions.clone(),
439            awaiting: Default::default(),
440            _invalid: Default::default(),
441        }
442    }
443
444    /// Clears the internal state
445    pub fn clear(&mut self) {
446        self.provided_markers.clear();
447        self.ready_tx.write().clear();
448        self.independent_transactions.clear();
449    }
450
451    /// Returns true if the transaction is part of the queue.
452    pub fn contains(&self, hash: &TxHash) -> bool {
453        self.ready_tx.read().contains_key(hash)
454    }
455
456    /// Returns the number of ready transactions without cloning the snapshot
457    pub fn len(&self) -> usize {
458        self.ready_tx.read().len()
459    }
460
461    /// Returns true if there are no ready transactions
462    pub fn is_empty(&self) -> bool {
463        self.ready_tx.read().is_empty()
464    }
465
466    /// Returns the transaction for the hash if it's in the ready pool but not yet mined
467    pub fn get(&self, hash: &TxHash) -> Option<ReadyTransaction<T>> {
468        self.ready_tx.read().get(hash).cloned()
469    }
470
471    pub const fn provided_markers(&self) -> &HashMap<TxMarker, TxHash> {
472        &self.provided_markers
473    }
474
475    const fn next_id(&mut self) -> u64 {
476        let id = self.id;
477        self.id = self.id.wrapping_add(1);
478        id
479    }
480
481    /// Removes the transactions from the ready queue and returns the removed transactions.
482    /// This will also remove all transactions that depend on those.
483    pub fn clear_transactions(&mut self, tx_hashes: &[TxHash]) -> Vec<Arc<PoolTransaction<T>>> {
484        self.remove_with_markers(tx_hashes.to_vec(), None)
485    }
486
487    /// Removes the transactions that provide the marker
488    ///
489    /// This will also remove all transactions that lead to the transaction that provides the
490    /// marker.
491    pub fn prune_tags(&mut self, marker: TxMarker) -> Vec<Arc<PoolTransaction<T>>> {
492        let mut removed_tx = vec![];
493
494        // the markers to remove
495        let mut remove = vec![marker];
496
497        while let Some(marker) = remove.pop() {
498            let res = self
499                .provided_markers
500                .remove(&marker)
501                .and_then(|hash| self.ready_tx.write().remove(&hash));
502
503            if let Some(tx) = res {
504                let unlocks = tx.unlocks;
505                self.independent_transactions.remove(&tx.transaction);
506                let tx = tx.transaction.transaction;
507
508                // also prune previous transactions
509                {
510                    let hash = tx.hash();
511                    let mut ready = self.ready_tx.write();
512
513                    let mut previous_markers = |marker| -> Option<Vec<TxMarker>> {
514                        let prev_hash = self.provided_markers.get(marker)?;
515                        let tx2 = ready.get_mut(prev_hash)?;
516                        // remove hash
517                        if let Some(idx) = tx2.unlocks.iter().position(|i| i == &hash) {
518                            tx2.unlocks.swap_remove(idx);
519                        }
520                        tx2.unlocks.is_empty().then(|| tx2.transaction.transaction.provides.clone())
521                    };
522
523                    // find previous transactions
524                    for marker in &tx.requires {
525                        if let Some(mut tags_to_remove) = previous_markers(marker) {
526                            remove.append(&mut tags_to_remove);
527                        }
528                    }
529                }
530
531                // add the transactions that just got unlocked to independent set
532                for hash in unlocks {
533                    if let Some(tx) = self.ready_tx.write().get_mut(&hash) {
534                        tx.requires_offset += 1;
535                        if tx.requires_offset == tx.transaction.transaction.requires.len() {
536                            self.independent_transactions.insert(tx.transaction.clone());
537                        }
538                    }
539                }
540                // finally, remove the markers that this transaction provides
541                let current_marker = &marker;
542                for marker in &tx.provides {
543                    let removed = self.provided_markers.remove(marker);
544                    assert_eq!(
545                        removed,
546                        if current_marker == marker { None } else { Some(tx.hash()) },
547                        "The pool contains exactly one transaction providing given tag; the removed transaction
548						claims to provide that tag, so it has to be mapped to it's hash; qed"
549                    );
550                }
551                removed_tx.push(tx);
552            }
553        }
554
555        removed_tx
556    }
557
558    /// Removes transactions and those that depend on them and satisfy at least one marker in the
559    /// given filter set.
560    pub fn remove_with_markers(
561        &mut self,
562        mut tx_hashes: Vec<TxHash>,
563        marker_filter: Option<HashSet<TxMarker>>,
564    ) -> Vec<Arc<PoolTransaction<T>>> {
565        let mut removed = Vec::new();
566        let mut ready = self.ready_tx.write();
567
568        while let Some(hash) = tx_hashes.pop() {
569            if let Some(mut tx) = ready.remove(&hash) {
570                let invalidated = tx.transaction.transaction.provides.iter().filter(|mark| {
571                    marker_filter.as_ref().map(|filter| !filter.contains(&**mark)).unwrap_or(true)
572                });
573
574                let mut removed_some_marks = false;
575                // remove entries from provided_markers
576                for mark in invalidated {
577                    removed_some_marks = true;
578                    self.provided_markers.remove(mark);
579                }
580
581                // remove from unlocks
582                for mark in &tx.transaction.transaction.requires {
583                    if let Some(provider_hash) = self.provided_markers.get(mark)
584                        && let Some(provider_tx) = ready.get_mut(provider_hash)
585                        && let Some(idx) = provider_tx.unlocks.iter().position(|i| i == &hash)
586                    {
587                        provider_tx.unlocks.swap_remove(idx);
588                    }
589                }
590
591                // remove from the independent set
592                self.independent_transactions.remove(&tx.transaction);
593
594                if removed_some_marks {
595                    // remove all transactions that the current one unlocks
596                    tx_hashes.append(&mut tx.unlocks);
597                }
598
599                // remove transaction
600                removed.push(tx.transaction.transaction);
601            }
602        }
603
604        removed
605    }
606}
607
608impl<T: Transaction> ReadyTransactions<T> {
609    /// Adds a new transactions to the ready queue.
610    ///
611    /// # Panics
612    ///
613    /// If the pending transaction is not ready ([`PendingPoolTransaction::is_ready`])
614    /// or the transaction is already included.
615    pub fn add_transaction(
616        &mut self,
617        tx: PendingPoolTransaction<T>,
618    ) -> Result<Vec<Arc<PoolTransaction<T>>>, PoolError> {
619        assert!(tx.is_ready(), "transaction must be ready",);
620        assert!(
621            !self.ready_tx.read().contains_key(&tx.transaction.hash()),
622            "transaction already included"
623        );
624
625        let (replaced_tx, unlocks) = self.replaced_transactions(&tx.transaction)?;
626
627        let id = self.next_id();
628        let hash = tx.transaction.hash();
629
630        let mut independent = true;
631        let mut requires_offset = 0;
632        let mut ready = self.ready_tx.write();
633        // Add links to transactions that unlock the current one
634        for mark in &tx.transaction.requires {
635            // Check if the transaction that satisfies the mark is still in the queue.
636            if let Some(other) = self.provided_markers.get(mark) {
637                let tx = ready.get_mut(other).expect("hash included;");
638                tx.unlocks.push(hash);
639                // tx still depends on other tx
640                independent = false;
641            } else {
642                requires_offset += 1;
643            }
644        }
645
646        // update markers
647        for mark in tx.transaction.provides.iter().cloned() {
648            self.provided_markers.insert(mark, hash);
649        }
650
651        let transaction = PoolTransactionRef { id, transaction: tx.transaction };
652
653        // add to the independent set
654        if independent {
655            self.independent_transactions.insert(transaction.clone());
656        }
657
658        // insert to ready queue
659        ready.insert(hash, ReadyTransaction { transaction, unlocks, requires_offset });
660
661        Ok(replaced_tx)
662    }
663
664    /// Removes and returns those transactions that got replaced by the `tx`
665    fn replaced_transactions(
666        &mut self,
667        tx: &PoolTransaction<T>,
668    ) -> Result<ReplacedTransactions<T>, PoolError> {
669        // check if we are replacing transactions
670        let remove_hashes: HashSet<_> =
671            tx.provides.iter().filter_map(|mark| self.provided_markers.get(mark)).collect();
672
673        // early exit if we are not replacing anything.
674        if remove_hashes.is_empty() {
675            return Ok((Vec::new(), Vec::new()));
676        }
677
678        // check if we're replacing the same transaction and if it can be replaced
679        let mut unlocked_tx = Vec::new();
680        {
681            // construct a list of unlocked transactions
682            // also check for transactions that shouldn't be replaced because underpriced
683            let ready = self.ready_tx.read();
684            for to_remove in remove_hashes.iter().filter_map(|hash| ready.get(*hash)) {
685                // if we're attempting to replace a transaction that provides the exact same markers
686                // (addr + nonce) then we check for gas price
687                if to_remove.provides() == tx.provides {
688                    // check if underpriced
689                    if tx.pending_transaction.transaction.max_fee_per_gas()
690                        <= to_remove.max_fee_per_gas()
691                    {
692                        warn!(target: "txpool", "ready replacement transaction underpriced [{:?}]", tx.hash());
693                        return Err(PoolError::ReplacementUnderpriced(tx.hash()));
694                    }
695                    trace!(target: "txpool", "replacing ready transaction [{:?}] with higher gas price [{:?}]", to_remove.transaction.transaction.hash(), tx.hash());
696                }
697
698                unlocked_tx.extend(to_remove.unlocks.iter().copied())
699            }
700        }
701
702        let remove_hashes = remove_hashes.into_iter().copied().collect::<Vec<_>>();
703
704        let new_provides = tx.provides.iter().cloned().collect::<HashSet<_>>();
705        let removed_tx = self.remove_with_markers(remove_hashes, Some(new_provides));
706
707        Ok((removed_tx, unlocked_tx))
708    }
709}
710
711/// A reference to a transaction in the pool
712#[derive(Debug)]
713pub struct PoolTransactionRef<T> {
714    /// actual transaction
715    pub transaction: Arc<PoolTransaction<T>>,
716    /// identifier used to internally compare the transaction in the pool
717    pub id: u64,
718}
719
720impl<T> Clone for PoolTransactionRef<T> {
721    fn clone(&self) -> Self {
722        Self { transaction: Arc::clone(&self.transaction), id: self.id }
723    }
724}
725
726impl<T> Eq for PoolTransactionRef<T> {}
727
728impl<T> PartialEq<Self> for PoolTransactionRef<T> {
729    fn eq(&self, other: &Self) -> bool {
730        self.cmp(other) == Ordering::Equal
731    }
732}
733
734impl<T> PartialOrd<Self> for PoolTransactionRef<T> {
735    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
736        Some(self.cmp(other))
737    }
738}
739
740impl<T> Ord for PoolTransactionRef<T> {
741    fn cmp(&self, other: &Self) -> Ordering {
742        self.transaction
743            .priority
744            .cmp(&other.transaction.priority)
745            .then_with(|| other.id.cmp(&self.id))
746    }
747}
748
749#[derive(Debug)]
750pub struct ReadyTransaction<T> {
751    /// ref to the actual transaction
752    pub transaction: PoolTransactionRef<T>,
753    /// tracks the transactions that get unlocked by this transaction
754    pub unlocks: Vec<TxHash>,
755    /// amount of required markers that are inherently provided
756    pub requires_offset: usize,
757}
758
759impl<T> Clone for ReadyTransaction<T> {
760    fn clone(&self) -> Self {
761        Self {
762            transaction: self.transaction.clone(),
763            unlocks: self.unlocks.clone(),
764            requires_offset: self.requires_offset,
765        }
766    }
767}
768
769impl<T> ReadyTransaction<T> {
770    pub fn provides(&self) -> &[TxMarker] {
771        &self.transaction.transaction.provides
772    }
773}
774
775impl<T: Transaction> ReadyTransaction<T> {
776    pub fn max_fee_per_gas(&self) -> u128 {
777        self.transaction.transaction.max_fee_per_gas()
778    }
779}
780
781/// creates an unique identifier for aan (`nonce` + `Address`) combo
782pub fn to_marker(nonce: u64, from: Address) -> TxMarker {
783    let mut data = [0u8; 28];
784    data[..8].copy_from_slice(&nonce.to_le_bytes()[..]);
785    data[8..].copy_from_slice(&from.0[..]);
786    data.to_vec()
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}