revm_context_interface/
transaction.rs

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