1#[cfg(feature = "alloc")]
4pub mod owned;
5
6#[cfg(feature = "alloc")]
7use crate::block::header::owned::{
8 GenericOwnedBlockHeader, OwnedBeaconChainHeader, OwnedBlockHeader,
9 OwnedIntermediateShardHeader, OwnedLeafShardHeader,
10};
11use crate::block::{BlockNumber, BlockRoot, BlockTimestamp};
12use crate::ed25519::{Ed25519PublicKey, Ed25519Signature};
13use crate::hashes::Blake3Hash;
14use crate::pot::{PotOutput, PotParametersChange, SlotNumber};
15use crate::segments::SuperSegmentRoot;
16use crate::shard::{NumShards, NumShardsUnchecked, RealShardKind, ShardIndex, ShardKind};
17use crate::solutions::{Solution, SolutionRange};
18use ab_blake3::{BLOCK_LEN, single_block_hash, single_chunk_hash};
19use ab_io_type::trivial_type::TrivialType;
20use ab_merkle_tree::unbalanced::UnbalancedMerkleTree;
21use blake3::CHUNK_LEN;
22use core::num::NonZeroU32;
23use core::ops::Deref;
24use core::{fmt, slice};
25use derive_more::{Deref, From};
26#[cfg(feature = "scale-codec")]
27use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
28#[cfg(feature = "serde")]
29use serde::{Deserialize, Serialize};
30use yoke::Yokeable;
31
32pub trait GenericBlockHeader<'a>
34where
35 Self: Clone
36 + fmt::Debug
37 + Deref<Target = SharedBlockHeader<'a>>
38 + Into<BlockHeader<'a>>
39 + Send
40 + Sync,
41{
42 const SHARD_KIND: RealShardKind;
44
45 #[cfg(feature = "alloc")]
47 type Owned: GenericOwnedBlockHeader<Header<'a> = Self>
48 where
49 Self: 'a;
50
51 #[cfg(feature = "alloc")]
53 fn to_owned(self) -> Self::Owned;
54
55 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync;
62
63 fn pre_seal_hash(&self) -> Blake3Hash;
65}
66
67#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
71#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
72#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
73#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
74#[repr(C)]
75pub struct BlockHeaderPrefix {
76 pub number: BlockNumber,
78 pub shard_index: ShardIndex,
80 pub padding_0: [u8; 4],
82 pub timestamp: BlockTimestamp,
84 pub parent_root: BlockRoot,
86 pub mmr_root: Blake3Hash,
89}
90
91impl BlockHeaderPrefix {
92 pub fn hash(&self) -> Blake3Hash {
94 const {
95 assert!(size_of::<Self>() <= CHUNK_LEN);
96 }
97 Blake3Hash::new(
99 single_chunk_hash(self.as_bytes())
100 .expect("Less than a single chunk worth of bytes; qed"),
101 )
102 }
103}
104
105#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
107#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
108#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
109#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
110#[repr(C)]
111pub struct BlockHeaderConsensusInfo {
112 pub slot: SlotNumber,
114 pub proof_of_time: PotOutput,
116 pub future_proof_of_time: PotOutput,
118 pub solution: Solution,
120}
121
122impl BlockHeaderConsensusInfo {
123 pub fn hash(&self) -> Blake3Hash {
125 Blake3Hash::from(blake3::hash(self.as_bytes()))
127 }
128}
129
130#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, TrivialType)]
132#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
135#[repr(C)]
136pub struct BlockHeaderBeaconChainInfo {
137 pub number: BlockNumber,
139 pub root: BlockRoot,
141}
142
143impl BlockHeaderBeaconChainInfo {
144 pub fn hash(&self) -> Blake3Hash {
146 const {
147 assert!(size_of::<Self>() <= BLOCK_LEN);
148 }
149 Blake3Hash::new(
151 single_block_hash(self.as_bytes())
152 .expect("Less than a single block worth of bytes; qed"),
153 )
154 }
155}
156
157#[derive(Debug, Copy, Clone, Eq, PartialEq)]
159#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
160#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
161#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
162pub struct BlockHeaderFixedConsensusParameters {
163 pub solution_range: SolutionRange,
165 pub slot_iterations: NonZeroU32,
170 pub num_shards: NumShards,
172}
173
174impl BlockHeaderFixedConsensusParameters {
175 #[inline]
181 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(Self, &[u8])> {
182 let solution_range = bytes.split_off(..size_of::<SolutionRange>())?;
188 let solution_range = SolutionRange::from_bytes([
189 solution_range[0],
190 solution_range[1],
191 solution_range[2],
192 solution_range[3],
193 solution_range[4],
194 solution_range[5],
195 solution_range[6],
196 solution_range[7],
197 ]);
198
199 let pot_slot_iterations = bytes.split_off(..size_of::<u32>())?;
200 let slot_iterations = u32::from_le_bytes([
201 pot_slot_iterations[0],
202 pot_slot_iterations[1],
203 pot_slot_iterations[2],
204 pot_slot_iterations[3],
205 ]);
206 let slot_iterations = NonZeroU32::new(slot_iterations)?;
207 let num_shards = unsafe {
209 bytes
210 .split_off(..size_of::<NumShardsUnchecked>())?
211 .as_ptr()
212 .cast::<NumShardsUnchecked>()
213 .read_unaligned()
214 };
215 let num_shards = NumShards::try_from(num_shards).ok()?;
216
217 Some((
218 Self {
219 solution_range,
220 slot_iterations,
221 num_shards,
222 },
223 bytes,
224 ))
225 }
226}
227
228#[derive(Debug, Copy, Clone, Eq, PartialEq)]
232#[repr(C, packed)]
233pub struct BlockHeaderPotParametersChange {
234 slot: SlotNumber,
238 slot_iterations: NonZeroU32,
240 entropy: Blake3Hash,
242}
243
244impl From<BlockHeaderPotParametersChange> for PotParametersChange {
245 #[inline(always)]
246 fn from(value: BlockHeaderPotParametersChange) -> Self {
247 let BlockHeaderPotParametersChange {
248 slot,
249 slot_iterations,
250 entropy,
251 } = value;
252
253 PotParametersChange {
254 slot,
255 slot_iterations,
256 entropy,
257 }
258 }
259}
260
261impl From<PotParametersChange> for BlockHeaderPotParametersChange {
262 #[inline(always)]
263 fn from(value: PotParametersChange) -> Self {
264 let PotParametersChange {
265 slot,
266 slot_iterations,
267 entropy,
268 } = value;
269
270 BlockHeaderPotParametersChange {
271 slot,
272 slot_iterations,
273 entropy,
274 }
275 }
276}
277
278impl BlockHeaderPotParametersChange {
279 #[inline]
285 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(&Self, &[u8])> {
286 let pot_parameters_change_ptr = bytes.as_ptr().cast::<Self>();
292
293 let _slot = bytes.split_off(..size_of::<SlotNumber>())?;
294
295 let slot_iterations = bytes.split_off(..size_of::<u32>())?;
296 if slot_iterations == [0, 0, 0, 0] {
297 return None;
298 }
299 let _entropy = bytes.split_off(..size_of::<Blake3Hash>())?;
300
301 let pot_parameters_change = unsafe { pot_parameters_change_ptr.as_ref_unchecked() };
303
304 Some((pot_parameters_change, bytes))
305 }
306}
307
308#[derive(Debug, Copy, Clone)]
310pub struct OwnedBlockHeaderConsensusParameters {
311 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
313 pub super_segment_root: Option<SuperSegmentRoot>,
315 pub next_solution_range: Option<SolutionRange>,
317 pub pot_parameters_change: Option<BlockHeaderPotParametersChange>,
319}
320
321impl OwnedBlockHeaderConsensusParameters {
322 #[inline]
324 pub fn as_ref(&self) -> BlockHeaderConsensusParameters<'_> {
325 BlockHeaderConsensusParameters {
326 fixed_parameters: self.fixed_parameters,
327 super_segment_root: self.super_segment_root.as_ref(),
328 next_solution_range: self.next_solution_range,
329 pot_parameters_change: self.pot_parameters_change.as_ref(),
330 }
331 }
332}
333
334#[derive(Debug, Copy, Clone, Eq, PartialEq)]
336pub struct BlockHeaderConsensusParameters<'a> {
337 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
339 pub super_segment_root: Option<&'a SuperSegmentRoot>,
341 pub next_solution_range: Option<SolutionRange>,
343 pub pot_parameters_change: Option<&'a BlockHeaderPotParametersChange>,
345}
346
347impl<'a> BlockHeaderConsensusParameters<'a> {
348 pub const MAX_SIZE: u32 = size_of::<BlockHeaderFixedConsensusParameters>() as u32
350 + u8::SIZE
351 + <SuperSegmentRoot as TrivialType>::SIZE
352 + <SolutionRange as TrivialType>::SIZE
353 + <NumShardsUnchecked as TrivialType>::SIZE
354 + size_of::<BlockHeaderPotParametersChange>() as u32;
355 pub const SUPER_SEGMENT_ROOT_MASK: u8 = 0b0000_0001;
357 pub const NEXT_SOLUTION_RANGE_MASK: u8 = 0b0000_0010;
359 pub const POT_PARAMETERS_CHANGE_MASK: u8 = 0b0000_0100;
361 pub const MASK_ALL: u8 = Self::SUPER_SEGMENT_ROOT_MASK
363 | Self::NEXT_SOLUTION_RANGE_MASK
364 | Self::POT_PARAMETERS_CHANGE_MASK;
365
366 #[inline]
372 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
373 let (fixed_parameters, mut remainder) =
381 BlockHeaderFixedConsensusParameters::try_from_bytes(bytes)?;
382
383 let bitflags = remainder.split_off(..size_of::<u8>())?;
384 let bitflags = bitflags[0];
385
386 if (bitflags & Self::MASK_ALL) != bitflags {
387 return None;
389 }
390
391 let super_segment_root = if bitflags & Self::SUPER_SEGMENT_ROOT_MASK != 0 {
392 let super_segment_root = remainder.split_off(..size_of::<SuperSegmentRoot>())?;
393 let super_segment_root = unsafe { SuperSegmentRoot::from_bytes(super_segment_root) }?;
395
396 Some(super_segment_root)
397 } else {
398 None
399 };
400
401 let next_solution_range = if bitflags & Self::NEXT_SOLUTION_RANGE_MASK != 0 {
402 let next_solution_range = remainder.split_off(..size_of::<SolutionRange>())?;
403 let next_solution_range = SolutionRange::from_bytes([
405 next_solution_range[0],
406 next_solution_range[1],
407 next_solution_range[2],
408 next_solution_range[3],
409 next_solution_range[4],
410 next_solution_range[5],
411 next_solution_range[6],
412 next_solution_range[7],
413 ]);
414
415 Some(next_solution_range)
416 } else {
417 None
418 };
419
420 let pot_parameters_change = if bitflags & Self::POT_PARAMETERS_CHANGE_MASK != 0 {
421 let pot_parameters_change;
422 (pot_parameters_change, remainder) =
423 BlockHeaderPotParametersChange::try_from_bytes(remainder)?;
424
425 Some(pot_parameters_change)
426 } else {
427 None
428 };
429
430 Some((
431 Self {
432 fixed_parameters,
433 super_segment_root,
434 next_solution_range,
435 pot_parameters_change,
436 },
437 remainder,
438 ))
439 }
440
441 pub fn hash(&self) -> Blake3Hash {
443 let Self {
444 super_segment_root,
445 fixed_parameters,
446 next_solution_range,
447 pot_parameters_change,
448 } = self;
449 let BlockHeaderFixedConsensusParameters {
450 solution_range,
451 slot_iterations,
452 num_shards,
453 } = fixed_parameters;
454
455 let mut hasher = blake3::Hasher::new();
457 hasher.update(solution_range.as_bytes());
458 hasher.update(&slot_iterations.get().to_le_bytes());
459 hasher.update(NumShardsUnchecked::from(*num_shards).as_bytes());
460
461 if let Some(super_segment_root) = super_segment_root {
462 hasher.update(super_segment_root.as_bytes());
463 }
464 if let Some(next_solution_range) = next_solution_range {
465 hasher.update(next_solution_range.as_bytes());
466 }
467 if let Some(pot_parameters_change) = pot_parameters_change.copied() {
468 let BlockHeaderPotParametersChange {
469 slot,
470 slot_iterations,
471 entropy,
472 } = pot_parameters_change;
473 hasher.update(slot.as_bytes());
474 hasher.update(&slot_iterations.get().to_le_bytes());
475 hasher.update(entropy.as_bytes());
476 }
477
478 Blake3Hash::from(hasher.finalize())
479 }
480}
481
482#[derive(Debug, Copy, Clone, Deref)]
484pub struct BlockHeaderChildShardBlocks<'a> {
485 pub child_shard_blocks: &'a [BlockRoot],
487}
488
489impl<'a> BlockHeaderChildShardBlocks<'a> {
490 #[inline]
496 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
497 let length = bytes.split_off(..size_of::<u16>())?;
503 let num_blocks = usize::from(*unsafe { <u16 as TrivialType>::from_bytes(length) }?);
505
506 let padding = bytes.split_off(..size_of::<[u8; 2]>())?;
507
508 if padding != [0, 0] {
510 return None;
511 }
512
513 let child_shard_blocks = bytes.split_off(..num_blocks * BlockRoot::SIZE)?;
514 let child_shard_blocks = unsafe {
516 slice::from_raw_parts(
517 child_shard_blocks
518 .as_ptr()
519 .cast::<[u8; const { BlockRoot::SIZE }]>(),
520 num_blocks,
521 )
522 };
523 let child_shard_blocks = BlockRoot::slice_from_repr(child_shard_blocks);
524
525 Some((Self { child_shard_blocks }, bytes))
526 }
527
528 pub fn root(&self) -> Option<Blake3Hash> {
532 let root =
533 UnbalancedMerkleTree::compute_root_only::<'_, const { u64::from(u32::MAX) }, _, _>(
534 self.child_shard_blocks
536 .iter()
537 .map(|child_shard_block_root| {
538 single_block_hash(child_shard_block_root.as_ref())
542 .expect("Less than a single block worth of bytes; qed")
543 }),
544 )?;
545 Some(Blake3Hash::new(root))
546 }
547}
548
549#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
553#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
554#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
555#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
556#[repr(C)]
557pub struct BlockHeaderResult {
558 pub body_root: Blake3Hash,
561 pub state_root: Blake3Hash,
564}
565
566impl BlockHeaderResult {
567 pub fn hash(&self) -> Blake3Hash {
569 const {
570 assert!(size_of::<Self>() <= BLOCK_LEN);
571 }
572 Blake3Hash::new(
574 single_block_hash(self.as_bytes())
575 .expect("Less than a single block worth of bytes; qed"),
576 )
577 }
578}
579
580#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
582#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
583#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
584#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
585#[repr(u8)]
586#[non_exhaustive]
587pub enum BlockHeaderSealType {
588 #[cfg_attr(feature = "scale-codec", codec(index = 0))]
590 Ed25519 = 0,
591}
592
593impl BlockHeaderSealType {
594 #[inline(always)]
596 pub const fn try_from_byte(byte: u8) -> Option<Self> {
597 if byte == Self::Ed25519 as u8 {
598 Some(Self::Ed25519)
599 } else {
600 None
601 }
602 }
603}
604
605#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
607#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
608#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
609#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
610#[repr(C)]
611pub struct BlockHeaderEd25519Seal {
612 pub public_key: Ed25519PublicKey,
614 pub signature: Ed25519Signature,
616}
617
618#[derive(Debug, Copy, Clone)]
620#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
621#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
622#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
623#[non_exhaustive]
624pub enum OwnedBlockHeaderSeal {
625 Ed25519(BlockHeaderEd25519Seal),
627}
628
629impl OwnedBlockHeaderSeal {
630 #[inline(always)]
632 pub fn as_ref(&self) -> BlockHeaderSeal<'_> {
633 match self {
634 Self::Ed25519(seal) => BlockHeaderSeal::Ed25519(seal),
635 }
636 }
637}
638
639#[derive(Debug, Copy, Clone)]
641#[non_exhaustive]
642pub enum BlockHeaderSeal<'a> {
643 Ed25519(&'a BlockHeaderEd25519Seal),
645}
646
647impl<'a> BlockHeaderSeal<'a> {
648 pub const MAX_SIZE: u32 = 1 + BlockHeaderEd25519Seal::SIZE;
650 #[inline]
656 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
657 let seal_type = bytes.split_off(..size_of::<u8>())?;
662 let seal_type = BlockHeaderSealType::try_from_byte(seal_type[0])?;
663
664 match seal_type {
665 BlockHeaderSealType::Ed25519 => {
666 let seal = bytes.split_off(..size_of::<BlockHeaderEd25519Seal>())?;
667 let seal = unsafe { BlockHeaderEd25519Seal::from_bytes(seal) }?;
669 Some((Self::Ed25519(seal), bytes))
670 }
671 }
672 }
673
674 #[inline]
676 pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
677 match self {
678 BlockHeaderSeal::Ed25519(seal) => seal
679 .public_key
680 .verify(&seal.signature, pre_seal_hash.as_bytes())
681 .is_ok(),
682 }
683 }
684
685 #[inline]
687 pub fn public_key_hash(&self) -> Blake3Hash {
688 match self {
689 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
690 }
691 }
692
693 #[inline]
695 pub fn hash(&self) -> Blake3Hash {
696 match self {
697 BlockHeaderSeal::Ed25519(seal) => {
698 let mut hasher = blake3::Hasher::new();
700 hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
701 hasher.update(seal.as_bytes());
702
703 Blake3Hash::from(hasher.finalize())
704 }
705 }
706 }
707}
708
709#[derive(Debug, Copy, Clone)]
711pub struct SharedBlockHeader<'a> {
712 pub prefix: &'a BlockHeaderPrefix,
714 pub result: &'a BlockHeaderResult,
716 pub consensus_info: &'a BlockHeaderConsensusInfo,
718 pub seal: BlockHeaderSeal<'a>,
720}
721
722#[derive(Debug, Clone, Yokeable)]
724#[non_exhaustive]
726pub struct BeaconChainHeader<'a> {
727 shared: SharedBlockHeader<'a>,
729 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
731 consensus_parameters: BlockHeaderConsensusParameters<'a>,
733 pre_seal_bytes: &'a [u8],
735 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
736 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
737 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
738 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
739}
740
741impl<'a> Deref for BeaconChainHeader<'a> {
742 type Target = SharedBlockHeader<'a>;
743
744 #[inline(always)]
745 fn deref(&self) -> &Self::Target {
746 &self.shared
747 }
748}
749
750impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
751 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
752
753 #[cfg(feature = "alloc")]
754 type Owned = OwnedBeaconChainHeader;
755
756 #[cfg(feature = "alloc")]
757 #[inline(always)]
758 fn to_owned(self) -> Self::Owned {
759 self.to_owned()
760 }
761
762 #[inline(always)]
763 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
764 self.root()
765 }
766
767 #[inline(always)]
768 fn pre_seal_hash(&self) -> Blake3Hash {
769 self.pre_seal_hash()
770 }
771}
772
773impl<'a> BeaconChainHeader<'a> {
774 #[inline]
781 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
782 let (prefix, consensus_info, result, remainder) =
791 BlockHeader::try_from_bytes_shared(bytes)?;
792
793 if prefix.shard_index.shard_kind() != Some(ShardKind::BeaconChain) {
794 return None;
795 }
796
797 let (child_shard_blocks, remainder) =
798 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
799
800 let (consensus_parameters, remainder) =
801 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
802
803 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
804
805 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
806
807 let shared = SharedBlockHeader {
808 prefix,
809 result,
810 consensus_info,
811 seal,
812 };
813
814 let header = Self {
815 shared,
816 child_shard_blocks,
817 consensus_parameters,
818 pre_seal_bytes,
819 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
820 cached_block_root: rclite::Arc::default(),
821 };
822
823 if !header.is_internally_consistent() {
824 return None;
825 }
826
827 Some((header, remainder))
828 }
829
830 #[inline]
835 pub fn is_internally_consistent(&self) -> bool {
836 let public_key_hash = match self.seal {
837 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
838 };
839 public_key_hash == self.shared.consensus_info.solution.public_key_hash
840 }
841
842 #[inline]
845 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
846 let (prefix, consensus_info, result, remainder) =
855 BlockHeader::try_from_bytes_shared(bytes)?;
856
857 if prefix.shard_index.shard_kind() != Some(ShardKind::BeaconChain) {
858 return None;
859 }
860
861 let (child_shard_blocks, remainder) =
862 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
863
864 let (consensus_parameters, remainder) =
865 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
866
867 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
868
869 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
870
871 let shared = SharedBlockHeader {
872 prefix,
873 result,
874 consensus_info,
875 seal,
876 };
877
878 Some((
879 Self {
880 shared,
881 child_shard_blocks,
882 consensus_parameters,
883 pre_seal_bytes,
884 #[cfg(any(
885 feature = "alloc",
886 not(any(target_os = "none", target_os = "unknown"))
887 ))]
888 cached_block_root: rclite::Arc::default(),
889 },
890 remainder,
891 ))
892 }
893
894 #[cfg(feature = "alloc")]
896 #[inline(always)]
897 pub fn to_owned(self) -> OwnedBeaconChainHeader {
898 let unsealed = OwnedBeaconChainHeader::from_parts(
899 self.shared.prefix,
900 self.shared.result,
901 self.shared.consensus_info,
902 &self.child_shard_blocks,
903 &self.consensus_parameters,
904 )
905 .expect("`self` is always a valid invariant; qed");
906
907 unsealed.with_seal(self.shared.seal)
908 }
909
910 #[inline(always)]
912 pub fn shared(&self) -> &SharedBlockHeader<'a> {
913 &self.shared
914 }
915
916 #[inline(always)]
918 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
919 &self.child_shard_blocks
920 }
921
922 #[inline(always)]
924 pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
925 &self.consensus_parameters
926 }
927
928 #[inline]
930 pub fn pre_seal_hash(&self) -> Blake3Hash {
931 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
933 }
934
935 #[inline]
938 pub fn is_sealed_correctly(&self) -> bool {
939 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
940 && self.seal.is_seal_valid(&self.pre_seal_hash())
941 }
942
943 #[inline]
951 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
952 let Self {
953 shared,
954 child_shard_blocks,
955 consensus_parameters,
956 pre_seal_bytes: _,
957 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
958 cached_block_root,
959 } = self;
960
961 let compute_root = || {
962 let SharedBlockHeader {
963 prefix,
964 result,
965 consensus_info,
966 seal,
967 } = shared;
968
969 let block_root = UnbalancedMerkleTree::compute_root_only_array(&[
970 prefix.hash(),
971 result.hash(),
972 consensus_info.hash(),
973 seal.hash(),
974 child_shard_blocks.root().unwrap_or_default(),
975 consensus_parameters.hash(),
976 ]);
977
978 BlockRoot::new(Blake3Hash::new(block_root))
979 };
980
981 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
982 {
983 cached_block_root.get_or_init(compute_root)
984 }
985 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
986 {
987 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
988 }
989 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
990 {
991 struct Wrapper(BlockRoot);
992
993 impl Deref for Wrapper {
994 type Target = BlockRoot;
995
996 #[inline(always)]
997 fn deref(&self) -> &Self::Target {
998 &self.0
999 }
1000 }
1001
1002 Wrapper(compute_root())
1003 }
1004 }
1005}
1006
1007#[derive(Debug, Clone, Yokeable)]
1009#[non_exhaustive]
1011pub struct IntermediateShardHeader<'a> {
1012 shared: SharedBlockHeader<'a>,
1014 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1016 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
1018 pre_seal_bytes: &'a [u8],
1020 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1021 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1022 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1023 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1024}
1025
1026impl<'a> Deref for IntermediateShardHeader<'a> {
1027 type Target = SharedBlockHeader<'a>;
1028
1029 #[inline(always)]
1030 fn deref(&self) -> &Self::Target {
1031 &self.shared
1032 }
1033}
1034
1035impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
1036 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
1037
1038 #[cfg(feature = "alloc")]
1039 type Owned = OwnedIntermediateShardHeader;
1040
1041 #[cfg(feature = "alloc")]
1042 #[inline(always)]
1043 fn to_owned(self) -> Self::Owned {
1044 self.to_owned()
1045 }
1046
1047 #[inline(always)]
1048 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1049 self.root()
1050 }
1051
1052 #[inline(always)]
1053 fn pre_seal_hash(&self) -> Blake3Hash {
1054 self.pre_seal_hash()
1055 }
1056}
1057
1058impl<'a> IntermediateShardHeader<'a> {
1059 #[inline]
1066 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1067 let (prefix, consensus_info, result, mut remainder) =
1076 BlockHeader::try_from_bytes_shared(bytes)?;
1077
1078 if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1079 return None;
1080 }
1081
1082 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1083 let beacon_chain_info =
1085 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1086
1087 let (child_shard_blocks, remainder) =
1088 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1089
1090 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1091
1092 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1093
1094 let shared = SharedBlockHeader {
1095 prefix,
1096 result,
1097 consensus_info,
1098 seal,
1099 };
1100
1101 let header = Self {
1102 shared,
1103 beacon_chain_info,
1104 child_shard_blocks,
1105 pre_seal_bytes,
1106 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1107 cached_block_root: rclite::Arc::default(),
1108 };
1109
1110 if !header.is_internally_consistent() {
1111 return None;
1112 }
1113
1114 Some((header, remainder))
1115 }
1116
1117 #[inline]
1122 pub fn is_internally_consistent(&self) -> bool {
1123 let public_key_hash = match self.seal {
1124 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1125 };
1126 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1127 }
1128
1129 #[inline]
1132 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1133 let (prefix, consensus_info, result, mut remainder) =
1142 BlockHeader::try_from_bytes_shared(bytes)?;
1143
1144 if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1145 return None;
1146 }
1147
1148 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1149 let beacon_chain_info =
1151 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1152
1153 let (child_shard_blocks, remainder) =
1154 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1155
1156 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1157
1158 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1159
1160 let shared = SharedBlockHeader {
1161 prefix,
1162 result,
1163 consensus_info,
1164 seal,
1165 };
1166
1167 Some((
1168 Self {
1169 shared,
1170 beacon_chain_info,
1171 child_shard_blocks,
1172 pre_seal_bytes,
1173 #[cfg(any(
1174 feature = "alloc",
1175 not(any(target_os = "none", target_os = "unknown"))
1176 ))]
1177 cached_block_root: rclite::Arc::default(),
1178 },
1179 remainder,
1180 ))
1181 }
1182
1183 #[cfg(feature = "alloc")]
1185 #[inline(always)]
1186 pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1187 let unsealed = OwnedIntermediateShardHeader::from_parts(
1188 self.shared.prefix,
1189 self.shared.result,
1190 self.shared.consensus_info,
1191 self.beacon_chain_info,
1192 &self.child_shard_blocks,
1193 )
1194 .expect("`self` is always a valid invariant; qed");
1195
1196 unsealed.with_seal(self.shared.seal)
1197 }
1198
1199 #[inline(always)]
1201 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1202 &self.shared
1203 }
1204
1205 #[inline(always)]
1207 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1208 self.beacon_chain_info
1209 }
1210
1211 #[inline(always)]
1213 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1214 &self.child_shard_blocks
1215 }
1216
1217 #[inline]
1219 pub fn pre_seal_hash(&self) -> Blake3Hash {
1220 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1222 }
1223
1224 #[inline]
1227 pub fn is_sealed_correctly(&self) -> bool {
1228 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1229 && self.seal.is_seal_valid(&self.pre_seal_hash())
1230 }
1231
1232 #[inline]
1240 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1241 let Self {
1242 shared,
1243 beacon_chain_info,
1244 child_shard_blocks,
1245 pre_seal_bytes: _,
1246 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1247 cached_block_root,
1248 } = self;
1249
1250 let compute_root = || {
1251 let SharedBlockHeader {
1252 prefix,
1253 result,
1254 consensus_info,
1255 seal,
1256 } = shared;
1257
1258 let block_root = UnbalancedMerkleTree::compute_root_only_array(&[
1259 prefix.hash(),
1260 result.hash(),
1261 consensus_info.hash(),
1262 seal.hash(),
1263 beacon_chain_info.hash(),
1264 child_shard_blocks.root().unwrap_or_default(),
1265 ]);
1266
1267 BlockRoot::new(Blake3Hash::new(block_root))
1268 };
1269
1270 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1271 {
1272 cached_block_root.get_or_init(compute_root)
1273 }
1274 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1275 {
1276 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1277 }
1278 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1279 {
1280 struct Wrapper(BlockRoot);
1281
1282 impl Deref for Wrapper {
1283 type Target = BlockRoot;
1284
1285 #[inline(always)]
1286 fn deref(&self) -> &Self::Target {
1287 &self.0
1288 }
1289 }
1290
1291 Wrapper(compute_root())
1292 }
1293 }
1294}
1295
1296#[derive(Debug, Clone, Yokeable)]
1298#[non_exhaustive]
1300pub struct LeafShardHeader<'a> {
1301 shared: SharedBlockHeader<'a>,
1303 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1305 pre_seal_bytes: &'a [u8],
1307 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1308 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1309 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1310 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1311}
1312
1313impl<'a> Deref for LeafShardHeader<'a> {
1314 type Target = SharedBlockHeader<'a>;
1315
1316 #[inline(always)]
1317 fn deref(&self) -> &Self::Target {
1318 &self.shared
1319 }
1320}
1321
1322impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1323 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1324
1325 #[cfg(feature = "alloc")]
1326 type Owned = OwnedLeafShardHeader;
1327
1328 #[cfg(feature = "alloc")]
1329 #[inline(always)]
1330 fn to_owned(self) -> Self::Owned {
1331 self.to_owned()
1332 }
1333
1334 #[inline(always)]
1335 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1336 self.root()
1337 }
1338
1339 #[inline(always)]
1340 fn pre_seal_hash(&self) -> Blake3Hash {
1341 self.pre_seal_hash()
1342 }
1343}
1344
1345impl<'a> LeafShardHeader<'a> {
1346 #[inline]
1353 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1354 let (prefix, consensus_info, result, mut remainder) =
1362 BlockHeader::try_from_bytes_shared(bytes)?;
1363
1364 if prefix.shard_index.shard_kind() != Some(ShardKind::LeafShard) {
1365 return None;
1366 }
1367
1368 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1369 let beacon_chain_info =
1371 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1372
1373 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1374
1375 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1376
1377 let shared = SharedBlockHeader {
1378 prefix,
1379 result,
1380 consensus_info,
1381 seal,
1382 };
1383
1384 let header = Self {
1385 shared,
1386 beacon_chain_info,
1387 pre_seal_bytes,
1388 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1389 cached_block_root: rclite::Arc::default(),
1390 };
1391
1392 if !header.is_internally_consistent() {
1393 return None;
1394 }
1395
1396 Some((header, remainder))
1397 }
1398
1399 #[inline]
1404 pub fn is_internally_consistent(&self) -> bool {
1405 let public_key_hash = match self.seal {
1406 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1407 };
1408 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1409 }
1410
1411 #[inline]
1414 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1415 let (prefix, consensus_info, result, mut remainder) =
1423 BlockHeader::try_from_bytes_shared(bytes)?;
1424
1425 if prefix.shard_index.shard_kind() != Some(ShardKind::LeafShard) {
1426 return None;
1427 }
1428
1429 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1430 let beacon_chain_info =
1432 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1433
1434 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1435
1436 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1437
1438 let shared = SharedBlockHeader {
1439 prefix,
1440 result,
1441 consensus_info,
1442 seal,
1443 };
1444
1445 Some((
1446 Self {
1447 shared,
1448 beacon_chain_info,
1449 pre_seal_bytes,
1450 #[cfg(any(
1451 feature = "alloc",
1452 not(any(target_os = "none", target_os = "unknown"))
1453 ))]
1454 cached_block_root: rclite::Arc::default(),
1455 },
1456 remainder,
1457 ))
1458 }
1459
1460 #[cfg(feature = "alloc")]
1462 #[inline(always)]
1463 pub fn to_owned(self) -> OwnedLeafShardHeader {
1464 let unsealed = OwnedLeafShardHeader::from_parts(
1465 self.shared.prefix,
1466 self.shared.result,
1467 self.shared.consensus_info,
1468 self.beacon_chain_info,
1469 );
1470
1471 unsealed.with_seal(self.shared.seal)
1472 }
1473
1474 #[inline(always)]
1476 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1477 &self.shared
1478 }
1479
1480 #[inline(always)]
1482 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1483 self.beacon_chain_info
1484 }
1485
1486 #[inline]
1488 pub fn pre_seal_hash(&self) -> Blake3Hash {
1489 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1491 }
1492
1493 #[inline]
1496 pub fn is_sealed_correctly(&self) -> bool {
1497 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1498 && self.seal.is_seal_valid(&self.pre_seal_hash())
1499 }
1500
1501 #[inline]
1509 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1510 let Self {
1511 shared,
1512 beacon_chain_info,
1513 pre_seal_bytes: _,
1514 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1515 cached_block_root,
1516 } = self;
1517
1518 let compute_root = || {
1519 let SharedBlockHeader {
1520 prefix,
1521 result,
1522 consensus_info,
1523 seal,
1524 } = shared;
1525
1526 let block_root = UnbalancedMerkleTree::compute_root_only_array(&[
1527 prefix.hash(),
1528 result.hash(),
1529 consensus_info.hash(),
1530 seal.hash(),
1531 beacon_chain_info.hash(),
1532 ]);
1533
1534 BlockRoot::new(Blake3Hash::new(block_root))
1535 };
1536
1537 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1538 {
1539 cached_block_root.get_or_init(compute_root)
1540 }
1541 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1542 {
1543 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1544 }
1545 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1546 {
1547 struct Wrapper(BlockRoot);
1548
1549 impl Deref for Wrapper {
1550 type Target = BlockRoot;
1551
1552 #[inline(always)]
1553 fn deref(&self) -> &Self::Target {
1554 &self.0
1555 }
1556 }
1557
1558 Wrapper(compute_root())
1559 }
1560 }
1561}
1562
1563#[derive(Debug, Clone, From)]
1568pub enum BlockHeader<'a> {
1569 BeaconChain(BeaconChainHeader<'a>),
1571 IntermediateShard(IntermediateShardHeader<'a>),
1573 LeafShard(LeafShardHeader<'a>),
1575}
1576
1577impl<'a> Deref for BlockHeader<'a> {
1578 type Target = SharedBlockHeader<'a>;
1579
1580 #[inline(always)]
1581 fn deref(&self) -> &Self::Target {
1582 match self {
1583 Self::BeaconChain(header) => header,
1584 Self::IntermediateShard(header) => header,
1585 Self::LeafShard(header) => header,
1586 }
1587 }
1588}
1589
1590impl<'a> BlockHeader<'a> {
1591 #[inline]
1598 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1599 match shard_kind {
1600 RealShardKind::BeaconChain => {
1601 let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1602 Some((Self::BeaconChain(header), remainder))
1603 }
1604 RealShardKind::IntermediateShard => {
1605 let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1606 Some((Self::IntermediateShard(header), remainder))
1607 }
1608 RealShardKind::LeafShard => {
1609 let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1610 Some((Self::LeafShard(header), remainder))
1611 }
1612 }
1613 }
1614
1615 #[inline]
1620 pub fn is_internally_consistent(&self) -> bool {
1621 match self {
1622 Self::BeaconChain(header) => header.is_internally_consistent(),
1623 Self::IntermediateShard(header) => header.is_internally_consistent(),
1624 Self::LeafShard(header) => header.is_internally_consistent(),
1625 }
1626 }
1627
1628 #[inline]
1631 pub fn try_from_bytes_unchecked(
1632 bytes: &'a [u8],
1633 shard_kind: RealShardKind,
1634 ) -> Option<(Self, &'a [u8])> {
1635 match shard_kind {
1636 RealShardKind::BeaconChain => {
1637 let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1638 Some((Self::BeaconChain(header), remainder))
1639 }
1640 RealShardKind::IntermediateShard => {
1641 let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1642 Some((Self::IntermediateShard(header), remainder))
1643 }
1644 RealShardKind::LeafShard => {
1645 let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1646 Some((Self::LeafShard(header), remainder))
1647 }
1648 }
1649 }
1650
1651 #[inline]
1652 fn try_from_bytes_shared(
1653 mut bytes: &'a [u8],
1654 ) -> Option<(
1655 &'a BlockHeaderPrefix,
1656 &'a BlockHeaderConsensusInfo,
1657 &'a BlockHeaderResult,
1658 &'a [u8],
1659 )> {
1660 let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1661 let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1663
1664 if !(prefix.padding_0 == [0; _]
1665 && u32::from(prefix.shard_index) <= ShardIndex::MAX_SHARD_INDEX)
1666 {
1667 return None;
1668 }
1669
1670 let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1671 let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1673
1674 let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1675 let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1677
1678 if consensus_info.solution.padding != [0; _] {
1679 return None;
1680 }
1681
1682 Some((prefix, consensus_info, result, bytes))
1683 }
1684
1685 #[cfg(feature = "alloc")]
1687 #[inline(always)]
1688 pub fn to_owned(self) -> OwnedBlockHeader {
1689 match self {
1690 Self::BeaconChain(header) => header.to_owned().into(),
1691 Self::IntermediateShard(header) => header.to_owned().into(),
1692 Self::LeafShard(header) => header.to_owned().into(),
1693 }
1694 }
1695
1696 #[inline]
1698 pub fn pre_seal_hash(&self) -> Blake3Hash {
1699 match self {
1700 Self::BeaconChain(header) => header.pre_seal_hash(),
1701 Self::IntermediateShard(header) => header.pre_seal_hash(),
1702 Self::LeafShard(header) => header.pre_seal_hash(),
1703 }
1704 }
1705
1706 #[inline]
1709 pub fn is_sealed_correctly(&self) -> bool {
1710 match self {
1711 Self::BeaconChain(header) => header.is_sealed_correctly(),
1712 Self::IntermediateShard(header) => header.is_sealed_correctly(),
1713 Self::LeafShard(header) => header.is_sealed_correctly(),
1714 }
1715 }
1716
1717 #[inline]
1725 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1726 enum Wrapper<B, I, L> {
1727 BeaconChain(B),
1728 IntermediateShard(I),
1729 LeafShard(L),
1730 }
1731
1732 impl<B, I, L> Deref for Wrapper<B, I, L>
1733 where
1734 B: Deref<Target = BlockRoot>,
1735 I: Deref<Target = BlockRoot>,
1736 L: Deref<Target = BlockRoot>,
1737 {
1738 type Target = BlockRoot;
1739
1740 #[inline(always)]
1741 fn deref(&self) -> &Self::Target {
1742 match self {
1743 Wrapper::BeaconChain(block_root) => block_root,
1744 Wrapper::IntermediateShard(block_root) => block_root,
1745 Wrapper::LeafShard(block_root) => block_root,
1746 }
1747 }
1748 }
1749
1750 match self {
1752 Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1753 Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1754 Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1755 }
1756 }
1757}