stratus/eth/primitives/
log.rs

1use display_json::DebugAsJson;
2
3use crate::alias::AlloyLog;
4use crate::alias::RevmLog;
5use crate::eth::primitives::Address;
6use crate::eth::primitives::Bytes;
7use crate::eth::primitives::LogTopic;
8
9/// Log is an event emitted by the EVM during contract execution.
10#[derive(DebugAsJson, Clone, Default, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize)]
11pub struct Log {
12    /// Address that emitted the log.
13    pub address: Address,
14
15    /// Topics (0 to 4 positions) describing the log.
16    pub topic0: Option<LogTopic>,
17    pub topic1: Option<LogTopic>,
18    pub topic2: Option<LogTopic>,
19    pub topic3: Option<LogTopic>,
20
21    /// Additional data.
22    pub data: Bytes,
23}
24
25impl Log {
26    /// Returns all topics in the log.
27    pub fn topics(&self) -> [Option<LogTopic>; 4] {
28        [self.topic0, self.topic1, self.topic2, self.topic3]
29    }
30
31    /// Returns all non-empty topics in the log.
32    pub fn topics_non_empty(&self) -> Vec<LogTopic> {
33        self.topics().into_iter().flatten().collect()
34    }
35}
36
37// -----------------------------------------------------------------------------
38// Conversions: Other -> Self
39// ----------------------------------------------------------------------------
40impl From<RevmLog> for Log {
41    fn from(value: RevmLog) -> Self {
42        let (topics, data) = value.data.split();
43        let topics_len = topics.len();
44
45        let mut log = Self {
46            address: value.address.into(),
47            data: data.into(),
48            ..Default::default()
49        };
50
51        // you may not like it but this is what peak performance looks like
52        match topics_len {
53            4 => {
54                log.topic0 = Some(topics[0].into());
55                log.topic1 = Some(topics[1].into());
56                log.topic2 = Some(topics[2].into());
57                log.topic3 = Some(topics[3].into());
58            }
59            3 => {
60                log.topic0 = Some(topics[0].into());
61                log.topic1 = Some(topics[1].into());
62                log.topic2 = Some(topics[2].into());
63            }
64            2 => {
65                log.topic0 = Some(topics[0].into());
66                log.topic1 = Some(topics[1].into());
67            }
68            1 => {
69                log.topic0 = Some(topics[0].into());
70            }
71            _ => {}
72        }
73
74        log
75    }
76}
77
78impl From<AlloyLog> for Log {
79    fn from(value: AlloyLog) -> Self {
80        let topics = value.inner.topics().to_vec();
81        let topics_len = topics.len();
82
83        let mut log = Self {
84            address: value.inner.address.into(),
85            data: value.inner.data.data.into(),
86            ..Default::default()
87        };
88
89        // you may not like it but this is what peak performance looks like
90        match topics_len {
91            4 => {
92                log.topic0 = Some(topics[0].into());
93                log.topic1 = Some(topics[1].into());
94                log.topic2 = Some(topics[2].into());
95                log.topic3 = Some(topics[3].into());
96            }
97            3 => {
98                log.topic0 = Some(topics[0].into());
99                log.topic1 = Some(topics[1].into());
100                log.topic2 = Some(topics[2].into());
101            }
102            2 => {
103                log.topic0 = Some(topics[0].into());
104                log.topic1 = Some(topics[1].into());
105            }
106            1 => {
107                log.topic0 = Some(topics[0].into());
108            }
109            _ => {}
110        }
111
112        log
113    }
114}