reth_primitives_traits/header/
sealed.rs1use crate::InMemorySize;
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
11#[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp))]
16pub struct SealedHeader<H = Header> {
17 hash: BlockHash,
19 #[as_ref]
21 #[deref]
22 header: H,
23}
24
25impl<H> SealedHeader<H> {
26 #[inline]
28 pub const fn new(header: H, hash: BlockHash) -> Self {
29 Self { header, hash }
30 }
31
32 #[inline]
34 pub const fn header(&self) -> &H {
35 &self.header
36 }
37
38 #[inline]
40 pub const fn hash(&self) -> BlockHash {
41 self.hash
42 }
43
44 pub fn unseal(self) -> H {
46 self.header
47 }
48
49 pub fn split(self) -> (H, BlockHash) {
51 (self.header, self.hash)
52 }
53}
54
55impl<H: Sealable> SealedHeader<H> {
56 pub fn seal(header: H) -> Self {
58 let hash = header.hash_slow();
59 Self::new(header, hash)
60 }
61}
62
63impl<H: alloy_consensus::BlockHeader> SealedHeader<H> {
64 pub fn num_hash(&self) -> BlockNumHash {
66 BlockNumHash::new(self.number(), self.hash)
67 }
68
69 pub fn block_with_parent(&self) -> BlockWithParent {
71 BlockWithParent { parent: self.parent_hash(), block: self.num_hash() }
72 }
73}
74
75impl<H: InMemorySize> InMemorySize for SealedHeader<H> {
76 #[inline]
78 fn size(&self) -> usize {
79 self.header.size() + mem::size_of::<BlockHash>()
80 }
81}
82
83impl<H: Sealable + Default> Default for SealedHeader<H> {
84 fn default() -> Self {
85 Self::seal(H::default())
86 }
87}
88
89impl Encodable for SealedHeader {
90 fn encode(&self, out: &mut dyn BufMut) {
91 self.header.encode(out);
92 }
93}
94
95impl Decodable for SealedHeader {
96 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
97 let b = &mut &**buf;
98 let started_len = buf.len();
99
100 let header = Header::decode(b)?;
102
103 let consumed = started_len - b.len();
105 let hash = keccak256(&buf[..consumed]);
106
107 *buf = *b;
109
110 Ok(Self { header, hash })
111 }
112}
113
114#[cfg(any(test, feature = "test-utils"))]
115impl SealedHeader {
116 pub fn set_header(&mut self, header: Header) {
118 self.header = header
119 }
120
121 pub fn set_hash(&mut self, hash: BlockHash) {
123 self.hash = hash
124 }
125
126 pub fn set_parent_hash(&mut self, hash: BlockHash) {
128 self.header.parent_hash = hash
129 }
130
131 pub fn set_block_number(&mut self, number: alloy_primitives::BlockNumber) {
133 self.header.number = number;
134 }
135
136 pub fn set_state_root(&mut self, state_root: alloy_primitives::B256) {
138 self.header.state_root = state_root;
139 }
140
141 pub fn set_difficulty(&mut self, difficulty: alloy_primitives::U256) {
143 self.header.difficulty = difficulty;
144 }
145}
146
147impl<H> From<SealedHeader<H>> for Sealed<H> {
148 fn from(value: SealedHeader<H>) -> Self {
149 Self::new_unchecked(value.header, value.hash)
150 }
151}
152
153#[cfg(any(test, feature = "arbitrary"))]
154impl<'a, H> arbitrary::Arbitrary<'a> for SealedHeader<H>
155where
156 H: for<'b> arbitrary::Arbitrary<'b> + Sealable,
157{
158 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
159 let header = H::arbitrary(u)?;
160
161 Ok(Self::seal(header))
162 }
163}
164
165#[cfg(feature = "serde-bincode-compat")]
167pub(super) mod serde_bincode_compat {
168 use alloy_primitives::BlockHash;
169 use serde::{Deserialize, Deserializer, Serialize, Serializer};
170 use serde_with::{DeserializeAs, SerializeAs};
171
172 use crate::serde_bincode_compat::SerdeBincodeCompat;
173
174 #[derive(derive_more::Debug, Serialize, Deserialize)]
190 #[debug(bound(H::BincodeRepr<'a>: core::fmt::Debug))]
191 pub struct SealedHeader<'a, H: SerdeBincodeCompat = super::Header> {
192 hash: BlockHash,
193 header: H::BincodeRepr<'a>,
194 }
195
196 impl<'a, H: SerdeBincodeCompat> From<&'a super::SealedHeader<H>> for SealedHeader<'a, H> {
197 fn from(value: &'a super::SealedHeader<H>) -> Self {
198 Self { hash: value.hash, header: (&value.header).into() }
199 }
200 }
201
202 impl<'a, H: SerdeBincodeCompat> From<SealedHeader<'a, H>> for super::SealedHeader<H> {
203 fn from(value: SealedHeader<'a, H>) -> Self {
204 Self { hash: value.hash, header: value.header.into() }
205 }
206 }
207
208 impl SerializeAs<super::SealedHeader> for SealedHeader<'_> {
209 fn serialize_as<S>(source: &super::SealedHeader, serializer: S) -> Result<S::Ok, S::Error>
210 where
211 S: Serializer,
212 {
213 SealedHeader::from(source).serialize(serializer)
214 }
215 }
216
217 impl<'de> DeserializeAs<'de, super::SealedHeader> for SealedHeader<'de> {
218 fn deserialize_as<D>(deserializer: D) -> Result<super::SealedHeader, D::Error>
219 where
220 D: Deserializer<'de>,
221 {
222 SealedHeader::deserialize(deserializer).map(Into::into)
223 }
224 }
225
226 impl<H: SerdeBincodeCompat> SerdeBincodeCompat for super::SealedHeader<H> {
227 type BincodeRepr<'a> = SealedHeader<'a, H>;
228 }
229 #[cfg(test)]
230 mod tests {
231 use super::super::{serde_bincode_compat, SealedHeader};
232 use arbitrary::Arbitrary;
233 use rand::Rng;
234 use serde::{Deserialize, Serialize};
235 use serde_with::serde_as;
236
237 #[test]
238 fn test_sealed_header_bincode_roundtrip() {
239 #[serde_as]
240 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
241 struct Data {
242 #[serde_as(as = "serde_bincode_compat::SealedHeader")]
243 transaction: SealedHeader,
244 }
245
246 let mut bytes = [0u8; 1024];
247 rand::thread_rng().fill(&mut bytes[..]);
248 let data = Data {
249 transaction: SealedHeader::arbitrary(&mut arbitrary::Unstructured::new(&bytes))
250 .unwrap(),
251 };
252
253 let encoded = bincode::serialize(&data).unwrap();
254 let decoded: Data = bincode::deserialize(&encoded).unwrap();
255 assert_eq!(decoded, data);
256 }
257 }
258}