stratus/eth/primitives/
log_message.rs

1use display_json::DebugAsJson;
2use jsonrpsee::SubscriptionMessage;
3
4use crate::alias::AlloyLog;
5use crate::alias::AlloyLogData;
6use crate::alias::AlloyLogPrimitive;
7use crate::alias::JsonValue;
8use crate::eth::primitives::BlockNumber;
9use crate::eth::primitives::Hash;
10use crate::eth::primitives::Index;
11use crate::eth::primitives::Log;
12use crate::ext::to_json_value;
13
14/// Log that was emitted by the EVM and added to a block.
15#[derive(DebugAsJson, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[cfg_attr(test, derive(fake::Dummy))]
17pub struct LogMessage {
18    /// Original log emitted by the EVM.
19    pub log: Log,
20
21    /// Hash of the transaction that emitted this log.
22    pub transaction_hash: Hash,
23
24    /// Position of the transaction that emitted this log inside the block.
25    pub transaction_index: Index,
26
27    /// Block number where the log was mined.
28    pub block_number: BlockNumber,
29
30    /// Block hash where the log was mined.
31    pub block_hash: Hash,
32
33    pub index: Index,
34}
35
36impl LogMessage {
37    /// Serializes itself to JSON-RPC log format.
38    pub fn to_json_rpc_log(self) -> JsonValue {
39        let alloy_log: AlloyLog = self.into();
40        to_json_value(alloy_log)
41    }
42
43    pub fn new(log: Log, block_number: BlockNumber, block_hash: Hash, transaction_hash: Hash, transaction_index: Index, log_index: Index) -> Self {
44        Self {
45            log,
46            transaction_hash,
47            transaction_index,
48            block_number,
49            block_hash,
50            index: log_index,
51        }
52    }
53}
54
55impl From<LogMessage> for AlloyLog {
56    fn from(value: LogMessage) -> Self {
57        Self {
58            inner: AlloyLogPrimitive {
59                address: value.log.address.into(),
60                // Using new_unchecked is safe because topics_non_empty() guarantees ≤ 4 topics
61                data: AlloyLogData::new_unchecked(value.log.topics_non_empty().into_iter().map(Into::into).collect(), value.log.data.into()),
62            },
63            block_hash: Some(value.block_hash.into()),
64            block_number: Some(value.block_number.as_u64()),
65            block_timestamp: None,
66            transaction_hash: Some(value.transaction_hash.into()),
67            transaction_index: Some(value.transaction_index.into()),
68            log_index: Some(value.index.into()),
69            removed: false,
70        }
71    }
72}
73
74impl TryFrom<LogMessage> for SubscriptionMessage {
75    type Error = serde_json::Error;
76
77    fn try_from(value: LogMessage) -> Result<Self, Self::Error> {
78        Ok(serde_json::value::RawValue::from_string(serde_json::to_string(&Into::<AlloyLog>::into(value))?)?.into())
79    }
80}