reth_primitives_traits/header/
sealed.rs1use crate::{sync::OnceLock, InMemorySize, NodePrimitives};
2pub use alloy_consensus::Header;
3use alloy_consensus::Sealed;
4use alloy_eips::{eip1898::BlockWithParent, BlockNumHash};
5use alloy_primitives::{keccak256, BlockHash, Sealable};
6use alloy_rlp::{Decodable, Encodable};
7use bytes::BufMut;
8use core::mem;
9use derive_more::{AsRef, Deref};
10
11pub type SealedHeaderFor<N> = SealedHeader<<N as NodePrimitives>::BlockHeader>;
13
14#[derive(Debug, Clone, AsRef, Deref)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp))]
24pub struct SealedHeader<H = Header> {
25 #[cfg_attr(feature = "serde", serde(skip))]
27 hash: OnceLock<BlockHash>,
28 #[as_ref]
30 #[deref]
31 header: H,
32}
33
34impl<H> SealedHeader<H> {
35 #[inline]
37 pub fn new_unhashed(header: H) -> Self {
38 Self { header, hash: Default::default() }
39 }
40
41 #[inline]
43 pub fn new(header: H, hash: BlockHash) -> Self {
44 Self { header, hash: hash.into() }
45 }
46
47 #[inline]
49 pub const fn header(&self) -> &H {
50 &self.header
51 }
52
53 pub fn clone_header(&self) -> H
55 where
56 H: Clone,
57 {
58 self.header.clone()
59 }
60
61 pub fn into_header(self) -> H {
63 self.header
64 }
65
66 pub fn unseal(self) -> H {
68 self.header
69 }
70
71 pub fn sealed_ref(&self) -> SealedHeader<&H> {
73 SealedHeader { hash: self.hash.clone(), header: &self.header }
74 }
75}
76
77impl<H: Sealable> SealedHeader<H> {
78 pub fn seal_slow(header: H) -> Self {
80 let hash = header.hash_slow();
81 Self::new(header, hash)
82 }
83
84 pub fn hash_ref(&self) -> &BlockHash {
89 self.hash.get_or_init(|| self.header.hash_slow())
90 }
91
92 pub fn hash(&self) -> BlockHash {
94 *self.hash_ref()
95 }
96
97 pub fn split(self) -> (H, BlockHash) {
99 let hash = self.hash();
100 (self.header, hash)
101 }
102
103 pub fn split_ref(&self) -> (&H, &BlockHash) {
105 (self.header(), self.hash_ref())
106 }
107}
108
109impl<H: Sealable> SealedHeader<&H> {
110 pub fn cloned(self) -> SealedHeader<H>
112 where
113 H: Clone,
114 {
115 let Self { hash, header } = self;
116 SealedHeader { hash, header: header.clone() }
117 }
118}
119
120impl<H: alloy_consensus::BlockHeader + Sealable> SealedHeader<H> {
121 pub fn num_hash(&self) -> BlockNumHash {
123 BlockNumHash::new(self.number(), self.hash())
124 }
125
126 pub fn block_with_parent(&self) -> BlockWithParent {
128 BlockWithParent { parent: self.parent_hash(), block: self.num_hash() }
129 }
130}
131
132impl<H: Sealable> Eq for SealedHeader<H> {}
133
134impl<H: Sealable> PartialEq for SealedHeader<H> {
135 fn eq(&self, other: &Self) -> bool {
136 self.hash() == other.hash()
137 }
138}
139
140impl<H: Sealable> core::hash::Hash for SealedHeader<H> {
141 fn hash<Ha: core::hash::Hasher>(&self, state: &mut Ha) {
142 self.hash().hash(state)
143 }
144}
145
146impl<H: InMemorySize> InMemorySize for SealedHeader<H> {
147 #[inline]
149 fn size(&self) -> usize {
150 self.header.size() + mem::size_of::<BlockHash>()
151 }
152}
153
154impl<H: Sealable + Default> Default for SealedHeader<H> {
155 fn default() -> Self {
156 Self::seal_slow(H::default())
157 }
158}
159
160impl Encodable for SealedHeader {
161 fn encode(&self, out: &mut dyn BufMut) {
162 self.header.encode(out);
163 }
164}
165
166impl Decodable for SealedHeader {
167 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
168 let b = &mut &**buf;
169 let started_len = buf.len();
170
171 let header = Header::decode(b)?;
173
174 let consumed = started_len - b.len();
176 let hash = keccak256(&buf[..consumed]);
177
178 *buf = *b;
180
181 Ok(Self::new(header, hash))
182 }
183}
184
185impl<H: Sealable> From<SealedHeader<H>> for Sealed<H> {
186 fn from(value: SealedHeader<H>) -> Self {
187 let (header, hash) = value.split();
188 Self::new_unchecked(header, hash)
189 }
190}
191
192#[cfg(any(test, feature = "arbitrary"))]
193impl<'a, H> arbitrary::Arbitrary<'a> for SealedHeader<H>
194where
195 H: for<'b> arbitrary::Arbitrary<'b> + Sealable,
196{
197 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
198 let header = H::arbitrary(u)?;
199
200 Ok(Self::seal_slow(header))
201 }
202}
203
204#[cfg(any(test, feature = "test-utils"))]
205impl<H: crate::test_utils::TestHeader> SealedHeader<H> {
206 pub fn set_header(&mut self, header: H) {
208 self.header = header
209 }
210
211 pub fn set_hash(&mut self, hash: BlockHash) {
213 self.hash = hash.into()
214 }
215
216 pub const fn header_mut(&mut self) -> &mut H {
218 &mut self.header
219 }
220
221 pub fn set_parent_hash(&mut self, hash: BlockHash) {
223 self.header.set_parent_hash(hash);
224 }
225
226 pub fn set_block_number(&mut self, number: alloy_primitives::BlockNumber) {
228 self.header.set_block_number(number);
229 }
230
231 pub fn set_timestamp(&mut self, timestamp: u64) {
233 self.header.set_timestamp(timestamp);
234 }
235
236 pub fn set_state_root(&mut self, state_root: alloy_primitives::B256) {
238 self.header.set_state_root(state_root);
239 }
240
241 pub fn set_difficulty(&mut self, difficulty: alloy_primitives::U256) {
243 self.header.set_difficulty(difficulty);
244 }
245}
246
247#[cfg(feature = "rpc-compat")]
248mod rpc_compat {
249 use super::*;
250
251 impl<H> SealedHeader<H> {
252 pub fn into_rpc_header(self) -> alloy_rpc_types_eth::Header<H>
256 where
257 H: Sealable,
258 {
259 alloy_rpc_types_eth::Header::from_sealed(self.into())
260 }
261
262 pub fn from_rpc_header(header: alloy_rpc_types_eth::Header<H>) -> Self {
264 Self::new(header.inner, header.hash)
265 }
266 }
267
268 impl<H> From<alloy_rpc_types_eth::Header<H>> for SealedHeader<H> {
269 fn from(value: alloy_rpc_types_eth::Header<H>) -> Self {
270 Self::from_rpc_header(value)
271 }
272 }
273}
274
275#[cfg(feature = "serde-bincode-compat")]
277pub(super) mod serde_bincode_compat {
278 use crate::serde_bincode_compat::SerdeBincodeCompat;
279 use alloy_primitives::{BlockHash, Sealable};
280 use serde::{Deserialize, Deserializer, Serialize, Serializer};
281 use serde_with::{DeserializeAs, SerializeAs};
282
283 #[derive(derive_more::Debug, Serialize, Deserialize)]
299 #[debug(bound(H::BincodeRepr<'a>: core::fmt::Debug))]
300 pub struct SealedHeader<'a, H: Sealable + SerdeBincodeCompat = super::Header> {
301 hash: BlockHash,
302 header: H::BincodeRepr<'a>,
303 }
304
305 impl<'a, H: Sealable + SerdeBincodeCompat> From<&'a super::SealedHeader<H>>
306 for SealedHeader<'a, H>
307 {
308 fn from(value: &'a super::SealedHeader<H>) -> Self {
309 Self { hash: value.hash(), header: value.header.as_repr() }
310 }
311 }
312
313 impl<'a, H: Sealable + SerdeBincodeCompat> From<SealedHeader<'a, H>> for super::SealedHeader<H> {
314 fn from(value: SealedHeader<'a, H>) -> Self {
315 Self::new(SerdeBincodeCompat::from_repr(value.header), value.hash)
316 }
317 }
318
319 impl SerializeAs<super::SealedHeader> for SealedHeader<'_> {
320 fn serialize_as<S>(source: &super::SealedHeader, serializer: S) -> Result<S::Ok, S::Error>
321 where
322 S: Serializer,
323 {
324 SealedHeader::from(source).serialize(serializer)
325 }
326 }
327
328 impl<'de> DeserializeAs<'de, super::SealedHeader> for SealedHeader<'de> {
329 fn deserialize_as<D>(deserializer: D) -> Result<super::SealedHeader, D::Error>
330 where
331 D: Deserializer<'de>,
332 {
333 SealedHeader::deserialize(deserializer).map(Into::into)
334 }
335 }
336
337 impl<H: Sealable + SerdeBincodeCompat> SerdeBincodeCompat for super::SealedHeader<H> {
338 type BincodeRepr<'a> = SealedHeader<'a, H>;
339 fn as_repr(&self) -> Self::BincodeRepr<'_> {
340 self.into()
341 }
342
343 fn from_repr(repr: Self::BincodeRepr<'_>) -> Self {
344 repr.into()
345 }
346 }
347
348 #[cfg(test)]
349 mod tests {
350 use super::super::{serde_bincode_compat, SealedHeader};
351 use arbitrary::Arbitrary;
352 use rand::Rng;
353 use serde::{Deserialize, Serialize};
354 use serde_with::serde_as;
355
356 #[test]
357 fn test_sealed_header_bincode_roundtrip() {
358 #[serde_as]
359 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
360 struct Data {
361 #[serde_as(as = "serde_bincode_compat::SealedHeader")]
362 transaction: SealedHeader,
363 }
364
365 let mut bytes = [0u8; 1024];
366 rand::rng().fill(&mut bytes[..]);
367 let data = Data {
368 transaction: SealedHeader::arbitrary(&mut arbitrary::Unstructured::new(&bytes))
369 .unwrap(),
370 };
371
372 let encoded = bincode::serialize(&data).unwrap();
373 let decoded: Data = bincode::deserialize(&encoded).unwrap();
374 assert_eq!(decoded, data);
375 }
376 }
377}