1use anvil_zksync_common::{address_map, utils::format::write_interspersed};
2use zksync_multivm::interface::{Call, ExecutionResult, VmEvent};
3use zksync_types::{
4 l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log},
5 web3::Bytes,
6 Address, H160, H256, U256,
7};
8
9use crate::numbers::SignedU256;
10
11#[derive(Clone, Debug, PartialEq, Eq)]
13pub enum L2L1Log {
14 User(UserL2ToL1Log),
15 System(SystemL2ToL1Log),
16}
17
18pub struct LogData {
20 topics: Vec<H256>,
22 pub data: Bytes,
24}
25
26impl LogData {
27 #[inline]
31 pub const fn new_unchecked(topics: Vec<H256>, data: Bytes) -> Self {
32 Self { topics, data }
33 }
34
35 #[inline]
37 pub fn new(topics: Vec<H256>, data: Bytes) -> Option<Self> {
38 let this = Self::new_unchecked(topics, data);
39 this.is_valid().then_some(this)
40 }
41
42 #[inline]
44 pub const fn empty() -> Self {
45 Self {
46 topics: Vec::new(),
47 data: Bytes(Vec::new()),
48 }
49 }
50
51 #[inline]
53 pub fn is_valid(&self) -> bool {
54 self.topics.len() <= 4
55 }
56
57 #[inline]
59 pub fn topics(&self) -> &[H256] {
60 &self.topics
61 }
62
63 #[inline]
66 pub fn topics_mut(&mut self) -> &mut [H256] {
67 &mut self.topics
68 }
69
70 #[inline]
73 pub fn topics_mut_unchecked(&mut self) -> &mut Vec<H256> {
74 &mut self.topics
75 }
76
77 #[inline]
80 pub fn set_topics_unchecked(&mut self, topics: Vec<H256>) {
81 self.topics = topics;
82 }
83
84 #[inline]
86 pub fn set_topics_truncating(&mut self, mut topics: Vec<H256>) {
87 topics.truncate(4);
88 self.set_topics_unchecked(topics);
89 }
90
91 #[inline]
93 pub fn split(self) -> (Vec<H256>, Bytes) {
94 (self.topics, self.data)
95 }
96}
97
98pub type Label = String;
99pub type Word32 = [u8; 32];
100pub type Word24 = [u8; 24];
101
102#[derive(Clone, Debug, Default, Eq, PartialEq)]
103pub struct LabeledAddress {
104 pub label: Option<Label>,
105 pub address: Address,
106}
107
108#[derive(Clone, Debug, Eq, PartialEq)]
121pub enum DecodedValue {
122 Bool(bool),
124 Int(SignedU256),
126 Uint(U256),
128 FixedBytes(Word32, usize),
130 Address(LabeledAddress),
132 Function(Word24),
134
135 Bytes(Vec<u8>),
137 String(String),
139
140 Array(Vec<DecodedValue>),
142 FixedArray(Vec<DecodedValue>),
144 Tuple(Vec<DecodedValue>),
146
147 CustomStruct {
149 name: String,
151 prop_names: Vec<String>,
153 tuple: Vec<DecodedValue>,
155 },
156}
157
158impl std::fmt::Display for LabeledAddress {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 let LabeledAddress { label, address } = self;
161
162 if let Some(label) = label {
163 f.write_fmt(format_args!("{label}: "))?;
164 }
165 write!(f, "[0x{}]", hex::encode(address))
166 }
167}
168
169impl std::fmt::Display for DecodedValue {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 match self {
172 DecodedValue::Bool(inner) => inner.fmt(f),
173 DecodedValue::Int(inner) => inner.fmt(f),
174 DecodedValue::Uint(inner) => inner.fmt(f),
175 DecodedValue::FixedBytes(word, size) => {
176 f.write_fmt(format_args!("0x{}", hex::encode(&word[..*size])))
177 }
178 DecodedValue::Address(labeled_address) => labeled_address.fmt(f),
179 DecodedValue::Function(inner) => f.write_fmt(format_args!("0x{}", hex::encode(inner))),
180 DecodedValue::Bytes(inner) => f.write_fmt(format_args!("0x{}", hex::encode(inner))),
181 DecodedValue::String(inner) => f.write_str(&inner.escape_debug().to_string()),
182 DecodedValue::Array(vec) | DecodedValue::FixedArray(vec) => {
183 f.write_str("[")?;
184 write_interspersed(f, vec.iter(), ", ")?;
185 f.write_str("]")
186 }
187 DecodedValue::Tuple(vec) => {
188 f.write_str("(")?;
189 write_interspersed(f, vec.iter(), ", ")?;
190 f.write_str(")")
191 }
192 DecodedValue::CustomStruct { tuple, .. } => DecodedValue::Tuple(tuple.clone()).fmt(f),
193 }
194 }
195}
196
197impl DecodedValue {
198 pub fn as_bytes(&self) -> Option<&Vec<u8>> {
199 if let Self::Bytes(v) = self {
200 Some(v)
201 } else {
202 None
203 }
204 }
205}
206
207impl std::fmt::Display for DecodedError {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 match self {
210 DecodedError::Empty => write!(f, ""),
211 DecodedError::CustomError { name, fields } => {
212 write!(f, "{name}(")?;
213 write_interspersed(f, fields.iter(), ", ")?;
214 write!(f, ")")
215 }
216 DecodedError::GenericCustomError { selector, raw } => {
217 write!(
218 f,
219 "custom error with function selector 0x{}",
220 hex::encode(selector)
221 )?;
222 if !raw.is_empty() {
223 write!(f, ": ")?;
224 match std::str::from_utf8(raw) {
225 Ok(data) => write!(f, "{}", data),
226 Err(_) => write!(f, "{}", hex::encode(raw)),
227 }
228 } else {
229 Ok(())
230 }
231 }
232 DecodedError::Revert(message) => write!(f, "{}", message),
233 DecodedError::Panic(message) => write!(f, "{}", message),
234 DecodedError::Raw(data) => {
235 if !data.is_empty() {
236 let var_name = write!(
237 f,
238 "{}",
239 anvil_zksync_common::utils::format::trimmed_hex(data)
240 );
241 var_name?;
242 } else {
243 write!(f, "<empty revert data>")?;
244 }
245 Ok(())
246 }
247 DecodedError::String(message) => write!(f, "{}", message),
248 }
249 }
250}
251
252impl std::fmt::Display for DecodedRevertData {
253 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254 match self {
255 DecodedRevertData::Value(value) => value.fmt(f),
256 DecodedRevertData::Error(error) => error.fmt(f),
257 }
258 }
259}
260#[derive(Clone, Debug, PartialEq, Eq)]
261pub enum DecodedReturnData {
262 NormalReturn(Vec<DecodedValue>),
263 Revert(DecodedRevertData),
264}
265
266impl Default for DecodedReturnData {
267 fn default() -> Self {
268 Self::NormalReturn(vec![])
269 }
270}
271
272impl std::fmt::Display for DecodedReturnData {
273 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274 match self {
275 DecodedReturnData::NormalReturn(values) => {
276 if values.is_empty() {
277 Ok(())
278 } else {
279 write_interspersed(f, values.iter(), ", ")
280 }
281 }
282 DecodedReturnData::Revert(revert_data) => revert_data.fmt(f),
283 }
284 }
285}
286
287#[derive(Clone, Debug, PartialEq, Eq)]
288pub enum DecodedError {
289 Empty,
290 CustomError {
291 name: String,
292 fields: Vec<DecodedValue>,
293 },
294 GenericCustomError {
295 selector: [u8; 4],
296 raw: Vec<u8>,
297 },
298 Revert(String),
299 Panic(String),
300 Raw(Vec<u8>),
301 String(String),
302}
303
304#[derive(Clone, Debug, PartialEq, Eq)]
305pub enum DecodedRevertData {
306 Value(DecodedValue),
307 Error(DecodedError),
308}
309
310#[derive(Clone, Debug, Default, PartialEq, Eq)]
312pub struct DecodedCallData {
313 pub signature: String,
315 pub args: Vec<DecodedValue>,
317}
318
319#[derive(Clone, Debug, Default, PartialEq, Eq)]
321pub struct DecodedCallTrace {
322 pub label: Option<Label>,
324 pub return_data: DecodedReturnData,
326 pub call_data: Option<DecodedCallData>,
328}
329
330#[derive(Clone, Debug, Default, PartialEq, Eq)]
332pub struct DecodedCallLog {
333 pub name: Option<String>,
335 pub params: Option<Vec<(String, DecodedValue)>>,
338}
339
340#[derive(Clone, Debug, Default)]
342pub struct CallLog {
343 pub raw_log: VmEvent,
345 pub decoded: DecodedCallEvent,
347 pub position: u64,
349}
350
351#[derive(Clone, Debug)]
353pub struct L2L1Logs {
354 pub raw_log: L2L1Log,
356 pub position: u64,
358}
359
360impl CallLog {
361 #[inline]
363 pub fn with_position(mut self, position: u64) -> Self {
364 self.position = position;
365 self
366 }
367}
368
369#[derive(Clone, Debug)]
371pub struct CallTrace {
372 pub success: bool,
374 pub caller: Address,
376 pub address: Address,
382 pub execution_result: ExecutionResult,
384 pub decoded: DecodedCallTrace,
386 pub call: Call,
388}
389
390#[derive(Clone, Debug, Default, PartialEq, Eq)]
392pub struct DecodedCallEvent {
393 pub name: Option<String>,
395 pub params: Option<Vec<(String, DecodedValue)>>,
398}
399
400#[derive(Clone, Debug)]
402pub struct CallTraceNode {
403 pub parent: Option<usize>,
405 pub children: Vec<usize>,
407 pub idx: usize,
409 pub trace: CallTrace,
411 pub logs: Vec<CallLog>,
413 pub l2_l1_logs: Vec<L2L1Logs>,
415 pub ordering: Vec<TraceMemberOrder>,
417}
418
419impl Default for CallTraceNode {
420 fn default() -> Self {
421 Self {
422 parent: None,
423 children: Vec::new(),
424 idx: 0,
425 trace: CallTrace {
426 success: true,
427 caller: H160::zero(),
428 address: H160::zero(),
429 execution_result: ExecutionResult::Success { output: vec![] },
430 decoded: DecodedCallTrace::default(),
431 call: Call::default(),
432 },
433 logs: Vec::new(),
434 l2_l1_logs: Vec::new(),
435 ordering: Vec::new(),
436 }
437 }
438}
439
440#[derive(Clone, Copy, Debug, PartialEq, Eq)]
442pub enum TraceMemberOrder {
443 Log(usize),
445 Call(usize),
447 L1L2Log(usize),
449}
450
451#[derive(Clone, Debug)]
455pub struct CallTraceArena {
456 pub arena: Vec<CallTraceNode>,
458}
459
460impl Default for CallTraceArena {
461 fn default() -> Self {
462 let root_node = CallTraceNode {
463 parent: None,
464 children: Vec::new(),
465 idx: 0,
466 trace: CallTrace {
467 success: true,
468 caller: H160::zero(),
469 address: H160::zero(),
470 execution_result: ExecutionResult::Success { output: vec![] },
471 decoded: DecodedCallTrace::default(),
472 call: Call::default(),
473 },
474 logs: Vec::new(),
475 l2_l1_logs: Vec::new(),
476 ordering: Vec::new(),
477 };
478
479 Self {
481 arena: vec![root_node],
482 }
483 }
484}
485
486impl CallTraceArena {
487 pub fn add_node(&mut self, parent: Option<usize>, mut node: CallTraceNode) -> usize {
489 let idx = self.arena.len();
490 node.idx = idx;
491 node.parent = parent;
492
493 node.ordering = (0..node.logs.len()).map(TraceMemberOrder::Log).collect();
495
496 self.arena.push(node);
497
498 if let Some(parent_idx) = parent {
500 self.arena[parent_idx].children.push(idx);
501 let child_local_idx = self.arena[parent_idx].children.len() - 1;
502 self.arena[parent_idx]
503 .ordering
504 .push(TraceMemberOrder::Call(child_local_idx));
505 }
506 idx
507 }
508
509 pub fn nodes(&self) -> &[CallTraceNode] {
511 &self.arena
512 }
513
514 pub fn nodes_mut(&mut self) -> &mut Vec<CallTraceNode> {
516 &mut self.arena
517 }
518
519 pub fn into_nodes(self) -> Vec<CallTraceNode> {
521 self.arena
522 }
523
524 #[inline]
528 pub fn clear(&mut self) {
529 self.arena.clear();
530 self.arena.push(Default::default());
531 }
532
533 pub fn filter_out_precompiles(&mut self) {
535 self.arena
536 .retain(|node| !address_map::is_precompile(&node.trace.address));
537 }
538
539 pub fn filter_out_system_contracts(&mut self) {
541 self.arena
542 .retain(|node| !address_map::is_system(&node.trace.address));
543 }
544}
545
546pub trait ExecutionResultDisplay {
548 fn display(&self) -> String;
549}
550
551impl ExecutionResultDisplay for ExecutionResult {
552 fn display(&self) -> String {
553 match self {
554 ExecutionResult::Success { .. } => "Success".to_string(),
555 ExecutionResult::Revert { output } => format!("Revert: {}", output),
556 ExecutionResult::Halt { reason } => format!("Halt: {:?}", reason),
557 }
558 }
559}