revm_statetest_types/
test.rs

1use revm::{
2    context::tx::TxEnv,
3    primitives::{Address, Bytes, HashMap, TxKind, B256},
4};
5use serde::Deserialize;
6
7use crate::{
8    error::TestError, transaction::TxPartIndices, utils::recover_address, AccountInfo, TestUnit,
9};
10
11/// State test indexed state result deserialization.
12#[derive(Debug, PartialEq, Eq, Deserialize)]
13#[serde(rename_all = "camelCase", deny_unknown_fields)]
14pub struct Test {
15    /// Expected exception for this test case, if any.
16    ///
17    /// This field contains an optional string describing an expected error or exception
18    /// that should occur during the execution of this state test. If present, the test
19    /// is expected to fail with this specific error message or exception type.
20    pub expect_exception: Option<String>,
21
22    /// Indexes
23    pub indexes: TxPartIndices,
24    /// Post state hash
25    pub hash: B256,
26    /// Post state
27    #[serde(default)]
28    pub post_state: HashMap<Address, AccountInfo>,
29
30    /// Logs root
31    pub logs: B256,
32
33    /// Output state.
34    ///
35    /// Note: Not used.
36    #[serde(default)]
37    state: HashMap<Address, AccountInfo>,
38
39    /// Tx bytes
40    pub txbytes: Option<Bytes>,
41}
42
43impl Test {
44    /// Create a transaction environment from this test and the test unit.
45    ///
46    /// This function sets up the transaction environment using the test's
47    /// indices to select the appropriate transaction parameters from the
48    /// test unit.
49    ///
50    /// # Arguments
51    ///
52    /// * `unit` - The test unit containing transaction parts
53    ///
54    /// # Returns
55    ///
56    /// A configured [`TxEnv`] ready for execution, or an error if setup fails
57    ///
58    /// # Errors
59    ///
60    /// Returns an error if:
61    /// - The private key cannot be used to recover the sender address
62    /// - The transaction type is invalid and no exception is expected
63    pub fn tx_env(&self, unit: &TestUnit) -> Result<TxEnv, TestError> {
64        // Setup sender
65        let caller = if let Some(address) = unit.transaction.sender {
66            address
67        } else {
68            recover_address(unit.transaction.secret_key.as_slice())
69                .ok_or(TestError::UnknownPrivateKey(unit.transaction.secret_key))?
70        };
71
72        // Transaction specific fields
73        let tx_type = unit.transaction.tx_type(self.indexes.data).ok_or_else(|| {
74            if self.expect_exception.is_some() {
75                TestError::UnexpectedException {
76                    expected_exception: self.expect_exception.clone(),
77                    got_exception: Some("Invalid transaction type".to_string()),
78                }
79            } else {
80                TestError::InvalidTransactionType
81            }
82        })?;
83
84        let tx = TxEnv {
85            caller,
86            gas_price: unit
87                .transaction
88                .gas_price
89                .or(unit.transaction.max_fee_per_gas)
90                .unwrap_or_default()
91                .try_into()
92                .unwrap_or(u128::MAX),
93            gas_priority_fee: unit
94                .transaction
95                .max_priority_fee_per_gas
96                .map(|b| u128::try_from(b).expect("max priority fee less than u128::MAX")),
97            blob_hashes: unit.transaction.blob_versioned_hashes.clone(),
98            max_fee_per_blob_gas: unit
99                .transaction
100                .max_fee_per_blob_gas
101                .map(|b| u128::try_from(b).expect("max fee less than u128::MAX"))
102                .unwrap_or(u128::MAX),
103            tx_type: tx_type as u8,
104            gas_limit: unit.transaction.gas_limit[self.indexes.gas].saturating_to(),
105            data: unit.transaction.data[self.indexes.data].clone(),
106            nonce: u64::try_from(unit.transaction.nonce).unwrap(),
107            value: unit.transaction.value[self.indexes.value],
108            access_list: unit
109                .transaction
110                .access_lists
111                .get(self.indexes.data)
112                .cloned()
113                .flatten()
114                .unwrap_or_default(),
115            authorization_list: unit
116                .transaction
117                .authorization_list
118                .clone()
119                .map(|auth_list| {
120                    auth_list
121                        .into_iter()
122                        .map(|i| revm::context::either::Either::Left(i.into()))
123                        .collect::<Vec<_>>()
124                })
125                .unwrap_or_default(),
126            kind: match unit.transaction.to {
127                Some(add) => TxKind::Call(add),
128                None => TxKind::Create,
129            },
130            ..TxEnv::default()
131        };
132
133        Ok(tx)
134    }
135}