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)]
128#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
129#[cfg_attr(
130 feature = "serde",
131 serde(
132 rename_all = "camelCase",
133 bound(
134 deserialize = "TxReq: serde::Deserialize<'de>",
135 serialize = "TxReq: serde::Serialize"
136 )
137 )
138)]
139pub struct SimulatePayload<TxReq = TransactionRequest> {
140 #[cfg_attr(feature = "serde", serde(default))]
142 pub block_state_calls: Vec<SimBlock<TxReq>>,
143 #[cfg_attr(feature = "serde", serde(default))]
145 pub trace_transfers: bool,
146 #[cfg_attr(feature = "serde", serde(default))]
148 pub validation: bool,
149 #[cfg_attr(feature = "serde", serde(default))]
151 pub return_full_transactions: bool,
152}
153
154impl<TxReq> Default for SimulatePayload<TxReq> {
155 fn default() -> Self {
156 Self {
157 block_state_calls: Vec::new(),
158 trace_transfers: false,
159 validation: false,
160 return_full_transactions: false,
161 }
162 }
163}
164
165impl<TxReq> SimulatePayload<TxReq> {
166 pub fn extend(mut self, block: SimBlock<TxReq>) -> Self {
168 self.block_state_calls.push(block);
169 self
170 }
171
172 pub fn extend_blocks(mut self, blocks: impl IntoIterator<Item = SimBlock<TxReq>>) -> Self {
174 self.block_state_calls.extend(blocks);
175 self
176 }
177
178 pub const fn with_trace_transfers(mut self) -> Self {
180 self.trace_transfers = true;
181 self
182 }
183
184 pub const fn with_validation(mut self) -> Self {
186 self.validation = true;
187 self
188 }
189
190 pub const fn with_full_transactions(mut self) -> Self {
192 self.return_full_transactions = true;
193 self
194 }
195}
196
197#[derive(Clone, Debug)]
199#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
200#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
201pub struct SimulateError {
202 pub code: i32,
208 pub message: String,
210 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
212 pub data: Option<Bytes>,
213}
214
215impl SimulateError {
216 pub const EXECUTION_REVERTED_CODE: i32 = EthRpcErrorCode::ExecutionError.code();
218 pub const VM_EXECUTION_ERROR_CODE: i32 = -32015;
220 pub const INVALID_PARAMS_ERROR_CODE: i32 = -32602;
222
223 pub fn invalid_params() -> Self {
225 Self {
226 code: Self::INVALID_PARAMS_ERROR_CODE,
227 message: "invalid params".to_string(),
228 data: None,
229 }
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236 use alloy_primitives::{bytes, Address, TxKind};
237 #[cfg(feature = "serde")]
238 use serde_json::json;
239 use similar_asserts::assert_eq;
240
241 #[test]
242 #[cfg(feature = "serde")]
243 fn test_deserialize_simulate_error_no_data() {
244 let error_json = json!({
245 "code": -32000,
246 "message": "Execution reverted"
247 });
248 let err: SimulateError = serde_json::from_value(error_json).unwrap();
249 assert_eq!(err.data, None);
250 }
251
252 #[test]
253 #[cfg(feature = "serde")]
254 fn test_deserialize_simulate_error_with_data() {
255 let error_json = json!({
256 "code": -32000,
257 "message": "Execution reverted",
258 "data": "0xcabedea8"
259 });
260 let err: SimulateError = serde_json::from_value(error_json).unwrap();
261 assert_eq!(err.data, Some(bytes!("cabedea8")));
262 }
263
264 #[test]
265 #[cfg(feature = "serde")]
266 fn test_eth_simulate_v1_account_not_precompile() {
267 let request_json = json!({
268 "jsonrpc": "2.0",
269 "id": 1,
270 "method": "eth_simulateV1",
271 "params": [{
272 "blockStateCalls": [
273 {
274 "blockOverrides": {},
275 "stateOverrides": {
276 "0xc000000000000000000000000000000000000000": {
277 "nonce": "0x5"
278 }
279 },
280 "calls": []
281 },
282 {
283 "blockOverrides": {},
284 "stateOverrides": {
285 "0xc000000000000000000000000000000000000000": {
286 "code": "0x600035600055"
287 }
288 },
289 "calls": [
290 {
291 "from": "0xc000000000000000000000000000000000000000",
292 "to": "0xc000000000000000000000000000000000000000",
293 "nonce": "0x0"
294 },
295 {
296 "from": "0xc100000000000000000000000000000000000000",
297 "to": "0xc100000000000000000000000000000000000000",
298 "nonce": "0x5"
299 }
300 ]
301 }
302 ],
303 "traceTransfers": false,
304 "validation": true,
305 "returnFullTransactions": false
306 }, "latest"]
307 });
308
309 let sim_opts: SimulatePayload =
310 serde_json::from_value(request_json["params"][0].clone()).unwrap();
311
312 let address_1: Address = "0xc000000000000000000000000000000000000000".parse().unwrap();
313 let address_2: Address = "0xc100000000000000000000000000000000000000".parse().unwrap();
314
315 assert!(sim_opts.validation);
316 assert_eq!(sim_opts.block_state_calls.len(), 2);
317
318 let block_state_call_1 = &sim_opts.block_state_calls[0];
319 assert!(block_state_call_1.state_overrides.as_ref().unwrap().contains_key(&address_1));
320 assert_eq!(
321 block_state_call_1
322 .state_overrides
323 .as_ref()
324 .unwrap()
325 .get(&address_1)
326 .unwrap()
327 .nonce
328 .unwrap(),
329 5
330 );
331
332 let block_state_call_2 = &sim_opts.block_state_calls[1];
333 assert!(block_state_call_2.state_overrides.as_ref().unwrap().contains_key(&address_1));
334
335 assert_eq!(block_state_call_2.calls.len(), 2);
336 assert_eq!(block_state_call_2.calls[0].from.unwrap(), address_1);
337 assert_eq!(block_state_call_2.calls[0].to.unwrap(), TxKind::Call(address_1));
338 assert_eq!(block_state_call_2.calls[0].nonce.unwrap(), 0);
339 assert_eq!(block_state_call_2.calls[1].from.unwrap(), address_2);
340 assert_eq!(block_state_call_2.calls[1].to.unwrap(), TxKind::Call(address_2));
341 assert_eq!(block_state_call_2.calls[1].nonce.unwrap(), 5);
342 }
343
344 #[test]
345 fn test_simulate_error_codes() {
346 assert_eq!(SimulateError::EXECUTION_REVERTED_CODE, EthRpcErrorCode::ExecutionError.code());
347 assert_eq!(SimulateError::VM_EXECUTION_ERROR_CODE, -32015);
348 assert_eq!(SimulateError::invalid_params().code, SimulateError::INVALID_PARAMS_ERROR_CODE);
349 }
350}