1use crate::{state::StateOverride, Block, BlockOverrides, Log, TransactionRequest};
4use alloc::{string::String, vec::Vec};
5use alloy_primitives::Bytes;
6
7pub const MAX_SIMULATE_BLOCKS: u64 = 256;
9
10#[derive(Clone, Debug, Default)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
16pub struct SimBlock {
17 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
19 pub block_overrides: Option<BlockOverrides>,
20 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
22 pub state_overrides: Option<StateOverride>,
23 #[cfg_attr(feature = "serde", serde(default))]
25 pub calls: Vec<TransactionRequest>,
26}
27
28impl SimBlock {
29 pub fn with_state_overrides(mut self, overrides: StateOverride) -> Self {
31 self.state_overrides = Some(overrides);
32 self
33 }
34
35 pub fn with_block_overrides(mut self, overrides: BlockOverrides) -> Self {
37 self.block_overrides = Some(overrides);
38 self
39 }
40
41 pub fn call(mut self, call: TransactionRequest) -> Self {
43 self.calls.push(call);
44 self
45 }
46
47 pub fn extend_calls(mut self, calls: impl IntoIterator<Item = TransactionRequest>) -> Self {
49 self.calls.extend(calls);
50 self
51 }
52}
53
54#[derive(Clone, Debug)]
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
58pub struct SimulatedBlock<B = Block> {
59 #[cfg_attr(feature = "serde", serde(flatten))]
61 pub inner: B,
62 pub calls: Vec<SimCallResult>,
64}
65
66#[derive(Clone, Debug)]
69#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
70#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
71pub struct SimCallResult {
72 pub return_data: Bytes,
74 #[cfg_attr(feature = "serde", serde(default))]
76 pub logs: Vec<Log>,
77 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
79 pub gas_used: u64,
80 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
82 pub status: bool,
83 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
85 pub error: Option<SimulateError>,
86}
87
88#[derive(Clone, Debug, Default)]
93#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
94#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
95pub struct SimulatePayload {
96 #[cfg_attr(feature = "serde", serde(default))]
98 pub block_state_calls: Vec<SimBlock>,
99 #[cfg_attr(feature = "serde", serde(default))]
101 pub trace_transfers: bool,
102 #[cfg_attr(feature = "serde", serde(default))]
104 pub validation: bool,
105 #[cfg_attr(feature = "serde", serde(default))]
107 pub return_full_transactions: bool,
108}
109
110impl SimulatePayload {
111 pub fn extend(mut self, block: SimBlock) -> Self {
113 self.block_state_calls.push(block);
114 self
115 }
116
117 pub fn extend_blocks(mut self, blocks: impl IntoIterator<Item = SimBlock>) -> Self {
119 self.block_state_calls.extend(blocks);
120 self
121 }
122
123 pub const fn with_trace_transfers(mut self) -> Self {
125 self.trace_transfers = true;
126 self
127 }
128
129 pub const fn with_validation(mut self) -> Self {
131 self.validation = true;
132 self
133 }
134
135 pub const fn with_full_transactions(mut self) -> Self {
137 self.return_full_transactions = true;
138 self
139 }
140}
141
142#[derive(Clone, Debug)]
144#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
145#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
146pub struct SimulateError {
147 pub code: i32,
151 pub message: String,
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158 use alloy_primitives::{Address, TxKind};
159 #[cfg(feature = "serde")]
160 use serde_json::json;
161 use similar_asserts::assert_eq;
162
163 #[test]
164 #[cfg(feature = "serde")]
165 fn test_eth_simulate_v1_account_not_precompile() {
166 let request_json = json!({
167 "jsonrpc": "2.0",
168 "id": 1,
169 "method": "eth_simulateV1",
170 "params": [{
171 "blockStateCalls": [
172 {
173 "blockOverrides": {},
174 "stateOverrides": {
175 "0xc000000000000000000000000000000000000000": {
176 "nonce": "0x5"
177 }
178 },
179 "calls": []
180 },
181 {
182 "blockOverrides": {},
183 "stateOverrides": {
184 "0xc000000000000000000000000000000000000000": {
185 "code": "0x600035600055"
186 }
187 },
188 "calls": [
189 {
190 "from": "0xc000000000000000000000000000000000000000",
191 "to": "0xc000000000000000000000000000000000000000",
192 "nonce": "0x0"
193 },
194 {
195 "from": "0xc100000000000000000000000000000000000000",
196 "to": "0xc100000000000000000000000000000000000000",
197 "nonce": "0x5"
198 }
199 ]
200 }
201 ],
202 "traceTransfers": false,
203 "validation": true,
204 "returnFullTransactions": false
205 }, "latest"]
206 });
207
208 let sim_opts: SimulatePayload =
209 serde_json::from_value(request_json["params"][0].clone()).unwrap();
210
211 let address_1: Address = "0xc000000000000000000000000000000000000000".parse().unwrap();
212 let address_2: Address = "0xc100000000000000000000000000000000000000".parse().unwrap();
213
214 assert!(sim_opts.validation);
215 assert_eq!(sim_opts.block_state_calls.len(), 2);
216
217 let block_state_call_1 = &sim_opts.block_state_calls[0];
218 assert!(block_state_call_1.state_overrides.as_ref().unwrap().contains_key(&address_1));
219 assert_eq!(
220 block_state_call_1
221 .state_overrides
222 .as_ref()
223 .unwrap()
224 .get(&address_1)
225 .unwrap()
226 .nonce
227 .unwrap(),
228 5
229 );
230
231 let block_state_call_2 = &sim_opts.block_state_calls[1];
232 assert!(block_state_call_2.state_overrides.as_ref().unwrap().contains_key(&address_1));
233
234 assert_eq!(block_state_call_2.calls.len(), 2);
235 assert_eq!(block_state_call_2.calls[0].from.unwrap(), address_1);
236 assert_eq!(block_state_call_2.calls[0].to.unwrap(), TxKind::Call(address_1));
237 assert_eq!(block_state_call_2.calls[0].nonce.unwrap(), 0);
238 assert_eq!(block_state_call_2.calls[1].from.unwrap(), address_2);
239 assert_eq!(block_state_call_2.calls[1].to.unwrap(), TxKind::Call(address_2));
240 assert_eq!(block_state_call_2.calls[1].nonce.unwrap(), 5);
241 }
242}