revm_context_interface/
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
pub mod transaction_type;

use specification::eip4844::GAS_PER_BLOB;
pub use transaction_type::TransactionType;

use auto_impl::auto_impl;
use core::cmp::min;
use core::fmt::Debug;
use primitives::{Address, Bytes, TxKind, B256, U256};
use std::boxed::Box;

/// Transaction validity error types.
pub trait TransactionError: Debug + core::error::Error {}

/// (Optional signer, chain id, nonce, address)
pub type AuthorizationItem = (Option<Address>, U256, u64, Address);

/// Main Transaction trait that abstracts and specifies all transaction currently supported by Ethereum
///
/// Access to any associated type is gaited behind [`tx_type`][Transaction::tx_type] function.
///
/// It can be extended to support new transaction types and only transaction types can be
/// deprecated by not returning tx_type.
#[auto_impl(&, Box, Arc, Rc)]
pub trait Transaction {
    /// Returns the transaction type.
    ///
    /// Depending on this field other functions should be called.
    fn tx_type(&self) -> u8;

    /// Caller aka Author aka transaction signer.
    ///
    /// Note : Common field for all transactions.
    fn caller(&self) -> Address;

    /// The maximum amount of gas the transaction can use.
    ///
    /// Note : Common field for all transactions.
    fn gas_limit(&self) -> u64;

    /// The value sent to the receiver of [`TxKind::Call`][primitives::TxKind::Call].
    ///
    /// Note : Common field for all transactions.
    fn value(&self) -> U256;

    /// Returns the input data of the transaction.
    ///
    /// Note : Common field for all transactions.
    fn input(&self) -> &Bytes;

    /// The nonce of the transaction.
    ///
    /// Note : Common field for all transactions.
    fn nonce(&self) -> u64;

    /// Transaction kind. It can be Call or Create.
    ///
    /// Kind is applicable for: Legacy, EIP-2930, EIP-1559
    /// And is Call for EIP-4844 and EIP-7702 transactions.
    fn kind(&self) -> TxKind;

    /// Chain Id is optional for legacy transactions.
    ///
    /// As it was introduced in EIP-155.
    fn chain_id(&self) -> Option<u64>;

    /// Gas price for the transaction.
    /// It is only applicable for Legacy and EIP-2930 transactions.
    /// For Eip1559 it is max_fee_per_gas.
    fn gas_price(&self) -> u128;

    fn access_list(&self) -> Option<impl Iterator<Item = (&Address, &[B256])>>;

    fn access_list_nums(&self) -> Option<(usize, usize)> {
        self.access_list().map(|al| {
            let mut accounts_num = 0;
            let mut storage_num = 0;
            for (_, storage) in al {
                accounts_num += 1;
                storage_num += storage.len();
            }

            (accounts_num, storage_num)
        })
    }
    /// Returns vector of fixed size hash(32 bytes)
    ///
    /// Note : EIP-4844 transaction field.
    fn blob_versioned_hashes(&self) -> &[B256];

    /// Max fee per data gas
    ///
    /// Note : EIP-4844 transaction field.
    fn max_fee_per_blob_gas(&self) -> u128;

    /// Total gas for all blobs. Max number of blocks is already checked
    /// so we dont need to check for overflow.
    ///
    /// TODO remove this
    fn total_blob_gas(&self) -> u64 {
        GAS_PER_BLOB * self.blob_versioned_hashes().len() as u64
    }

    /// Calculates the maximum [EIP-4844] `data_fee` of the transaction.
    ///
    /// This is used for ensuring that the user has at least enough funds to pay the
    /// `max_fee_per_blob_gas * total_blob_gas`, on top of regular gas costs.
    ///
    /// See EIP-4844:
    /// <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md#execution-layer-validation>
    ///
    /// TODO remove it, make a utility trait.
    fn calc_max_data_fee(&self) -> U256 {
        let blob_gas = U256::from(self.total_blob_gas());
        let max_blob_fee = U256::from(self.max_fee_per_blob_gas());
        max_blob_fee.saturating_mul(blob_gas)
    }

    /// Returns length of the authorization list.
    ///
    /// # Note
    /// Transaction is considered invalid if list is empty.
    fn authorization_list_len(&self) -> usize;

    /// List of authorizations, that contains the signature that authorizes this
    /// caller to place the code to signer account.
    ///
    /// Set EOA account code for one transaction
    ///
    /// [EIP-Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702)
    fn authorization_list(&self) -> impl Iterator<Item = AuthorizationItem>;

    /// Returns maximum fee that can be paid for the transaction.
    fn max_fee_per_gas(&self) -> u128 {
        self.gas_price()
    }

    /// Maximum priority fee per gas.
    fn max_priority_fee_per_gas(&self) -> Option<u128>;

    /// Returns effective gas price is gas price field for Legacy and Eip2930 transaction.
    ///
    /// While for transactions after Eip1559 it is minimum of max_fee and `base + max_priority_fee`.
    fn effective_gas_price(&self, base_fee: u128) -> u128 {
        let max_fee = self.gas_price();
        let Some(max_priority_fee) = self.max_priority_fee_per_gas() else {
            return max_fee;
        };
        min(max_fee, base_fee.saturating_add(max_priority_fee))
    }
}

#[auto_impl(&, &mut, Box, Arc)]
pub trait TransactionGetter {
    type Transaction: Transaction;

    fn tx(&self) -> &Self::Transaction;
}

pub trait TransactionSetter: TransactionGetter {
    fn set_tx(&mut self, tx: <Self as TransactionGetter>::Transaction);
}

impl<T: TransactionSetter> TransactionSetter for &mut T {
    fn set_tx(&mut self, block: <Self as TransactionGetter>::Transaction) {
        (**self).set_tx(block)
    }
}

impl<T: TransactionSetter> TransactionSetter for Box<T> {
    fn set_tx(&mut self, block: <Self as TransactionGetter>::Transaction) {
        (**self).set_tx(block)
    }
}