tempo_primitives/reth_compat/
header.rs1use crate::{TempoConsensusContext, TempoHeader};
2use alloy_primitives::{B256, BlockNumber, Bytes, U256};
3
4impl reth_primitives_traits::InMemorySize for TempoConsensusContext {
5 fn size(&self) -> usize {
6 self.epoch.size() + self.view.size() + self.proposer.size() + self.parent_view.size()
7 }
8}
9
10impl reth_primitives_traits::InMemorySize for TempoHeader {
11 fn size(&self) -> usize {
12 let Self {
13 inner,
14 general_gas_limit,
15 timestamp_millis_part,
16 shared_gas_limit,
17 consensus_context,
18 } = self;
19 inner.size()
20 + general_gas_limit.size()
21 + timestamp_millis_part.size()
22 + shared_gas_limit.size()
23 + consensus_context.as_ref().map_or(0, |f| f.size())
24 }
25}
26
27impl reth_primitives_traits::BlockHeader for TempoHeader {}
28
29impl reth_primitives_traits::header::HeaderMut for TempoHeader {
30 fn set_parent_hash(&mut self, hash: B256) {
31 self.inner.set_parent_hash(hash);
32 }
33
34 fn set_block_number(&mut self, number: BlockNumber) {
35 self.inner.set_block_number(number);
36 }
37
38 fn set_timestamp(&mut self, timestamp: u64) {
39 self.inner.set_timestamp(timestamp);
40 }
41
42 fn set_state_root(&mut self, state_root: B256) {
43 self.inner.set_state_root(state_root);
44 }
45
46 fn set_difficulty(&mut self, difficulty: U256) {
47 self.inner.set_difficulty(difficulty);
48 }
49
50 fn set_mix_hash(&mut self, mix_hash: B256) {
51 self.inner.set_mix_hash(mix_hash);
52 }
53
54 fn set_extra_data(&mut self, extra_data: Bytes) {
55 self.inner.set_extra_data(extra_data);
56 }
57
58 fn set_parent_beacon_block_root(&mut self, parent_beacon_block_root: Option<B256>) {
59 self.inner
60 .set_parent_beacon_block_root(parent_beacon_block_root);
61 }
62}
63
64#[cfg(feature = "reth-codec")]
65mod codec {
66 use crate::{TempoConsensusContext, TempoHeader};
67 use alloy_consensus::Header;
68
69 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq, reth_codecs::Compact)]
73 #[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
74 #[cfg_attr(test, reth_codecs::add_arbitrary_tests(compact))]
75 struct TempoHeaderTrailingCompact {
76 consensus_context: Option<TempoConsensusContext>,
77 }
78
79 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq, reth_codecs::Compact)]
82 #[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
83 #[cfg_attr(test, reth_codecs::add_arbitrary_tests(compact))]
84 struct TempoHeaderCompact {
85 pub general_gas_limit: u64,
87 pub shared_gas_limit: u64,
89 pub timestamp_millis_part: u64,
91 pub trailing: Option<TempoHeaderTrailingCompact>,
93 pub inner: Header,
95 }
96
97 impl reth_codecs::Compact for TempoHeader {
98 fn to_compact<B>(&self, buf: &mut B) -> usize
99 where
100 B: alloy_rlp::bytes::BufMut + AsMut<[u8]>,
101 {
102 let trailing = self
103 .consensus_context
104 .map(|ctx| TempoHeaderTrailingCompact {
105 consensus_context: Some(ctx),
106 });
107
108 let header = TempoHeaderCompact {
109 general_gas_limit: self.general_gas_limit,
110 shared_gas_limit: self.shared_gas_limit,
111 timestamp_millis_part: self.timestamp_millis_part,
112 trailing,
113 inner: self.inner.clone(),
114 };
115
116 header.to_compact(buf)
117 }
118
119 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
120 let (header_compat, buf) = TempoHeaderCompact::from_compact(buf, len);
121 let header = Self {
122 general_gas_limit: header_compat.general_gas_limit,
123 shared_gas_limit: header_compat.shared_gas_limit,
124 timestamp_millis_part: header_compat.timestamp_millis_part,
125 consensus_context: header_compat.trailing.and_then(|f| f.consensus_context),
126 inner: header_compat.inner,
127 };
128
129 (header, buf)
130 }
131 }
132
133 impl reth_db_api::table::Compress for TempoHeader {
134 type Compressed = alloc::vec::Vec<u8>;
135
136 fn compress_to_buf<B: alloy_primitives::bytes::BufMut + AsMut<[u8]>>(&self, buf: &mut B) {
137 let _ = reth_codecs::Compact::to_compact(self, buf);
138 }
139 }
140
141 impl reth_db_api::table::Decompress for TempoHeader {
142 fn decompress(value: &[u8]) -> Result<Self, reth_codecs::DecompressError> {
143 let (obj, _) = reth_codecs::Compact::from_compact(value, value.len());
144 Ok(obj)
145 }
146 }
147
148 #[cfg(test)]
149 mod tests {
150 use super::*;
151 use alloy_primitives::{Address, B256, Bloom, U256, address, b256, bytes, hex};
152 use alloy_rlp::Decodable;
153 use reth_codecs::Compact;
154
155 #[test]
163 fn tempo_header_has_unused_compact_bits() {
164 assert_ne!(
165 TempoHeaderCompact::bitflag_unused_bits(),
166 0,
167 "TempoHeaderCompact bitflag has no unused bits left — use an extension type"
168 );
169 }
170
171 #[test]
172 fn tempo_header_trailing_has_unused_compact_bits() {
173 assert_ne!(
174 TempoHeaderTrailingCompact::bitflag_unused_bits(),
175 0,
176 "TempoHeaderTrailingCompact bitflag has no unused bits left — use another extension type"
177 );
178 }
179
180 #[test]
181 fn tempo_header_compact_roundtrip() {
182 let header = TempoHeader {
183 general_gas_limit: 30_000_000,
184 shared_gas_limit: 10_000_000,
185 timestamp_millis_part: 500,
186 consensus_context: None,
187 inner: Header {
188 parent_hash: b256!(
189 "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
190 ),
191 ommers_hash: b256!(
192 "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
193 ),
194 beneficiary: address!("0x000000000000000000000000000000000000beef"),
195 state_root: b256!(
196 "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
197 ),
198 transactions_root: b256!(
199 "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
200 ),
201 receipts_root: b256!(
202 "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
203 ),
204 logs_bloom: Bloom::with_last_byte(0xff),
205 difficulty: U256::from(1u64),
206 number: 1000,
207 gas_limit: 30_000_000,
208 gas_used: 15_000_000,
209 timestamp: 1_700_000_000,
210 extra_data: bytes!("deadbeef"),
211 mix_hash: b256!(
212 "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
213 ),
214 nonce: alloy_primitives::B64::from(42u64),
215 base_fee_per_gas: Some(7),
216 withdrawals_root: Some(b256!(
217 "0x1111111111111111111111111111111111111111111111111111111111111111"
218 )),
219 blob_gas_used: Some(131072),
220 excess_blob_gas: Some(65536),
221 parent_beacon_block_root: Some(b256!(
222 "0x2222222222222222222222222222222222222222222222222222222222222222"
223 )),
224 requests_hash: Some(b256!(
225 "0x3333333333333333333333333333333333333333333333333333333333333333"
226 )),
227 block_access_list_hash: None,
228 slot_number: None,
229 },
230 };
231
232 let expected = hex!(
233 "340201c9c38098968001f403a1a1f8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347000000000000000000000000000000000000beefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd1111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff0103e801c9c380e4e1c06553f100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee2a01070302000003010000222222222222222222222222222222222222222222222222222222222222222221013333333333333333333333333333333333333333333333333333333333333333deadbeef"
234 );
235
236 let mut buf = vec![];
237 let len = header.to_compact(&mut buf);
238 assert_eq!(
239 buf, expected,
240 "compact encoding changed — this breaks backwards compatibility"
241 );
242 assert_eq!(len, expected.len());
243
244 let (decoded, _) = TempoHeader::from_compact(&expected, expected.len());
245 assert_eq!(decoded, header);
246 }
247
248 fn presto_block_1() -> TempoHeader {
250 TempoHeader {
251 general_gas_limit: 0xd693a40,
252 shared_gas_limit: 0x2faf080,
253 timestamp_millis_part: 0x2c5,
254 consensus_context: None,
255 inner: Header {
256 parent_hash: b256!(
257 "49d7ec7085e77bf5a403d0fcb4cfc42a4084a89dfff60477579c5e09c9e03c54"
258 ),
259 ommers_hash: b256!(
260 "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
261 ),
262 state_root: b256!(
263 "83408974323f63ab969b23f0fe1dba30d7ee5dc5c524a975bae38187eaa2c7f6"
264 ),
265 transactions_root: b256!(
266 "6cbfac2d2b694b71b37538fe5bcc8450fc4bdab1c3c2119a450e333a724d1b44"
267 ),
268 receipts_root: b256!(
269 "b64408da6b8fe39ab764af88ece1e8cca1c35fd988db57806e99138c629365a0"
270 ),
271 withdrawals_root: Some(b256!(
272 "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
273 )),
274 parent_beacon_block_root: Some(B256::ZERO),
275 requests_hash: Some(b256!(
276 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
277 )),
278 number: 1,
279 gas_limit: 0x1dcd6500,
280 gas_used: 0,
281 timestamp: 0x696aa4c7,
282 base_fee_per_gas: Some(0x2540be400),
283 blob_gas_used: Some(0),
284 excess_blob_gas: Some(0),
285 beneficiary: Address::ZERO,
286 ..Default::default()
287 },
288 }
289 }
290
291 #[test]
292 fn presto_block_1_hash_backwards_compat() {
293 use alloy_consensus::Sealable;
294
295 let header = presto_block_1();
296 let hash = header.hash_slow();
297
298 let expected = "0x76e86f9739fbe17669b01b24e976ac214742c4b1bbc6ae0c083a87e43a5e9b0f";
300 assert_eq!(format!("{hash:#x}"), expected);
301 }
302
303 #[test]
304 fn presto_block_1_rlp_roundtrip() {
305 let header = presto_block_1();
306 let encoded = alloy_rlp::encode(&header);
307 let decoded = TempoHeader::decode(&mut encoded.as_slice()).unwrap();
308 assert_eq!(header, decoded);
309 }
310
311 #[derive(reth_codecs::Compact)]
312 struct TestPreT4TempoHeader {
313 pub general_gas_limit: u64,
314 pub shared_gas_limit: u64,
315 pub timestamp_millis_part: u64,
316 pub inner: Header,
317 }
318
319 #[test]
320 fn presto_block_1_compact_roundtrip() {
321 let header = presto_block_1();
322 let pre_t4_header = TestPreT4TempoHeader {
323 general_gas_limit: header.general_gas_limit,
324 shared_gas_limit: header.shared_gas_limit,
325 timestamp_millis_part: header.timestamp_millis_part,
326 inner: header.inner.clone(),
327 };
328
329 let mut header_buf = vec![];
330 let mut pre_t4_header_buf = vec![];
331
332 let header_len = header.to_compact(&mut header_buf);
333 let pre_t4_len = pre_t4_header.to_compact(&mut pre_t4_header_buf);
334
335 assert_eq!(header_len, pre_t4_len);
336 assert_eq!(header_buf, pre_t4_header_buf);
337
338 let (legacy_header, _) = TempoHeader::from_compact(&pre_t4_header_buf, pre_t4_len);
339 assert_eq!(legacy_header, header);
340 }
341 }
342}