1use crate::{
4 alloc::string::ToString, error::EthRpcErrorCode, state::StateOverride, Block, BlockOverrides,
5 Log, TransactionRequest,
6};
7use alloc::{string::String, vec::Vec};
8use alloy_primitives::{Bytes, U256};
9
10pub const MAX_SIMULATE_BLOCKS: u64 = 256;
12
13#[derive(Clone, Debug)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[cfg_attr(
19 feature = "serde",
20 serde(
21 rename_all = "camelCase",
22 bound(
23 deserialize = "TxReq: serde::Deserialize<'de>",
24 serialize = "TxReq: serde::Serialize"
25 )
26 )
27)]
28pub struct SimBlock<TxReq = TransactionRequest> {
29 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
31 pub block_overrides: Option<BlockOverrides>,
32 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
34 pub state_overrides: Option<StateOverride>,
35 #[cfg_attr(feature = "serde", serde(default = "Vec::new"))]
37 pub calls: Vec<TxReq>,
38}
39
40impl<TxReq> Default for SimBlock<TxReq> {
41 fn default() -> Self {
42 Self { block_overrides: None, state_overrides: None, calls: Vec::new() }
43 }
44}
45
46impl<TxReq> SimBlock<TxReq> {
47 pub fn with_state_overrides(mut self, overrides: StateOverride) -> Self {
49 self.state_overrides = Some(overrides);
50 self
51 }
52
53 pub fn with_block_overrides(mut self, overrides: BlockOverrides) -> Self {
55 self.block_overrides = Some(overrides);
56 self
57 }
58
59 pub fn call(mut self, call: TxReq) -> Self {
61 self.calls.push(call);
62 self
63 }
64
65 pub fn extend_calls(mut self, calls: impl IntoIterator<Item = TxReq>) -> Self {
67 self.calls.extend(calls);
68 self
69 }
70
71 pub fn block_number_override(&self) -> Option<U256> {
73 self.block_overrides.as_ref().and_then(|overrides| overrides.number)
74 }
75}
76
77#[derive(Clone, Debug, Default)]
79#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
80#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
81pub struct SimulatedBlock<B = Block> {
82 #[cfg_attr(feature = "serde", serde(flatten))]
84 pub inner: B,
85 pub calls: Vec<SimCallResult>,
87}
88
89#[derive(Clone, Debug, Default)]
92#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
93#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
94pub struct SimCallResult {
95 pub return_data: Bytes,
97 #[cfg_attr(feature = "serde", serde(default))]
99 pub logs: Vec<Log>,
100 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
102 pub gas_used: u64,
103 #[cfg_attr(
105 feature = "serde",
106 serde(
107 default,
108 skip_serializing_if = "Option::is_none",
109 with = "alloy_serde::quantity::opt"
110 )
111 )]
112 pub max_used_gas: Option<u64>,
113 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
115 pub status: bool,
116 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
118 pub error: Option<SimulateError>,
119}
120
121#[derive(Clone, Debug)]
126#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
127#[cfg_attr(
128 feature = "serde",
129 serde(
130 rename_all = "camelCase",
131 bound(
132 deserialize = "TxReq: serde::Deserialize<'de>",
133 serialize = "TxReq: serde::Serialize"
134 )
135 )
136)]
137pub struct SimulatePayload<TxReq = TransactionRequest> {
138 #[cfg_attr(feature = "serde", serde(default))]
140 pub block_state_calls: Vec<SimBlock<TxReq>>,
141 #[cfg_attr(feature = "serde", serde(default))]
143 pub trace_transfers: bool,
144 #[cfg_attr(feature = "serde", serde(default))]
146 pub validation: bool,
147 #[cfg_attr(feature = "serde", serde(default))]
149 pub return_full_transactions: bool,
150}
151
152impl<TxReq> Default for SimulatePayload<TxReq> {
153 fn default() -> Self {
154 Self {
155 block_state_calls: Vec::new(),
156 trace_transfers: false,
157 validation: false,
158 return_full_transactions: false,
159 }
160 }
161}
162
163impl<TxReq> SimulatePayload<TxReq> {
164 pub fn extend(mut self, block: SimBlock<TxReq>) -> Self {
166 self.block_state_calls.push(block);
167 self
168 }
169
170 pub fn extend_blocks(mut self, blocks: impl IntoIterator<Item = SimBlock<TxReq>>) -> Self {
172 self.block_state_calls.extend(blocks);
173 self
174 }
175
176 pub const fn with_trace_transfers(mut self) -> Self {
178 self.trace_transfers = true;
179 self
180 }
181
182 pub const fn with_validation(mut self) -> Self {
184 self.validation = true;
185 self
186 }
187
188 pub const fn with_full_transactions(mut self) -> Self {
190 self.return_full_transactions = true;
191 self
192 }
193}
194
195#[derive(Clone, Debug)]
197#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
198#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
199pub struct SimulateError {
200 pub code: i32,
206 pub message: String,
208 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
210 pub data: Option<Bytes>,
211}
212
213impl SimulateError {
214 pub const EXECUTION_REVERTED_CODE: i32 = EthRpcErrorCode::ExecutionError.code();
216 pub const VM_EXECUTION_ERROR_CODE: i32 = -32015;
218 pub const INVALID_PARAMS_ERROR_CODE: i32 = -32602;
220
221 pub fn invalid_params() -> Self {
223 Self {
224 code: Self::INVALID_PARAMS_ERROR_CODE,
225 message: "invalid params".to_string(),
226 data: None,
227 }
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234 use alloy_primitives::{bytes, Address, TxKind};
235 #[cfg(feature = "serde")]
236 use serde_json::json;
237 use similar_asserts::assert_eq;
238
239 #[test]
240 #[cfg(feature = "serde")]
241 fn test_deserialize_simulate_error_no_data() {
242 let error_json = json!({
243 "code": -32000,
244 "message": "Execution reverted"
245 });
246 let err: SimulateError = serde_json::from_value(error_json).unwrap();
247 assert_eq!(err.data, None);
248 }
249
250 #[test]
251 #[cfg(feature = "serde")]
252 fn test_deserialize_simulate_error_with_data() {
253 let error_json = json!({
254 "code": -32000,
255 "message": "Execution reverted",
256 "data": "0xcabedea8"
257 });
258 let err: SimulateError = serde_json::from_value(error_json).unwrap();
259 assert_eq!(err.data, Some(bytes!("cabedea8")));
260 }
261
262 #[test]
263 #[cfg(feature = "serde")]
264 fn test_eth_simulate_v1_account_not_precompile() {
265 let request_json = json!({
266 "jsonrpc": "2.0",
267 "id": 1,
268 "method": "eth_simulateV1",
269 "params": [{
270 "blockStateCalls": [
271 {
272 "blockOverrides": {},
273 "stateOverrides": {
274 "0xc000000000000000000000000000000000000000": {
275 "nonce": "0x5"
276 }
277 },
278 "calls": []
279 },
280 {
281 "blockOverrides": {},
282 "stateOverrides": {
283 "0xc000000000000000000000000000000000000000": {
284 "code": "0x600035600055"
285 }
286 },
287 "calls": [
288 {
289 "from": "0xc000000000000000000000000000000000000000",
290 "to": "0xc000000000000000000000000000000000000000",
291 "nonce": "0x0"
292 },
293 {
294 "from": "0xc100000000000000000000000000000000000000",
295 "to": "0xc100000000000000000000000000000000000000",
296 "nonce": "0x5"
297 }
298 ]
299 }
300 ],
301 "traceTransfers": false,
302 "validation": true,
303 "returnFullTransactions": false
304 }, "latest"]
305 });
306
307 let sim_opts: SimulatePayload =
308 serde_json::from_value(request_json["params"][0].clone()).unwrap();
309
310 let address_1: Address = "0xc000000000000000000000000000000000000000".parse().unwrap();
311 let address_2: Address = "0xc100000000000000000000000000000000000000".parse().unwrap();
312
313 assert!(sim_opts.validation);
314 assert_eq!(sim_opts.block_state_calls.len(), 2);
315
316 let block_state_call_1 = &sim_opts.block_state_calls[0];
317 assert!(block_state_call_1.state_overrides.as_ref().unwrap().contains_key(&address_1));
318 assert_eq!(
319 block_state_call_1
320 .state_overrides
321 .as_ref()
322 .unwrap()
323 .get(&address_1)
324 .unwrap()
325 .nonce
326 .unwrap(),
327 5
328 );
329
330 let block_state_call_2 = &sim_opts.block_state_calls[1];
331 assert!(block_state_call_2.state_overrides.as_ref().unwrap().contains_key(&address_1));
332
333 assert_eq!(block_state_call_2.calls.len(), 2);
334 assert_eq!(block_state_call_2.calls[0].from.unwrap(), address_1);
335 assert_eq!(block_state_call_2.calls[0].to.unwrap(), TxKind::Call(address_1));
336 assert_eq!(block_state_call_2.calls[0].nonce.unwrap(), 0);
337 assert_eq!(block_state_call_2.calls[1].from.unwrap(), address_2);
338 assert_eq!(block_state_call_2.calls[1].to.unwrap(), TxKind::Call(address_2));
339 assert_eq!(block_state_call_2.calls[1].nonce.unwrap(), 5);
340 }
341
342 #[test]
343 fn test_simulate_error_codes() {
344 assert_eq!(SimulateError::EXECUTION_REVERTED_CODE, EthRpcErrorCode::ExecutionError.code());
345 assert_eq!(SimulateError::VM_EXECUTION_ERROR_CODE, -32015);
346 assert_eq!(SimulateError::invalid_params().code, SimulateError::INVALID_PARAMS_ERROR_CODE);
347 }
348}