kona_genesis/updates/
batcher.rs

1//! The batcher update type.
2
3use alloy_primitives::{Address, LogData};
4use alloy_sol_types::{SolType, sol};
5
6use crate::{BatcherUpdateError, SystemConfig, SystemConfigLog};
7
8/// The batcher update type.
9#[derive(Debug, Clone, Hash, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct BatcherUpdate {
12    /// The batcher address.
13    pub batcher_address: Address,
14}
15
16impl BatcherUpdate {
17    /// Applies the update to the [`SystemConfig`].
18    pub const fn apply(&self, config: &mut SystemConfig) {
19        config.batcher_address = self.batcher_address;
20    }
21}
22
23impl TryFrom<&SystemConfigLog> for BatcherUpdate {
24    type Error = BatcherUpdateError;
25
26    fn try_from(log: &SystemConfigLog) -> Result<Self, Self::Error> {
27        let LogData { data, .. } = &log.log.data;
28        if data.len() != 96 {
29            return Err(BatcherUpdateError::InvalidDataLen(data.len()));
30        }
31
32        let Ok(pointer) = <sol!(uint64)>::abi_decode_validate(&data[0..32]) else {
33            return Err(BatcherUpdateError::PointerDecodingError);
34        };
35        if pointer != 32 {
36            return Err(BatcherUpdateError::InvalidDataPointer(pointer));
37        }
38
39        let Ok(length) = <sol!(uint64)>::abi_decode_validate(&data[32..64]) else {
40            return Err(BatcherUpdateError::LengthDecodingError);
41        };
42        if length != 32 {
43            return Err(BatcherUpdateError::InvalidDataLength(length));
44        }
45
46        let Ok(batcher_address) = <sol!(address)>::abi_decode_validate(&data[64..96]) else {
47            return Err(BatcherUpdateError::BatcherAddressDecodingError);
48        };
49
50        Ok(Self { batcher_address })
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57    use crate::{CONFIG_UPDATE_EVENT_VERSION_0, CONFIG_UPDATE_TOPIC};
58    use alloc::vec;
59    use alloy_primitives::{B256, Bytes, Log, LogData, address, hex};
60
61    #[test]
62    fn test_batcher_update_try_from() {
63        let update_type = B256::ZERO;
64
65        let log = Log {
66            address: Address::ZERO,
67            data: LogData::new_unchecked(
68                vec![
69                    CONFIG_UPDATE_TOPIC,
70                    CONFIG_UPDATE_EVENT_VERSION_0,
71                    update_type,
72                ],
73                hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000beef").into()
74            )
75        };
76
77        let system_log = SystemConfigLog::new(log, false);
78        let update = BatcherUpdate::try_from(&system_log).unwrap();
79        assert_eq!(update.batcher_address, address!("000000000000000000000000000000000000bEEF"),);
80    }
81
82    #[test]
83    fn test_batcher_update_invalid_data_len() {
84        let log =
85            Log { address: Address::ZERO, data: LogData::new_unchecked(vec![], Bytes::default()) };
86        let system_log = SystemConfigLog::new(log, false);
87        let err = BatcherUpdate::try_from(&system_log).unwrap_err();
88        assert_eq!(err, BatcherUpdateError::InvalidDataLen(0));
89    }
90
91    #[test]
92    fn test_batcher_update_pointer_decoding_error() {
93        let log = Log {
94            address: Address::ZERO,
95            data: LogData::new_unchecked(
96                vec![
97                    CONFIG_UPDATE_TOPIC,
98                    CONFIG_UPDATE_EVENT_VERSION_0,
99                    B256::ZERO,
100                ],
101                hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000babe0000beef").into()
102            )
103        };
104
105        let system_log = SystemConfigLog::new(log, false);
106        let err = BatcherUpdate::try_from(&system_log).unwrap_err();
107        assert_eq!(err, BatcherUpdateError::PointerDecodingError);
108    }
109
110    #[test]
111    fn test_batcher_update_invalid_pointer_length() {
112        let log = Log {
113            address: Address::ZERO,
114            data: LogData::new_unchecked(
115                vec![
116                    CONFIG_UPDATE_TOPIC,
117                    CONFIG_UPDATE_EVENT_VERSION_0,
118                    B256::ZERO,
119                ],
120                hex!("000000000000000000000000000000000000000000000000000000000000002100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000babe0000beef").into()
121            )
122        };
123
124        let system_log = SystemConfigLog::new(log, false);
125        let err = BatcherUpdate::try_from(&system_log).unwrap_err();
126        assert_eq!(err, BatcherUpdateError::InvalidDataPointer(33));
127    }
128
129    #[test]
130    fn test_batcher_update_length_decoding_error() {
131        let log = Log {
132            address: Address::ZERO,
133            data: LogData::new_unchecked(
134                vec![
135                    CONFIG_UPDATE_TOPIC,
136                    CONFIG_UPDATE_EVENT_VERSION_0,
137                    B256::ZERO,
138                ],
139                hex!("0000000000000000000000000000000000000000000000000000000000000020FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000babe0000beef").into()
140            )
141        };
142
143        let system_log = SystemConfigLog::new(log, false);
144        let err = BatcherUpdate::try_from(&system_log).unwrap_err();
145        assert_eq!(err, BatcherUpdateError::LengthDecodingError);
146    }
147
148    #[test]
149    fn test_batcher_update_invalid_data_length() {
150        let log = Log {
151            address: Address::ZERO,
152            data: LogData::new_unchecked(
153                vec![
154                    CONFIG_UPDATE_TOPIC,
155                    CONFIG_UPDATE_EVENT_VERSION_0,
156                    B256::ZERO,
157                ],
158                hex!("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000babe0000beef").into()
159            )
160        };
161
162        let system_log = SystemConfigLog::new(log, false);
163        let err = BatcherUpdate::try_from(&system_log).unwrap_err();
164        assert_eq!(err, BatcherUpdateError::InvalidDataLength(33));
165    }
166
167    #[test]
168    fn test_batcher_update_batcher_decoding_error() {
169        let log = Log {
170            address: Address::ZERO,
171            data: LogData::new_unchecked(
172                vec![
173                    CONFIG_UPDATE_TOPIC,
174                    CONFIG_UPDATE_EVENT_VERSION_0,
175                    B256::ZERO,
176                ],
177                hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").into()
178            )
179        };
180
181        let system_log = SystemConfigLog::new(log, false);
182        let err = BatcherUpdate::try_from(&system_log).unwrap_err();
183        assert_eq!(err, BatcherUpdateError::BatcherAddressDecodingError);
184    }
185}