1use anvil_zksync_common::{address_map, utils::format::write_interspersed};
2use zksync_multivm::interface::{Call, Halt, 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(Debug, Clone, PartialEq)]
373pub enum ExecutionResult {
374 Success { output: Vec<u8> },
376 Revert { output: String },
378 Halt { reason: Halt },
380}
381
382impl ExecutionResult {
383 pub fn is_failed(&self) -> bool {
385 matches!(self, Self::Revert { .. } | Self::Halt { .. })
386 }
387}
388
389impl From<zksync_multivm::interface::ExecutionResult> for ExecutionResult {
390 fn from(value: zksync_multivm::interface::ExecutionResult) -> Self {
391 match value {
392 zksync_multivm::interface::ExecutionResult::Success { output } => {
393 ExecutionResult::Success { output }
394 }
395 zksync_multivm::interface::ExecutionResult::Revert { output } => {
396 ExecutionResult::Revert {
397 output: output.to_user_friendly_string(),
398 }
399 }
400 zksync_multivm::interface::ExecutionResult::Halt { reason } => {
401 ExecutionResult::Halt { reason }
402 }
403 }
404 }
405}
406
407#[derive(Clone, Debug)]
409pub struct CallTrace {
410 pub success: bool,
412 pub caller: Address,
414 pub address: Address,
420 pub execution_result: ExecutionResult,
422 pub decoded: DecodedCallTrace,
424 pub call: Call,
426}
427
428#[derive(Clone, Debug, Default, PartialEq, Eq)]
430pub struct DecodedCallEvent {
431 pub name: Option<String>,
433 pub params: Option<Vec<(String, DecodedValue)>>,
436}
437
438#[derive(Clone, Debug)]
440pub struct CallTraceNode {
441 pub parent: Option<usize>,
443 pub children: Vec<usize>,
445 pub idx: usize,
447 pub trace: CallTrace,
449 pub logs: Vec<CallLog>,
451 pub l2_l1_logs: Vec<L2L1Logs>,
453 pub ordering: Vec<TraceMemberOrder>,
455}
456
457impl Default for CallTraceNode {
458 fn default() -> Self {
459 Self {
460 parent: None,
461 children: Vec::new(),
462 idx: 0,
463 trace: CallTrace {
464 success: true,
465 caller: H160::zero(),
466 address: H160::zero(),
467 execution_result: ExecutionResult::Success { output: vec![] },
468 decoded: DecodedCallTrace::default(),
469 call: Call::default(),
470 },
471 logs: Vec::new(),
472 l2_l1_logs: Vec::new(),
473 ordering: Vec::new(),
474 }
475 }
476}
477
478#[derive(Clone, Copy, Debug, PartialEq, Eq)]
480pub enum TraceMemberOrder {
481 Log(usize),
483 Call(usize),
485 L1L2Log(usize),
487}
488
489#[derive(Clone, Debug)]
493pub struct CallTraceArena {
494 pub arena: Vec<CallTraceNode>,
496}
497
498impl Default for CallTraceArena {
499 fn default() -> Self {
500 let root_node = CallTraceNode {
501 parent: None,
502 children: Vec::new(),
503 idx: 0,
504 trace: CallTrace {
505 success: true,
506 caller: H160::zero(),
507 address: H160::zero(),
508 execution_result: ExecutionResult::Success { output: vec![] },
509 decoded: DecodedCallTrace::default(),
510 call: Call::default(),
511 },
512 logs: Vec::new(),
513 l2_l1_logs: Vec::new(),
514 ordering: Vec::new(),
515 };
516
517 Self {
519 arena: vec![root_node],
520 }
521 }
522}
523
524impl CallTraceArena {
525 pub fn add_node(&mut self, parent: Option<usize>, mut node: CallTraceNode) -> usize {
527 let idx = self.arena.len();
528 node.idx = idx;
529 node.parent = parent;
530
531 node.ordering = (0..node.logs.len()).map(TraceMemberOrder::Log).collect();
533
534 self.arena.push(node);
535
536 if let Some(parent_idx) = parent {
538 self.arena[parent_idx].children.push(idx);
539 let child_local_idx = self.arena[parent_idx].children.len() - 1;
540 self.arena[parent_idx]
541 .ordering
542 .push(TraceMemberOrder::Call(child_local_idx));
543 }
544 idx
545 }
546
547 pub fn nodes(&self) -> &[CallTraceNode] {
549 &self.arena
550 }
551
552 pub fn nodes_mut(&mut self) -> &mut Vec<CallTraceNode> {
554 &mut self.arena
555 }
556
557 pub fn into_nodes(self) -> Vec<CallTraceNode> {
559 self.arena
560 }
561
562 #[inline]
566 pub fn clear(&mut self) {
567 self.arena.clear();
568 self.arena.push(Default::default());
569 }
570
571 pub fn filter_out_precompiles(&mut self) {
573 self.arena
574 .retain(|node| !address_map::is_precompile(&node.trace.address));
575 }
576
577 pub fn filter_out_system_contracts(&mut self) {
579 self.arena
580 .retain(|node| !address_map::is_system(&node.trace.address));
581 }
582}
583
584pub trait ExecutionResultDisplay {
586 fn display(&self) -> String;
587}
588
589impl ExecutionResultDisplay for ExecutionResult {
590 fn display(&self) -> String {
591 match self {
592 ExecutionResult::Success { .. } => "Success".to_string(),
593 ExecutionResult::Revert { output } => format!("Revert: {}", output),
594 ExecutionResult::Halt { reason } => format!("Halt: {:?}", reason),
595 }
596 }
597}