reth_payload_util/
transaction.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use crate::PayloadTransactions;
use alloy_consensus::Transaction;
use alloy_primitives::Address;
use reth_primitives::RecoveredTx;

/// An implementation of [`crate::traits::PayloadTransactions`] that yields
/// a pre-defined set of transactions.
///
/// This is useful to put a sequencer-specified set of transactions into the block
/// and compose it with the rest of the transactions.
#[derive(Debug)]
pub struct PayloadTransactionsFixed<T> {
    transactions: Vec<T>,
    index: usize,
}

impl<T> PayloadTransactionsFixed<T> {
    /// Constructs a new [`PayloadTransactionsFixed`].
    pub fn new(transactions: Vec<T>) -> Self {
        Self { transactions, index: Default::default() }
    }

    /// Constructs a new [`PayloadTransactionsFixed`] with a single transaction.
    pub fn single(transaction: T) -> Self {
        Self { transactions: vec![transaction], index: Default::default() }
    }
}

impl<T: Clone> PayloadTransactions for PayloadTransactionsFixed<RecoveredTx<T>> {
    type Transaction = T;

    fn next(&mut self, _ctx: ()) -> Option<RecoveredTx<T>> {
        (self.index < self.transactions.len()).then(|| {
            let tx = self.transactions[self.index].clone();
            self.index += 1;
            tx
        })
    }

    fn mark_invalid(&mut self, _sender: Address, _nonce: u64) {}
}

/// Wrapper over [`crate::traits::PayloadTransactions`] that combines transactions from multiple
/// `PayloadTransactions` iterators and keeps track of the gas for both of iterators.
///
/// We can't use [`Iterator::chain`], because:
/// (a) we need to propagate the `mark_invalid` and `no_updates`
/// (b) we need to keep track of the gas
///
/// Notes that [`PayloadTransactionsChain`] fully drains the first iterator
/// before moving to the second one.
///
/// If the `before` iterator has transactions that are not fitting into the block,
/// the after iterator will get propagated a `mark_invalid` call for each of them.
#[derive(Debug)]
pub struct PayloadTransactionsChain<B: PayloadTransactions, A: PayloadTransactions> {
    /// Iterator that will be used first
    before: B,
    /// Allowed gas for the transactions from `before` iterator. If `None`, no gas limit is
    /// enforced.
    before_max_gas: Option<u64>,
    /// Gas used by the transactions from `before` iterator
    before_gas: u64,
    /// Iterator that will be used after `before` iterator
    after: A,
    /// Allowed gas for the transactions from `after` iterator. If `None`, no gas limit is
    /// enforced.
    after_max_gas: Option<u64>,
    /// Gas used by the transactions from `after` iterator
    after_gas: u64,
}

impl<B: PayloadTransactions, A: PayloadTransactions> PayloadTransactionsChain<B, A> {
    /// Constructs a new [`PayloadTransactionsChain`].
    pub fn new(
        before: B,
        before_max_gas: Option<u64>,
        after: A,
        after_max_gas: Option<u64>,
    ) -> Self {
        Self {
            before,
            before_max_gas,
            before_gas: Default::default(),
            after,
            after_max_gas,
            after_gas: Default::default(),
        }
    }
}

impl<A, B> PayloadTransactions for PayloadTransactionsChain<A, B>
where
    A: PayloadTransactions<Transaction: Transaction>,
    B: PayloadTransactions<Transaction = A::Transaction>,
{
    type Transaction = A::Transaction;

    fn next(&mut self, ctx: ()) -> Option<RecoveredTx<Self::Transaction>> {
        while let Some(tx) = self.before.next(ctx) {
            if let Some(before_max_gas) = self.before_max_gas {
                if self.before_gas + tx.as_signed().gas_limit() <= before_max_gas {
                    self.before_gas += tx.as_signed().gas_limit();
                    return Some(tx);
                }
                self.before.mark_invalid(tx.signer(), tx.as_signed().nonce());
                self.after.mark_invalid(tx.signer(), tx.as_signed().nonce());
            } else {
                return Some(tx);
            }
        }

        while let Some(tx) = self.after.next(ctx) {
            if let Some(after_max_gas) = self.after_max_gas {
                if self.after_gas + tx.as_signed().gas_limit() <= after_max_gas {
                    self.after_gas += tx.as_signed().gas_limit();
                    return Some(tx);
                }
                self.after.mark_invalid(tx.signer(), tx.as_signed().nonce());
            } else {
                return Some(tx);
            }
        }

        None
    }

    fn mark_invalid(&mut self, sender: Address, nonce: u64) {
        self.before.mark_invalid(sender, nonce);
        self.after.mark_invalid(sender, nonce);
    }
}