reth_primitives_traits/header/
sealed.rs
1use 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 = "serde-bincode-compat")]
244pub(super) mod serde_bincode_compat {
245 use crate::serde_bincode_compat::SerdeBincodeCompat;
246 use alloy_primitives::{BlockHash, Sealable};
247 use serde::{Deserialize, Deserializer, Serialize, Serializer};
248 use serde_with::{DeserializeAs, SerializeAs};
249
250 #[derive(derive_more::Debug, Serialize, Deserialize)]
266 #[debug(bound(H::BincodeRepr<'a>: core::fmt::Debug))]
267 pub struct SealedHeader<'a, H: Sealable + SerdeBincodeCompat = super::Header> {
268 hash: BlockHash,
269 header: H::BincodeRepr<'a>,
270 }
271
272 impl<'a, H: Sealable + SerdeBincodeCompat> From<&'a super::SealedHeader<H>>
273 for SealedHeader<'a, H>
274 {
275 fn from(value: &'a super::SealedHeader<H>) -> Self {
276 Self { hash: value.hash(), header: value.header.as_repr() }
277 }
278 }
279
280 impl<'a, H: Sealable + SerdeBincodeCompat> From<SealedHeader<'a, H>> for super::SealedHeader<H> {
281 fn from(value: SealedHeader<'a, H>) -> Self {
282 Self::new(SerdeBincodeCompat::from_repr(value.header), value.hash)
283 }
284 }
285
286 impl SerializeAs<super::SealedHeader> for SealedHeader<'_> {
287 fn serialize_as<S>(source: &super::SealedHeader, serializer: S) -> Result<S::Ok, S::Error>
288 where
289 S: Serializer,
290 {
291 SealedHeader::from(source).serialize(serializer)
292 }
293 }
294
295 impl<'de> DeserializeAs<'de, super::SealedHeader> for SealedHeader<'de> {
296 fn deserialize_as<D>(deserializer: D) -> Result<super::SealedHeader, D::Error>
297 where
298 D: Deserializer<'de>,
299 {
300 SealedHeader::deserialize(deserializer).map(Into::into)
301 }
302 }
303
304 impl<H: Sealable + SerdeBincodeCompat> SerdeBincodeCompat for super::SealedHeader<H> {
305 type BincodeRepr<'a> = SealedHeader<'a, H>;
306 fn as_repr(&self) -> Self::BincodeRepr<'_> {
307 self.into()
308 }
309
310 fn from_repr(repr: Self::BincodeRepr<'_>) -> Self {
311 repr.into()
312 }
313 }
314
315 #[cfg(test)]
316 mod tests {
317 use super::super::{serde_bincode_compat, SealedHeader};
318 use arbitrary::Arbitrary;
319 use rand::Rng;
320 use serde::{Deserialize, Serialize};
321 use serde_with::serde_as;
322
323 #[test]
324 fn test_sealed_header_bincode_roundtrip() {
325 #[serde_as]
326 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
327 struct Data {
328 #[serde_as(as = "serde_bincode_compat::SealedHeader")]
329 transaction: SealedHeader,
330 }
331
332 let mut bytes = [0u8; 1024];
333 rand::rng().fill(&mut bytes[..]);
334 let data = Data {
335 transaction: SealedHeader::arbitrary(&mut arbitrary::Unstructured::new(&bytes))
336 .unwrap(),
337 };
338
339 let encoded = bincode::serialize(&data).unwrap();
340 let decoded: Data = bincode::deserialize(&encoded).unwrap();
341 assert_eq!(decoded, data);
342 }
343 }
344}