cfx_execute_helper/observer/exec_tracer/
error_unwind.rs1use super::{
2 action_types::{Action, Call, CallResult, Create, CreateResult, Outcome},
3 trace_types::ExecTrace,
4 ExecTraceKey,
5};
6use cfx_executor::executive::Executed;
7use cfx_types::Address;
8use solidity_abi::string_revert_reason_decode;
9
10#[derive(Default)]
17pub struct ErrorUnwind {
18 callstack: Vec<Address>,
19 pub errors: Vec<(Address, String)>,
20}
21
22impl ErrorUnwind {
23 pub fn from_executed(executed: &Executed) -> Self {
24 Self::from_traces(
25 executed.ext_result.get::<ExecTraceKey>().unwrap_or(&vec![]),
26 )
27 }
28
29 pub fn from_traces(traces: &[ExecTrace]) -> Self {
30 let mut errors = ErrorUnwind::default();
31 for trace in traces.iter() {
32 match &trace.action {
33 Action::Call(call) => errors.accept_call(call),
34 Action::Create(create) => errors.accept_create(create),
35 Action::CallResult(result) => errors.accept_call_result(result),
36 Action::CreateResult(result) => {
37 errors.accept_create_result(result)
38 }
39 Action::InternalTransferAction(_) => {}
40 Action::SetAuth(_) => {}
41 Action::SelfDestruct(_) => {}
42 }
43 }
44 errors
45 }
46
47 fn accept_call(&mut self, call: &Call) {
51 self.callstack.push(call.to);
52 self.errors.clear();
53 }
54
55 fn accept_create(&mut self, _create: &Create) { self.errors.clear(); }
56
57 fn accept_call_result(&mut self, result: &CallResult) {
58 let address = self
59 .callstack
60 .pop()
61 .expect("trace call and their results must be matched");
62
63 match Self::error_message(&result.outcome, &result.return_data) {
64 Some(message) => self.errors.push((address, message)),
69 None => self.errors.clear(),
74 }
75 }
76
77 fn accept_create_result(&mut self, result: &CreateResult) {
78 let address = result.addr;
79
80 match Self::error_message(&result.outcome, &result.return_data) {
81 Some(message) => self.errors.push((address, message)),
86 None => self.errors.clear(),
91 }
92 }
93
94 fn error_message(
95 outcome: &Outcome, return_data: &Vec<u8>,
96 ) -> Option<String> {
97 match outcome {
98 Outcome::Success => None,
99 Outcome::Reverted => Some(format!(
100 "Vm reverted. {}",
101 string_revert_reason_decode(return_data)
102 )),
103 Outcome::Fail => Some(
104 String::from_utf8(return_data.clone())
105 .expect("Return data is encoded from valid utf-8 string"),
106 ),
107 }
108 }
109}