revm_statetest_types/
test.rs1use 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#[derive(Debug, PartialEq, Eq, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct Test {
13 pub expect_exception: Option<String>,
19
20 pub indexes: TxPartIndices,
22 pub hash: B256,
24 #[serde(default)]
26 pub post_state: AddressMap<AccountInfo>,
27
28 pub logs: B256,
30
31 #[serde(default)]
35 state: AddressMap<AccountInfo>,
36
37 pub txbytes: Option<Bytes>,
39}
40
41impl Test {
42 pub fn tx_env(&self, unit: &TestUnit) -> Result<TxEnv, TestError> {
62 let Some(secret_key) = unit.transaction.secret_key else {
66 return Err(TestError::UnexpectedException {
67 expected_exception: self.expect_exception.clone(),
68 got_exception: Some("Missing secret key".to_string()),
69 });
70 };
71
72 let caller = if let Some(address) = unit.transaction.sender {
74 address
75 } else {
76 recover_address(secret_key.as_slice())
77 .ok_or(TestError::UnknownPrivateKey(secret_key))?
78 };
79
80 let tx_type = unit.transaction.tx_type(self.indexes.data).ok_or_else(|| {
82 if self.expect_exception.is_some() {
83 TestError::UnexpectedException {
84 expected_exception: self.expect_exception.clone(),
85 got_exception: Some("Invalid transaction type".to_string()),
86 }
87 } else {
88 TestError::InvalidTransactionType
89 }
90 })?;
91
92 let tx = TxEnv {
93 caller,
94 gas_price: unit
95 .transaction
96 .gas_price
97 .or(unit.transaction.max_fee_per_gas)
98 .unwrap_or_default()
99 .try_into()
100 .unwrap_or(u128::MAX),
101 gas_priority_fee: unit
102 .transaction
103 .max_priority_fee_per_gas
104 .map(|b| u128::try_from(b).expect("max priority fee less than u128::MAX")),
105 blob_hashes: unit.transaction.blob_versioned_hashes.clone(),
106 max_fee_per_blob_gas: unit
107 .transaction
108 .max_fee_per_blob_gas
109 .map(|b| u128::try_from(b).expect("max fee less than u128::MAX"))
110 .unwrap_or(u128::MAX),
111 tx_type: tx_type as u8,
112 gas_limit: unit.transaction.gas_limit[self.indexes.gas].saturating_to(),
113 data: unit.transaction.data[self.indexes.data].clone(),
114 nonce: u64::try_from(unit.transaction.nonce).map_err(|_| {
115 TestError::UnexpectedException {
116 expected_exception: self.expect_exception.clone(),
117 got_exception: Some("Nonce overflow".to_string()),
118 }
119 })?,
120 chain_id: Some(
121 unit.transaction
122 .chain_id
123 .map(|id| id.try_into().unwrap_or(u64::MAX))
124 .unwrap_or(1),
125 ),
126 value: unit.transaction.value[self.indexes.value],
127 access_list: unit
128 .transaction
129 .access_lists
130 .get(self.indexes.data)
131 .cloned()
132 .flatten()
133 .unwrap_or_default(),
134 authorization_list: unit
135 .transaction
136 .authorization_list
137 .clone()
138 .map(|auth_list| {
139 auth_list
140 .into_iter()
141 .map(|i| context::either::Either::Left(i.into()))
142 .collect::<Vec<_>>()
143 })
144 .unwrap_or_default(),
145 kind: match unit.transaction.to {
146 Some(add) => TxKind::Call(add),
147 None => TxKind::Create,
148 },
149 };
150
151 Ok(tx)
152 }
153}