reth_payload_util/
transaction.rs

1use crate::PayloadTransactions;
2use alloy_consensus::Transaction;
3use alloy_primitives::Address;
4use reth_transaction_pool::PoolTransaction;
5
6/// An implementation of [`crate::traits::PayloadTransactions`] that yields
7/// a pre-defined set of transactions.
8///
9/// This is useful to put a sequencer-specified set of transactions into the block
10/// and compose it with the rest of the transactions.
11#[derive(Debug)]
12pub struct PayloadTransactionsFixed<T> {
13    transactions: Vec<T>,
14    index: usize,
15}
16
17impl<T> PayloadTransactionsFixed<T> {
18    /// Constructs a new [`PayloadTransactionsFixed`].
19    pub fn new(transactions: Vec<T>) -> Self {
20        Self { transactions, index: Default::default() }
21    }
22
23    /// Constructs a new [`PayloadTransactionsFixed`] with a single transaction.
24    pub fn single(transaction: T) -> Self {
25        Self { transactions: vec![transaction], index: Default::default() }
26    }
27}
28
29impl<T: Clone> PayloadTransactions for PayloadTransactionsFixed<T> {
30    type Transaction = T;
31
32    fn next(&mut self, _ctx: ()) -> Option<T> {
33        (self.index < self.transactions.len()).then(|| {
34            let tx = self.transactions[self.index].clone();
35            self.index += 1;
36            tx
37        })
38    }
39
40    fn mark_invalid(&mut self, _sender: Address, _nonce: u64) {}
41}
42
43/// Wrapper over [`crate::traits::PayloadTransactions`] that combines transactions from multiple
44/// `PayloadTransactions` iterators and keeps track of the gas for both of iterators.
45///
46/// We can't use [`Iterator::chain`], because:
47/// (a) we need to propagate the `mark_invalid` and `no_updates`
48/// (b) we need to keep track of the gas
49///
50/// Notes that [`PayloadTransactionsChain`] fully drains the first iterator
51/// before moving to the second one.
52///
53/// If the `before` iterator has transactions that are not fitting into the block,
54/// the after iterator will get propagated a `mark_invalid` call for each of them.
55#[derive(Debug)]
56pub struct PayloadTransactionsChain<B: PayloadTransactions, A: PayloadTransactions> {
57    /// Iterator that will be used first
58    before: B,
59    /// Allowed gas for the transactions from `before` iterator. If `None`, no gas limit is
60    /// enforced.
61    before_max_gas: Option<u64>,
62    /// Gas used by the transactions from `before` iterator
63    before_gas: u64,
64    /// Iterator that will be used after `before` iterator
65    after: A,
66    /// Allowed gas for the transactions from `after` iterator. If `None`, no gas limit is
67    /// enforced.
68    after_max_gas: Option<u64>,
69    /// Gas used by the transactions from `after` iterator
70    after_gas: u64,
71}
72
73impl<B: PayloadTransactions, A: PayloadTransactions> PayloadTransactionsChain<B, A> {
74    /// Constructs a new [`PayloadTransactionsChain`].
75    pub fn new(
76        before: B,
77        before_max_gas: Option<u64>,
78        after: A,
79        after_max_gas: Option<u64>,
80    ) -> Self {
81        Self {
82            before,
83            before_max_gas,
84            before_gas: Default::default(),
85            after,
86            after_max_gas,
87            after_gas: Default::default(),
88        }
89    }
90}
91
92impl<A, B> PayloadTransactions for PayloadTransactionsChain<A, B>
93where
94    A: PayloadTransactions<Transaction: PoolTransaction>,
95    B: PayloadTransactions<Transaction = A::Transaction>,
96{
97    type Transaction = A::Transaction;
98
99    fn next(&mut self, ctx: ()) -> Option<Self::Transaction> {
100        while let Some(tx) = self.before.next(ctx) {
101            if let Some(before_max_gas) = self.before_max_gas {
102                if self.before_gas + tx.gas_limit() <= before_max_gas {
103                    self.before_gas += tx.gas_limit();
104                    return Some(tx);
105                }
106                self.before.mark_invalid(tx.sender(), tx.nonce());
107                self.after.mark_invalid(tx.sender(), tx.nonce());
108            } else {
109                return Some(tx);
110            }
111        }
112
113        while let Some(tx) = self.after.next(ctx) {
114            if let Some(after_max_gas) = self.after_max_gas {
115                if self.after_gas + tx.gas_limit() <= after_max_gas {
116                    self.after_gas += tx.gas_limit();
117                    return Some(tx);
118                }
119                self.after.mark_invalid(tx.sender(), tx.nonce());
120            } else {
121                return Some(tx);
122            }
123        }
124
125        None
126    }
127
128    fn mark_invalid(&mut self, sender: Address, nonce: u64) {
129        self.before.mark_invalid(sender, nonce);
130        self.after.mark_invalid(sender, nonce);
131    }
132}