alloy_primitives/log/
serde.rs

1//! This is an implementation of serde for Log for
2//! both human-readable and binary forms.
3//!
4//! Ethereum JSON RPC requires logs in a flattened form.
5//! However `serde(flatten)` breaks binary implementations.
6//!
7//! This module uses a trick to select a proxy for serde:
8//! 1. LogFlattenSerializer for a human-readable (JSON) serializer,
9//! 2. LogFlattenDeserializer for a human-readable (JSON) deserializer,
10//! 3. LogUnflattenSerializer for a binary serializer,
11//! 4. LogUnflattenDeserializer for a binary deserializer.
12
13use crate::{Address, Log};
14use serde::{Deserialize, Deserializer, Serialize, Serializer};
15
16#[derive(Serialize)]
17#[serde(rename = "Log")]
18struct LogFlattenSerializer<'a, T> {
19    address: &'a Address,
20    #[serde(flatten)]
21    data: &'a T,
22}
23
24#[derive(Deserialize)]
25#[serde(rename = "Log")]
26struct LogFlattenDeserializer<T> {
27    address: Address,
28    #[serde(flatten)]
29    data: T,
30}
31
32#[derive(Serialize)]
33#[serde(rename = "Log")]
34struct LogUnflattenSerializer<'a, T> {
35    address: &'a Address,
36    data: &'a T,
37}
38
39#[derive(Deserialize)]
40#[serde(rename = "Log")]
41struct LogUnflattenDeserializer<T> {
42    address: Address,
43    data: T,
44}
45
46impl<T: Serialize> Serialize for Log<T> {
47    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
48    where
49        S: Serializer,
50    {
51        let Self { address, data } = self;
52        if serializer.is_human_readable() {
53            let replace = LogFlattenSerializer { address, data };
54            replace.serialize(serializer)
55        } else {
56            let replace = LogUnflattenSerializer { address, data };
57            replace.serialize(serializer)
58        }
59    }
60}
61
62impl<'de, T: Deserialize<'de>> Deserialize<'de> for Log<T> {
63    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
64    where
65        D: Deserializer<'de>,
66    {
67        if deserializer.is_human_readable() {
68            let LogFlattenDeserializer { address, data } = <_>::deserialize(deserializer)?;
69            Ok(Self { address, data })
70        } else {
71            let LogUnflattenDeserializer { address, data } = <_>::deserialize(deserializer)?;
72            Ok(Self { address, data })
73        }
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use crate::{
80        log::{Log, LogData},
81        Bytes,
82    };
83    use alloc::vec::Vec;
84
85    #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
86    struct TestStruct {
87        logs: Vec<Log>,
88    }
89
90    fn gen_test_struct() -> TestStruct {
91        // assume it's random:
92        TestStruct {
93            logs: vec![Log {
94                address: address!("0x3100000000000000000000000000000000000001"),
95                data: LogData::new(
96                    vec![b256!("0x32eff959e2e8d1609edc4b39ccf75900aa6c1da5719f8432752963fdf008234f")],
97                    Bytes::from_static(b"00000000000000000000000000000000000000000000000000000000000000021e9dbc1a11f8e046a72d1296cc2d8bb0d1544d56fd0b9bb8890a0f89b88036541e9dbc1a11f8e046a72d1296cc2d8bb0d1544d56fd0b9bb8890a0f89b8803654"),
98                ).unwrap(),
99            }],
100        }
101    }
102
103    #[test]
104    fn test_log_bincode_roundtrip() {
105        let generated = gen_test_struct();
106
107        let bytes = bincode::serialize(&generated).unwrap();
108        let parsed: TestStruct = bincode::deserialize(&bytes).unwrap();
109        assert_eq!(generated, parsed);
110    }
111
112    #[test]
113    fn test_log_bcs_roundtrip() {
114        let generated = gen_test_struct();
115
116        let bytes = bcs::to_bytes(&generated).unwrap();
117        let parsed: TestStruct = bcs::from_bytes(&bytes).unwrap();
118        assert_eq!(generated, parsed);
119    }
120
121    #[test]
122    fn test_log_json_roundtrip() {
123        let expected = "{\"logs\":[{\"address\":\"0x3100000000000000000000000000000000000001\",\"topics\":[\"0x32eff959e2e8d1609edc4b39ccf75900aa6c1da5719f8432752963fdf008234f\"],\"data\":\"0x303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030323165396462633161313166386530343661373264313239366363326438626230643135343464353666643062396262383839306130663839623838303336353431653964626331613131663865303436613732643132393663633264386262306431353434643536666430623962623838393061306638396238383033363534\"}]}";
124
125        let parsed: TestStruct = serde_json::from_str(expected).unwrap();
126        let dumped = serde_json::to_string(&parsed).unwrap();
127
128        assert_eq!(expected, dumped);
129    }
130}