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)
}
}