Skip to main content

revive_strategy/tracing/
revert_tracer.rs

1use polkadot_sdk::{
2    pallet_revive::{Code, tracing::Tracing},
3    sp_core::{H160, U256},
4};
5
6#[derive(Debug)]
7pub(crate) struct RevertTracer {
8    pub max_depth: usize,
9    pub has_reverted: Option<polkadot_sdk::sp_core::H160>,
10    pub calls: Vec<polkadot_sdk::sp_core::H160>,
11    pub is_create: bool,
12    pub call_types: Vec<Type>,
13}
14
15#[derive(Debug)]
16pub enum Type {
17    Create,
18    Rest,
19}
20
21impl RevertTracer {
22    fn current_addr(&self) -> H160 {
23        self.calls.last().copied().unwrap_or_default()
24    }
25    pub fn new() -> Self {
26        Self {
27            max_depth: 1,
28            has_reverted: None,
29            calls: vec![],
30            is_create: false,
31            call_types: vec![],
32        }
33    }
34}
35
36impl Tracing for RevertTracer {
37    fn instantiate_code(&mut self, _code: &Code, _salt: Option<&[u8; 32]>) {
38        self.is_create = true;
39    }
40
41    fn enter_child_span(
42        &mut self,
43        _from: H160,
44        to: H160,
45        _is_delegate_call: Option<H160>,
46        _is_read_only: bool,
47        _value: U256,
48        _input: &[u8],
49        _gas: U256,
50    ) {
51        self.call_types.push(if self.is_create { Type::Create } else { Type::Rest });
52
53        self.calls.push(if self.call_types.last().is_some_and(|x| matches!(x, Type::Create)) {
54            self.current_addr()
55        } else {
56            to
57        });
58
59        if self.has_reverted.is_none() {
60            self.max_depth += 1;
61        }
62    }
63
64    fn exit_child_span(
65        &mut self,
66        output: &polkadot_sdk::pallet_revive::ExecReturnValue,
67        _gas_left: U256,
68    ) {
69        let addr = self.calls.pop().unwrap_or_default();
70
71        if output.did_revert() && self.has_reverted.is_none() {
72            self.has_reverted = Some(addr);
73        }
74        let typ = self.call_types.pop();
75        if typ.is_some_and(|x| matches!(x, Type::Create)) {
76            self.is_create = false;
77        }
78        if self.has_reverted.is_none() {
79            self.max_depth -= 1;
80        }
81    }
82    fn exit_child_span_with_error(
83        &mut self,
84        _error: polkadot_sdk::sp_runtime::DispatchError,
85        _gas_used: U256,
86    ) {
87        let addr = self.calls.pop().unwrap_or_default();
88        if self.has_reverted.is_none() {
89            self.has_reverted = Some(addr);
90        }
91        let typ = self.call_types.pop();
92        if typ.is_some_and(|x| matches!(x, Type::Create)) {
93            self.is_create = false;
94        }
95        if self.has_reverted.is_none() {
96            self.max_depth -= 1;
97        }
98    }
99}