revm_context_interface/
transaction.rs

1mod alloy_types;
2pub mod eip2930;
3pub mod eip7702;
4pub mod transaction_type;
5
6pub use alloy_types::{
7    AccessList, AccessListItem, Authorization, RecoveredAuthority, RecoveredAuthorization,
8    SignedAuthorization,
9};
10pub use eip2930::AccessListItemTr;
11pub use eip7702::AuthorizationTr;
12pub use transaction_type::TransactionType;
13
14use crate::result::InvalidTransaction;
15use auto_impl::auto_impl;
16use core::cmp::min;
17use core::fmt::Debug;
18use primitives::{eip4844::GAS_PER_BLOB, Address, Bytes, TxKind, B256, U256};
19
20/// Transaction validity error types.
21pub trait TransactionError: Debug + core::error::Error {}
22
23/// Main Transaction trait that abstracts and specifies all transaction currently supported by Ethereum
24///
25/// Access to any associated type is gaited behind [`tx_type`][Transaction::tx_type] function.
26///
27/// It can be extended to support new transaction types and only transaction types can be
28/// deprecated by not returning tx_type.
29#[auto_impl(&, Box, Arc, Rc)]
30pub trait Transaction {
31    type AccessListItem<'a>: AccessListItemTr
32    where
33        Self: 'a;
34    type Authorization<'a>: AuthorizationTr
35    where
36        Self: 'a;
37
38    /// Returns the transaction type.
39    ///
40    /// Depending on this field other functions should be called.
41    fn tx_type(&self) -> u8;
42
43    /// Caller aka Author aka transaction signer.
44    ///
45    /// Note : Common field for all transactions.
46    fn caller(&self) -> Address;
47
48    /// The maximum amount of gas the transaction can use.
49    ///
50    /// Note : Common field for all transactions.
51    fn gas_limit(&self) -> u64;
52
53    /// The value sent to the receiver of [`TxKind::Call`][primitives::TxKind::Call].
54    ///
55    /// Note : Common field for all transactions.
56    fn value(&self) -> U256;
57
58    /// Returns the input data of the transaction.
59    ///
60    /// Note : Common field for all transactions.
61    fn input(&self) -> &Bytes;
62
63    /// The nonce of the transaction.
64    ///
65    /// Note : Common field for all transactions.
66    fn nonce(&self) -> u64;
67
68    /// Transaction kind. It can be Call or Create.
69    ///
70    /// Kind is applicable for: Legacy, EIP-2930, EIP-1559
71    /// And is Call for EIP-4844 and EIP-7702 transactions.
72    fn kind(&self) -> TxKind;
73
74    /// Chain Id is optional for legacy transactions.
75    ///
76    /// As it was introduced in EIP-155.
77    fn chain_id(&self) -> Option<u64>;
78
79    /// Gas price for the transaction.
80    /// It is only applicable for Legacy and EIP-2930 transactions.
81    /// For Eip1559 it is max_fee_per_gas.
82    fn gas_price(&self) -> u128;
83
84    /// Access list for the transaction.
85    ///
86    /// Introduced in EIP-2930.
87    fn access_list(&self) -> Option<impl Iterator<Item = Self::AccessListItem<'_>>>;
88
89    /// Returns vector of fixed size hash(32 bytes)
90    ///
91    /// Note : EIP-4844 transaction field.
92    fn blob_versioned_hashes(&self) -> &[B256];
93
94    /// Max fee per data gas
95    ///
96    /// Note : EIP-4844 transaction field.
97    fn max_fee_per_blob_gas(&self) -> u128;
98
99    /// Total gas for all blobs. Max number of blocks is already checked
100    /// so we dont need to check for overflow.
101    fn total_blob_gas(&self) -> u64 {
102        GAS_PER_BLOB * self.blob_versioned_hashes().len() as u64
103    }
104
105    /// Calculates the maximum [EIP-4844] `data_fee` of the transaction.
106    ///
107    /// This is used for ensuring that the user has at least enough funds to pay the
108    /// `max_fee_per_blob_gas * total_blob_gas`, on top of regular gas costs.
109    ///
110    /// See EIP-4844:
111    /// <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md#execution-layer-validation>
112    fn calc_max_data_fee(&self) -> U256 {
113        let blob_gas = U256::from(self.total_blob_gas());
114        let max_blob_fee = U256::from(self.max_fee_per_blob_gas());
115        max_blob_fee.saturating_mul(blob_gas)
116    }
117
118    /// Returns length of the authorization list.
119    ///
120    /// # Note
121    ///
122    /// Transaction is considered invalid if list is empty.
123    fn authorization_list_len(&self) -> usize;
124
125    /// List of authorizations, that contains the signature that authorizes this
126    /// caller to place the code to signer account.
127    ///
128    /// Set EOA account code for one transaction
129    ///
130    /// [EIP-Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702)
131    fn authorization_list(&self) -> impl Iterator<Item = Self::Authorization<'_>>;
132
133    // TODO(EOF)
134    // /// List of initcodes found in Initcode transaction. Initcodes can only be accessed
135    // /// by TXCREATE opcode to create a new EOF contract.
136    // ///
137    // /// Each transaction can contain up to [`primitives::eof::MAX_INITCODE_COUNT`] initcodes,
138    // /// with each initcode not exceeding [`primitives::MAX_INITCODE_SIZE`] bytes in size.
139    // ///
140    // /// EIP link: <https://eips.ethereum.org/EIPS/eip-7873>
141    // fn initcodes(&self) -> &[Bytes];
142
143    /// Returns maximum fee that can be paid for the transaction.
144    fn max_fee_per_gas(&self) -> u128 {
145        self.gas_price()
146    }
147
148    /// Maximum priority fee per gas.
149    fn max_priority_fee_per_gas(&self) -> Option<u128>;
150
151    /// Returns effective gas price is gas price field for Legacy and Eip2930 transaction.
152    ///
153    /// While for transactions after Eip1559 it is minimum of max_fee and `base + max_priority_fee`.
154    fn effective_gas_price(&self, base_fee: u128) -> u128 {
155        if self.tx_type() == TransactionType::Legacy as u8
156            || self.tx_type() == TransactionType::Eip2930 as u8
157        {
158            return self.gas_price();
159        }
160
161        // for EIP-1559 tx and onwards gas_price represents maximum price.
162        let max_price = self.gas_price();
163        let Some(max_priority_fee) = self.max_priority_fee_per_gas() else {
164            return max_price;
165        };
166        min(max_price, base_fee.saturating_add(max_priority_fee))
167    }
168
169    /// Returns the maximum balance that can be spent by the transaction.
170    ///
171    /// Return U256 or error if all values overflow U256 number.
172    fn max_balance_spending(&self) -> Result<U256, InvalidTransaction> {
173        // gas_limit * max_fee + value + additional_gas_cost
174        let mut max_balance_spending = U256::from(self.gas_limit())
175            .checked_mul(U256::from(self.max_fee_per_gas()))
176            .and_then(|gas_cost| gas_cost.checked_add(self.value()))
177            .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?;
178
179        // add blob fee
180        if self.tx_type() == TransactionType::Eip4844 {
181            let data_fee = self.calc_max_data_fee();
182            max_balance_spending = max_balance_spending
183                .checked_add(data_fee)
184                .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?;
185        }
186        Ok(max_balance_spending)
187    }
188
189    /// Returns the effective balance that is going to be spent that depends on base_fee
190    ///
191    /// This is always strictly less than [`Self::max_balance_spending`].
192    ///
193    /// Return U256 or error if all values overflow U256 number.
194    fn effective_balance_spending(
195        &self,
196        base_fee: u128,
197        blob_price: u128,
198    ) -> Result<U256, InvalidTransaction> {
199        // gas_limit * max_fee + value + additional_gas_cost
200        let mut effective_balance_spending = U256::from(self.gas_limit())
201            .checked_mul(U256::from(self.effective_gas_price(base_fee)))
202            .and_then(|gas_cost| gas_cost.checked_add(self.value()))
203            .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?;
204
205        // add blob fee
206        if self.tx_type() == TransactionType::Eip4844 {
207            let blob_gas = self.total_blob_gas() as u128;
208            effective_balance_spending = effective_balance_spending
209                .checked_add(U256::from(blob_price).saturating_mul(U256::from(blob_gas)))
210                .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?;
211        }
212
213        Ok(effective_balance_spending)
214    }
215}
216
217#[auto_impl(&, &mut, Box, Arc)]
218pub trait TransactionGetter {
219    type Transaction: Transaction;
220
221    fn tx(&self) -> &Self::Transaction;
222}