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 #[cfg(feature = "ed25519")]
673 #[inline]
674 pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
675 match self {
676 BlockHeaderSeal::Ed25519(seal) => seal
677 .public_key
678 .verify(&seal.signature, pre_seal_hash.as_bytes())
679 .is_ok(),
680 }
681 }
682
683 #[inline]
685 pub fn public_key_hash(&self) -> Blake3Hash {
686 match self {
687 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
688 }
689 }
690
691 #[inline]
693 pub fn hash(&self) -> Blake3Hash {
694 match self {
695 BlockHeaderSeal::Ed25519(seal) => {
696 let mut hasher = blake3::Hasher::new();
698 hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
699 hasher.update(seal.as_bytes());
700
701 Blake3Hash::from(hasher.finalize())
702 }
703 }
704 }
705}
706
707#[derive(Debug, Copy, Clone)]
709pub struct SharedBlockHeader<'a> {
710 pub prefix: &'a BlockHeaderPrefix,
712 pub result: &'a BlockHeaderResult,
714 pub consensus_info: &'a BlockHeaderConsensusInfo,
716 pub seal: BlockHeaderSeal<'a>,
718}
719
720#[derive(Debug, Clone, Yokeable)]
722#[non_exhaustive]
724pub struct BeaconChainHeader<'a> {
725 shared: SharedBlockHeader<'a>,
727 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
729 consensus_parameters: BlockHeaderConsensusParameters<'a>,
731 pre_seal_bytes: &'a [u8],
733 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
734 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
735 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
736 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
737}
738
739impl<'a> Deref for BeaconChainHeader<'a> {
740 type Target = SharedBlockHeader<'a>;
741
742 #[inline(always)]
743 fn deref(&self) -> &Self::Target {
744 &self.shared
745 }
746}
747
748impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
749 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
750
751 #[cfg(feature = "alloc")]
752 type Owned = OwnedBeaconChainHeader;
753
754 #[cfg(feature = "alloc")]
755 #[inline(always)]
756 fn to_owned(self) -> Self::Owned {
757 self.to_owned()
758 }
759
760 #[inline(always)]
761 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
762 self.root()
763 }
764
765 #[inline(always)]
766 fn pre_seal_hash(&self) -> Blake3Hash {
767 self.pre_seal_hash()
768 }
769}
770
771impl<'a> BeaconChainHeader<'a> {
772 #[inline]
779 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
780 let (prefix, consensus_info, result, remainder) =
789 BlockHeader::try_from_bytes_shared(bytes)?;
790
791 if prefix.shard_index.shard_kind() != Some(ShardKind::BeaconChain) {
792 return None;
793 }
794
795 let (child_shard_blocks, remainder) =
796 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
797
798 let (consensus_parameters, remainder) =
799 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
800
801 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
802
803 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
804
805 let shared = SharedBlockHeader {
806 prefix,
807 result,
808 consensus_info,
809 seal,
810 };
811
812 let header = Self {
813 shared,
814 child_shard_blocks,
815 consensus_parameters,
816 pre_seal_bytes,
817 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
818 cached_block_root: rclite::Arc::default(),
819 };
820
821 if !header.is_internally_consistent() {
822 return None;
823 }
824
825 Some((header, remainder))
826 }
827
828 #[inline]
833 pub fn is_internally_consistent(&self) -> bool {
834 let public_key_hash = match self.seal {
835 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
836 };
837 public_key_hash == self.shared.consensus_info.solution.public_key_hash
838 }
839
840 #[inline]
843 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
844 let (prefix, consensus_info, result, remainder) =
853 BlockHeader::try_from_bytes_shared(bytes)?;
854
855 if prefix.shard_index.shard_kind() != Some(ShardKind::BeaconChain) {
856 return None;
857 }
858
859 let (child_shard_blocks, remainder) =
860 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
861
862 let (consensus_parameters, remainder) =
863 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
864
865 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
866
867 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
868
869 let shared = SharedBlockHeader {
870 prefix,
871 result,
872 consensus_info,
873 seal,
874 };
875
876 Some((
877 Self {
878 shared,
879 child_shard_blocks,
880 consensus_parameters,
881 pre_seal_bytes,
882 #[cfg(any(
883 feature = "alloc",
884 not(any(target_os = "none", target_os = "unknown"))
885 ))]
886 cached_block_root: rclite::Arc::default(),
887 },
888 remainder,
889 ))
890 }
891
892 #[cfg(feature = "alloc")]
894 #[inline(always)]
895 pub fn to_owned(self) -> OwnedBeaconChainHeader {
896 let unsealed = OwnedBeaconChainHeader::from_parts(
897 self.shared.prefix,
898 self.shared.result,
899 self.shared.consensus_info,
900 &self.child_shard_blocks,
901 &self.consensus_parameters,
902 )
903 .expect("`self` is always a valid invariant; qed");
904
905 unsealed.with_seal(self.shared.seal)
906 }
907
908 #[inline(always)]
910 pub fn shared(&self) -> &SharedBlockHeader<'a> {
911 &self.shared
912 }
913
914 #[inline(always)]
916 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
917 &self.child_shard_blocks
918 }
919
920 #[inline(always)]
922 pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
923 &self.consensus_parameters
924 }
925
926 #[inline]
928 pub fn pre_seal_hash(&self) -> Blake3Hash {
929 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
931 }
932
933 #[cfg(feature = "ed25519")]
936 #[inline]
937 pub fn is_sealed_correctly(&self) -> bool {
938 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
939 && self.seal.is_seal_valid(&self.pre_seal_hash())
940 }
941
942 #[inline]
950 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
951 let Self {
952 shared,
953 child_shard_blocks,
954 consensus_parameters,
955 pre_seal_bytes: _,
956 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
957 cached_block_root,
958 } = self;
959
960 let compute_root = || {
961 let SharedBlockHeader {
962 prefix,
963 result,
964 consensus_info,
965 seal,
966 } = shared;
967
968 let block_root = UnbalancedMerkleTree::compute_root_only_array(&[
969 prefix.hash(),
970 result.hash(),
971 consensus_info.hash(),
972 seal.hash(),
973 child_shard_blocks.root().unwrap_or_default(),
974 consensus_parameters.hash(),
975 ]);
976
977 BlockRoot::new(Blake3Hash::new(block_root))
978 };
979
980 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
981 {
982 cached_block_root.get_or_init(compute_root)
983 }
984 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
985 {
986 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
987 }
988 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
989 {
990 struct Wrapper(BlockRoot);
991
992 impl Deref for Wrapper {
993 type Target = BlockRoot;
994
995 #[inline(always)]
996 fn deref(&self) -> &Self::Target {
997 &self.0
998 }
999 }
1000
1001 Wrapper(compute_root())
1002 }
1003 }
1004}
1005
1006#[derive(Debug, Clone, Yokeable)]
1008#[non_exhaustive]
1010pub struct IntermediateShardHeader<'a> {
1011 shared: SharedBlockHeader<'a>,
1013 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1015 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
1017 pre_seal_bytes: &'a [u8],
1019 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1020 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1021 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1022 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1023}
1024
1025impl<'a> Deref for IntermediateShardHeader<'a> {
1026 type Target = SharedBlockHeader<'a>;
1027
1028 #[inline(always)]
1029 fn deref(&self) -> &Self::Target {
1030 &self.shared
1031 }
1032}
1033
1034impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
1035 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
1036
1037 #[cfg(feature = "alloc")]
1038 type Owned = OwnedIntermediateShardHeader;
1039
1040 #[cfg(feature = "alloc")]
1041 #[inline(always)]
1042 fn to_owned(self) -> Self::Owned {
1043 self.to_owned()
1044 }
1045
1046 #[inline(always)]
1047 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1048 self.root()
1049 }
1050
1051 #[inline(always)]
1052 fn pre_seal_hash(&self) -> Blake3Hash {
1053 self.pre_seal_hash()
1054 }
1055}
1056
1057impl<'a> IntermediateShardHeader<'a> {
1058 #[inline]
1065 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1066 let (prefix, consensus_info, result, mut remainder) =
1075 BlockHeader::try_from_bytes_shared(bytes)?;
1076
1077 if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1078 return None;
1079 }
1080
1081 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1082 let beacon_chain_info =
1084 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1085
1086 let (child_shard_blocks, remainder) =
1087 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1088
1089 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1090
1091 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1092
1093 let shared = SharedBlockHeader {
1094 prefix,
1095 result,
1096 consensus_info,
1097 seal,
1098 };
1099
1100 let header = Self {
1101 shared,
1102 beacon_chain_info,
1103 child_shard_blocks,
1104 pre_seal_bytes,
1105 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1106 cached_block_root: rclite::Arc::default(),
1107 };
1108
1109 if !header.is_internally_consistent() {
1110 return None;
1111 }
1112
1113 Some((header, remainder))
1114 }
1115
1116 #[inline]
1121 pub fn is_internally_consistent(&self) -> bool {
1122 let public_key_hash = match self.seal {
1123 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1124 };
1125 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1126 }
1127
1128 #[inline]
1131 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1132 let (prefix, consensus_info, result, mut remainder) =
1141 BlockHeader::try_from_bytes_shared(bytes)?;
1142
1143 if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1144 return None;
1145 }
1146
1147 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1148 let beacon_chain_info =
1150 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1151
1152 let (child_shard_blocks, remainder) =
1153 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1154
1155 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1156
1157 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1158
1159 let shared = SharedBlockHeader {
1160 prefix,
1161 result,
1162 consensus_info,
1163 seal,
1164 };
1165
1166 Some((
1167 Self {
1168 shared,
1169 beacon_chain_info,
1170 child_shard_blocks,
1171 pre_seal_bytes,
1172 #[cfg(any(
1173 feature = "alloc",
1174 not(any(target_os = "none", target_os = "unknown"))
1175 ))]
1176 cached_block_root: rclite::Arc::default(),
1177 },
1178 remainder,
1179 ))
1180 }
1181
1182 #[cfg(feature = "alloc")]
1184 #[inline(always)]
1185 pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1186 let unsealed = OwnedIntermediateShardHeader::from_parts(
1187 self.shared.prefix,
1188 self.shared.result,
1189 self.shared.consensus_info,
1190 self.beacon_chain_info,
1191 &self.child_shard_blocks,
1192 )
1193 .expect("`self` is always a valid invariant; qed");
1194
1195 unsealed.with_seal(self.shared.seal)
1196 }
1197
1198 #[inline(always)]
1200 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1201 &self.shared
1202 }
1203
1204 #[inline(always)]
1206 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1207 self.beacon_chain_info
1208 }
1209
1210 #[inline(always)]
1212 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1213 &self.child_shard_blocks
1214 }
1215
1216 #[inline]
1218 pub fn pre_seal_hash(&self) -> Blake3Hash {
1219 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1221 }
1222
1223 #[cfg(feature = "ed25519")]
1226 #[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 #[cfg(feature = "ed25519")]
1496 #[inline]
1497 pub fn is_sealed_correctly(&self) -> bool {
1498 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1499 && self.seal.is_seal_valid(&self.pre_seal_hash())
1500 }
1501
1502 #[inline]
1510 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1511 let Self {
1512 shared,
1513 beacon_chain_info,
1514 pre_seal_bytes: _,
1515 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1516 cached_block_root,
1517 } = self;
1518
1519 let compute_root = || {
1520 let SharedBlockHeader {
1521 prefix,
1522 result,
1523 consensus_info,
1524 seal,
1525 } = shared;
1526
1527 let block_root = UnbalancedMerkleTree::compute_root_only_array(&[
1528 prefix.hash(),
1529 result.hash(),
1530 consensus_info.hash(),
1531 seal.hash(),
1532 beacon_chain_info.hash(),
1533 ]);
1534
1535 BlockRoot::new(Blake3Hash::new(block_root))
1536 };
1537
1538 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1539 {
1540 cached_block_root.get_or_init(compute_root)
1541 }
1542 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1543 {
1544 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1545 }
1546 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1547 {
1548 struct Wrapper(BlockRoot);
1549
1550 impl Deref for Wrapper {
1551 type Target = BlockRoot;
1552
1553 #[inline(always)]
1554 fn deref(&self) -> &Self::Target {
1555 &self.0
1556 }
1557 }
1558
1559 Wrapper(compute_root())
1560 }
1561 }
1562}
1563
1564#[derive(Debug, Clone, From)]
1569pub enum BlockHeader<'a> {
1570 BeaconChain(BeaconChainHeader<'a>),
1572 IntermediateShard(IntermediateShardHeader<'a>),
1574 LeafShard(LeafShardHeader<'a>),
1576}
1577
1578impl<'a> Deref for BlockHeader<'a> {
1579 type Target = SharedBlockHeader<'a>;
1580
1581 #[inline(always)]
1582 fn deref(&self) -> &Self::Target {
1583 match self {
1584 Self::BeaconChain(header) => header,
1585 Self::IntermediateShard(header) => header,
1586 Self::LeafShard(header) => header,
1587 }
1588 }
1589}
1590
1591impl<'a> BlockHeader<'a> {
1592 #[inline]
1599 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1600 match shard_kind {
1601 RealShardKind::BeaconChain => {
1602 let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1603 Some((Self::BeaconChain(header), remainder))
1604 }
1605 RealShardKind::IntermediateShard => {
1606 let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1607 Some((Self::IntermediateShard(header), remainder))
1608 }
1609 RealShardKind::LeafShard => {
1610 let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1611 Some((Self::LeafShard(header), remainder))
1612 }
1613 }
1614 }
1615
1616 #[inline]
1621 pub fn is_internally_consistent(&self) -> bool {
1622 match self {
1623 Self::BeaconChain(header) => header.is_internally_consistent(),
1624 Self::IntermediateShard(header) => header.is_internally_consistent(),
1625 Self::LeafShard(header) => header.is_internally_consistent(),
1626 }
1627 }
1628
1629 #[inline]
1632 pub fn try_from_bytes_unchecked(
1633 bytes: &'a [u8],
1634 shard_kind: RealShardKind,
1635 ) -> Option<(Self, &'a [u8])> {
1636 match shard_kind {
1637 RealShardKind::BeaconChain => {
1638 let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1639 Some((Self::BeaconChain(header), remainder))
1640 }
1641 RealShardKind::IntermediateShard => {
1642 let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1643 Some((Self::IntermediateShard(header), remainder))
1644 }
1645 RealShardKind::LeafShard => {
1646 let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1647 Some((Self::LeafShard(header), remainder))
1648 }
1649 }
1650 }
1651
1652 #[inline]
1653 fn try_from_bytes_shared(
1654 mut bytes: &'a [u8],
1655 ) -> Option<(
1656 &'a BlockHeaderPrefix,
1657 &'a BlockHeaderConsensusInfo,
1658 &'a BlockHeaderResult,
1659 &'a [u8],
1660 )> {
1661 let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1662 let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1664
1665 if !(prefix.padding_0 == [0; _]
1666 && u32::from(prefix.shard_index) <= ShardIndex::MAX_SHARD_INDEX)
1667 {
1668 return None;
1669 }
1670
1671 let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1672 let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1674
1675 let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1676 let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1678
1679 if consensus_info.solution.padding != [0; _] {
1680 return None;
1681 }
1682
1683 Some((prefix, consensus_info, result, bytes))
1684 }
1685
1686 #[cfg(feature = "alloc")]
1688 #[inline(always)]
1689 pub fn to_owned(self) -> OwnedBlockHeader {
1690 match self {
1691 Self::BeaconChain(header) => header.to_owned().into(),
1692 Self::IntermediateShard(header) => header.to_owned().into(),
1693 Self::LeafShard(header) => header.to_owned().into(),
1694 }
1695 }
1696
1697 #[inline]
1699 pub fn pre_seal_hash(&self) -> Blake3Hash {
1700 match self {
1701 Self::BeaconChain(header) => header.pre_seal_hash(),
1702 Self::IntermediateShard(header) => header.pre_seal_hash(),
1703 Self::LeafShard(header) => header.pre_seal_hash(),
1704 }
1705 }
1706
1707 #[cfg(feature = "ed25519")]
1710 #[inline]
1711 pub fn is_sealed_correctly(&self) -> bool {
1712 match self {
1713 Self::BeaconChain(header) => header.is_sealed_correctly(),
1714 Self::IntermediateShard(header) => header.is_sealed_correctly(),
1715 Self::LeafShard(header) => header.is_sealed_correctly(),
1716 }
1717 }
1718
1719 #[inline]
1727 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1728 enum Wrapper<B, I, L> {
1729 BeaconChain(B),
1730 IntermediateShard(I),
1731 LeafShard(L),
1732 }
1733
1734 impl<B, I, L> Deref for Wrapper<B, I, L>
1735 where
1736 B: Deref<Target = BlockRoot>,
1737 I: Deref<Target = BlockRoot>,
1738 L: Deref<Target = BlockRoot>,
1739 {
1740 type Target = BlockRoot;
1741
1742 #[inline(always)]
1743 fn deref(&self) -> &Self::Target {
1744 match self {
1745 Wrapper::BeaconChain(block_root) => block_root,
1746 Wrapper::IntermediateShard(block_root) => block_root,
1747 Wrapper::LeafShard(block_root) => block_root,
1748 }
1749 }
1750 }
1751
1752 match self {
1754 Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1755 Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1756 Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1757 }
1758 }
1759}