1use std::collections::BTreeMap;
17use std::fmt;
18use std::sync::Arc;
19
20use bytes::Bytes;
21use serde::de::{self, SeqAccess, Visitor};
22use serde::ser::{SerializeSeq, SerializeStruct};
23use serde::{Deserialize, Deserializer, Serialize, Serializer};
24use thiserror::Error;
25
26use crate::memory::{MemoryRef, MemoryStore};
27use crate::{
28 encode_hex, opcode, EvmWord, Hex, MemoryWriteError, StepSnapshot, StorageChange, TraceStep,
29 Word, WordError,
30};
31
32pub const STACK_CHECKPOINT: usize = 32;
35
36const CHUNK_BITS: u32 = 14;
37const CHUNK: usize = 1 << CHUNK_BITS;
38
39#[derive(Debug, Clone)]
44struct Column<T> {
45 full: Vec<Box<[T]>>,
47 tail: Vec<T>,
49}
50
51impl<T> Default for Column<T> {
52 fn default() -> Self {
53 Self {
54 full: Vec::new(),
55 tail: Vec::new(),
56 }
57 }
58}
59
60impl<T: Copy> Column<T> {
61 fn len(&self) -> usize {
62 self.full.len() * CHUNK + self.tail.len()
63 }
64
65 fn push(&mut self, value: T) {
66 if self.tail.len() == CHUNK {
67 let full = std::mem::replace(&mut self.tail, Vec::with_capacity(CHUNK));
68 self.full.push(full.into_boxed_slice());
69 }
70 self.tail.push(value);
71 }
72
73 fn get(&self, index: usize) -> &T {
74 let chunk = index >> CHUNK_BITS;
75 match self.full.get(chunk) {
76 Some(full) => &full[index & (CHUNK - 1)],
77 None => &self.tail[index - self.full.len() * CHUNK],
78 }
79 }
80
81 fn get_mut(&mut self, index: usize) -> &mut T {
82 let chunk = index >> CHUNK_BITS;
83 let full = self.full.len();
84 match self.full.get_mut(chunk) {
85 Some(full) => &mut full[index & (CHUNK - 1)],
86 None => &mut self.tail[index - full * CHUNK],
87 }
88 }
89
90 fn last(&self) -> Option<&T> {
91 self.tail.last().or_else(|| self.full.last()?.last())
92 }
93
94 fn reserve(&mut self, chunks: usize, first: usize) {
96 self.full.reserve(chunks);
97 if self.full.is_empty() && self.tail.is_empty() {
98 self.tail.reserve(first.min(CHUNK));
99 }
100 }
101
102 fn truncate(&mut self, len: usize) {
103 if len >= self.len() {
104 return;
105 }
106 let whole = len / CHUNK;
107 if whole < self.full.len() {
108 self.full.truncate(whole + 1);
110 self.tail = self.full.pop().map(Vec::from).unwrap_or_default();
111 }
112 self.tail.truncate(len - whole * CHUNK);
113 }
114}
115
116#[derive(Debug, Clone, Copy)]
119struct Row {
120 gas: u64,
121 gas_cost: u64,
122 stack_start: u64,
124 memory: MemoryRef,
125 pc: u32,
127 stack_len: u32,
128 stack_kept: u32,
131 depth: u16,
133 op: u8,
134 failed: bool,
136}
137
138#[derive(Debug, Clone, Default, PartialEq, Eq)]
141pub struct StepRecord {
142 pub pc: u64,
143 pub op: u8,
144 pub gas: u64,
145 pub gas_cost: u64,
147 pub depth: u64,
148 pub error: Option<String>,
149 pub memory: Option<Bytes>,
153 pub storage: Option<Arc<BTreeMap<String, String>>>,
155 pub storage_diff: Option<BTreeMap<String, StorageChange>>,
157 pub transient_storage: Option<BTreeMap<String, String>>,
159 pub return_data: Option<Arc<str>>,
162}
163
164#[derive(Debug, Clone, PartialEq, Eq, Error)]
166pub enum StepError {
167 #[error("step {step}: stack word {position}: {error}")]
168 StackWord {
169 step: usize,
170 position: usize,
171 error: WordError,
172 },
173}
174
175#[derive(Clone, Default)]
177pub struct StepTable {
178 rows: Column<Row>,
179 words: Column<EvmWord>,
180 mnemonics: Vec<(usize, Word)>,
183 errors: Vec<(usize, Box<str>)>,
184 wide_pcs: Vec<(usize, u64)>,
187 wide_depths: Vec<(usize, u64)>,
188 storage: Vec<(usize, Arc<BTreeMap<String, String>>)>,
190 storage_diffs: Vec<(usize, BTreeMap<String, StorageChange>)>,
191 transient_storage: Vec<(usize, BTreeMap<String, String>)>,
192 return_data: Vec<(usize, Option<Arc<str>>)>,
194 memories: MemoryStore,
195 last_stack: Vec<EvmWord>,
197 last_spelled: Vec<Word>,
201 spellings: Vec<(Word, Option<u8>, bool)>,
204 scratch: Vec<EvmWord>,
206}
207
208const SPELLINGS: usize = 64;
211
212static EMPTY_STORAGE: BTreeMap<String, String> = BTreeMap::new();
213static EMPTY_STORAGE_DIFF: BTreeMap<String, StorageChange> = BTreeMap::new();
214
215impl StepTable {
216 #[must_use]
217 pub fn new() -> Self {
218 Self::default()
219 }
220
221 #[must_use]
223 pub fn with_capacity(steps: usize) -> Self {
224 let mut table = Self::new();
225 table.rows.reserve(steps.div_ceil(CHUNK), steps);
226 table
227 }
228
229 pub fn try_from_steps(steps: impl IntoIterator<Item = TraceStep>) -> Result<Self, StepError> {
235 let mut table = Self::new();
236 for step in steps {
237 table.try_push(step)?;
238 }
239 Ok(table)
240 }
241
242 #[must_use]
243 pub fn len(&self) -> usize {
244 self.rows.len()
245 }
246
247 #[must_use]
248 pub fn is_empty(&self) -> bool {
249 self.len() == 0
250 }
251
252 #[must_use]
253 pub fn get(&self, index: usize) -> Option<StepView<'_>> {
254 (index < self.len()).then_some(StepView { table: self, index })
255 }
256
257 #[must_use]
263 pub fn step(&self, index: usize) -> StepView<'_> {
264 assert!(
265 index < self.len(),
266 "step {index} of a trace of {} steps",
267 self.len()
268 );
269 StepView { table: self, index }
270 }
271
272 #[must_use]
273 pub fn first(&self) -> Option<StepView<'_>> {
274 self.get(0)
275 }
276
277 #[must_use]
278 pub fn last(&self) -> Option<StepView<'_>> {
279 self.len().checked_sub(1).and_then(|index| self.get(index))
280 }
281
282 #[must_use]
283 pub fn iter(&self) -> Steps<'_> {
284 Steps {
285 table: self,
286 front: 0,
287 back: self.len(),
288 }
289 }
290
291 pub fn push(&mut self, step: TraceStep) {
299 if let Err(error) = self.try_push(step) {
300 panic!("a step built in this process holds a stack word that is not hex: {error}");
301 }
302 }
303
304 pub fn try_push(&mut self, step: TraceStep) -> Result<(), StepError> {
310 let index = self.len();
311 let step = step.normalized();
312 let snapshot = step.snapshot;
313 let mut stack = std::mem::take(&mut self.scratch);
314 stack.clear();
315 let mut kept = 0;
316 for (position, word) in snapshot.stack.iter().enumerate() {
317 let shared = self
318 .last_spelled
319 .get(position)
320 .is_some_and(|before| Arc::ptr_eq(before, word));
321 let parsed = match self.last_stack.get(position) {
322 Some(before) if shared => *before,
323 _ => match EvmWord::parse(word) {
324 Ok(parsed) => parsed,
325 Err(error) => {
326 self.scratch = stack;
327 return Err(StepError::StackWord {
328 step: index,
329 position,
330 error,
331 });
332 }
333 },
334 };
335 if kept == position && self.last_stack.get(position) == Some(&parsed) {
336 kept += 1;
337 }
338 stack.push(parsed);
339 }
340 let (op, canonical) = self.spelling(&step.op);
341 self.append_inner(
342 StepRecord {
343 pc: step.pc,
344 op: op.unwrap_or(opcode::INVALID),
345 gas: step.gas,
346 gas_cost: step.gas_cost,
347 depth: step.depth,
348 error: step.error,
349 memory: None,
350 storage: Some(snapshot.storage),
351 storage_diff: Some(snapshot.storage_diff),
352 transient_storage: Some(snapshot.transient_storage),
353 return_data: None,
354 },
355 kept,
356 stack[kept..].iter().copied(),
357 );
358 self.scratch = stack;
359 self.last_spelled = snapshot.stack;
360 self.change_return_data(index, snapshot.return_data);
361 if !canonical {
362 self.mnemonics.push((index, step.op));
363 }
364 let memory = match snapshot.memory {
366 Some(memory) => self.memories.snapshot(memory),
367 None => MemoryRef::NONE,
368 };
369 self.rows.get_mut(index).memory = memory;
370 Ok(())
371 }
372
373 fn spelling(&mut self, spelled: &Word) -> (Option<u8>, bool) {
376 if let Some((_, op, canonical)) = self
377 .spellings
378 .iter()
379 .find(|(known, _, _)| Arc::ptr_eq(known, spelled))
380 {
381 return (*op, *canonical);
382 }
383 let op = opcode::from_spelling(spelled);
384 let canonical = op.is_some_and(|op| opcode::mnemonic(op) == &**spelled);
385 if self.spellings.len() < SPELLINGS {
386 self.spellings.push((Arc::clone(spelled), op, canonical));
387 }
388 (op, canonical)
389 }
390
391 pub fn append(&mut self, record: StepRecord, stack: impl IntoIterator<Item = EvmWord>) {
394 let mut words = stack.into_iter();
396 let mut kept = 0;
397 let mut first_new = None;
398 for word in words.by_ref() {
399 if self.last_stack.get(kept) == Some(&word) {
400 kept += 1;
401 } else {
402 first_new = Some(word);
403 break;
404 }
405 }
406 self.last_spelled.clear();
407 self.append_inner(record, kept, first_new.into_iter().chain(words));
408 }
409
410 pub fn append_kept(
418 &mut self,
419 record: StepRecord,
420 kept: usize,
421 words: impl IntoIterator<Item = EvmWord>,
422 ) {
423 self.last_spelled.clear();
424 self.append_inner(record, kept, words);
425 }
426
427 fn append_inner(
428 &mut self,
429 record: StepRecord,
430 kept: usize,
431 words: impl IntoIterator<Item = EvmWord>,
432 ) {
433 let index = self.len();
434 assert!(
435 kept <= self.last_stack.len(),
436 "step {index} keeps {kept} stack words, but the step before has {}",
437 self.last_stack.len()
438 );
439
440 self.last_stack.truncate(kept);
441 self.last_stack.extend(words);
442 let stored_from = if index.is_multiple_of(STACK_CHECKPOINT) {
443 0
444 } else {
445 kept
446 };
447 let stack_start = self.words.len() as u64;
448 for word in &self.last_stack[stored_from..] {
449 self.words.push(*word);
450 }
451 let pc = match u32::try_from(record.pc) {
452 Ok(pc) if pc != u32::MAX => pc,
453 _ => {
454 self.wide_pcs.push((index, record.pc));
455 u32::MAX
456 }
457 };
458 let depth = match u16::try_from(record.depth) {
459 Ok(depth) if depth != u16::MAX => depth,
460 _ => {
461 self.wide_depths.push((index, record.depth));
462 u16::MAX
463 }
464 };
465 let memory = match record.memory {
466 Some(memory) => self.memories.snapshot(memory),
467 None if self.memories.recording() => self.memories.current(),
468 None => self.rows.last().map_or(MemoryRef::NONE, |row| row.memory),
469 };
470 self.rows.push(Row {
471 gas: record.gas,
472 gas_cost: record.gas_cost,
473 stack_start,
474 memory,
475 pc,
476 stack_len: u32::try_from(self.last_stack.len()).unwrap_or(u32::MAX),
478 stack_kept: u32::try_from(stored_from).unwrap_or(u32::MAX),
479 depth,
480 op: record.op,
481 failed: record.error.is_some(),
482 });
483 if let Some(error) = record.error {
484 self.errors.push((index, error.into_boxed_str()));
485 }
486 if let Some(storage) = record.storage {
487 self.change_storage(index, storage);
488 }
489 if let Some(diff) = record.storage_diff.filter(|diff| !diff.is_empty()) {
490 self.storage_diffs.push((index, diff));
491 }
492 if let Some(slots) = record.transient_storage.filter(|slots| !slots.is_empty()) {
493 self.transient_storage.push((index, slots));
494 }
495 if let Some(return_data) = record.return_data {
496 self.change_return_data(index, Some(return_data));
497 }
498 }
499
500 pub fn start_memory_frame(&mut self) {
504 self.memories.start_frame();
505 }
506
507 pub fn end_memory_frame(&mut self) {
510 self.memories.end_frame();
511 }
512
513 pub fn write_memory(
523 &mut self,
524 offset: u64,
525 data: &[u8],
526 size: u64,
527 ) -> Result<(), MemoryWriteError> {
528 self.memories.write(offset, data, size)
529 }
530
531 fn change_storage(&mut self, index: usize, storage: Arc<BTreeMap<String, String>>) {
534 let current = self.storage.last().map(|(_, storage)| storage);
535 let unchanged = match current {
536 Some(current) => Arc::ptr_eq(current, &storage) || **current == *storage,
537 None => storage.is_empty(),
538 };
539 if !unchanged {
540 set_sparse(&mut self.storage, index, storage);
541 }
542 }
543
544 fn change_return_data(&mut self, index: usize, return_data: Option<Arc<str>>) {
547 let return_data = return_data.filter(|data| !data.is_empty());
548 let current = self.return_data.last().and_then(|(_, data)| data.as_ref());
549 let unchanged = match (current, &return_data) {
552 (Some(current), Some(data)) => Arc::ptr_eq(current, data) || current == data,
553 (current, data) => current.is_none() && data.is_none(),
554 };
555 if !unchanged {
556 set_sparse(&mut self.return_data, index, return_data);
557 }
558 }
559
560 pub fn storage_diffs(
562 &self,
563 ) -> impl DoubleEndedIterator<Item = (usize, &BTreeMap<String, StorageChange>)> {
564 self.storage_diffs
565 .iter()
566 .map(|(index, diff)| (*index, diff))
567 }
568
569 pub fn transient_storage(
571 &self,
572 ) -> impl DoubleEndedIterator<Item = (usize, &BTreeMap<String, String>)> {
573 self.transient_storage
574 .iter()
575 .map(|(index, slots)| (*index, slots))
576 }
577
578 pub fn truncate(&mut self, len: usize) {
580 if len >= self.len() {
581 return;
582 }
583 let last_stack = len
584 .checked_sub(1)
585 .map(|last| self.step(last).stack().to_vec())
586 .unwrap_or_default();
587 let words = len.checked_sub(1).map_or(0, |last| {
588 let row = self.rows.get(last);
589 row.stack_start as usize + row.stack_len as usize - row.stack_kept as usize
590 });
591 self.rows.truncate(len);
592 self.words.truncate(words);
593 self.mnemonics.retain(|(index, _)| *index < len);
594 self.errors.retain(|(index, _)| *index < len);
595 self.wide_pcs.retain(|(index, _)| *index < len);
596 self.wide_depths.retain(|(index, _)| *index < len);
597 self.storage.retain(|(index, _)| *index < len);
598 self.storage_diffs.retain(|(index, _)| *index < len);
599 self.transient_storage.retain(|(index, _)| *index < len);
600 self.return_data.retain(|(index, _)| *index < len);
601 self.last_stack = last_stack;
602 self.last_spelled.clear();
603 }
604
605 #[must_use]
607 pub fn to_steps(&self) -> Vec<TraceStep> {
608 self.iter().map(|step| step.to_trace_step()).collect()
609 }
610
611 fn stack_word(&self, index: usize, position: usize) -> EvmWord {
614 let mut step = index;
615 loop {
616 let row = self.rows.get(step);
617 let kept = row.stack_kept as usize;
618 if position >= kept {
619 return *self.words.get(row.stack_start as usize + position - kept);
620 }
621 step -= 1;
624 }
625 }
626}
627
628fn run_value<T>(runs: &[(usize, T)], index: usize) -> Option<&T> {
630 let after = runs.partition_point(|(start, _)| *start <= index);
631 after.checked_sub(1).map(|run| &runs[run].1)
632}
633
634fn sparse_value<T>(entries: &[(usize, T)], index: usize) -> Option<&T> {
636 entries
637 .binary_search_by_key(&index, |(step, _)| *step)
638 .ok()
639 .map(|position| &entries[position].1)
640}
641
642fn set_sparse<T>(entries: &mut Vec<(usize, T)>, index: usize, value: T) {
644 match entries.last_mut() {
645 Some((last, current)) if *last == index => *current = value,
646 _ => entries.push((index, value)),
647 }
648}
649
650impl From<Vec<TraceStep>> for StepTable {
651 fn from(steps: Vec<TraceStep>) -> Self {
655 steps.into_iter().collect()
656 }
657}
658
659impl FromIterator<TraceStep> for StepTable {
660 fn from_iter<I: IntoIterator<Item = TraceStep>>(steps: I) -> Self {
664 let mut table = Self::new();
665 table.extend(steps);
666 table
667 }
668}
669
670impl Extend<TraceStep> for StepTable {
671 fn extend<I: IntoIterator<Item = TraceStep>>(&mut self, steps: I) {
675 for step in steps {
676 self.push(step);
677 }
678 }
679}
680
681impl PartialEq for StepTable {
682 fn eq(&self, other: &Self) -> bool {
683 self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a == b)
684 }
685}
686
687impl Eq for StepTable {}
688
689impl fmt::Debug for StepTable {
690 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
691 formatter.debug_list().entries(self.iter()).finish()
692 }
693}
694
695impl<'a> IntoIterator for &'a StepTable {
696 type Item = StepView<'a>;
697 type IntoIter = Steps<'a>;
698
699 fn into_iter(self) -> Self::IntoIter {
700 self.iter()
701 }
702}
703
704#[derive(Debug, Clone)]
706pub struct Steps<'a> {
707 table: &'a StepTable,
708 front: usize,
709 back: usize,
710}
711
712impl<'a> Iterator for Steps<'a> {
713 type Item = StepView<'a>;
714
715 fn next(&mut self) -> Option<Self::Item> {
716 (self.front < self.back).then(|| {
717 self.front += 1;
718 StepView {
719 table: self.table,
720 index: self.front - 1,
721 }
722 })
723 }
724
725 fn size_hint(&self) -> (usize, Option<usize>) {
726 let remaining = self.back - self.front;
727 (remaining, Some(remaining))
728 }
729
730 fn nth(&mut self, n: usize) -> Option<Self::Item> {
731 self.front = self.front.saturating_add(n).min(self.back);
732 self.next()
733 }
734}
735
736impl DoubleEndedIterator for Steps<'_> {
737 fn next_back(&mut self) -> Option<Self::Item> {
738 (self.front < self.back).then(|| {
739 self.back -= 1;
740 StepView {
741 table: self.table,
742 index: self.back,
743 }
744 })
745 }
746}
747
748impl ExactSizeIterator for Steps<'_> {}
749
750#[derive(Clone, Copy)]
752pub struct StepView<'a> {
753 table: &'a StepTable,
754 index: usize,
755}
756
757impl<'a> StepView<'a> {
758 #[must_use]
760 pub fn index(&self) -> usize {
761 self.index
762 }
763
764 fn row(&self) -> &'a Row {
765 self.table.rows.get(self.index)
766 }
767
768 #[must_use]
769 pub fn pc(&self) -> u64 {
770 match self.row().pc {
771 u32::MAX => sparse_value(&self.table.wide_pcs, self.index)
772 .copied()
773 .unwrap_or(u64::from(u32::MAX)),
774 pc => u64::from(pc),
775 }
776 }
777
778 #[must_use]
781 pub fn op(&self) -> u8 {
782 self.row().op
783 }
784
785 #[must_use]
787 pub fn mnemonic(&self) -> &'a str {
788 if !self.table.mnemonics.is_empty() {
789 if let Some(spelled) = sparse_value(&self.table.mnemonics, self.index) {
790 return spelled;
791 }
792 }
793 opcode::mnemonic(self.op())
794 }
795
796 #[must_use]
797 pub fn gas(&self) -> u64 {
798 self.row().gas
799 }
800
801 #[must_use]
803 pub fn gas_cost(&self) -> u64 {
804 self.row().gas_cost
805 }
806
807 #[must_use]
808 pub fn depth(&self) -> u64 {
809 match self.row().depth {
810 u16::MAX => sparse_value(&self.table.wide_depths, self.index)
811 .copied()
812 .unwrap_or(u64::from(u16::MAX)),
813 depth => u64::from(depth),
814 }
815 }
816
817 #[must_use]
818 pub fn error(&self) -> Option<&'a str> {
819 if !self.row().failed {
820 return None;
821 }
822 sparse_value(&self.table.errors, self.index).map(|error| &**error)
823 }
824
825 #[must_use]
826 pub fn stack(&self) -> Stack<'a> {
827 Stack {
828 table: self.table,
829 step: self.index,
830 len: self.row().stack_len as usize,
831 }
832 }
833
834 #[must_use]
838 pub fn memory(&self) -> Option<Bytes> {
839 self.table.memories.read(self.row().memory)
840 }
841
842 #[must_use]
844 pub fn storage(&self) -> &'a BTreeMap<String, String> {
845 run_value(&self.table.storage, self.index).map_or(&EMPTY_STORAGE, |storage| storage)
846 }
847
848 #[must_use]
850 pub fn storage_diff(&self) -> &'a BTreeMap<String, StorageChange> {
851 sparse_value(&self.table.storage_diffs, self.index).unwrap_or(&EMPTY_STORAGE_DIFF)
852 }
853
854 #[must_use]
856 pub fn transient_storage(&self) -> &'a BTreeMap<String, String> {
857 sparse_value(&self.table.transient_storage, self.index).unwrap_or(&EMPTY_STORAGE)
858 }
859
860 #[must_use]
862 pub fn return_data(&self) -> Option<&'a str> {
863 run_value(&self.table.return_data, self.index).and_then(|data| data.as_deref())
864 }
865
866 #[must_use]
868 pub fn to_trace_step(&self) -> TraceStep {
869 TraceStep::new(
870 self.pc(),
871 Arc::from(self.mnemonic()),
872 self.gas(),
873 self.gas_cost(),
874 self.depth(),
875 self.error().map(str::to_owned),
876 StepSnapshot {
877 stack: self
878 .stack()
879 .iter()
880 .map(|word| Arc::from(word.to_string()))
881 .collect(),
882 memory: self.memory(),
883 storage: run_value(&self.table.storage, self.index)
884 .cloned()
885 .unwrap_or_default(),
886 storage_diff: self.storage_diff().clone(),
887 transient_storage: self.transient_storage().clone(),
888 return_data: run_value(&self.table.return_data, self.index)
889 .cloned()
890 .flatten(),
891 },
892 )
893 }
894}
895
896impl PartialEq for StepView<'_> {
897 fn eq(&self, other: &Self) -> bool {
899 self.pc() == other.pc()
900 && self.mnemonic() == other.mnemonic()
901 && self.gas() == other.gas()
902 && self.gas_cost() == other.gas_cost()
903 && self.depth() == other.depth()
904 && self.error() == other.error()
905 && self.stack() == other.stack()
906 && self.memory() == other.memory()
907 && self.storage() == other.storage()
908 && self.storage_diff() == other.storage_diff()
909 && self.transient_storage() == other.transient_storage()
910 && self.return_data() == other.return_data()
911 }
912}
913
914impl Eq for StepView<'_> {}
915
916impl fmt::Debug for StepView<'_> {
917 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
918 formatter
919 .debug_struct("StepView")
920 .field("index", &self.index)
921 .field("pc", &self.pc())
922 .field("op", &self.mnemonic())
923 .field("gas", &self.gas())
924 .field("gas_cost", &self.gas_cost())
925 .field("depth", &self.depth())
926 .field("error", &self.error())
927 .field("stack", &self.stack().to_vec())
928 .field("memory", &self.memory().map(|memory| encode_hex(&memory)))
929 .field("storage", self.storage())
930 .field("storage_diff", self.storage_diff())
931 .field("transient_storage", self.transient_storage())
932 .field("return_data", &self.return_data())
933 .finish()
934 }
935}
936
937impl Serialize for StepView<'_> {
938 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
940 let stack = self.stack().to_vec();
941 let memory = self.memory();
942 let memory = memory.as_deref().map(Hex);
943 let mut state = serializer.serialize_struct("TraceStep", 10)?;
944 state.serialize_field("pc", &self.pc())?;
945 state.serialize_field("op", self.mnemonic())?;
946 state.serialize_field("gas", &self.gas())?;
947 state.serialize_field("gas_cost", &self.gas_cost())?;
948 state.serialize_field("depth", &self.depth())?;
949 state.serialize_field("stack", &stack)?;
950 state.serialize_field("memory", &memory)?;
951 state.serialize_field("storage", self.storage())?;
952 state.serialize_field("error", &self.error())?;
953 state.serialize_field(
954 "snapshot",
955 &SnapshotOut {
956 stack: &stack,
957 memory,
958 storage: self.storage(),
959 storage_diff: self.storage_diff(),
960 transient_storage: self.transient_storage(),
961 return_data: self.return_data(),
962 },
963 )?;
964 state.end()
965 }
966}
967
968struct SnapshotOut<'a> {
970 stack: &'a [EvmWord],
971 memory: Option<Hex<'a>>,
972 storage: &'a BTreeMap<String, String>,
973 storage_diff: &'a BTreeMap<String, StorageChange>,
974 transient_storage: &'a BTreeMap<String, String>,
975 return_data: Option<&'a str>,
976}
977
978impl Serialize for SnapshotOut<'_> {
979 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
980 let mut state = serializer.serialize_struct("StepSnapshot", 6)?;
981 state.serialize_field("stack", self.stack)?;
982 state.serialize_field("memory", &self.memory)?;
983 state.serialize_field("storage", self.storage)?;
984 state.serialize_field("storage_diff", self.storage_diff)?;
985 if self.transient_storage.is_empty() {
987 state.skip_field("transient_storage")?;
988 } else {
989 state.serialize_field("transient_storage", self.transient_storage)?;
990 }
991 if self.return_data.is_none() {
992 state.skip_field("return_data")?;
993 } else {
994 state.serialize_field("return_data", &self.return_data)?;
995 }
996 state.end()
997 }
998}
999
1000impl Serialize for StepTable {
1001 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1002 let mut sequence = serializer.serialize_seq(Some(self.len()))?;
1003 for step in self {
1004 sequence.serialize_element(&step)?;
1005 }
1006 sequence.end()
1007 }
1008}
1009
1010impl<'de> Deserialize<'de> for StepTable {
1011 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
1014 struct Steps;
1015
1016 impl<'de> Visitor<'de> for Steps {
1017 type Value = StepTable;
1018
1019 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1020 formatter.write_str("an array of trace steps")
1021 }
1022
1023 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
1024 let mut table = StepTable::new();
1025 while let Some(step) = seq.next_element::<TraceStep>()? {
1026 table.try_push(step).map_err(de::Error::custom)?;
1027 }
1028 Ok(table)
1029 }
1030 }
1031
1032 deserializer.deserialize_seq(Steps)
1033 }
1034}
1035
1036#[derive(Clone, Copy)]
1038pub struct Stack<'a> {
1039 table: &'a StepTable,
1040 step: usize,
1041 len: usize,
1042}
1043
1044impl<'a> Stack<'a> {
1045 #[must_use]
1046 pub fn len(&self) -> usize {
1047 self.len
1048 }
1049
1050 #[must_use]
1051 pub fn is_empty(&self) -> bool {
1052 self.len == 0
1053 }
1054
1055 #[must_use]
1057 pub fn get(&self, position: usize) -> Option<EvmWord> {
1058 (position < self.len).then(|| self.table.stack_word(self.step, position))
1059 }
1060
1061 #[must_use]
1063 pub fn peek(&self, depth: usize) -> Option<EvmWord> {
1064 self.len
1065 .checked_sub(depth.checked_add(1)?)
1066 .and_then(|position| self.get(position))
1067 }
1068
1069 #[must_use]
1071 pub fn top(&self) -> Option<EvmWord> {
1072 self.peek(0)
1073 }
1074
1075 #[must_use]
1077 pub fn to_vec(&self) -> Vec<EvmWord> {
1078 let mut words = vec![EvmWord::ZERO; self.len];
1079 let mut step = self.step;
1082 let mut end = self.len;
1083 loop {
1084 let row = self.table.rows.get(step);
1085 let stored_from = row.stack_kept as usize;
1086 let kept = stored_from.min(end);
1087 let start = row.stack_start as usize;
1088 for (position, slot) in words.iter_mut().enumerate().take(end).skip(kept) {
1089 *slot = *self.table.words.get(start + position - stored_from);
1090 }
1091 if kept == 0 {
1092 return words;
1093 }
1094 end = kept;
1095 step -= 1;
1096 }
1097 }
1098
1099 pub fn iter(&self) -> impl DoubleEndedIterator<Item = EvmWord> + ExactSizeIterator {
1101 self.to_vec().into_iter()
1102 }
1103}
1104
1105impl PartialEq for Stack<'_> {
1106 fn eq(&self, other: &Self) -> bool {
1107 self.len == other.len && self.to_vec() == other.to_vec()
1108 }
1109}
1110
1111impl PartialEq<[EvmWord]> for Stack<'_> {
1112 fn eq(&self, other: &[EvmWord]) -> bool {
1113 self.len == other.len() && self.to_vec() == other
1114 }
1115}
1116
1117impl fmt::Debug for Stack<'_> {
1118 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1119 formatter.debug_list().entries(self.to_vec()).finish()
1120 }
1121}
1122
1123#[cfg(test)]
1124mod tests {
1125 use std::collections::BTreeMap;
1126 use std::sync::Arc;
1127
1128 use bytes::Bytes;
1129
1130 use super::{StepRecord, StepTable, STACK_CHECKPOINT};
1131 use crate::{opcode, EvmWord, StepSnapshot, StorageChange, TraceStep};
1132
1133 struct Random(u64);
1135
1136 impl Random {
1137 fn next(&mut self) -> u64 {
1138 self.0 ^= self.0 << 13;
1139 self.0 ^= self.0 >> 7;
1140 self.0 ^= self.0 << 17;
1141 self.0
1142 }
1143
1144 fn below(&mut self, bound: u64) -> u64 {
1145 self.next() % bound
1146 }
1147 }
1148
1149 fn word(value: u64) -> Arc<str> {
1150 Arc::from(EvmWord::from(value).to_string())
1151 }
1152
1153 fn random_steps(count: usize, seed: u64) -> Vec<TraceStep> {
1156 let mut random = Random(seed);
1157 let mut stack = Vec::<Arc<str>>::new();
1158 let mut memory = Bytes::from(vec![0_u8; 64]);
1159 let mut storage = Arc::new(BTreeMap::new());
1160 let mut return_data: Option<String> = None;
1161 (0..count)
1162 .map(|index| {
1163 match random.below(4) {
1164 0 => {
1165 stack.pop();
1166 }
1167 1 if !stack.is_empty() => {
1168 let top = stack.len() - 1;
1169 stack[top] = word(random.below(1 << 20));
1170 }
1171 _ => stack.push(word(random.next())),
1172 }
1173 if random.below(10) == 0 {
1174 let mut changed = memory.to_vec();
1175 let at = random.below(changed.len() as u64) as usize;
1176 changed[at] = random.next() as u8;
1177 if random.below(3) == 0 {
1178 changed.extend_from_slice(&[0; 32]);
1179 }
1180 memory = Bytes::from(changed);
1181 }
1182 let mut storage_diff = BTreeMap::new();
1183 if random.below(20) == 0 {
1184 let slot = format!("0x{:x}", random.below(5));
1185 let value = format!("0x{:x}", random.next());
1186 storage_diff.insert(
1187 slot.clone(),
1188 StorageChange {
1189 before: storage.get(&slot).cloned(),
1190 after: Some(value.clone()),
1191 },
1192 );
1193 Arc::make_mut(&mut storage).insert(slot, value);
1194 }
1195 if random.below(25) == 0 {
1196 return_data =
1197 (random.below(2) == 0).then(|| format!("{:02x}", random.next() as u8));
1198 }
1199 let transient = if random.below(30) == 0 {
1200 BTreeMap::from([("0x1".to_owned(), format!("0x{:x}", random.next()))])
1201 } else {
1202 BTreeMap::new()
1203 };
1204 let op = match random.below(6) {
1205 0 => "SSTORE".to_owned(),
1206 1 => "SHA3".to_owned(),
1207 2 => "UNKNOWN(0x0c)".to_owned(),
1208 _ => opcode::mnemonic(random.next() as u8).to_owned(),
1209 };
1210 TraceStep::new(
1211 if random.below(100) == 0 {
1212 u64::MAX - index as u64
1213 } else {
1214 random.below(30_000)
1215 },
1216 Arc::from(op),
1217 random.next(),
1218 random.below(100),
1219 if random.below(100) == 0 {
1220 1 << 40
1221 } else {
1222 random.below(4) + 1
1223 },
1224 (random.below(50) == 0).then(|| "revert".to_owned()),
1225 StepSnapshot {
1226 stack: stack.clone(),
1227 memory: (random.below(40) != 0).then(|| memory.clone()),
1228 storage: Arc::clone(&storage),
1229 storage_diff,
1230 transient_storage: transient,
1231 return_data: return_data.clone().map(Arc::from),
1232 },
1233 )
1234 })
1235 .collect()
1236 }
1237
1238 #[test]
1239 fn columns_span_chunks() {
1240 let mut column = super::Column::<u32>::default();
1241 let total = 2 * super::CHUNK + 5;
1242 for value in 0..total {
1243 column.push(value as u32);
1244 }
1245 assert_eq!(column.len(), total);
1246 assert_eq!(column.full.len(), 2);
1247 for index in [
1248 0,
1249 super::CHUNK - 1,
1250 super::CHUNK,
1251 2 * super::CHUNK,
1252 total - 1,
1253 ] {
1254 assert_eq!(*column.get(index), index as u32);
1255 }
1256 assert_eq!(column.last(), Some(&(total as u32 - 1)));
1257 *column.get_mut(super::CHUNK) = 7;
1258 assert_eq!(*column.get(super::CHUNK), 7);
1259
1260 column.truncate(super::CHUNK + 3);
1262 assert_eq!((column.len(), column.full.len()), (super::CHUNK + 3, 1));
1263 column.push(99);
1264 assert_eq!(*column.get(super::CHUNK + 3), 99);
1265 column.truncate(super::CHUNK);
1266 assert_eq!(column.last(), Some(&(super::CHUNK as u32 - 1)));
1267 column.truncate(0);
1268 assert_eq!((column.len(), column.last()), (0, None));
1269 }
1270
1271 #[test]
1272 fn writes_exactly_what_the_steps_wrote() {
1273 for seed in [1, 2, 3] {
1274 let steps = random_steps(500, seed);
1275 let table = StepTable::from(steps.clone());
1276 assert_eq!(table.len(), steps.len());
1277 assert_eq!(
1278 serde_json::to_string(&table).expect("table"),
1279 serde_json::to_string(&steps).expect("steps"),
1280 "seed {seed}"
1281 );
1282 for (index, step) in steps.iter().enumerate() {
1283 assert_eq!(table.step(index).to_trace_step(), *step, "step {index}");
1284 }
1285 let read: StepTable =
1286 serde_json::from_str(&serde_json::to_string(&steps).expect("steps")).expect("read");
1287 assert_eq!(read, table);
1288 }
1289 }
1290
1291 #[test]
1292 fn stacks_read_back_across_checkpoints() {
1293 let steps = random_steps(5 * STACK_CHECKPOINT + 7, 9);
1294 let table = StepTable::from(steps.clone());
1295 let mut stored = 0;
1296 for (index, step) in steps.iter().enumerate() {
1297 let expected = step
1298 .snapshot
1299 .stack
1300 .iter()
1301 .map(|word| EvmWord::parse(word).expect("word"))
1302 .collect::<Vec<_>>();
1303 let stack = table.step(index).stack();
1304 assert_eq!(stack.to_vec(), expected, "step {index}");
1305 assert_eq!(stack.len(), expected.len());
1306 for (position, word) in expected.iter().enumerate() {
1307 assert_eq!(stack.get(position), Some(*word));
1308 }
1309 assert_eq!(stack.top(), expected.last().copied());
1310 assert_eq!(stack.peek(expected.len()), None);
1311 stored += expected.len();
1312 }
1313 assert!(
1315 table.words.len() < stored / 2,
1316 "{} of {stored}",
1317 table.words.len()
1318 );
1319 }
1320
1321 #[test]
1322 fn appending_records_what_pushing_records() {
1323 let steps = random_steps(300, 4);
1324 let pushed = StepTable::from(steps.clone());
1325 let mut appended = StepTable::with_capacity(steps.len());
1326 let mut previous: Option<&TraceStep> = None;
1327 for step in &steps {
1328 let snapshot = &step.snapshot;
1329 appended.append(
1330 StepRecord {
1331 pc: step.pc,
1332 op: opcode::from_spelling(&step.op).expect("known"),
1333 gas: step.gas,
1334 gas_cost: step.gas_cost,
1335 depth: step.depth,
1336 error: step.error.clone(),
1337 memory: snapshot.memory.clone(),
1338 storage: Some(Arc::clone(&snapshot.storage)),
1339 storage_diff: Some(snapshot.storage_diff.clone()),
1340 transient_storage: Some(snapshot.transient_storage.clone()),
1341 return_data: Some(
1342 snapshot
1343 .return_data
1344 .clone()
1345 .unwrap_or_else(|| Arc::from("")),
1346 ),
1347 },
1348 snapshot
1349 .stack
1350 .iter()
1351 .map(|word| EvmWord::parse(word).expect("word")),
1352 );
1353 if snapshot.memory.is_none()
1355 && previous.is_some_and(|step| step.snapshot.memory.is_some())
1356 {
1357 let last = appended.len() - 1;
1358 appended.rows.get_mut(last).memory = super::MemoryRef::NONE;
1359 }
1360 previous = Some(step);
1361 }
1362 for index in 0..steps.len() {
1364 let (a, b) = (pushed.step(index), appended.step(index));
1365 assert_eq!(a.op(), b.op());
1366 assert_eq!(a.stack(), b.stack());
1367 assert_eq!(a.memory(), b.memory());
1368 assert_eq!(a.storage(), b.storage());
1369 assert_eq!(a.storage_diff(), b.storage_diff());
1370 assert_eq!(a.transient_storage(), b.transient_storage());
1371 assert_eq!(a.return_data(), b.return_data());
1372 assert_eq!(
1373 (a.pc(), a.depth(), a.gas(), a.error()),
1374 (b.pc(), b.depth(), b.gas(), b.error())
1375 );
1376 }
1377 }
1378
1379 #[test]
1380 fn keeps_a_backends_spelling_with_the_byte_it_means() {
1381 let step =
1382 |op: &str| TraceStep::new(0, Arc::from(op), 0, 0, 1, None, StepSnapshot::default());
1383 let table = StepTable::from(vec![
1384 step("SHA3"),
1385 step("KECCAK256"),
1386 step("opcode 0xef not defined"),
1387 step("NOT AN OPCODE"),
1388 ]);
1389 let ops = table
1390 .iter()
1391 .map(|step| (step.op(), step.mnemonic()))
1392 .collect::<Vec<_>>();
1393 assert_eq!(
1394 ops,
1395 [
1396 (opcode::KECCAK256, "SHA3"),
1397 (opcode::KECCAK256, "KECCAK256"),
1398 (0xef, "opcode 0xef not defined"),
1399 (opcode::INVALID, "NOT AN OPCODE"),
1400 ]
1401 );
1402 }
1403
1404 #[test]
1405 fn a_word_that_is_not_hex_is_refused() {
1406 let mut table = StepTable::new();
1407 let mut step = TraceStep::new(0, Arc::from("ADD"), 0, 0, 1, None, StepSnapshot::default());
1408 step.snapshot.stack = vec![Arc::from("0x1"), Arc::from("zz")];
1409 let error = table.try_push(step).expect_err("not hex");
1410 assert_eq!(
1411 error.to_string(),
1412 "step 0: stack word 1: `z` at offset 0 is not a hex digit"
1413 );
1414 assert!(table.is_empty());
1415 }
1416
1417 #[test]
1418 fn truncating_keeps_what_comes_before() {
1419 let steps = random_steps(3 * STACK_CHECKPOINT, 5);
1420 let mut table = StepTable::from(steps.clone());
1421 table.truncate(STACK_CHECKPOINT + 3);
1422 table.extend(steps[STACK_CHECKPOINT + 3..].iter().cloned());
1424 assert_eq!(table, StepTable::from(steps));
1425 table.truncate(0);
1426 assert!(table.is_empty() && table.first().is_none());
1427 }
1428
1429 #[test]
1430 fn memory_recorded_write_by_write() {
1431 let record = |pc| StepRecord {
1432 pc,
1433 op: opcode::MSTORE,
1434 depth: 1,
1435 ..StepRecord::default()
1436 };
1437 let mut table = StepTable::new();
1438 table.append(record(0), []);
1439 assert_eq!(table.step(0).memory(), None);
1440 table.start_memory_frame();
1441 table.append(record(1), []);
1442 table.write_memory(0, &[7; 32], 32).expect("write");
1443 table.append(record(2), []);
1444 table.start_memory_frame();
1445 table.append(record(3), []);
1446 table.end_memory_frame();
1447 table.write_memory(32, &[], 64).expect("grow");
1448 table.append(record(4), []);
1449 let memories = table
1450 .iter()
1451 .map(|step| step.memory().map(|memory| memory.to_vec()))
1452 .collect::<Vec<_>>();
1453 let mut grown = vec![7; 32];
1454 grown.resize(64, 0);
1455 assert_eq!(
1456 memories,
1457 [
1458 None,
1459 Some(Vec::new()),
1460 Some(vec![7; 32]),
1461 Some(Vec::new()),
1462 Some(grown)
1463 ]
1464 );
1465 }
1466}