moonbeam_client_evm_tracing/listeners/
raw.rs1use ethereum_types::{H160, H256};
18use std::{collections::btree_map::BTreeMap, vec, vec::Vec};
19
20use crate::types::{convert_memory, single::RawStepLog, ContextType};
21use evm_tracing_events::{
22 runtime::{Capture, ExitReason},
23 Event, GasometerEvent, Listener as ListenerT, RuntimeEvent, StepEventFilter,
24};
25
26#[derive(Debug)]
27pub struct Listener {
28 disable_storage: bool,
29 disable_memory: bool,
30 disable_stack: bool,
31
32 new_context: bool,
33 context_stack: Vec<Context>,
34
35 pub struct_logs: Vec<RawStepLog>,
36 pub return_value: Vec<u8>,
37 pub final_gas: u64,
38 pub remaining_memory_usage: Option<usize>,
39}
40
41#[derive(Debug)]
42struct Context {
43 storage_cache: BTreeMap<H256, H256>,
44 address: H160,
45 current_step: Option<Step>,
46 global_storage_changes: BTreeMap<H160, BTreeMap<H256, H256>>,
47}
48
49#[derive(Debug)]
50struct Step {
51 opcode: Vec<u8>,
53 depth: usize,
55 gas: u64,
57 gas_cost: u64,
59 position: usize,
61 memory: Option<Vec<u8>>,
63 stack: Option<Vec<H256>>,
65}
66
67impl Listener {
68 pub fn new(
69 disable_storage: bool,
70 disable_memory: bool,
71 disable_stack: bool,
72 raw_max_memory_usage: usize,
73 ) -> Self {
74 Self {
75 disable_storage,
76 disable_memory,
77 disable_stack,
78 remaining_memory_usage: Some(raw_max_memory_usage),
79
80 struct_logs: vec![],
81 return_value: vec![],
82 final_gas: 0,
83
84 new_context: false,
85 context_stack: vec![],
86 }
87 }
88
89 pub fn using<R, F: FnOnce() -> R>(&mut self, f: F) -> R {
90 evm_tracing_events::using(self, f)
91 }
92
93 pub fn gasometer_event(&mut self, event: GasometerEvent) {
94 match event {
95 GasometerEvent::RecordTransaction { cost, .. } => {
96 self.new_context = true;
99 self.final_gas = cost;
100 }
101 GasometerEvent::RecordCost { cost, snapshot } => {
102 if let Some(context) = self.context_stack.last_mut() {
103 if let Some(step) = &mut context.current_step {
105 step.gas = snapshot.gas();
106 step.gas_cost = cost;
107 }
108
109 self.final_gas = snapshot.used_gas;
110 }
111 }
112 GasometerEvent::RecordDynamicCost {
113 gas_cost, snapshot, ..
114 } => {
115 if let Some(context) = self.context_stack.last_mut() {
116 if let Some(step) = &mut context.current_step {
118 step.gas = snapshot.gas();
119 step.gas_cost = gas_cost;
120 }
121
122 self.final_gas = snapshot.used_gas;
123 }
124 }
125 #[allow(unreachable_patterns)]
127 _ => (),
128 }
129 }
130
131 pub fn runtime_event(&mut self, event: RuntimeEvent) {
132 match event {
133 RuntimeEvent::Step {
134 context,
135 opcode,
136 position,
137 stack,
138 memory,
139 } => {
140 if self.new_context {
142 self.new_context = false;
143
144 self.context_stack.push(Context {
145 storage_cache: BTreeMap::new(),
146 address: context.address,
147 current_step: None,
148 global_storage_changes: BTreeMap::new(),
149 });
150 }
151
152 let depth = self.context_stack.len();
153
154 if let Some(context) = self.context_stack.last_mut() {
156 context.current_step = Some(Step {
157 opcode,
158 depth,
159 gas: 0, gas_cost: 0, position: *position.as_ref().unwrap_or(&0) as usize,
162 memory: if self.disable_memory {
163 None
164 } else {
165 let memory = memory.expect("memory data to not be filtered out");
166
167 self.remaining_memory_usage = self
168 .remaining_memory_usage
169 .and_then(|inner| inner.checked_sub(memory.data.len()));
170
171 if self.remaining_memory_usage.is_none() {
172 return;
173 }
174
175 Some(memory.data.clone())
176 },
177 stack: if self.disable_stack {
178 None
179 } else {
180 let stack = stack.expect("stack data to not be filtered out");
181
182 self.remaining_memory_usage = self
183 .remaining_memory_usage
184 .and_then(|inner| inner.checked_sub(stack.data.len()));
185
186 if self.remaining_memory_usage.is_none() {
187 return;
188 }
189
190 Some(stack.data.clone())
191 },
192 });
193 }
194 }
195 RuntimeEvent::StepResult {
196 result,
197 return_value,
198 } => {
199 if let Some(context) = self.context_stack.last_mut() {
204 if let Some(current_step) = context.current_step.take() {
205 let Step {
206 opcode,
207 depth,
208 gas,
209 gas_cost,
210 position,
211 memory,
212 stack,
213 } = current_step;
214
215 let memory = memory.map(convert_memory);
216
217 let storage = if self.disable_storage {
218 None
219 } else {
220 self.remaining_memory_usage =
221 self.remaining_memory_usage.and_then(|inner| {
222 inner.checked_sub(context.storage_cache.len() * 64)
223 });
224
225 if self.remaining_memory_usage.is_none() {
226 return;
227 }
228
229 Some(context.storage_cache.clone())
230 };
231
232 self.struct_logs.push(RawStepLog {
233 depth: depth.into(),
234 gas: gas.into(),
235 gas_cost: gas_cost.into(),
236 memory,
237 op: opcode,
238 pc: position.into(),
239 stack,
240 storage,
241 });
242 }
243 }
244
245 match result {
247 Err(Capture::Exit(reason)) => {
248 if let Some(mut context) = self.context_stack.pop() {
250 if self.context_stack.is_empty() {
252 self.return_value = return_value.to_vec();
253 }
254
255 if !self.disable_storage && matches!(reason, ExitReason::Succeed(_)) {
258 if let Some(parent_context) = self.context_stack.last_mut() {
259 context
261 .global_storage_changes
262 .insert(context.address, context.storage_cache);
263
264 for (address, mut storage) in
266 context.global_storage_changes.into_iter()
267 {
268 if parent_context.address == address {
270 for (cached_key, cached_value) in
271 parent_context.storage_cache.iter_mut()
272 {
273 if let Some(value) = storage.remove(cached_key) {
274 *cached_value = value;
275 }
276 }
277 }
278 else {
280 parent_context
281 .global_storage_changes
282 .entry(address)
283 .or_insert_with(BTreeMap::new)
284 .append(&mut storage);
285 }
286 }
287 }
288 }
289 }
290 }
291 Err(Capture::Trap(opcode)) if ContextType::from(opcode.clone()).is_some() => {
292 self.new_context = true;
293 }
294 _ => (),
295 }
296 }
297 RuntimeEvent::SLoad {
298 address: _,
299 index,
300 value,
301 }
302 | RuntimeEvent::SStore {
303 address: _,
304 index,
305 value,
306 } => {
307 if let Some(context) = self.context_stack.last_mut() {
308 if !self.disable_storage {
309 context.storage_cache.insert(index, value);
310 }
311 }
312 }
313 #[allow(unreachable_patterns)]
315 _ => (),
316 }
317 }
318}
319
320impl ListenerT for Listener {
321 fn event(&mut self, event: Event) {
322 if self.remaining_memory_usage.is_none() {
323 return;
324 }
325
326 match event {
327 Event::Gasometer(e) => self.gasometer_event(e),
328 Event::Runtime(e) => self.runtime_event(e),
329 _ => {}
330 };
331 }
332
333 fn step_event_filter(&self) -> StepEventFilter {
334 StepEventFilter {
335 enable_memory: !self.disable_memory,
336 enable_stack: !self.disable_stack,
337 }
338 }
339}