1use crate::PayloadTransactions;
2use alloy_consensus::Transaction;
3use alloy_primitives::Address;
4use reth_transaction_pool::PoolTransaction;
56/// 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}
1617impl<T> PayloadTransactionsFixed<T> {
18/// Constructs a new [`PayloadTransactionsFixed`].
19pub fn new(transactions: Vec<T>) -> Self {
20Self { transactions, index: Default::default() }
21 }
2223/// Constructs a new [`PayloadTransactionsFixed`] with a single transaction.
24pub fn single(transaction: T) -> Self {
25Self { transactions: vec![transaction], index: Default::default() }
26 }
27}
2829impl<T: Clone> PayloadTransactionsfor PayloadTransactionsFixed<T> {
30type Transaction = T;
3132fn next(&mut self, _ctx: ()) -> Option<T> {
33 (self.index < self.transactions.len()).then(|| {
34let tx = self.transactions[self.index].clone();
35self.index += 1;
36tx37 })
38 }
3940fn mark_invalid(&mut self, _sender: Address, _nonce: u64) {}
41}
4243/// 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
58before: B,
59/// Allowed gas for the transactions from `before` iterator. If `None`, no gas limit is
60 /// enforced.
61before_max_gas: Option<u64>,
62/// Gas used by the transactions from `before` iterator
63before_gas: u64,
64/// Iterator that will be used after `before` iterator
65after: A,
66/// Allowed gas for the transactions from `after` iterator. If `None`, no gas limit is
67 /// enforced.
68after_max_gas: Option<u64>,
69/// Gas used by the transactions from `after` iterator
70after_gas: u64,
71}
7273impl<B: PayloadTransactions, A: PayloadTransactions> PayloadTransactionsChain<B, A> {
74/// Constructs a new [`PayloadTransactionsChain`].
75pub fn new(
76 before: B,
77 before_max_gas: Option<u64>,
78 after: A,
79 after_max_gas: Option<u64>,
80 ) -> Self {
81Self {
82before,
83before_max_gas,
84 before_gas: Default::default(),
85after,
86after_max_gas,
87 after_gas: Default::default(),
88 }
89 }
90}
9192impl<A, B> PayloadTransactionsfor PayloadTransactionsChain<A, B>
93where
94A: PayloadTransactions<Transaction: PoolTransaction>,
95 B: PayloadTransactions<Transaction = A::Transaction>,
96{
97type Transaction = A::Transaction;
9899fn next(&mut self, ctx: ()) -> Option<Self::Transaction> {
100while let Some(tx) = self.before.next(ctx) {
101if let Some(before_max_gas) = self.before_max_gas {
102if self.before_gas + tx.gas_limit() <= before_max_gas {
103self.before_gas += tx.gas_limit();
104return Some(tx);
105 }
106self.before.mark_invalid(tx.sender(), tx.nonce());
107self.after.mark_invalid(tx.sender(), tx.nonce());
108 } else {
109return Some(tx);
110 }
111 }
112113while let Some(tx) = self.after.next(ctx) {
114if let Some(after_max_gas) = self.after_max_gas {
115if self.after_gas + tx.gas_limit() <= after_max_gas {
116self.after_gas += tx.gas_limit();
117return Some(tx);
118 }
119self.after.mark_invalid(tx.sender(), tx.nonce());
120 } else {
121return Some(tx);
122 }
123 }
124125None126 }
127128fn mark_invalid(&mut self, sender: Address, nonce: u64) {
129self.before.mark_invalid(sender, nonce);
130self.after.mark_invalid(sender, nonce);
131 }
132}