kona_genesis/updates/
eip1559.rs

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