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_state_root(&mut self, state_root: alloy_primitives::B256) {
233 self.header.set_state_root(state_root);
234 }
235
236 pub fn set_difficulty(&mut self, difficulty: alloy_primitives::U256) {
238 self.header.set_difficulty(difficulty);
239 }
240}
241
242#[cfg(feature = "rpc-compat")]
243mod rpc_compat {
244 use super::*;
245
246 impl<H> SealedHeader<H> {
247 pub fn into_rpc_header(self) -> alloy_rpc_types_eth::Header<H>
251 where
252 H: Sealable,
253 {
254 alloy_rpc_types_eth::Header::from_sealed(self.into())
255 }
256
257 pub fn from_rpc_header(header: alloy_rpc_types_eth::Header<H>) -> Self {
259 Self::new(header.inner, header.hash)
260 }
261 }
262
263 impl<H> From<alloy_rpc_types_eth::Header<H>> for SealedHeader<H> {
264 fn from(value: alloy_rpc_types_eth::Header<H>) -> Self {
265 Self::from_rpc_header(value)
266 }
267 }
268}
269
270#[cfg(feature = "serde-bincode-compat")]
272pub(super) mod serde_bincode_compat {
273 use crate::serde_bincode_compat::SerdeBincodeCompat;
274 use alloy_primitives::{BlockHash, Sealable};
275 use serde::{Deserialize, Deserializer, Serialize, Serializer};
276 use serde_with::{DeserializeAs, SerializeAs};
277
278 #[derive(derive_more::Debug, Serialize, Deserialize)]
294 #[debug(bound(H::BincodeRepr<'a>: core::fmt::Debug))]
295 pub struct SealedHeader<'a, H: Sealable + SerdeBincodeCompat = super::Header> {
296 hash: BlockHash,
297 header: H::BincodeRepr<'a>,
298 }
299
300 impl<'a, H: Sealable + SerdeBincodeCompat> From<&'a super::SealedHeader<H>>
301 for SealedHeader<'a, H>
302 {
303 fn from(value: &'a super::SealedHeader<H>) -> Self {
304 Self { hash: value.hash(), header: value.header.as_repr() }
305 }
306 }
307
308 impl<'a, H: Sealable + SerdeBincodeCompat> From<SealedHeader<'a, H>> for super::SealedHeader<H> {
309 fn from(value: SealedHeader<'a, H>) -> Self {
310 Self::new(SerdeBincodeCompat::from_repr(value.header), value.hash)
311 }
312 }
313
314 impl SerializeAs<super::SealedHeader> for SealedHeader<'_> {
315 fn serialize_as<S>(source: &super::SealedHeader, serializer: S) -> Result<S::Ok, S::Error>
316 where
317 S: Serializer,
318 {
319 SealedHeader::from(source).serialize(serializer)
320 }
321 }
322
323 impl<'de> DeserializeAs<'de, super::SealedHeader> for SealedHeader<'de> {
324 fn deserialize_as<D>(deserializer: D) -> Result<super::SealedHeader, D::Error>
325 where
326 D: Deserializer<'de>,
327 {
328 SealedHeader::deserialize(deserializer).map(Into::into)
329 }
330 }
331
332 impl<H: Sealable + SerdeBincodeCompat> SerdeBincodeCompat for super::SealedHeader<H> {
333 type BincodeRepr<'a> = SealedHeader<'a, H>;
334 fn as_repr(&self) -> Self::BincodeRepr<'_> {
335 self.into()
336 }
337
338 fn from_repr(repr: Self::BincodeRepr<'_>) -> Self {
339 repr.into()
340 }
341 }
342
343 #[cfg(test)]
344 mod tests {
345 use super::super::{serde_bincode_compat, SealedHeader};
346 use arbitrary::Arbitrary;
347 use rand::Rng;
348 use serde::{Deserialize, Serialize};
349 use serde_with::serde_as;
350
351 #[test]
352 fn test_sealed_header_bincode_roundtrip() {
353 #[serde_as]
354 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
355 struct Data {
356 #[serde_as(as = "serde_bincode_compat::SealedHeader")]
357 transaction: SealedHeader,
358 }
359
360 let mut bytes = [0u8; 1024];
361 rand::rng().fill(&mut bytes[..]);
362 let data = Data {
363 transaction: SealedHeader::arbitrary(&mut arbitrary::Unstructured::new(&bytes))
364 .unwrap(),
365 };
366
367 let encoded = bincode::serialize(&data).unwrap();
368 let decoded: Data = bincode::deserialize(&encoded).unwrap();
369 assert_eq!(decoded, data);
370 }
371 }
372}