revm_statetest_types/
transaction.rs

1use crate::{deserializer::deserialize_maybe_empty, TestAuthorization};
2use revm::{
3    context_interface::transaction::{AccessList, TransactionType},
4    primitives::{Address, Bytes, B256, U256},
5};
6use serde::{Deserialize, Serialize};
7
8/// Transaction parts.
9#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct TransactionParts {
12    pub data: Vec<Bytes>,
13    pub gas_limit: Vec<U256>,
14    pub gas_price: Option<U256>,
15    pub nonce: U256,
16    pub secret_key: B256,
17    /// if sender is not present we need to derive it from secret key.
18    #[serde(default)]
19    pub sender: Option<Address>,
20    #[serde(default, deserialize_with = "deserialize_maybe_empty")]
21    pub to: Option<Address>,
22    pub value: Vec<U256>,
23    pub max_fee_per_gas: Option<U256>,
24    pub max_priority_fee_per_gas: Option<U256>,
25
26    #[serde(default)]
27    pub access_lists: Vec<Option<AccessList>>,
28    pub authorization_list: Option<Vec<TestAuthorization>>,
29    #[serde(default)]
30    pub blob_versioned_hashes: Vec<B256>,
31    pub max_fee_per_blob_gas: Option<U256>,
32}
33
34impl TransactionParts {
35    /// Returns the transaction type.   
36    ///
37    /// As this information is derived from the fields it is not stored in the struct.
38    ///
39    /// Returns `None` if the transaction is invalid:
40    ///   * It has both blob gas and no destination.
41    ///   * It has authorization list and no destination.
42    pub fn tx_type(&self, access_list_index: usize) -> Option<TransactionType> {
43        let mut tx_type = TransactionType::Legacy;
44
45        // If it has access list it is EIP-2930 tx
46        if let Some(access_list) = self.access_lists.get(access_list_index) {
47            if access_list.is_some() {
48                tx_type = TransactionType::Eip2930;
49            }
50        }
51
52        // If there is max_fee it is EIP-1559 tx
53        if self.max_fee_per_gas.is_some() {
54            tx_type = TransactionType::Eip1559;
55        }
56
57        // If it has max_fee_per_blob_gas it is EIP-4844 tx
58        if self.max_fee_per_blob_gas.is_some() {
59            // target need to be present for EIP-4844 tx
60            self.to?;
61            tx_type = TransactionType::Eip4844;
62        }
63
64        // And if it has authorization list it is EIP-7702 tx
65        if self.authorization_list.is_some() {
66            // Target need to be present for EIP-7702 tx
67            self.to?;
68            tx_type = TransactionType::Eip7702;
69        }
70
71        Some(tx_type)
72    }
73}
74
75/// Transaction part indices.
76#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
77#[serde(rename_all = "camelCase", deny_unknown_fields)]
78pub struct TxPartIndices {
79    pub data: usize,
80    pub gas: usize,
81    pub value: usize,
82}
83
84#[cfg(test)]
85mod test {
86
87    use super::*;
88
89    #[test]
90    fn decode_tx_parts() {
91        let tx = r#"{
92            "nonce": "0x00",
93            "maxPriorityFeePerGas": "0x00",
94            "maxFeePerGas": "0x07",
95            "gasLimit": [
96                "0x0423ff"
97            ],
98            "to": "0x0000000000000000000000000000000000001000",
99            "value": [
100                "0x00"
101            ],
102            "data": [
103                "0x"
104            ],
105            "accessLists": [
106                [
107                    {
108                        "address": "0x6389e7f33ce3b1e94e4325ef02829cd12297ef71",
109                        "storageKeys": [
110                            "0x0000000000000000000000000000000000000000000000000000000000000000"
111                        ]
112                    }
113                ]
114            ],
115            "authorizationList": [
116                {
117                    "chainId": "0x00",
118                    "address": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
119                    "nonce": "0x00",
120                    "v": "0x01",
121                    "r": "0x5a8cac98fd240d8ef83c22db4a061ffa0facb1801245283cc05fc809d8b92837",
122                    "s": "0x1c3162fe11d91bc24d4fa00fb19ca34531e0eacdf8142c804be44058d5b8244f",
123                    "signer": "0x6389e7f33ce3b1e94e4325ef02829cd12297ef71"
124                }
125            ],
126            "sender": "0x8a0a19589531694250d570040a0c4b74576919b8",
127            "secretKey": "0x9e7645d0cfd9c3a04eb7a9db59a4eb7d359f2e75c9164a9d6b9a7d54e1b6a36f"
128        }"#;
129
130        let _: TransactionParts = serde_json::from_str(tx).unwrap();
131    }
132}