1use std::collections::BTreeMap;
19use std::fmt;
20use std::sync::Arc;
21
22use serde::de::{self, Visitor};
23use serde::ser::SerializeStruct;
24use serde::{Deserialize, Deserializer, Serialize, Serializer};
25use thiserror::Error;
26
27pub use bytes::Bytes;
28
29mod memory;
30pub mod opcode;
31mod table;
32mod word;
33
34pub use memory::MemoryWriteError;
35pub use table::{Stack, StepError, StepRecord, StepTable, StepView, Steps, STACK_CHECKPOINT};
36pub use word::{EvmWord, WordError};
37
38#[derive(Debug, Error)]
39pub enum SoldbError {
40 #[error("{0}")]
42 Message(String),
43 #[error("")]
49 AlreadyReported,
50}
51
52pub type SoldbResult<T> = Result<T, SoldbError>;
53
54impl From<StepError> for SoldbError {
55 fn from(error: StepError) -> Self {
56 Self::Message(format!("invalid trace step: {error}"))
57 }
58}
59
60#[derive(Debug, Clone, Eq)]
77pub struct TraceStep {
78 pub pc: u64,
79 pub op: Word,
82 pub gas: u64,
83 pub gas_cost: u64,
86 pub depth: u64,
87 pub stack: Vec<Word>,
89 pub memory: Option<Bytes>,
91 pub storage: Option<BTreeMap<String, String>>,
93 pub error: Option<String>,
94 pub snapshot: StepSnapshot,
95}
96
97impl TraceStep {
98 #[must_use]
100 pub fn new(
101 pc: u64,
102 op: Word,
103 gas: u64,
104 gas_cost: u64,
105 depth: u64,
106 error: Option<String>,
107 snapshot: StepSnapshot,
108 ) -> Self {
109 Self {
110 pc,
111 op,
112 gas,
113 gas_cost,
114 depth,
115 stack: Vec::new(),
116 memory: None,
117 storage: None,
118 error,
119 snapshot,
120 }
121 }
122
123 #[must_use]
133 pub fn snapshot_ref(&self) -> StepSnapshotRef<'_> {
134 static EMPTY_STORAGE: BTreeMap<String, String> = BTreeMap::new();
135 static EMPTY_STORAGE_DIFF: BTreeMap<String, StorageChange> = BTreeMap::new();
136
137 if !self.snapshot.is_empty() {
138 return StepSnapshotRef {
139 stack: &self.snapshot.stack,
140 memory: self.snapshot.memory.as_deref(),
141 storage: &self.snapshot.storage,
142 storage_diff: &self.snapshot.storage_diff,
143 transient_storage: &self.snapshot.transient_storage,
144 return_data: self.snapshot.return_data.as_deref(),
145 };
146 }
147 StepSnapshotRef {
148 stack: &self.stack,
149 memory: self.memory.as_deref(),
150 storage: self.storage.as_ref().unwrap_or(&EMPTY_STORAGE),
151 storage_diff: &EMPTY_STORAGE_DIFF,
152 transient_storage: &EMPTY_STORAGE,
153 return_data: None,
154 }
155 }
156
157 #[must_use]
162 pub fn normalized_snapshot(&self) -> StepSnapshot {
163 self.snapshot_ref().to_owned_snapshot()
164 }
165
166 pub(crate) fn normalized(mut self) -> Self {
169 if self.snapshot.is_empty() {
170 self.snapshot = StepSnapshot {
171 stack: std::mem::take(&mut self.stack),
172 memory: self.memory.take(),
173 storage: Arc::new(self.storage.take().unwrap_or_default()),
174 storage_diff: BTreeMap::new(),
175 transient_storage: BTreeMap::new(),
176 return_data: None,
177 };
178 } else {
179 self.stack = Vec::new();
180 self.memory = None;
181 self.storage = None;
182 }
183 self
184 }
185}
186
187impl PartialEq for TraceStep {
188 fn eq(&self, other: &Self) -> bool {
190 self.pc == other.pc
191 && self.op == other.op
192 && self.gas == other.gas
193 && self.gas_cost == other.gas_cost
194 && self.depth == other.depth
195 && self.error == other.error
196 && self.snapshot_ref() == other.snapshot_ref()
197 }
198}
199
200impl Serialize for TraceStep {
201 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
204 let snapshot = self.snapshot_ref();
205 let mut state = serializer.serialize_struct("TraceStep", 10)?;
206 state.serialize_field("pc", &self.pc)?;
207 state.serialize_field("op", &self.op)?;
208 state.serialize_field("gas", &self.gas)?;
209 state.serialize_field("gas_cost", &self.gas_cost)?;
210 state.serialize_field("depth", &self.depth)?;
211 state.serialize_field("stack", snapshot.stack)?;
212 state.serialize_field("memory", &snapshot.memory.map(Hex))?;
213 state.serialize_field("storage", snapshot.storage)?;
214 state.serialize_field("error", &self.error)?;
215 state.serialize_field("snapshot", &snapshot)?;
216 state.end()
217 }
218}
219
220#[derive(Deserialize)]
222struct TraceStepRepr {
223 pc: u64,
224 op: String,
225 gas: u64,
226 gas_cost: u64,
227 depth: u64,
228 #[serde(default)]
229 stack: Vec<String>,
230 #[serde(default, deserialize_with = "deserialize_memory")]
231 memory: Option<Bytes>,
232 #[serde(default)]
233 storage: Option<BTreeMap<String, String>>,
234 #[serde(default)]
235 error: Option<String>,
236 #[serde(default)]
237 snapshot: StepSnapshot,
238}
239
240impl<'de> Deserialize<'de> for TraceStep {
241 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
242 let repr = TraceStepRepr::deserialize(deserializer)?;
243 Ok(TraceStep {
244 pc: repr.pc,
245 op: Arc::from(repr.op),
246 gas: repr.gas,
247 gas_cost: repr.gas_cost,
248 depth: repr.depth,
249 stack: repr.stack.into_iter().map(Arc::from).collect(),
250 memory: repr.memory,
251 storage: repr.storage,
252 error: repr.error,
253 snapshot: repr.snapshot,
254 }
255 .normalized())
256 }
257}
258
259pub type Word = Arc<str>;
268
269#[derive(Debug, Default)]
274pub struct WordInterner {
275 words: std::collections::HashMap<Word, Word>,
276}
277
278impl WordInterner {
279 #[must_use]
280 pub fn new() -> Self {
281 Self::default()
282 }
283
284 #[must_use]
286 pub fn intern(&mut self, word: &str) -> Word {
287 if let Some(shared) = self.words.get(word) {
288 return Arc::clone(shared);
289 }
290 let shared: Word = Arc::from(word);
291 self.words.insert(Arc::clone(&shared), Arc::clone(&shared));
292 shared
293 }
294
295 pub fn intern_stack(&mut self, stack: &mut [Word]) {
297 for word in stack {
298 *word = self.intern(word);
299 }
300 }
301
302 #[must_use]
304 pub fn len(&self) -> usize {
305 self.words.len()
306 }
307
308 #[must_use]
309 pub fn is_empty(&self) -> bool {
310 self.words.is_empty()
311 }
312}
313
314#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
319pub struct StepSnapshotRef<'a> {
320 pub stack: &'a [Word],
321 #[serde(serialize_with = "serialize_memory")]
323 pub memory: Option<&'a [u8]>,
324 pub storage: &'a BTreeMap<String, String>,
325 pub storage_diff: &'a BTreeMap<String, StorageChange>,
326 #[serde(skip_serializing_if = "is_empty_ref")]
327 pub transient_storage: &'a BTreeMap<String, String>,
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub return_data: Option<&'a str>,
330}
331
332fn is_empty_ref(map: &&BTreeMap<String, String>) -> bool {
333 map.is_empty()
334}
335
336fn serialize_memory<S: Serializer>(
337 memory: &Option<&[u8]>,
338 serializer: S,
339) -> Result<S::Ok, S::Error> {
340 memory.map(Hex).serialize(serializer)
341}
342
343impl StepSnapshotRef<'_> {
344 #[must_use]
346 pub fn to_owned_snapshot(&self) -> StepSnapshot {
347 StepSnapshot {
348 stack: self.stack.to_vec(),
349 memory: self.memory.map(Bytes::copy_from_slice),
350 storage: Arc::new(self.storage.clone()),
351 storage_diff: self.storage_diff.clone(),
352 transient_storage: self.transient_storage.clone(),
353 return_data: self.return_data.map(Arc::from),
354 }
355 }
356}
357
358#[derive(Debug, Clone, PartialEq, Eq, Default, Deserialize)]
369#[serde(from = "StepSnapshotRepr")]
370pub struct StepSnapshot {
371 pub stack: Vec<Word>,
372 pub memory: Option<Bytes>,
375 pub storage: Arc<BTreeMap<String, String>>,
376 pub storage_diff: BTreeMap<String, StorageChange>,
377 pub transient_storage: BTreeMap<String, String>,
379 pub return_data: Option<Arc<str>>,
381}
382
383impl StepSnapshot {
384 #[must_use]
386 pub fn new(
387 stack: Vec<Word>,
388 memory: Option<Bytes>,
389 storage: BTreeMap<String, String>,
390 storage_diff: BTreeMap<String, StorageChange>,
391 ) -> Self {
392 Self {
393 stack,
394 memory,
395 storage: Arc::new(storage),
396 storage_diff,
397 transient_storage: BTreeMap::new(),
398 return_data: None,
399 }
400 }
401
402 #[must_use]
404 pub fn with_transient_storage(mut self, transient_storage: BTreeMap<String, String>) -> Self {
405 self.transient_storage = transient_storage;
406 self
407 }
408
409 #[must_use]
411 pub fn with_return_data(mut self, return_data: Option<String>) -> Self {
412 self.return_data = return_data.filter(|data| !data.is_empty()).map(Arc::from);
413 self
414 }
415
416 #[must_use]
417 pub fn is_empty(&self) -> bool {
418 self.stack.is_empty()
419 && self.memory.is_none()
420 && self.storage.is_empty()
421 && self.storage_diff.is_empty()
422 && self.transient_storage.is_empty()
423 && self.return_data.is_none()
424 }
425}
426
427impl Serialize for StepSnapshot {
428 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
429 let mut state = serializer.serialize_struct("StepSnapshot", 6)?;
430 state.serialize_field("stack", &self.stack)?;
431 state.serialize_field("memory", &self.memory.as_deref().map(Hex))?;
432 state.serialize_field("storage", &*self.storage)?;
433 state.serialize_field("storage_diff", &self.storage_diff)?;
434 if self.transient_storage.is_empty() {
436 state.skip_field("transient_storage")?;
437 } else {
438 state.serialize_field("transient_storage", &self.transient_storage)?;
439 }
440 if self.return_data.is_none() {
441 state.skip_field("return_data")?;
442 } else {
443 state.serialize_field("return_data", &self.return_data.as_deref())?;
444 }
445 state.end()
446 }
447}
448
449#[derive(Deserialize, Default)]
450struct StepSnapshotRepr {
451 #[serde(default)]
452 stack: Vec<Word>,
453 #[serde(default, deserialize_with = "deserialize_memory")]
454 memory: Option<Bytes>,
455 #[serde(default)]
456 storage: BTreeMap<String, String>,
457 #[serde(default)]
458 storage_diff: BTreeMap<String, StorageChange>,
459 #[serde(default)]
460 transient_storage: BTreeMap<String, String>,
461 #[serde(default)]
462 return_data: Option<String>,
463}
464
465impl From<StepSnapshotRepr> for StepSnapshot {
466 fn from(repr: StepSnapshotRepr) -> Self {
467 Self::new(repr.stack, repr.memory, repr.storage, repr.storage_diff)
468 .with_transient_storage(repr.transient_storage)
469 .with_return_data(repr.return_data)
470 }
471}
472
473#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
474pub struct StorageChange {
475 pub before: Option<String>,
476 pub after: Option<String>,
477}
478
479#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
485#[serde(from = "TransactionTraceRepr")]
486pub struct TransactionTrace {
487 pub tx_hash: Option<String>,
488 pub from_addr: String,
489 pub to_addr: Option<String>,
490 pub value: String,
491 pub input_data: String,
492 pub gas_used: u64,
493 pub output: String,
494 pub success: bool,
495 pub error: Option<String>,
496 pub debug_trace_available: bool,
497 pub contract_address: Option<String>,
498 #[serde(default)]
499 pub backend: Option<String>,
500 #[serde(default)]
501 pub capabilities: TraceCapabilities,
502 #[serde(default)]
503 pub artifacts: TraceArtifacts,
504 pub steps: StepTable,
505}
506
507#[derive(Deserialize)]
509struct TransactionTraceRepr {
510 tx_hash: Option<String>,
511 from_addr: String,
512 to_addr: Option<String>,
513 value: String,
514 input_data: String,
515 gas_used: u64,
516 output: String,
517 success: bool,
518 error: Option<String>,
519 debug_trace_available: bool,
520 contract_address: Option<String>,
521 #[serde(default)]
522 backend: Option<String>,
523 #[serde(default)]
524 capabilities: TraceCapabilities,
525 #[serde(default)]
526 artifacts: TraceArtifacts,
527 steps: StepTable,
528}
529
530impl From<TransactionTraceRepr> for TransactionTrace {
531 fn from(repr: TransactionTraceRepr) -> Self {
532 Self {
533 tx_hash: repr.tx_hash,
534 from_addr: repr.from_addr,
535 to_addr: repr.to_addr,
536 value: repr.value,
537 input_data: repr.input_data,
538 gas_used: repr.gas_used,
539 output: repr.output,
540 success: repr.success,
541 error: repr.error,
542 debug_trace_available: repr.debug_trace_available,
543 contract_address: repr.contract_address,
544 backend: repr.backend,
545 capabilities: repr.capabilities,
546 artifacts: repr.artifacts,
547 steps: repr.steps,
548 }
549 }
550}
551
552#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
553pub struct TraceCapabilities {
554 #[serde(default)]
555 pub opcode_steps: bool,
556 #[serde(default)]
557 pub stack: bool,
558 #[serde(default)]
559 pub memory: bool,
560 #[serde(default)]
561 pub storage: bool,
562 #[serde(default)]
563 pub storage_diff: bool,
564 #[serde(default)]
565 pub call_trace: bool,
566 #[serde(default)]
567 pub contract_creation: bool,
568 #[serde(default)]
569 pub logs: bool,
570 #[serde(default)]
571 pub revert_data: bool,
572 #[serde(default)]
573 pub gas_details: bool,
574 #[serde(default)]
575 pub account_changes: bool,
576 #[serde(default)]
578 pub transient_storage: bool,
579 #[serde(default)]
581 pub return_data: bool,
582 #[serde(default)]
583 pub notes: Vec<String>,
584}
585
586#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
587pub struct TraceArtifacts {
588 #[serde(default)]
589 pub calls: Vec<ExecutionCall>,
590 #[serde(default)]
591 pub creations: Vec<ContractCreation>,
592 #[serde(default)]
593 pub logs: Vec<ExecutionLog>,
594 #[serde(default)]
595 pub account_changes: Vec<AccountChange>,
596 #[serde(default)]
597 pub gas: Option<GasSummary>,
598 #[serde(default)]
599 pub revert_data: Option<String>,
600 #[serde(default, skip_serializing_if = "Vec::is_empty")]
603 pub root_kinds: Vec<RootKind>,
604}
605
606#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
608pub struct RootKind {
609 pub entry_step: usize,
610 pub kind: String,
611}
612
613#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
614pub struct ExecutionCall {
615 pub id: usize,
616 pub parent_id: Option<usize>,
617 pub depth: u64,
618 #[serde(default, skip_serializing_if = "Option::is_none")]
619 pub entry_step: Option<usize>,
620 #[serde(default, skip_serializing_if = "Option::is_none")]
621 pub exit_step: Option<usize>,
622 pub call_type: String,
623 pub from: String,
624 pub to: String,
625 pub bytecode_address: String,
626 pub value: String,
627 pub input: String,
628 pub gas_limit: u64,
629 pub gas_used: Option<u64>,
630 pub output: Option<String>,
631 pub success: Option<bool>,
632 pub error: Option<String>,
633 #[serde(default, skip_serializing_if = "Option::is_none")]
636 pub code_hash: Option<String>,
637}
638
639#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
640pub struct ContractCreation {
641 pub id: usize,
642 pub parent_id: Option<usize>,
643 pub depth: u64,
644 #[serde(default, skip_serializing_if = "Option::is_none")]
645 pub entry_step: Option<usize>,
646 #[serde(default, skip_serializing_if = "Option::is_none")]
647 pub exit_step: Option<usize>,
648 pub create_type: String,
649 pub caller: String,
650 pub address: Option<String>,
651 pub value: String,
652 pub init_code: String,
653 pub gas_limit: u64,
654 pub gas_used: Option<u64>,
655 pub output: Option<String>,
656 pub success: Option<bool>,
657 pub error: Option<String>,
658 #[serde(default, skip_serializing_if = "Option::is_none")]
661 pub code_hash: Option<String>,
662}
663
664#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
665pub struct ExecutionLog {
666 pub index: usize,
667 pub depth: u64,
668 pub address: String,
669 pub topics: Vec<String>,
670 pub data: String,
671}
672
673#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
674pub struct AccountChange {
675 pub depth: u64,
676 pub kind: String,
677 pub address: Option<String>,
678 pub from: Option<String>,
679 pub to: Option<String>,
680 pub value: Option<String>,
681 pub key: Option<String>,
682 pub previous_value: Option<String>,
683 pub previous_nonce: Option<u64>,
684}
685
686#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
687pub struct GasSummary {
688 pub used: u64,
689 pub spent: Option<u64>,
690 pub refunded: Option<u64>,
691 pub remaining: Option<u64>,
692 pub limit: Option<u64>,
693}
694
695#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
696pub struct FunctionCall {
697 pub name: String,
698 pub selector: String,
699 pub entry_step: usize,
700 pub exit_step: Option<usize>,
701 pub gas_used: u64,
702 pub depth: u64,
703 pub call_type: String,
704 pub contract_address: Option<String>,
705}
706
707#[must_use]
710pub fn same_buffer(a: &[u8], b: &[u8]) -> bool {
711 a.as_ptr() == b.as_ptr() && a.len() == b.len()
712}
713
714#[derive(Debug, Clone, PartialEq, Eq, Error)]
716pub enum HexError {
717 #[error("{0} hex digits is not a whole number of bytes")]
719 OddLength(usize),
720 #[error("`{character}` at offset {offset} is not a hex digit")]
722 InvalidDigit { offset: usize, character: char },
723}
724
725#[must_use]
728pub fn encode_hex(bytes: &[u8]) -> String {
729 let mut hex = String::with_capacity(bytes.len() * 2);
730 for byte in bytes {
731 hex.push(char::from(HEX_DIGITS[usize::from(byte >> 4)]));
732 hex.push(char::from(HEX_DIGITS[usize::from(byte & 0x0f)]));
733 }
734 hex
735}
736
737pub fn decode_hex(hex: &str) -> Result<Vec<u8>, HexError> {
744 let mut bytes = Vec::new();
745 decode_hex_into(hex, &mut bytes)?;
746 Ok(bytes)
747}
748
749pub fn decode_hex_into(hex: &str, bytes: &mut Vec<u8>) -> Result<(), HexError> {
755 let digits = hex
756 .strip_prefix("0x")
757 .or_else(|| hex.strip_prefix("0X"))
758 .unwrap_or(hex);
759 let raw = digits.as_bytes();
762 let invalid = |offset: usize| HexError::InvalidDigit {
763 offset,
764 character: digits
766 .get(offset..)
767 .and_then(|rest| rest.chars().next())
768 .unwrap_or(char::REPLACEMENT_CHARACTER),
769 };
770 bytes.reserve(raw.len() / 2);
771 let (pairs, rest) = raw.as_chunks::<2>();
772 for (index, [high, low]) in pairs.iter().enumerate() {
773 let high = hex_value(*high).ok_or_else(|| invalid(index * 2))?;
774 let low = hex_value(*low).ok_or_else(|| invalid(index * 2 + 1))?;
775 bytes.push(high << 4 | low);
776 }
777 if let [last] = rest {
778 return Err(match hex_value(*last) {
779 Some(_) => HexError::OddLength(raw.len()),
780 None => invalid(raw.len() - 1),
781 });
782 }
783 Ok(())
784}
785
786const HEX_DIGITS: &[u8; 16] = b"0123456789abcdef";
787
788fn hex_value(digit: u8) -> Option<u8> {
789 match digit {
790 b'0'..=b'9' => Some(digit - b'0'),
791 b'a'..=b'f' => Some(digit - b'a' + 10),
792 b'A'..=b'F' => Some(digit - b'A' + 10),
793 _ => None,
794 }
795}
796
797#[derive(Clone, Copy)]
801pub(crate) struct Hex<'a>(pub(crate) &'a [u8]);
802
803impl fmt::Display for Hex<'_> {
804 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
805 let mut buffer = [0_u8; 128];
806 for chunk in self.0.chunks(buffer.len() / 2) {
807 for (index, byte) in chunk.iter().enumerate() {
808 buffer[index * 2] = HEX_DIGITS[usize::from(byte >> 4)];
809 buffer[index * 2 + 1] = HEX_DIGITS[usize::from(byte & 0x0f)];
810 }
811 let digits = std::str::from_utf8(&buffer[..chunk.len() * 2]).map_err(|_| fmt::Error)?;
812 formatter.write_str(digits)?;
813 }
814 Ok(())
815 }
816}
817
818impl Serialize for Hex<'_> {
819 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
820 serializer.collect_str(self)
821 }
822}
823
824fn deserialize_memory<'de, D: Deserializer<'de>>(
826 deserializer: D,
827) -> Result<Option<Bytes>, D::Error> {
828 struct MemoryHex;
829
830 impl<'de> Visitor<'de> for MemoryHex {
831 type Value = Option<Bytes>;
832
833 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
834 formatter.write_str("memory as a hex string")
835 }
836
837 fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
838 Ok(None)
839 }
840
841 fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
842 Ok(None)
843 }
844
845 fn visit_some<D: Deserializer<'de>>(
846 self,
847 deserializer: D,
848 ) -> Result<Self::Value, D::Error> {
849 deserializer.deserialize_str(self)
850 }
851
852 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
853 decode_hex(value)
854 .map(|bytes| Some(Bytes::from(bytes)))
855 .map_err(|error| E::custom(format!("memory is not hex: {error}")))
856 }
857 }
858
859 deserializer.deserialize_option(MemoryHex)
860}
861
862#[cfg(test)]
863mod tests {
864 #[test]
867 fn repeated_stack_words_are_stored_once() {
868 let mut words = super::WordInterner::new();
869 assert!(words.is_empty());
870 let first = words.intern("0x2a");
871 let again = words.intern("0x2a");
872 let other = words.intern("0x1");
873 assert_eq!(words.len(), 2);
874 assert_eq!(&*first, "0x2a");
875 assert!(Arc::ptr_eq(&first, &again));
879 assert!(!Arc::ptr_eq(&first, &other));
880
881 let mut stack = vec![Arc::from("0x2a"), Arc::from("0x2a"), Arc::from("0x1")];
882 words.intern_stack(&mut stack);
883 assert!(Arc::ptr_eq(&stack[0], &stack[1]));
884 assert!(Arc::ptr_eq(&stack[0], &first));
885 assert_eq!(words.len(), 2, "nothing new was seen");
886 }
887
888 #[test]
889 fn a_parsed_trace_reads_its_stack_words() {
890 let document = serde_json::json!({
892 "tx_hash": "0xabc",
893 "from_addr": "0x1",
894 "to_addr": "0x2",
895 "value": "0x0",
896 "input_data": "0x",
897 "gas_used": 0,
898 "output": "0x",
899 "success": true,
900 "debug_trace_available": true,
901 "steps": [
902 {"pc": 0, "op": "PUSH1", "gas": 1, "gas_cost": 1, "depth": 1,
903 "stack": ["0x2a", "0x1"]},
904 {"pc": 2, "op": "ADD", "gas": 0, "gas_cost": 1, "depth": 1,
905 "stack": ["0x002A", "0x1"]}
906 ]
907 })
908 .to_string();
909 let trace: TransactionTrace = serde_json::from_str(&document).expect("trace");
910 let stack = |index: usize| trace.steps.step(index).stack().to_vec();
911 assert_eq!(stack(0), [EvmWord::from(0x2a), EvmWord::from(1)]);
912 assert_eq!(stack(1), stack(0));
913 let written = serde_json::to_value(&trace).expect("json");
915 assert_eq!(
916 written["steps"][1]["stack"],
917 serde_json::json!(["0x2a", "0x1"])
918 );
919 }
920 fn words(stack: &[super::Word]) -> Vec<&str> {
921 stack.iter().map(|word| &**word).collect()
922 }
923
924 use std::collections::BTreeMap;
925 use std::sync::Arc;
926
927 use super::{
928 decode_hex, encode_hex, same_buffer, Bytes, EvmWord, FunctionCall, HexError, StepSnapshot,
929 StorageChange, TraceArtifacts, TraceCapabilities, TraceStep, TransactionTrace,
930 };
931
932 fn memory(hex: &str) -> Bytes {
934 Bytes::from(decode_hex(hex).expect("test memory is hex"))
935 }
936
937 fn step_with(snapshot: StepSnapshot) -> TraceStep {
938 TraceStep {
939 pc: 3,
940 op: Arc::from("SSTORE"),
941 gas: 100,
942 gas_cost: 5,
943 depth: 1,
944 stack: vec![Arc::from("0x01"), Arc::from("0x02")],
945 memory: Some(memory("aabb")),
946 storage: Some(BTreeMap::from([("0x00".to_owned(), "0x2a".to_owned())])),
947 error: None,
948 snapshot,
949 }
950 }
951
952 #[test]
953 fn borrowed_snapshot_matches_the_owned_one() {
954 let flat = step_with(StepSnapshot::default());
959 let populated = step_with(StepSnapshot::new(
960 vec![Arc::from("0x09")],
961 Some(memory("ccdd")),
962 BTreeMap::from([("0x01".to_owned(), "0x63".to_owned())]),
963 BTreeMap::from([(
964 "0x01".to_owned(),
965 StorageChange {
966 before: None,
967 after: Some("0x63".to_owned()),
968 },
969 )]),
970 ));
971
972 for step in [&flat, &populated] {
973 assert_eq!(
974 step.snapshot_ref().to_owned_snapshot(),
975 step.normalized_snapshot()
976 );
977 assert_eq!(
978 serde_json::to_string(&step.snapshot_ref()).expect("borrowed snapshot"),
979 serde_json::to_string(&step.normalized_snapshot()).expect("owned snapshot"),
980 );
981 }
982
983 assert_eq!(words(flat.snapshot_ref().stack), ["0x01", "0x02"]);
985 assert_eq!(flat.snapshot_ref().memory, Some(&[0xaa, 0xbb][..]));
986 assert!(flat.snapshot_ref().storage_diff.is_empty());
987
988 assert_eq!(words(populated.snapshot_ref().stack), ["0x09"]);
990 assert_eq!(populated.snapshot_ref().memory, Some(&[0xcc, 0xdd][..]));
991 assert_eq!(populated.snapshot_ref().storage_diff.len(), 1);
992 }
993
994 #[test]
995 fn steps_serialize_in_the_wire_format_and_read_back_stored_once() {
996 let step = TraceStep::new(
999 3,
1000 Arc::from("SSTORE"),
1001 100,
1002 5,
1003 1,
1004 None,
1005 StepSnapshot::new(
1006 vec![Arc::from("0x01")],
1007 Some(memory("aabb")),
1008 BTreeMap::from([("0x00".to_owned(), "0x2a".to_owned())]),
1009 BTreeMap::new(),
1010 ),
1011 );
1012 let json: serde_json::Value = serde_json::to_value(&step).expect("json");
1013 assert_eq!(json["stack"], serde_json::json!(["0x01"]));
1014 assert_eq!(json["memory"], "aabb");
1015 assert_eq!(json["storage"]["0x00"], "0x2a");
1016 assert_eq!(json["snapshot"]["memory"], "aabb");
1017 assert_eq!(json["snapshot"]["storage"]["0x00"], "0x2a");
1018 assert_eq!(json["gas_cost"], 5);
1019
1020 let flat = step_with(StepSnapshot::default());
1022 let flat_json: serde_json::Value = serde_json::to_value(&flat).expect("json");
1023 assert_eq!(
1024 flat_json["snapshot"]["stack"],
1025 serde_json::json!(["0x01", "0x02"])
1026 );
1027 assert_eq!(flat_json["stack"], serde_json::json!(["0x01", "0x02"]));
1028
1029 let restored: TraceStep = serde_json::from_value(json).expect("step");
1032 assert_eq!(restored, step);
1033 assert!(
1034 restored.stack.is_empty() && restored.memory.is_none() && restored.storage.is_none()
1035 );
1036 let legacy: TraceStep = serde_json::from_str(
1037 r#"{"pc":1,"op":"ADD","gas":9,"gas_cost":3,"depth":1,"stack":["0x1"],"memory":"cc","storage":{"0x0":"0x1"},"error":null}"#,
1038 )
1039 .expect("legacy step");
1040 assert_eq!(words(legacy.snapshot_ref().stack), ["0x1"]);
1041 assert_eq!(legacy.snapshot_ref().memory, Some(&[0xcc][..]));
1042 assert_eq!(legacy.snapshot_ref().storage["0x0"], "0x1");
1043 assert!(legacy.stack.is_empty());
1044 assert_eq!(legacy, step_with_legacy_fields());
1045
1046 let shared = TraceStep::new(
1048 4,
1049 Arc::from("POP"),
1050 95,
1051 2,
1052 1,
1053 None,
1054 StepSnapshot {
1055 stack: Vec::new(),
1056 memory: step.snapshot.memory.clone(),
1057 storage: Arc::clone(&step.snapshot.storage),
1058 storage_diff: BTreeMap::new(),
1059 transient_storage: BTreeMap::new(),
1060 return_data: None,
1061 },
1062 );
1063 assert!(Arc::ptr_eq(
1064 &shared.snapshot.storage,
1065 &step.snapshot.storage
1066 ));
1067 assert_eq!(shared.snapshot_ref().memory, Some(&[0xaa, 0xbb][..]));
1068 assert!(same_buffer(
1069 shared.snapshot_ref().memory.expect("memory"),
1070 step.snapshot_ref().memory.expect("memory")
1071 ));
1072 }
1073
1074 #[test]
1075 fn transient_storage_is_written_only_where_a_step_touched_it() {
1076 let plain = TraceStep::new(
1077 0,
1078 Arc::from("ADD"),
1079 1,
1080 1,
1081 1,
1082 None,
1083 StepSnapshot::new(
1084 vec![Arc::from("0x1")],
1085 None,
1086 BTreeMap::new(),
1087 BTreeMap::new(),
1088 ),
1089 );
1090 let json = serde_json::to_value(&plain).expect("json");
1091 assert!(json["snapshot"].get("transient_storage").is_none());
1092
1093 let touched = TraceStep::new(
1094 1,
1095 Arc::from("TSTORE"),
1096 1,
1097 100,
1098 1,
1099 None,
1100 StepSnapshot::new(
1101 vec![Arc::from("0x1")],
1102 None,
1103 BTreeMap::new(),
1104 BTreeMap::new(),
1105 )
1106 .with_transient_storage(BTreeMap::from([("0x0".to_owned(), "0x2".to_owned())])),
1107 );
1108 let json = serde_json::to_value(&touched).expect("json");
1109 assert_eq!(json["snapshot"]["transient_storage"]["0x0"], "0x2");
1110 assert_eq!(
1111 serde_json::to_value(touched.snapshot_ref()).expect("borrowed"),
1112 json["snapshot"]
1113 );
1114 let restored: TraceStep = serde_json::from_value(json).expect("step");
1115 assert_eq!(restored, touched);
1116 assert_eq!(restored.snapshot_ref().transient_storage["0x0"], "0x2");
1117
1118 let capabilities: TraceCapabilities =
1121 serde_json::from_str(r#"{"stack":true}"#).expect("capabilities");
1122 assert!(!capabilities.transient_storage);
1123 }
1124
1125 #[test]
1126 fn return_data_is_written_only_where_the_buffer_holds_some() {
1127 let snapshot = || {
1128 StepSnapshot::new(
1129 vec![Arc::from("0x1")],
1130 None,
1131 BTreeMap::new(),
1132 BTreeMap::new(),
1133 )
1134 };
1135 let empty = TraceStep::new(
1136 0,
1137 Arc::from("CALL"),
1138 1,
1139 1,
1140 1,
1141 None,
1142 snapshot().with_return_data(Some(String::new())),
1143 );
1144 assert!(empty.snapshot.return_data.is_none());
1145 let json = serde_json::to_value(&empty).expect("json");
1146 assert!(json["snapshot"].get("return_data").is_none());
1147
1148 let filled = TraceStep::new(
1149 1,
1150 Arc::from("RETURNDATASIZE"),
1151 1,
1152 2,
1153 1,
1154 None,
1155 snapshot().with_return_data(Some("2a".to_owned())),
1156 );
1157 let json = serde_json::to_value(&filled).expect("json");
1158 assert_eq!(json["snapshot"]["return_data"], "2a");
1159 assert_eq!(
1160 serde_json::to_value(filled.snapshot_ref()).expect("borrowed"),
1161 json["snapshot"]
1162 );
1163 let restored: TraceStep = serde_json::from_value(json).expect("step");
1164 assert_eq!(restored, filled);
1165 assert_eq!(restored.snapshot_ref().return_data, Some("2a"));
1166
1167 let mut trace = TransactionTrace {
1169 tx_hash: None,
1170 from_addr: "0x1".to_owned(),
1171 to_addr: None,
1172 value: "0x0".to_owned(),
1173 input_data: "0x".to_owned(),
1174 gas_used: 0,
1175 output: "0x".to_owned(),
1176 success: true,
1177 error: None,
1178 debug_trace_available: true,
1179 contract_address: None,
1180 backend: None,
1181 capabilities: TraceCapabilities::default(),
1182 artifacts: TraceArtifacts::default(),
1183 steps: vec![filled.clone(), filled].into(),
1184 };
1185 trace = serde_json::from_str(&serde_json::to_string(&trace).expect("json")).expect("trace");
1186 let data = |index: usize| trace.steps.step(index).return_data().expect("data");
1187 assert!(std::ptr::eq(data(0), data(1)));
1188 assert!(!trace.capabilities.return_data);
1189 }
1190
1191 fn step_with_legacy_fields() -> TraceStep {
1192 TraceStep {
1193 pc: 1,
1194 op: Arc::from("ADD"),
1195 gas: 9,
1196 gas_cost: 3,
1197 depth: 1,
1198 stack: vec![Arc::from("0x1")],
1199 memory: Some(memory("cc")),
1200 storage: Some(BTreeMap::from([("0x0".to_owned(), "0x1".to_owned())])),
1201 error: None,
1202 snapshot: StepSnapshot::default(),
1203 }
1204 }
1205
1206 #[test]
1207 fn reading_a_trace_back_shares_unchanged_state_between_steps() {
1208 let snapshot = |hex: &str, slot: &str| {
1209 StepSnapshot::new(
1210 Vec::new(),
1211 Some(memory(hex)),
1212 BTreeMap::from([("0x0".to_owned(), slot.to_owned())]),
1213 BTreeMap::new(),
1214 )
1215 };
1216 let step = |pc: u64, snapshot: StepSnapshot| {
1217 TraceStep::new(pc, Arc::from("PUSH1"), 1, 1, 1, None, snapshot)
1218 };
1219 let trace = TransactionTrace {
1220 tx_hash: None,
1221 from_addr: "0x1".to_owned(),
1222 to_addr: None,
1223 value: "0x0".to_owned(),
1224 input_data: "0x".to_owned(),
1225 gas_used: 0,
1226 output: "0x".to_owned(),
1227 success: true,
1228 error: None,
1229 debug_trace_available: true,
1230 contract_address: None,
1231 backend: None,
1232 capabilities: TraceCapabilities::default(),
1233 artifacts: TraceArtifacts::default(),
1234 steps: vec![
1235 step(0, snapshot("aa", "0x1")),
1236 step(1, snapshot("aa", "0x1")),
1237 step(2, snapshot("bb", "0x1")),
1238 step(3, snapshot("bb", "0x2")),
1239 ]
1240 .into(),
1241 };
1242 let json = serde_json::to_string(&trace).expect("json");
1243 let restored: TransactionTrace = serde_json::from_str(&json).expect("trace");
1244 assert_eq!(restored, trace);
1245 for trace in [&restored, &trace] {
1248 let memory = |index: usize| trace.steps.step(index).memory().expect("memory");
1249 assert!(same_buffer(&memory(0), &memory(1)));
1250 assert!(!same_buffer(&memory(1), &memory(2)));
1251 assert!(same_buffer(&memory(2), &memory(3)));
1252 let storage = |index: usize| trace.steps.step(index).storage();
1253 assert!(std::ptr::eq(storage(0), storage(2)));
1254 assert!(!std::ptr::eq(storage(2), storage(3)));
1255 }
1256 }
1257
1258 #[test]
1259 fn core_models_are_serializable() {
1260 let trace = TransactionTrace {
1261 tx_hash: Some("0xabc".to_owned()),
1262 from_addr: "0x1".to_owned(),
1263 to_addr: Some("0x2".to_owned()),
1264 value: "0".to_owned(),
1265 input_data: "0x".to_owned(),
1266 gas_used: 1,
1267 output: "0x".to_owned(),
1268 success: true,
1269 error: None,
1270 steps: vec![TraceStep {
1271 pc: 0,
1272 op: Arc::from("STOP"),
1273 gas: 1,
1274 gas_cost: 0,
1275 depth: 0,
1276 stack: Vec::new(),
1277 memory: None,
1278 storage: None,
1279 error: None,
1280 snapshot: StepSnapshot::default(),
1281 }]
1282 .into(),
1283 debug_trace_available: true,
1284 contract_address: None,
1285 backend: Some("debug-rpc".to_owned()),
1286 capabilities: TraceCapabilities::default(),
1287 artifacts: TraceArtifacts::default(),
1288 };
1289
1290 let encoded = serde_json::to_string(&trace).expect("trace serializes");
1291 assert!(encoded.contains("\"success\":true"));
1292
1293 let call = FunctionCall {
1294 name: "runtime_dispatcher".to_owned(),
1295 selector: String::new(),
1296 entry_step: 0,
1297 exit_step: Some(0),
1298 gas_used: 1,
1299 depth: 0,
1300 call_type: "entry".to_owned(),
1301 contract_address: Some("0x2".to_owned()),
1302 };
1303 assert_eq!(call.call_type, "entry");
1304
1305 let change = StorageChange {
1306 before: None,
1307 after: Some("0x2a".to_owned()),
1308 };
1309 assert_eq!(change.after.as_deref(), Some("0x2a"));
1310 }
1311
1312 #[test]
1313 fn memory_reads_and_writes_as_the_same_hex_string() {
1314 let words = format!("{}{}", "00".repeat(31), "2a").repeat(3);
1318 let document = serde_json::json!({
1319 "tx_hash": "0xabc",
1320 "from_addr": "0x1",
1321 "to_addr": "0x2",
1322 "value": "0x0",
1323 "input_data": "0x",
1324 "gas_used": 0,
1325 "output": "0x",
1326 "success": true,
1327 "error": null,
1328 "debug_trace_available": true,
1329 "contract_address": null,
1330 "backend": "replay",
1331 "capabilities": TraceCapabilities::default(),
1332 "artifacts": TraceArtifacts::default(),
1333 "steps": [
1334 {"pc": 0, "op": "MSTORE", "gas": 1, "gas_cost": 1, "depth": 1,
1335 "stack": [], "memory": "", "storage": {}, "error": null,
1336 "snapshot": {"stack": [], "memory": "", "storage": {}, "storage_diff": {}}},
1337 {"pc": 1, "op": "MLOAD", "gas": 1, "gas_cost": 1, "depth": 1,
1338 "stack": [], "memory": words, "storage": {}, "error": null,
1339 "snapshot": {"stack": [], "memory": words, "storage": {}, "storage_diff": {}}},
1340 {"pc": 2, "op": "POP", "gas": 1, "gas_cost": 1, "depth": 1,
1341 "stack": [], "memory": words, "storage": {}, "error": null,
1342 "snapshot": {"stack": [], "memory": words, "storage": {}, "storage_diff": {}}},
1343 {"pc": 3, "op": "STOP", "gas": 1, "gas_cost": 0, "depth": 1,
1344 "stack": [], "memory": null, "storage": {}, "error": null,
1345 "snapshot": {"stack": [], "memory": null, "storage": {}, "storage_diff": {}}}
1346 ]
1347 })
1348 .to_string();
1349 let trace: TransactionTrace = serde_json::from_str(&document).expect("trace");
1350 let written = serde_json::to_string(&trace).expect("json");
1351 assert_eq!(
1352 serde_json::from_str::<serde_json::Value>(&written).expect("written json"),
1353 serde_json::from_str::<serde_json::Value>(&document).expect("document json"),
1354 );
1355 let again: TransactionTrace = serde_json::from_str(&written).expect("trace");
1357 assert_eq!(serde_json::to_string(&again).expect("json"), written);
1358
1359 let memory = |index: usize| trace.steps.step(index).memory();
1360 assert_eq!(memory(0).as_deref(), Some(&[][..]));
1361 assert_eq!(memory(1).map(|memory| memory.len()), Some(96));
1362 assert_eq!(
1363 memory(1).and_then(|memory| memory.get(31).copied()),
1364 Some(0x2a)
1365 );
1366 assert_eq!(memory(3), None);
1367 assert!(same_buffer(
1369 &memory(1).expect("memory"),
1370 &memory(2).expect("memory")
1371 ));
1372 }
1373
1374 #[test]
1375 fn memory_from_a_file_may_be_prefixed_but_must_be_hex() {
1376 let step = |memory: &str| {
1377 serde_json::from_str::<TraceStep>(&format!(
1378 r#"{{"pc":0,"op":"STOP","gas":0,"gas_cost":0,"depth":1,"memory":{memory}}}"#
1379 ))
1380 };
1381 let prefixed = step(r#""0xAABB""#).expect("prefixed memory");
1382 assert_eq!(prefixed.snapshot_ref().memory, Some(&[0xaa, 0xbb][..]));
1383 assert_eq!(
1385 serde_json::to_value(&prefixed).expect("json")["memory"],
1386 "aabb"
1387 );
1388
1389 let odd = step(r#""abc""#).expect_err("odd length");
1390 assert!(odd
1391 .to_string()
1392 .starts_with("memory is not hex: 3 hex digits"));
1393 let invalid = step(r#""aazz""#).expect_err("not hex");
1394 assert!(invalid
1395 .to_string()
1396 .starts_with("memory is not hex: `z` at offset 2"));
1397 }
1398
1399 #[test]
1400 fn hex_round_trips_and_names_what_is_wrong() {
1401 assert_eq!(encode_hex(&[0x00, 0x2a, 0xff]), "002aff");
1402 assert_eq!(decode_hex("002AfF"), Ok(vec![0x00, 0x2a, 0xff]));
1403 assert_eq!(decode_hex("0x"), Ok(Vec::new()));
1404 assert_eq!(decode_hex(""), Ok(Vec::new()));
1405 assert_eq!(decode_hex("0x2"), Err(HexError::OddLength(1)));
1406 assert_eq!(
1407 decode_hex("2x"),
1408 Err(HexError::InvalidDigit {
1409 offset: 1,
1410 character: 'x'
1411 })
1412 );
1413 assert_eq!(
1415 decode_hex("aé"),
1416 Err(HexError::InvalidDigit {
1417 offset: 1,
1418 character: 'é'
1419 })
1420 );
1421 }
1422}