use crate::inspectors::tx_inspector::TxInspector;
use revm::context_interface::result::HaltReason;
use revm::interpreter::{InstructionResult, SuccessOrHalt};
use crate::types::*;
use crate::utils::error_utils::parse_custom_error;
use alloy::primitives::{hex, Bytes, U256};
impl TxInspector {
pub fn get_error_trace_address(&self) -> Option<Vec<usize>> {
self.find_error_trace()
.map(|error_trace| error_trace.trace_address.clone())
}
pub fn find_error_trace(&self) -> Option<&CallTrace> {
fn find_error_recursive(trace: &CallTrace) -> Option<&CallTrace> {
let mut last_error = None;
for subtrace in &trace.subtraces {
if !subtrace.status.is_success() {
if let Some(error) = find_error_recursive(subtrace) {
last_error = Some(error);
}
}
}
if trace.error_origin {
Some(trace)
} else {
last_error
}
}
let mut last_error = None;
for trace in &self.call_traces {
if !trace.status.is_success() {
if let Some(error) = find_error_recursive(trace) {
last_error = Some(error);
}
}
}
last_error
}
pub fn handle_end(&mut self, result: InstructionResult, gas_used: u64, output: Bytes) {
if let Some(trace_index) = self.call_stack.pop() {
let trace = &mut self.call_traces[trace_index];
trace.gas_used = U256::from(gas_used);
trace.output = output.clone();
let status = match SuccessOrHalt::<HaltReason>::from(result) {
SuccessOrHalt::Success(_) => CallStatus::Success,
SuccessOrHalt::Revert => {
if let Some(error_msg) = parse_custom_error(&output) {
CallStatus::Revert(error_msg)
} else {
CallStatus::Revert(format!("0x{}", hex::encode(output)))
}
}
SuccessOrHalt::Halt(reason) => CallStatus::Halt(format!("{reason:?}")),
SuccessOrHalt::FatalExternalError => CallStatus::FatalError,
SuccessOrHalt::Internal(_) => CallStatus::Success,
};
trace.status = status;
trace.error_origin = !trace.status.is_success()
&& trace
.subtraces
.iter()
.all(|subtrace| subtrace.status.is_success());
if let Some(&parent_index) = self.call_stack.last() {
let trace = self.call_traces.remove(trace_index);
self.call_traces[parent_index].subtraces.push(trace);
}
}
}
}