Skip to main content

revm_statetest_types/
test.rs

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