revm_context/
tx.rs

1use crate::TransactionType;
2use context_interface::transaction::{
3    AccessList, AccessListItem, SignedAuthorization, Transaction,
4};
5use core::fmt::Debug;
6use primitives::{Address, Bytes, TxKind, B256, U256};
7use std::vec::Vec;
8
9/// The transaction environment
10#[derive(Clone, Debug, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct TxEnv {
13    pub tx_type: u8,
14    /// Caller aka Author aka transaction signer
15    pub caller: Address,
16    /// The gas limit of the transaction
17    pub gas_limit: u64,
18    /// The gas price of the transaction
19    pub gas_price: u128,
20    /// The destination of the transaction
21    pub kind: TxKind,
22    /// The value sent to `transact_to`
23    pub value: U256,
24    /// The data of the transaction
25    pub data: Bytes,
26
27    /// The nonce of the transaction
28    pub nonce: u64,
29
30    /// The chain ID of the transaction
31    ///
32    /// If set to [`None`], no checks are performed.
33    ///
34    /// Incorporated as part of the Spurious Dragon upgrade via [EIP-155].
35    ///
36    /// [EIP-155]: https://eips.ethereum.org/EIPS/eip-155
37    pub chain_id: Option<u64>,
38
39    /// A list of addresses and storage keys that the transaction plans to access
40    ///
41    /// Added in [EIP-2930].
42    ///
43    /// [EIP-2930]: https://eips.ethereum.org/EIPS/eip-2930
44    pub access_list: AccessList,
45
46    /// The priority fee per gas
47    ///
48    /// Incorporated as part of the London upgrade via [EIP-1559].
49    ///
50    /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559
51    pub gas_priority_fee: Option<u128>,
52
53    /// The list of blob versioned hashes
54    ///
55    /// Per EIP there should be at least one blob present if [`max_fee_per_blob_gas`][Self::max_fee_per_blob_gas] is [`Some`].
56    ///
57    /// Incorporated as part of the Cancun upgrade via [EIP-4844].
58    ///
59    /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844
60    pub blob_hashes: Vec<B256>,
61
62    /// The max fee per blob gas
63    ///
64    /// Incorporated as part of the Cancun upgrade via [EIP-4844].
65    ///
66    /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844
67    pub max_fee_per_blob_gas: u128,
68
69    /// List of authorizations
70    ///
71    /// `authorization_list` contains the signature that authorizes this
72    /// caller to place the code to signer account.
73    ///
74    /// Set EOA account code for one transaction via [EIP-7702].
75    ///
76    /// [EIP-7702]: https://eips.ethereum.org/EIPS/eip-7702
77    pub authorization_list: Vec<SignedAuthorization>,
78}
79
80impl Default for TxEnv {
81    fn default() -> Self {
82        Self {
83            tx_type: 0,
84            caller: Address::default(),
85            gas_limit: 30_000_000,
86            gas_price: 0,
87            kind: TxKind::Call(Address::default()),
88            value: U256::ZERO,
89            data: Bytes::default(),
90            nonce: 0,
91            chain_id: Some(1), // Mainnet chain ID is 1
92            access_list: Default::default(),
93            gas_priority_fee: Some(0),
94            blob_hashes: Vec::new(),
95            max_fee_per_blob_gas: 0,
96            authorization_list: Vec::new(),
97        }
98    }
99}
100
101#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
102#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103pub enum DeriveTxTypeError {
104    MissingTargetForEip4844,
105    MissingTargetForEip7702,
106}
107
108impl TxEnv {
109    /// Derives tx type from transaction fields and sets it to `tx_type`.
110    /// Returns error in case some fields were not set correctly.
111    pub fn derive_tx_type(&mut self) -> Result<(), DeriveTxTypeError> {
112        let mut tx_type = TransactionType::Legacy;
113
114        if !self.access_list.0.is_empty() {
115            tx_type = TransactionType::Eip2930;
116        }
117
118        if self.gas_priority_fee.is_some() {
119            tx_type = TransactionType::Eip1559;
120        }
121
122        if !self.blob_hashes.is_empty() {
123            if let TxKind::Call(_) = self.kind {
124                tx_type = TransactionType::Eip4844;
125            } else {
126                return Err(DeriveTxTypeError::MissingTargetForEip4844);
127            }
128        }
129
130        if !self.authorization_list.is_empty() {
131            if let TxKind::Call(_) = self.kind {
132                tx_type = TransactionType::Eip7702;
133            } else {
134                return Err(DeriveTxTypeError::MissingTargetForEip7702);
135            }
136        }
137
138        self.tx_type = tx_type as u8;
139        Ok(())
140    }
141}
142
143impl Transaction for TxEnv {
144    type AccessListItem = AccessListItem;
145    type Authorization = SignedAuthorization;
146
147    fn tx_type(&self) -> u8 {
148        self.tx_type
149    }
150
151    fn kind(&self) -> TxKind {
152        self.kind
153    }
154
155    fn caller(&self) -> Address {
156        self.caller
157    }
158
159    fn gas_limit(&self) -> u64 {
160        self.gas_limit
161    }
162
163    fn gas_price(&self) -> u128 {
164        self.gas_price
165    }
166
167    fn value(&self) -> U256 {
168        self.value
169    }
170
171    fn nonce(&self) -> u64 {
172        self.nonce
173    }
174
175    fn chain_id(&self) -> Option<u64> {
176        self.chain_id
177    }
178
179    fn access_list(&self) -> Option<impl Iterator<Item = &Self::AccessListItem>> {
180        Some(self.access_list.0.iter())
181    }
182
183    fn max_fee_per_gas(&self) -> u128 {
184        self.gas_price
185    }
186
187    fn max_fee_per_blob_gas(&self) -> u128 {
188        self.max_fee_per_blob_gas
189    }
190
191    fn authorization_list_len(&self) -> usize {
192        self.authorization_list.len()
193    }
194
195    fn authorization_list(&self) -> impl Iterator<Item = &Self::Authorization> {
196        self.authorization_list.iter()
197    }
198
199    fn input(&self) -> &Bytes {
200        &self.data
201    }
202
203    fn blob_versioned_hashes(&self) -> &[B256] {
204        &self.blob_hashes
205    }
206
207    fn max_priority_fee_per_gas(&self) -> Option<u128> {
208        self.gas_priority_fee
209    }
210}