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
104impl<H: Sealable> SealedHeader<&H> {
105 pub fn cloned(self) -> SealedHeader<H>
107 where
108 H: Clone,
109 {
110 let Self { hash, header } = self;
111 SealedHeader { hash, header: header.clone() }
112 }
113}
114
115impl<H: alloy_consensus::BlockHeader + Sealable> SealedHeader<H> {
116 pub fn num_hash(&self) -> BlockNumHash {
118 BlockNumHash::new(self.number(), self.hash())
119 }
120
121 pub fn block_with_parent(&self) -> BlockWithParent {
123 BlockWithParent { parent: self.parent_hash(), block: self.num_hash() }
124 }
125}
126
127impl<H: Sealable> Eq for SealedHeader<H> {}
128
129impl<H: Sealable> PartialEq for SealedHeader<H> {
130 fn eq(&self, other: &Self) -> bool {
131 self.hash() == other.hash()
132 }
133}
134
135impl<H: Sealable> core::hash::Hash for SealedHeader<H> {
136 fn hash<Ha: core::hash::Hasher>(&self, state: &mut Ha) {
137 self.hash().hash(state)
138 }
139}
140
141impl<H: InMemorySize> InMemorySize for SealedHeader<H> {
142 #[inline]
144 fn size(&self) -> usize {
145 self.header.size() + mem::size_of::<BlockHash>()
146 }
147}
148
149impl<H: Sealable + Default> Default for SealedHeader<H> {
150 fn default() -> Self {
151 Self::seal_slow(H::default())
152 }
153}
154
155impl Encodable for SealedHeader {
156 fn encode(&self, out: &mut dyn BufMut) {
157 self.header.encode(out);
158 }
159}
160
161impl Decodable for SealedHeader {
162 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
163 let b = &mut &**buf;
164 let started_len = buf.len();
165
166 let header = Header::decode(b)?;
168
169 let consumed = started_len - b.len();
171 let hash = keccak256(&buf[..consumed]);
172
173 *buf = *b;
175
176 Ok(Self::new(header, hash))
177 }
178}
179
180impl<H: Sealable> From<SealedHeader<H>> for Sealed<H> {
181 fn from(value: SealedHeader<H>) -> Self {
182 let (header, hash) = value.split();
183 Self::new_unchecked(header, hash)
184 }
185}
186
187#[cfg(any(test, feature = "arbitrary"))]
188impl<'a, H> arbitrary::Arbitrary<'a> for SealedHeader<H>
189where
190 H: for<'b> arbitrary::Arbitrary<'b> + Sealable,
191{
192 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
193 let header = H::arbitrary(u)?;
194
195 Ok(Self::seal_slow(header))
196 }
197}
198
199#[cfg(any(test, feature = "test-utils"))]
200impl<H: crate::test_utils::TestHeader> SealedHeader<H> {
201 pub fn set_header(&mut self, header: H) {
203 self.header = header
204 }
205
206 pub fn set_hash(&mut self, hash: BlockHash) {
208 self.hash = hash.into()
209 }
210
211 pub fn header_mut(&mut self) -> &mut H {
213 &mut self.header
214 }
215
216 pub fn set_parent_hash(&mut self, hash: BlockHash) {
218 self.header.set_parent_hash(hash);
219 }
220
221 pub fn set_block_number(&mut self, number: alloy_primitives::BlockNumber) {
223 self.header.set_block_number(number);
224 }
225
226 pub fn set_state_root(&mut self, state_root: alloy_primitives::B256) {
228 self.header.set_state_root(state_root);
229 }
230
231 pub fn set_difficulty(&mut self, difficulty: alloy_primitives::U256) {
233 self.header.set_difficulty(difficulty);
234 }
235}
236
237#[cfg(feature = "serde-bincode-compat")]
239pub(super) mod serde_bincode_compat {
240 use crate::serde_bincode_compat::SerdeBincodeCompat;
241 use alloy_primitives::{BlockHash, Sealable};
242 use serde::{Deserialize, Deserializer, Serialize, Serializer};
243 use serde_with::{DeserializeAs, SerializeAs};
244
245 #[derive(derive_more::Debug, Serialize, Deserialize)]
261 #[debug(bound(H::BincodeRepr<'a>: core::fmt::Debug))]
262 pub struct SealedHeader<'a, H: Sealable + SerdeBincodeCompat = super::Header> {
263 hash: BlockHash,
264 header: H::BincodeRepr<'a>,
265 }
266
267 impl<'a, H: Sealable + SerdeBincodeCompat> From<&'a super::SealedHeader<H>>
268 for SealedHeader<'a, H>
269 {
270 fn from(value: &'a super::SealedHeader<H>) -> Self {
271 Self { hash: value.hash(), header: value.header.as_repr() }
272 }
273 }
274
275 impl<'a, H: Sealable + SerdeBincodeCompat> From<SealedHeader<'a, H>> for super::SealedHeader<H> {
276 fn from(value: SealedHeader<'a, H>) -> Self {
277 Self::new(SerdeBincodeCompat::from_repr(value.header), value.hash)
278 }
279 }
280
281 impl SerializeAs<super::SealedHeader> for SealedHeader<'_> {
282 fn serialize_as<S>(source: &super::SealedHeader, serializer: S) -> Result<S::Ok, S::Error>
283 where
284 S: Serializer,
285 {
286 SealedHeader::from(source).serialize(serializer)
287 }
288 }
289
290 impl<'de> DeserializeAs<'de, super::SealedHeader> for SealedHeader<'de> {
291 fn deserialize_as<D>(deserializer: D) -> Result<super::SealedHeader, D::Error>
292 where
293 D: Deserializer<'de>,
294 {
295 SealedHeader::deserialize(deserializer).map(Into::into)
296 }
297 }
298
299 impl<H: Sealable + SerdeBincodeCompat> SerdeBincodeCompat for super::SealedHeader<H> {
300 type BincodeRepr<'a> = SealedHeader<'a, H>;
301 fn as_repr(&self) -> Self::BincodeRepr<'_> {
302 self.into()
303 }
304
305 fn from_repr(repr: Self::BincodeRepr<'_>) -> Self {
306 repr.into()
307 }
308 }
309
310 #[cfg(test)]
311 mod tests {
312 use super::super::{serde_bincode_compat, SealedHeader};
313 use arbitrary::Arbitrary;
314 use rand::Rng;
315 use serde::{Deserialize, Serialize};
316 use serde_with::serde_as;
317
318 #[test]
319 fn test_sealed_header_bincode_roundtrip() {
320 #[serde_as]
321 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
322 struct Data {
323 #[serde_as(as = "serde_bincode_compat::SealedHeader")]
324 transaction: SealedHeader,
325 }
326
327 let mut bytes = [0u8; 1024];
328 rand::thread_rng().fill(&mut bytes[..]);
329 let data = Data {
330 transaction: SealedHeader::arbitrary(&mut arbitrary::Unstructured::new(&bytes))
331 .unwrap(),
332 };
333
334 let encoded = bincode::serialize(&data).unwrap();
335 let decoded: Data = bincode::deserialize(&encoded).unwrap();
336 assert_eq!(decoded, data);
337 }
338 }
339}