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.as_ptr().cast::<[u8; BlockRoot::SIZE]>(),
518 num_blocks,
519 )
520 };
521 let child_shard_blocks = BlockRoot::slice_from_repr(child_shard_blocks);
522
523 Some((Self { child_shard_blocks }, bytes))
524 }
525
526 pub fn root(&self) -> Option<Blake3Hash> {
530 let root = UnbalancedMerkleTree::compute_root_only::<'_, { u64::from(u32::MAX) }, _, _>(
531 self.child_shard_blocks
533 .iter()
534 .map(|child_shard_block_root| {
535 single_block_hash(child_shard_block_root.as_ref())
539 .expect("Less than a single block worth of bytes; qed")
540 }),
541 )?;
542 Some(Blake3Hash::new(root))
543 }
544}
545
546#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
550#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
551#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
552#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
553#[repr(C)]
554pub struct BlockHeaderResult {
555 pub body_root: Blake3Hash,
558 pub state_root: Blake3Hash,
561}
562
563impl BlockHeaderResult {
564 pub fn hash(&self) -> Blake3Hash {
566 const {
567 assert!(size_of::<Self>() <= BLOCK_LEN);
568 }
569 Blake3Hash::new(
571 single_block_hash(self.as_bytes())
572 .expect("Less than a single block worth of bytes; qed"),
573 )
574 }
575}
576
577#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
579#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
580#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
581#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
582#[repr(u8)]
583#[non_exhaustive]
584pub enum BlockHeaderSealType {
585 #[cfg_attr(feature = "scale-codec", codec(index = 0))]
587 Ed25519 = 0,
588}
589
590impl BlockHeaderSealType {
591 #[inline(always)]
593 pub const fn try_from_byte(byte: u8) -> Option<Self> {
594 if byte == Self::Ed25519 as u8 {
595 Some(Self::Ed25519)
596 } else {
597 None
598 }
599 }
600}
601
602#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
604#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
605#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
606#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
607#[repr(C)]
608pub struct BlockHeaderEd25519Seal {
609 pub public_key: Ed25519PublicKey,
611 pub signature: Ed25519Signature,
613}
614
615#[derive(Debug, Copy, Clone)]
617#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
618#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
619#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
620#[non_exhaustive]
621pub enum OwnedBlockHeaderSeal {
622 Ed25519(BlockHeaderEd25519Seal),
624}
625
626impl OwnedBlockHeaderSeal {
627 #[inline(always)]
629 pub fn as_ref(&self) -> BlockHeaderSeal<'_> {
630 match self {
631 Self::Ed25519(seal) => BlockHeaderSeal::Ed25519(seal),
632 }
633 }
634}
635
636#[derive(Debug, Copy, Clone)]
638#[non_exhaustive]
639pub enum BlockHeaderSeal<'a> {
640 Ed25519(&'a BlockHeaderEd25519Seal),
642}
643
644impl<'a> BlockHeaderSeal<'a> {
645 pub const MAX_SIZE: u32 = 1 + BlockHeaderEd25519Seal::SIZE;
647 #[inline]
653 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
654 let seal_type = bytes.split_off(..size_of::<u8>())?;
659 let seal_type = BlockHeaderSealType::try_from_byte(seal_type[0])?;
660
661 match seal_type {
662 BlockHeaderSealType::Ed25519 => {
663 let seal = bytes.split_off(..size_of::<BlockHeaderEd25519Seal>())?;
664 let seal = unsafe { BlockHeaderEd25519Seal::from_bytes(seal) }?;
666 Some((Self::Ed25519(seal), bytes))
667 }
668 }
669 }
670
671 #[inline]
673 pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
674 match self {
675 BlockHeaderSeal::Ed25519(seal) => seal
676 .public_key
677 .verify(&seal.signature, pre_seal_hash.as_bytes())
678 .is_ok(),
679 }
680 }
681
682 #[inline]
684 pub fn public_key_hash(&self) -> Blake3Hash {
685 match self {
686 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
687 }
688 }
689
690 #[inline]
692 pub fn hash(&self) -> Blake3Hash {
693 match self {
694 BlockHeaderSeal::Ed25519(seal) => {
695 let mut hasher = blake3::Hasher::new();
697 hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
698 hasher.update(seal.as_bytes());
699
700 Blake3Hash::from(hasher.finalize())
701 }
702 }
703 }
704}
705
706#[derive(Debug, Copy, Clone)]
708pub struct SharedBlockHeader<'a> {
709 pub prefix: &'a BlockHeaderPrefix,
711 pub result: &'a BlockHeaderResult,
713 pub consensus_info: &'a BlockHeaderConsensusInfo,
715 pub seal: BlockHeaderSeal<'a>,
717}
718
719#[derive(Debug, Clone, Yokeable)]
721#[non_exhaustive]
723pub struct BeaconChainHeader<'a> {
724 shared: SharedBlockHeader<'a>,
726 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
728 consensus_parameters: BlockHeaderConsensusParameters<'a>,
730 pre_seal_bytes: &'a [u8],
732 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
733 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
734 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
735 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
736}
737
738impl<'a> Deref for BeaconChainHeader<'a> {
739 type Target = SharedBlockHeader<'a>;
740
741 #[inline(always)]
742 fn deref(&self) -> &Self::Target {
743 &self.shared
744 }
745}
746
747impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
748 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
749
750 #[cfg(feature = "alloc")]
751 type Owned = OwnedBeaconChainHeader;
752
753 #[cfg(feature = "alloc")]
754 #[inline(always)]
755 fn to_owned(self) -> Self::Owned {
756 self.to_owned()
757 }
758
759 #[inline(always)]
760 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
761 self.root()
762 }
763
764 #[inline(always)]
765 fn pre_seal_hash(&self) -> Blake3Hash {
766 self.pre_seal_hash()
767 }
768}
769
770impl<'a> BeaconChainHeader<'a> {
771 #[inline]
778 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
779 let (prefix, consensus_info, result, remainder) =
788 BlockHeader::try_from_bytes_shared(bytes)?;
789
790 if prefix.shard_index.shard_kind() != Some(ShardKind::BeaconChain) {
791 return None;
792 }
793
794 let (child_shard_blocks, remainder) =
795 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
796
797 let (consensus_parameters, remainder) =
798 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
799
800 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
801
802 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
803
804 let shared = SharedBlockHeader {
805 prefix,
806 result,
807 consensus_info,
808 seal,
809 };
810
811 let header = Self {
812 shared,
813 child_shard_blocks,
814 consensus_parameters,
815 pre_seal_bytes,
816 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
817 cached_block_root: rclite::Arc::default(),
818 };
819
820 if !header.is_internally_consistent() {
821 return None;
822 }
823
824 Some((header, remainder))
825 }
826
827 #[inline]
832 pub fn is_internally_consistent(&self) -> bool {
833 let public_key_hash = match self.seal {
834 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
835 };
836 public_key_hash == self.shared.consensus_info.solution.public_key_hash
837 }
838
839 #[inline]
842 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
843 let (prefix, consensus_info, result, remainder) =
852 BlockHeader::try_from_bytes_shared(bytes)?;
853
854 if prefix.shard_index.shard_kind() != Some(ShardKind::BeaconChain) {
855 return None;
856 }
857
858 let (child_shard_blocks, remainder) =
859 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
860
861 let (consensus_parameters, remainder) =
862 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
863
864 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
865
866 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
867
868 let shared = SharedBlockHeader {
869 prefix,
870 result,
871 consensus_info,
872 seal,
873 };
874
875 Some((
876 Self {
877 shared,
878 child_shard_blocks,
879 consensus_parameters,
880 pre_seal_bytes,
881 #[cfg(any(
882 feature = "alloc",
883 not(any(target_os = "none", target_os = "unknown"))
884 ))]
885 cached_block_root: rclite::Arc::default(),
886 },
887 remainder,
888 ))
889 }
890
891 #[cfg(feature = "alloc")]
893 #[inline(always)]
894 pub fn to_owned(self) -> OwnedBeaconChainHeader {
895 let unsealed = OwnedBeaconChainHeader::from_parts(
896 self.shared.prefix,
897 self.shared.result,
898 self.shared.consensus_info,
899 &self.child_shard_blocks,
900 &self.consensus_parameters,
901 )
902 .expect("`self` is always a valid invariant; qed");
903
904 unsealed.with_seal(self.shared.seal)
905 }
906
907 #[inline(always)]
909 pub fn shared(&self) -> &SharedBlockHeader<'a> {
910 &self.shared
911 }
912
913 #[inline(always)]
915 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
916 &self.child_shard_blocks
917 }
918
919 #[inline(always)]
921 pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
922 &self.consensus_parameters
923 }
924
925 #[inline]
927 pub fn pre_seal_hash(&self) -> Blake3Hash {
928 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
930 }
931
932 #[inline]
935 pub fn is_sealed_correctly(&self) -> bool {
936 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
937 && self.seal.is_seal_valid(&self.pre_seal_hash())
938 }
939
940 #[inline]
948 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
949 let Self {
950 shared,
951 child_shard_blocks,
952 consensus_parameters,
953 pre_seal_bytes: _,
954 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
955 cached_block_root,
956 } = self;
957
958 let compute_root = || {
959 let SharedBlockHeader {
960 prefix,
961 result,
962 consensus_info,
963 seal,
964 } = shared;
965
966 let block_root = UnbalancedMerkleTree::compute_root_only_array(&[
967 prefix.hash(),
968 result.hash(),
969 consensus_info.hash(),
970 seal.hash(),
971 child_shard_blocks.root().unwrap_or_default(),
972 consensus_parameters.hash(),
973 ]);
974
975 BlockRoot::new(Blake3Hash::new(block_root))
976 };
977
978 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
979 {
980 cached_block_root.get_or_init(compute_root)
981 }
982 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
983 {
984 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
985 }
986 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
987 {
988 struct Wrapper(BlockRoot);
989
990 impl Deref for Wrapper {
991 type Target = BlockRoot;
992
993 #[inline(always)]
994 fn deref(&self) -> &Self::Target {
995 &self.0
996 }
997 }
998
999 Wrapper(compute_root())
1000 }
1001 }
1002}
1003
1004#[derive(Debug, Clone, Yokeable)]
1006#[non_exhaustive]
1008pub struct IntermediateShardHeader<'a> {
1009 shared: SharedBlockHeader<'a>,
1011 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1013 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
1015 pre_seal_bytes: &'a [u8],
1017 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1018 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1019 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1020 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1021}
1022
1023impl<'a> Deref for IntermediateShardHeader<'a> {
1024 type Target = SharedBlockHeader<'a>;
1025
1026 #[inline(always)]
1027 fn deref(&self) -> &Self::Target {
1028 &self.shared
1029 }
1030}
1031
1032impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
1033 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
1034
1035 #[cfg(feature = "alloc")]
1036 type Owned = OwnedIntermediateShardHeader;
1037
1038 #[cfg(feature = "alloc")]
1039 #[inline(always)]
1040 fn to_owned(self) -> Self::Owned {
1041 self.to_owned()
1042 }
1043
1044 #[inline(always)]
1045 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1046 self.root()
1047 }
1048
1049 #[inline(always)]
1050 fn pre_seal_hash(&self) -> Blake3Hash {
1051 self.pre_seal_hash()
1052 }
1053}
1054
1055impl<'a> IntermediateShardHeader<'a> {
1056 #[inline]
1063 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1064 let (prefix, consensus_info, result, mut remainder) =
1073 BlockHeader::try_from_bytes_shared(bytes)?;
1074
1075 if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1076 return None;
1077 }
1078
1079 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1080 let beacon_chain_info =
1082 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1083
1084 let (child_shard_blocks, remainder) =
1085 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1086
1087 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1088
1089 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1090
1091 let shared = SharedBlockHeader {
1092 prefix,
1093 result,
1094 consensus_info,
1095 seal,
1096 };
1097
1098 let header = Self {
1099 shared,
1100 beacon_chain_info,
1101 child_shard_blocks,
1102 pre_seal_bytes,
1103 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1104 cached_block_root: rclite::Arc::default(),
1105 };
1106
1107 if !header.is_internally_consistent() {
1108 return None;
1109 }
1110
1111 Some((header, remainder))
1112 }
1113
1114 #[inline]
1119 pub fn is_internally_consistent(&self) -> bool {
1120 let public_key_hash = match self.seal {
1121 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1122 };
1123 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1124 }
1125
1126 #[inline]
1129 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1130 let (prefix, consensus_info, result, mut remainder) =
1139 BlockHeader::try_from_bytes_shared(bytes)?;
1140
1141 if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1142 return None;
1143 }
1144
1145 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1146 let beacon_chain_info =
1148 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1149
1150 let (child_shard_blocks, remainder) =
1151 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1152
1153 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1154
1155 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1156
1157 let shared = SharedBlockHeader {
1158 prefix,
1159 result,
1160 consensus_info,
1161 seal,
1162 };
1163
1164 Some((
1165 Self {
1166 shared,
1167 beacon_chain_info,
1168 child_shard_blocks,
1169 pre_seal_bytes,
1170 #[cfg(any(
1171 feature = "alloc",
1172 not(any(target_os = "none", target_os = "unknown"))
1173 ))]
1174 cached_block_root: rclite::Arc::default(),
1175 },
1176 remainder,
1177 ))
1178 }
1179
1180 #[cfg(feature = "alloc")]
1182 #[inline(always)]
1183 pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1184 let unsealed = OwnedIntermediateShardHeader::from_parts(
1185 self.shared.prefix,
1186 self.shared.result,
1187 self.shared.consensus_info,
1188 self.beacon_chain_info,
1189 &self.child_shard_blocks,
1190 )
1191 .expect("`self` is always a valid invariant; qed");
1192
1193 unsealed.with_seal(self.shared.seal)
1194 }
1195
1196 #[inline(always)]
1198 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1199 &self.shared
1200 }
1201
1202 #[inline(always)]
1204 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1205 self.beacon_chain_info
1206 }
1207
1208 #[inline(always)]
1210 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1211 &self.child_shard_blocks
1212 }
1213
1214 #[inline]
1216 pub fn pre_seal_hash(&self) -> Blake3Hash {
1217 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1219 }
1220
1221 #[inline]
1224 pub fn is_sealed_correctly(&self) -> bool {
1225 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1226 && self.seal.is_seal_valid(&self.pre_seal_hash())
1227 }
1228
1229 #[inline]
1237 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1238 let Self {
1239 shared,
1240 beacon_chain_info,
1241 child_shard_blocks,
1242 pre_seal_bytes: _,
1243 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1244 cached_block_root,
1245 } = self;
1246
1247 let compute_root = || {
1248 let SharedBlockHeader {
1249 prefix,
1250 result,
1251 consensus_info,
1252 seal,
1253 } = shared;
1254
1255 let block_root = UnbalancedMerkleTree::compute_root_only_array(&[
1256 prefix.hash(),
1257 result.hash(),
1258 consensus_info.hash(),
1259 seal.hash(),
1260 beacon_chain_info.hash(),
1261 child_shard_blocks.root().unwrap_or_default(),
1262 ]);
1263
1264 BlockRoot::new(Blake3Hash::new(block_root))
1265 };
1266
1267 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1268 {
1269 cached_block_root.get_or_init(compute_root)
1270 }
1271 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1272 {
1273 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1274 }
1275 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1276 {
1277 struct Wrapper(BlockRoot);
1278
1279 impl Deref for Wrapper {
1280 type Target = BlockRoot;
1281
1282 #[inline(always)]
1283 fn deref(&self) -> &Self::Target {
1284 &self.0
1285 }
1286 }
1287
1288 Wrapper(compute_root())
1289 }
1290 }
1291}
1292
1293#[derive(Debug, Clone, Yokeable)]
1295#[non_exhaustive]
1297pub struct LeafShardHeader<'a> {
1298 shared: SharedBlockHeader<'a>,
1300 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1302 pre_seal_bytes: &'a [u8],
1304 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1305 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1306 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1307 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1308}
1309
1310impl<'a> Deref for LeafShardHeader<'a> {
1311 type Target = SharedBlockHeader<'a>;
1312
1313 #[inline(always)]
1314 fn deref(&self) -> &Self::Target {
1315 &self.shared
1316 }
1317}
1318
1319impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1320 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1321
1322 #[cfg(feature = "alloc")]
1323 type Owned = OwnedLeafShardHeader;
1324
1325 #[cfg(feature = "alloc")]
1326 #[inline(always)]
1327 fn to_owned(self) -> Self::Owned {
1328 self.to_owned()
1329 }
1330
1331 #[inline(always)]
1332 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1333 self.root()
1334 }
1335
1336 #[inline(always)]
1337 fn pre_seal_hash(&self) -> Blake3Hash {
1338 self.pre_seal_hash()
1339 }
1340}
1341
1342impl<'a> LeafShardHeader<'a> {
1343 #[inline]
1350 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1351 let (prefix, consensus_info, result, mut remainder) =
1359 BlockHeader::try_from_bytes_shared(bytes)?;
1360
1361 if prefix.shard_index.shard_kind() != Some(ShardKind::LeafShard) {
1362 return None;
1363 }
1364
1365 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1366 let beacon_chain_info =
1368 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1369
1370 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1371
1372 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1373
1374 let shared = SharedBlockHeader {
1375 prefix,
1376 result,
1377 consensus_info,
1378 seal,
1379 };
1380
1381 let header = Self {
1382 shared,
1383 beacon_chain_info,
1384 pre_seal_bytes,
1385 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1386 cached_block_root: rclite::Arc::default(),
1387 };
1388
1389 if !header.is_internally_consistent() {
1390 return None;
1391 }
1392
1393 Some((header, remainder))
1394 }
1395
1396 #[inline]
1401 pub fn is_internally_consistent(&self) -> bool {
1402 let public_key_hash = match self.seal {
1403 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1404 };
1405 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1406 }
1407
1408 #[inline]
1411 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1412 let (prefix, consensus_info, result, mut remainder) =
1420 BlockHeader::try_from_bytes_shared(bytes)?;
1421
1422 if prefix.shard_index.shard_kind() != Some(ShardKind::LeafShard) {
1423 return None;
1424 }
1425
1426 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1427 let beacon_chain_info =
1429 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1430
1431 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1432
1433 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1434
1435 let shared = SharedBlockHeader {
1436 prefix,
1437 result,
1438 consensus_info,
1439 seal,
1440 };
1441
1442 Some((
1443 Self {
1444 shared,
1445 beacon_chain_info,
1446 pre_seal_bytes,
1447 #[cfg(any(
1448 feature = "alloc",
1449 not(any(target_os = "none", target_os = "unknown"))
1450 ))]
1451 cached_block_root: rclite::Arc::default(),
1452 },
1453 remainder,
1454 ))
1455 }
1456
1457 #[cfg(feature = "alloc")]
1459 #[inline(always)]
1460 pub fn to_owned(self) -> OwnedLeafShardHeader {
1461 let unsealed = OwnedLeafShardHeader::from_parts(
1462 self.shared.prefix,
1463 self.shared.result,
1464 self.shared.consensus_info,
1465 self.beacon_chain_info,
1466 );
1467
1468 unsealed.with_seal(self.shared.seal)
1469 }
1470
1471 #[inline(always)]
1473 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1474 &self.shared
1475 }
1476
1477 #[inline(always)]
1479 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1480 self.beacon_chain_info
1481 }
1482
1483 #[inline]
1485 pub fn pre_seal_hash(&self) -> Blake3Hash {
1486 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1488 }
1489
1490 #[inline]
1493 pub fn is_sealed_correctly(&self) -> bool {
1494 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1495 && self.seal.is_seal_valid(&self.pre_seal_hash())
1496 }
1497
1498 #[inline]
1506 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1507 let Self {
1508 shared,
1509 beacon_chain_info,
1510 pre_seal_bytes: _,
1511 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1512 cached_block_root,
1513 } = self;
1514
1515 let compute_root = || {
1516 let SharedBlockHeader {
1517 prefix,
1518 result,
1519 consensus_info,
1520 seal,
1521 } = shared;
1522
1523 let block_root = UnbalancedMerkleTree::compute_root_only_array(&[
1524 prefix.hash(),
1525 result.hash(),
1526 consensus_info.hash(),
1527 seal.hash(),
1528 beacon_chain_info.hash(),
1529 ]);
1530
1531 BlockRoot::new(Blake3Hash::new(block_root))
1532 };
1533
1534 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1535 {
1536 cached_block_root.get_or_init(compute_root)
1537 }
1538 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1539 {
1540 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1541 }
1542 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1543 {
1544 struct Wrapper(BlockRoot);
1545
1546 impl Deref for Wrapper {
1547 type Target = BlockRoot;
1548
1549 #[inline(always)]
1550 fn deref(&self) -> &Self::Target {
1551 &self.0
1552 }
1553 }
1554
1555 Wrapper(compute_root())
1556 }
1557 }
1558}
1559
1560#[derive(Debug, Clone, From)]
1565pub enum BlockHeader<'a> {
1566 BeaconChain(BeaconChainHeader<'a>),
1568 IntermediateShard(IntermediateShardHeader<'a>),
1570 LeafShard(LeafShardHeader<'a>),
1572}
1573
1574impl<'a> Deref for BlockHeader<'a> {
1575 type Target = SharedBlockHeader<'a>;
1576
1577 #[inline(always)]
1578 fn deref(&self) -> &Self::Target {
1579 match self {
1580 Self::BeaconChain(header) => header,
1581 Self::IntermediateShard(header) => header,
1582 Self::LeafShard(header) => header,
1583 }
1584 }
1585}
1586
1587impl<'a> BlockHeader<'a> {
1588 #[inline]
1595 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1596 match shard_kind {
1597 RealShardKind::BeaconChain => {
1598 let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1599 Some((Self::BeaconChain(header), remainder))
1600 }
1601 RealShardKind::IntermediateShard => {
1602 let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1603 Some((Self::IntermediateShard(header), remainder))
1604 }
1605 RealShardKind::LeafShard => {
1606 let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1607 Some((Self::LeafShard(header), remainder))
1608 }
1609 }
1610 }
1611
1612 #[inline]
1617 pub fn is_internally_consistent(&self) -> bool {
1618 match self {
1619 Self::BeaconChain(header) => header.is_internally_consistent(),
1620 Self::IntermediateShard(header) => header.is_internally_consistent(),
1621 Self::LeafShard(header) => header.is_internally_consistent(),
1622 }
1623 }
1624
1625 #[inline]
1628 pub fn try_from_bytes_unchecked(
1629 bytes: &'a [u8],
1630 shard_kind: RealShardKind,
1631 ) -> Option<(Self, &'a [u8])> {
1632 match shard_kind {
1633 RealShardKind::BeaconChain => {
1634 let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1635 Some((Self::BeaconChain(header), remainder))
1636 }
1637 RealShardKind::IntermediateShard => {
1638 let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1639 Some((Self::IntermediateShard(header), remainder))
1640 }
1641 RealShardKind::LeafShard => {
1642 let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1643 Some((Self::LeafShard(header), remainder))
1644 }
1645 }
1646 }
1647
1648 #[inline]
1649 fn try_from_bytes_shared(
1650 mut bytes: &'a [u8],
1651 ) -> Option<(
1652 &'a BlockHeaderPrefix,
1653 &'a BlockHeaderConsensusInfo,
1654 &'a BlockHeaderResult,
1655 &'a [u8],
1656 )> {
1657 let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1658 let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1660
1661 if !(prefix.padding_0 == [0; _]
1662 && u32::from(prefix.shard_index) <= ShardIndex::MAX_SHARD_INDEX)
1663 {
1664 return None;
1665 }
1666
1667 let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1668 let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1670
1671 let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1672 let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1674
1675 if consensus_info.solution.padding != [0; _] {
1676 return None;
1677 }
1678
1679 Some((prefix, consensus_info, result, bytes))
1680 }
1681
1682 #[cfg(feature = "alloc")]
1684 #[inline(always)]
1685 pub fn to_owned(self) -> OwnedBlockHeader {
1686 match self {
1687 Self::BeaconChain(header) => header.to_owned().into(),
1688 Self::IntermediateShard(header) => header.to_owned().into(),
1689 Self::LeafShard(header) => header.to_owned().into(),
1690 }
1691 }
1692
1693 #[inline]
1695 pub fn pre_seal_hash(&self) -> Blake3Hash {
1696 match self {
1697 Self::BeaconChain(header) => header.pre_seal_hash(),
1698 Self::IntermediateShard(header) => header.pre_seal_hash(),
1699 Self::LeafShard(header) => header.pre_seal_hash(),
1700 }
1701 }
1702
1703 #[inline]
1706 pub fn is_sealed_correctly(&self) -> bool {
1707 match self {
1708 Self::BeaconChain(header) => header.is_sealed_correctly(),
1709 Self::IntermediateShard(header) => header.is_sealed_correctly(),
1710 Self::LeafShard(header) => header.is_sealed_correctly(),
1711 }
1712 }
1713
1714 #[inline]
1722 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1723 enum Wrapper<B, I, L> {
1724 BeaconChain(B),
1725 IntermediateShard(I),
1726 LeafShard(L),
1727 }
1728
1729 impl<B, I, L> Deref for Wrapper<B, I, L>
1730 where
1731 B: Deref<Target = BlockRoot>,
1732 I: Deref<Target = BlockRoot>,
1733 L: Deref<Target = BlockRoot>,
1734 {
1735 type Target = BlockRoot;
1736
1737 #[inline(always)]
1738 fn deref(&self) -> &Self::Target {
1739 match self {
1740 Wrapper::BeaconChain(block_root) => block_root,
1741 Wrapper::IntermediateShard(block_root) => block_root,
1742 Wrapper::LeafShard(block_root) => block_root,
1743 }
1744 }
1745 }
1746
1747 match self {
1749 Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1750 Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1751 Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1752 }
1753 }
1754}