revm_statetest_types/
transaction.rs

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