stratus/eth/primitives/
execution_result.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use std::borrow::Cow;

use display_json::DebugAsJson;
use fake::Faker;

use crate::eth::codegen::error_sig_opt;
use crate::eth::primitives::Bytes;

/// Indicates how a transaction execution was finished.
#[derive(DebugAsJson, strum::Display, Clone, PartialEq, Eq, fake::Dummy, derive_new::new, serde::Serialize, serde::Deserialize, strum::EnumString)]
#[serde(rename_all = "snake_case")]
pub enum ExecutionResult {
    /// Finished normally (RETURN opcode).
    #[strum(to_string = "success")]
    Success,

    /// Transaction execution finished with a reversion (REVERT opcode).
    #[strum(to_string = "reverted")]
    Reverted { reason: RevertReason },

    /// Transaction execution did not finish.
    #[strum(to_string = "halted")]
    Halted { reason: String },
}

#[derive(Debug, thiserror::Error, serde::Serialize, serde::Deserialize, Default, Clone, PartialEq, Eq)]
pub struct RevertReason(pub Cow<'static, str>);

impl fake::Dummy<Faker> for RevertReason {
    fn dummy_with_rng<R: rand_core::RngCore + ?Sized>(_: &Faker, _rng: &mut R) -> Self {
        RevertReason(Cow::Borrowed("reverted"))
    }
}

impl From<&'static str> for RevertReason {
    fn from(value: &'static str) -> Self {
        RevertReason(Cow::Borrowed(value))
    }
}

impl From<&Bytes> for RevertReason {
    fn from(value: &Bytes) -> Self {
        let sig: Cow<str> = error_sig_opt(value).unwrap_or_else(|| Cow::Owned(value.to_string()));
        Self(sig)
    }
}

impl std::fmt::Display for RevertReason {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[cfg(test)]
mod tests {
    use alloy_primitives::hex;

    use super::*;

    #[test]
    fn test_revert_reason_from_bytes() {
        // Test string revert
        let input = hex::decode(
            "08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000\
0000000000014437573746f6d206572726f72206d657373616765000000000000000000000000",
        )
        .unwrap();
        let bytes = Bytes::from(input);
        let revert = RevertReason::from(&bytes);
        assert_eq!(revert.0, "Custom error message");

        // Test known error
        let input = hex::decode("22aa4404").unwrap();
        let bytes = Bytes::from(input);
        let revert = RevertReason::from(&bytes);
        assert_eq!(revert.0, "KnownError()");

        // Test unknown error
        let input = hex::decode("c39a0557").unwrap();
        let bytes = Bytes::from(input);
        let revert = RevertReason::from(&bytes);
        assert_eq!(revert.0, "0xc39a0557");
    }
}