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