From fba9a5980223bec014334ba4a4ae20589d66d03e Mon Sep 17 00:00:00 2001 From: PA <50184410+peyha@users.noreply.github.com> Date: Wed, 27 Dec 2023 13:40:37 +0100 Subject: [PATCH] feat(revm): use GenericRevertReason type (#5854) Co-authored-by: Matthias Seitz --- .../revm/revm-inspectors/src/tracing/types.rs | 19 ++------ .../revm/revm-inspectors/src/tracing/utils.rs | 43 +++++++++++++++++++ 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/crates/revm/revm-inspectors/src/tracing/types.rs b/crates/revm/revm-inspectors/src/tracing/types.rs index 4f559f43dc..beafb7f4c2 100644 --- a/crates/revm/revm-inspectors/src/tracing/types.rs +++ b/crates/revm/revm-inspectors/src/tracing/types.rs @@ -1,9 +1,9 @@ //! Types for representing call trace items. -use crate::tracing::{config::TraceStyle, utils::convert_memory}; +use crate::tracing::{config::TraceStyle, utils, utils::convert_memory}; pub use alloy_primitives::Log; use alloy_primitives::{Address, Bytes, U256, U64}; -use alloy_sol_types::decode_revert_reason; + use reth_rpc_types::trace::{ geth::{CallFrame, CallLogFrame, GethDefaultTracingOptions, StructLog}, parity::{ @@ -347,9 +347,7 @@ impl CallTraceNode { // we need to populate error and revert reason if !self.trace.success { - // decode the revert reason, but don't include it if it's empty - call_frame.revert_reason = decode_revert_reason(self.trace.output.as_ref()) - .filter(|reason| !reason.is_empty()); + call_frame.revert_reason = utils::maybe_revert_reason(self.trace.output.as_ref()); // Note: the call tracer mimics parity's trace transaction and geth maps errors to parity style error messages, call_frame.error = self.trace.as_error_msg(TraceStyle::Parity); @@ -679,14 +677,3 @@ impl AsRef<[u8]> for RecordedMemory { self.as_bytes() } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn decode_empty_revert() { - let reason = decode_revert_reason("".as_bytes()); - assert_eq!(reason, Some("".to_string())); - } -} diff --git a/crates/revm/revm-inspectors/src/tracing/utils.rs b/crates/revm/revm-inspectors/src/tracing/utils.rs index c8cd2dc48b..ac3172eb7b 100644 --- a/crates/revm/revm-inspectors/src/tracing/utils.rs +++ b/crates/revm/revm-inspectors/src/tracing/utils.rs @@ -1,6 +1,7 @@ //! Util functions for revm related ops use alloy_primitives::{hex, Address, Bytes, B256}; +use alloy_sol_types::{ContractError, GenericRevertReason}; use revm::{ interpreter::CreateInputs, primitives::{CreateScheme, SpecId, KECCAK_EMPTY}, @@ -58,3 +59,45 @@ pub(crate) fn load_account_code( }) .map(Into::into) } + +/// Returns a non empty revert reason if the output is a revert/error. +#[inline] +pub(crate) fn maybe_revert_reason(output: &[u8]) -> Option { + let reason = match GenericRevertReason::decode(output)? { + GenericRevertReason::ContractError(err) => { + match err { + ContractError::Revert(revert) => { + // return the raw revert reason and don't use the revert's display message + revert.reason + } + err => err.to_string(), + } + } + GenericRevertReason::RawString(err) => err, + }; + if reason.is_empty() { + None + } else { + Some(reason) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_sol_types::{GenericContractError, SolInterface}; + + #[test] + fn decode_empty_revert() { + let reason = GenericRevertReason::decode("".as_bytes()).map(|x| x.to_string()); + assert_eq!(reason, Some("".to_string())); + } + + #[test] + fn decode_revert_reason() { + let err = GenericContractError::Revert("my revert".into()); + let encoded = err.abi_encode(); + let reason = maybe_revert_reason(&encoded).unwrap(); + assert_eq!(reason, "my revert"); + } +}