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::{ShardIndex, ShardKind};
17use crate::solutions::{Solution, SolutionRange};
18use ab_io_type::trivial_type::TrivialType;
19use ab_merkle_tree::unbalanced::UnbalancedMerkleTree;
20use core::num::NonZeroU32;
21use core::ops::Deref;
22use core::{fmt, slice};
23use derive_more::{Deref, From};
24#[cfg(feature = "scale-codec")]
25use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
26#[cfg(feature = "scale-codec")]
27use scale_info::TypeInfo;
28#[cfg(feature = "serde")]
29use serde::{Deserialize, Serialize};
30use yoke::Yokeable;
31
32pub trait GenericBlockHeader<'a>
34where
35 Self: Clone + fmt::Debug + Deref<Target = SharedBlockHeader<'a>>,
36{
37 #[cfg(feature = "alloc")]
39 type Owned: GenericOwnedBlockHeader<Header<'a> = Self>
40 where
41 Self: 'a;
42
43 #[cfg(feature = "alloc")]
45 fn to_owned(self) -> Self::Owned;
46
47 fn root(&self) -> impl Deref<Target = BlockRoot>;
54}
55
56#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
60#[cfg_attr(
61 feature = "scale-codec",
62 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
63)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
66#[repr(C)]
67pub struct BlockHeaderPrefix {
68 pub number: BlockNumber,
70 pub shard_index: ShardIndex,
72 pub padding_0: [u8; 4],
74 pub timestamp: BlockTimestamp,
76 pub parent_root: BlockRoot,
78 pub mmr_root: Blake3Hash,
81}
82
83impl BlockHeaderPrefix {
84 pub fn hash(&self) -> Blake3Hash {
86 Blake3Hash::from(blake3::hash(self.as_bytes()))
88 }
89}
90
91#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
93#[cfg_attr(
94 feature = "scale-codec",
95 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
96)]
97#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
98#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
99#[repr(C)]
100pub struct BlockHeaderConsensusInfo {
101 pub slot: SlotNumber,
103 pub proof_of_time: PotOutput,
105 pub future_proof_of_time: PotOutput,
107 pub solution: Solution,
109}
110
111impl BlockHeaderConsensusInfo {
112 pub fn hash(&self) -> Blake3Hash {
114 Blake3Hash::from(blake3::hash(self.as_bytes()))
116 }
117}
118
119#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, TrivialType)]
121#[cfg_attr(
122 feature = "scale-codec",
123 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
124)]
125#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
126#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
127#[repr(C)]
128pub struct BlockHeaderBeaconChainInfo {
129 pub number: BlockNumber,
131 pub root: BlockRoot,
133}
134
135impl BlockHeaderBeaconChainInfo {
136 pub fn hash(&self) -> Blake3Hash {
138 Blake3Hash::from(blake3::hash(self.as_bytes()))
140 }
141}
142
143#[derive(Debug, Copy, Clone, Eq, PartialEq)]
145#[cfg_attr(
146 feature = "scale-codec",
147 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
148)]
149#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
150#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
151pub struct BlockHeaderFixedConsensusParameters {
152 pub solution_range: SolutionRange,
154 pub slot_iterations: NonZeroU32,
159}
160
161impl BlockHeaderFixedConsensusParameters {
162 #[inline]
168 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(Self, &[u8])> {
169 let solution_range = bytes.split_off(..size_of::<SolutionRange>())?;
174 let solution_range = SolutionRange::from_bytes([
175 solution_range[0],
176 solution_range[1],
177 solution_range[2],
178 solution_range[3],
179 solution_range[4],
180 solution_range[5],
181 solution_range[6],
182 solution_range[7],
183 ]);
184
185 let pot_slot_iterations = bytes.split_off(..size_of::<u32>())?;
186 let slot_iterations = u32::from_le_bytes([
187 pot_slot_iterations[0],
188 pot_slot_iterations[1],
189 pot_slot_iterations[2],
190 pot_slot_iterations[3],
191 ]);
192 let slot_iterations = NonZeroU32::new(slot_iterations)?;
193
194 Some((
195 Self {
196 solution_range,
197 slot_iterations,
198 },
199 bytes,
200 ))
201 }
202}
203
204#[derive(Debug, Copy, Clone, Eq, PartialEq)]
208#[repr(C, packed)]
209pub struct BlockHeaderPotParametersChange {
210 slot: SlotNumber,
214 slot_iterations: NonZeroU32,
216 entropy: Blake3Hash,
218}
219
220impl From<BlockHeaderPotParametersChange> for PotParametersChange {
221 #[inline(always)]
222 fn from(value: BlockHeaderPotParametersChange) -> Self {
223 let BlockHeaderPotParametersChange {
224 slot,
225 slot_iterations,
226 entropy,
227 } = value;
228
229 PotParametersChange {
230 slot,
231 slot_iterations,
232 entropy,
233 }
234 }
235}
236
237impl From<PotParametersChange> for BlockHeaderPotParametersChange {
238 #[inline(always)]
239 fn from(value: PotParametersChange) -> Self {
240 let PotParametersChange {
241 slot,
242 slot_iterations,
243 entropy,
244 } = value;
245
246 BlockHeaderPotParametersChange {
247 slot,
248 slot_iterations,
249 entropy,
250 }
251 }
252}
253
254impl BlockHeaderPotParametersChange {
255 #[inline]
261 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(&Self, &[u8])> {
262 let _slot = bytes.split_off(..size_of::<SlotNumber>())?;
268
269 let slot_iterations = bytes.split_off(..size_of::<u32>())?;
270 if slot_iterations == [0, 0, 0, 0] {
271 return None;
272 }
273 let _entropy = bytes.split_off(..size_of::<Blake3Hash>())?;
274
275 let pot_parameters_change = unsafe { bytes.as_ptr().cast::<Self>().as_ref_unchecked() };
277
278 Some((pot_parameters_change, bytes))
279 }
280}
281
282#[derive(Debug, Copy, Clone)]
284pub struct OwnedBlockHeaderConsensusParameters {
285 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
287 pub super_segment_root: Option<SuperSegmentRoot>,
289 pub next_solution_range: Option<SolutionRange>,
291 pub pot_parameters_change: Option<BlockHeaderPotParametersChange>,
293}
294
295impl OwnedBlockHeaderConsensusParameters {
296 #[inline]
298 pub fn as_ref(&self) -> BlockHeaderConsensusParameters<'_> {
299 BlockHeaderConsensusParameters {
300 fixed_parameters: self.fixed_parameters,
301 super_segment_root: self.super_segment_root.as_ref(),
302 next_solution_range: self.next_solution_range,
303 pot_parameters_change: self.pot_parameters_change.as_ref(),
304 }
305 }
306}
307
308#[derive(Debug, Copy, Clone, Eq, PartialEq)]
310pub struct BlockHeaderConsensusParameters<'a> {
311 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
313 pub super_segment_root: Option<&'a SuperSegmentRoot>,
315 pub next_solution_range: Option<SolutionRange>,
317 pub pot_parameters_change: Option<&'a BlockHeaderPotParametersChange>,
319}
320
321impl<'a> BlockHeaderConsensusParameters<'a> {
322 pub const MAX_SIZE: u32 = size_of::<BlockHeaderFixedConsensusParameters>() as u32
324 + u8::SIZE
325 + <SuperSegmentRoot as TrivialType>::SIZE
326 + <SolutionRange as TrivialType>::SIZE
327 + size_of::<BlockHeaderPotParametersChange>() as u32;
328 pub const SUPER_SEGMENT_ROOT_MASK: u8 = 0b_0000_0001;
330 pub const NEXT_SOLUTION_RANGE_MASK: u8 = 0b_0000_0010;
332 pub const POT_PARAMETERS_CHANGE_MASK: u8 = 0b_0000_0100;
334
335 #[inline]
341 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
342 let (fixed_parameters, mut remainder) =
350 BlockHeaderFixedConsensusParameters::try_from_bytes(bytes)?;
351
352 let bitflags = remainder.split_off(..size_of::<u8>())?;
353 let bitflags = bitflags[0];
354
355 let super_segment_root = if bitflags & Self::SUPER_SEGMENT_ROOT_MASK != 0 {
356 let super_segment_root = remainder.split_off(..size_of::<SuperSegmentRoot>())?;
357 let super_segment_root = unsafe { SuperSegmentRoot::from_bytes(super_segment_root) }?;
359
360 Some(super_segment_root)
361 } else {
362 None
363 };
364
365 let next_solution_range = if bitflags & Self::NEXT_SOLUTION_RANGE_MASK != 0 {
366 let next_solution_range = remainder.split_off(..size_of::<SolutionRange>())?;
367 let next_solution_range = SolutionRange::from_bytes([
369 next_solution_range[0],
370 next_solution_range[1],
371 next_solution_range[2],
372 next_solution_range[3],
373 next_solution_range[4],
374 next_solution_range[5],
375 next_solution_range[6],
376 next_solution_range[7],
377 ]);
378
379 Some(next_solution_range)
380 } else {
381 None
382 };
383
384 let pot_parameters_change = if bitflags & Self::POT_PARAMETERS_CHANGE_MASK != 0 {
385 let pot_parameters_change;
386 (pot_parameters_change, remainder) =
387 BlockHeaderPotParametersChange::try_from_bytes(remainder)?;
388
389 Some(pot_parameters_change)
390 } else {
391 None
392 };
393
394 Some((
395 Self {
396 super_segment_root,
397 fixed_parameters,
398 next_solution_range,
399 pot_parameters_change,
400 },
401 remainder,
402 ))
403 }
404
405 pub fn hash(&self) -> Blake3Hash {
407 let Self {
408 super_segment_root,
409 fixed_parameters,
410 next_solution_range,
411 pot_parameters_change,
412 } = self;
413 let BlockHeaderFixedConsensusParameters {
414 solution_range,
415 slot_iterations,
416 } = fixed_parameters;
417
418 let mut hasher = blake3::Hasher::new();
420 hasher.update(solution_range.as_bytes());
421 hasher.update(&slot_iterations.get().to_le_bytes());
422
423 if let Some(super_segment_root) = super_segment_root {
424 hasher.update(super_segment_root.as_bytes());
425 }
426 if let Some(next_solution_range) = next_solution_range {
427 hasher.update(next_solution_range.as_bytes());
428 }
429 if let Some(pot_parameters_change) = pot_parameters_change.copied() {
430 let BlockHeaderPotParametersChange {
431 slot,
432 slot_iterations,
433 entropy,
434 } = pot_parameters_change;
435 hasher.update(slot.as_bytes());
436 hasher.update(&slot_iterations.get().to_le_bytes());
437 hasher.update(entropy.as_bytes());
438 }
439
440 Blake3Hash::from(hasher.finalize())
441 }
442}
443
444#[derive(Debug, Copy, Clone, Deref)]
446pub struct BlockHeaderChildShardBlocks<'a> {
447 pub child_shard_blocks: &'a [BlockRoot],
449}
450
451impl<'a> BlockHeaderChildShardBlocks<'a> {
452 #[inline]
458 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
459 let length = bytes.split_off(..size_of::<u16>())?;
465 let num_blocks = usize::from(*unsafe { <u16 as TrivialType>::from_bytes(length) }?);
467
468 let padding = bytes.split_off(..size_of::<[u8; 2]>())?;
469
470 if padding != [0, 0] {
472 return None;
473 }
474
475 let child_shard_blocks = bytes.split_off(..num_blocks * BlockRoot::SIZE)?;
476 let child_shard_blocks = unsafe {
478 slice::from_raw_parts(
479 child_shard_blocks.as_ptr().cast::<[u8; BlockRoot::SIZE]>(),
480 num_blocks,
481 )
482 };
483 let child_shard_blocks = BlockRoot::slice_from_repr(child_shard_blocks);
484
485 Some((Self { child_shard_blocks }, bytes))
486 }
487
488 pub fn root(&self) -> Option<Blake3Hash> {
492 let root = UnbalancedMerkleTree::compute_root_only::<'_, { u32::MAX as u64 }, _, _>(
493 self.child_shard_blocks
495 .iter()
496 .map(|child_shard_block_root| {
497 blake3::hash(child_shard_block_root.as_ref())
502 }),
503 )?;
504 Some(Blake3Hash::new(root))
505 }
506}
507
508#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
512#[cfg_attr(
513 feature = "scale-codec",
514 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
515)]
516#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
517#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
518#[repr(C)]
519pub struct BlockHeaderResult {
520 pub body_root: Blake3Hash,
523 pub state_root: Blake3Hash,
526}
527
528impl BlockHeaderResult {
529 pub fn hash(&self) -> Blake3Hash {
531 Blake3Hash::from(blake3::hash(self.as_bytes()))
533 }
534}
535
536#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
538#[cfg_attr(
539 feature = "scale-codec",
540 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
541)]
542#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
543#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
544#[repr(u8)]
545#[non_exhaustive]
546pub enum BlockHeaderSealType {
547 #[cfg_attr(feature = "scale-codec", codec(index = 0))]
549 Ed25519 = 0,
550}
551
552impl BlockHeaderSealType {
553 #[inline(always)]
555 pub const fn try_from_byte(byte: u8) -> Option<Self> {
556 if byte == Self::Ed25519 as u8 {
557 Some(Self::Ed25519)
558 } else {
559 None
560 }
561 }
562}
563
564#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
566#[cfg_attr(
567 feature = "scale-codec",
568 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
569)]
570#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
571#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
572#[repr(C)]
573pub struct BlockHeaderEd25519Seal {
574 pub public_key: Ed25519PublicKey,
576 pub signature: Ed25519Signature,
578}
579
580#[derive(Debug, Copy, Clone)]
582#[cfg_attr(
583 feature = "scale-codec",
584 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
585)]
586#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
587#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
588#[non_exhaustive]
589pub enum OwnedBlockHeaderSeal {
590 Ed25519(BlockHeaderEd25519Seal),
592}
593
594impl OwnedBlockHeaderSeal {
595 #[inline(always)]
597 pub fn as_ref(&self) -> BlockHeaderSeal<'_> {
598 match self {
599 Self::Ed25519(seal) => BlockHeaderSeal::Ed25519(seal),
600 }
601 }
602}
603
604#[derive(Debug, Copy, Clone)]
606#[non_exhaustive]
607pub enum BlockHeaderSeal<'a> {
608 Ed25519(&'a BlockHeaderEd25519Seal),
610}
611
612impl<'a> BlockHeaderSeal<'a> {
613 pub const MAX_SIZE: u32 = 1 + BlockHeaderEd25519Seal::SIZE;
615 #[inline]
621 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
622 let seal_type = bytes.split_off(..size_of::<u8>())?;
627 let seal_type = BlockHeaderSealType::try_from_byte(seal_type[0])?;
628
629 match seal_type {
630 BlockHeaderSealType::Ed25519 => {
631 let seal = bytes.split_off(..size_of::<BlockHeaderEd25519Seal>())?;
632 let seal = unsafe { BlockHeaderEd25519Seal::from_bytes(seal) }?;
634 Some((Self::Ed25519(seal), bytes))
635 }
636 }
637 }
638
639 #[inline]
641 pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
642 match self {
643 BlockHeaderSeal::Ed25519(seal) => seal
644 .public_key
645 .verify(&seal.signature, pre_seal_hash.as_bytes())
646 .is_ok(),
647 }
648 }
649
650 #[inline]
652 pub fn public_key_hash(&self) -> Blake3Hash {
653 match self {
654 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
655 }
656 }
657
658 #[inline]
660 pub fn hash(&self) -> Blake3Hash {
661 match self {
662 BlockHeaderSeal::Ed25519(seal) => {
663 let mut hasher = blake3::Hasher::new();
665 hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
666 hasher.update(seal.as_bytes());
667
668 Blake3Hash::from(hasher.finalize())
669 }
670 }
671 }
672}
673
674#[derive(Debug, Copy, Clone)]
676pub struct SharedBlockHeader<'a> {
677 pub prefix: &'a BlockHeaderPrefix,
679 pub result: &'a BlockHeaderResult,
681 pub consensus_info: &'a BlockHeaderConsensusInfo,
683 pub seal: BlockHeaderSeal<'a>,
685}
686
687#[derive(Debug, Clone, Yokeable)]
689#[non_exhaustive]
691pub struct BeaconChainHeader<'a> {
692 shared: SharedBlockHeader<'a>,
694 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
696 consensus_parameters: BlockHeaderConsensusParameters<'a>,
698 pre_seal_bytes: &'a [u8],
700 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
701 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
702 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
703 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
704}
705
706impl<'a> Deref for BeaconChainHeader<'a> {
707 type Target = SharedBlockHeader<'a>;
708
709 #[inline(always)]
710 fn deref(&self) -> &Self::Target {
711 &self.shared
712 }
713}
714
715impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
716 #[cfg(feature = "alloc")]
717 type Owned = OwnedBeaconChainHeader;
718
719 #[cfg(feature = "alloc")]
720 #[inline(always)]
721 fn to_owned(self) -> Self::Owned {
722 self.to_owned()
723 }
724
725 #[inline(always)]
726 fn root(&self) -> impl Deref<Target = BlockRoot> {
727 self.root()
728 }
729}
730
731impl<'a> BeaconChainHeader<'a> {
732 #[inline]
739 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
740 let (prefix, consensus_info, result, remainder) =
749 BlockHeader::try_from_bytes_shared(bytes)?;
750
751 if prefix.shard_index.shard_kind() != ShardKind::BeaconChain {
752 return None;
753 }
754
755 let (child_shard_blocks, remainder) =
756 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
757
758 let (consensus_parameters, remainder) =
759 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
760
761 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
762
763 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
764
765 let shared = SharedBlockHeader {
766 prefix,
767 result,
768 consensus_info,
769 seal,
770 };
771
772 let header = Self {
773 shared,
774 child_shard_blocks,
775 consensus_parameters,
776 pre_seal_bytes,
777 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
778 cached_block_root: rclite::Arc::default(),
779 };
780
781 if !header.is_internally_consistent() {
782 return None;
783 }
784
785 Some((header, remainder))
786 }
787
788 #[inline]
793 pub fn is_internally_consistent(&self) -> bool {
794 let public_key_hash = match self.seal {
795 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
796 };
797 public_key_hash == self.shared.consensus_info.solution.public_key_hash
798 }
799
800 #[inline]
803 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
804 let (prefix, consensus_info, result, remainder) =
813 BlockHeader::try_from_bytes_shared(bytes)?;
814
815 if prefix.shard_index.shard_kind() != ShardKind::BeaconChain {
816 return None;
817 }
818
819 let (child_shard_blocks, remainder) =
820 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
821
822 let (consensus_parameters, remainder) =
823 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
824
825 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
826
827 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
828
829 let shared = SharedBlockHeader {
830 prefix,
831 result,
832 consensus_info,
833 seal,
834 };
835
836 Some((
837 Self {
838 shared,
839 child_shard_blocks,
840 consensus_parameters,
841 pre_seal_bytes,
842 #[cfg(any(
843 feature = "alloc",
844 not(any(target_os = "none", target_os = "unknown"))
845 ))]
846 cached_block_root: rclite::Arc::default(),
847 },
848 remainder,
849 ))
850 }
851
852 #[cfg(feature = "alloc")]
854 #[inline(always)]
855 pub fn to_owned(self) -> OwnedBeaconChainHeader {
856 let unsealed = OwnedBeaconChainHeader::from_parts(
857 self.shared.prefix,
858 self.shared.result,
859 self.shared.consensus_info,
860 &self.child_shard_blocks,
861 self.consensus_parameters,
862 )
863 .expect("`self` is always a valid invariant; qed");
864
865 unsealed.with_seal(self.shared.seal)
866 }
867
868 #[inline(always)]
870 pub fn shared(&self) -> &SharedBlockHeader<'a> {
871 &self.shared
872 }
873
874 #[inline(always)]
876 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
877 &self.child_shard_blocks
878 }
879
880 #[inline(always)]
882 pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
883 &self.consensus_parameters
884 }
885
886 #[inline]
888 pub fn pre_seal_hash(&self) -> Blake3Hash {
889 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
891 }
892
893 #[inline]
896 pub fn is_sealed_correctly(&self) -> bool {
897 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
898 && self.seal.is_seal_valid(&self.pre_seal_hash())
899 }
900
901 #[inline]
909 pub fn root(&self) -> impl Deref<Target = BlockRoot> {
910 let Self {
911 shared,
912 child_shard_blocks,
913 consensus_parameters,
914 pre_seal_bytes: _,
915 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
916 cached_block_root,
917 } = self;
918
919 let compute_root = || {
920 let SharedBlockHeader {
921 prefix,
922 result,
923 consensus_info,
924 seal,
925 } = shared;
926
927 const MAX_N: usize = 6;
928 let leaves: [_; MAX_N] = [
929 prefix.hash(),
930 result.hash(),
931 consensus_info.hash(),
932 seal.hash(),
933 child_shard_blocks.root().unwrap_or_default(),
934 consensus_parameters.hash(),
935 ];
936 let block_root =
937 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
938 .expect("The list is not empty; qed");
939
940 BlockRoot::new(Blake3Hash::new(block_root))
941 };
942
943 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
944 {
945 cached_block_root.get_or_init(compute_root)
946 }
947 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
948 {
949 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
950 }
951 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
952 {
953 struct Wrapper(BlockRoot);
954
955 impl Deref for Wrapper {
956 type Target = BlockRoot;
957
958 #[inline(always)]
959 fn deref(&self) -> &Self::Target {
960 &self.0
961 }
962 }
963
964 Wrapper(compute_root())
965 }
966 }
967}
968
969#[derive(Debug, Clone, Yokeable)]
971#[non_exhaustive]
973pub struct IntermediateShardHeader<'a> {
974 shared: SharedBlockHeader<'a>,
976 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
978 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
980 pre_seal_bytes: &'a [u8],
982 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
983 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
984 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
985 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
986}
987
988impl<'a> Deref for IntermediateShardHeader<'a> {
989 type Target = SharedBlockHeader<'a>;
990
991 #[inline(always)]
992 fn deref(&self) -> &Self::Target {
993 &self.shared
994 }
995}
996
997impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
998 #[cfg(feature = "alloc")]
999 type Owned = OwnedIntermediateShardHeader;
1000
1001 #[cfg(feature = "alloc")]
1002 #[inline(always)]
1003 fn to_owned(self) -> Self::Owned {
1004 self.to_owned()
1005 }
1006
1007 #[inline(always)]
1008 fn root(&self) -> impl Deref<Target = BlockRoot> {
1009 self.root()
1010 }
1011}
1012
1013impl<'a> IntermediateShardHeader<'a> {
1014 #[inline]
1021 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1022 let (prefix, consensus_info, result, mut remainder) =
1031 BlockHeader::try_from_bytes_shared(bytes)?;
1032
1033 if prefix.shard_index.shard_kind() != ShardKind::IntermediateShard {
1034 return None;
1035 }
1036
1037 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1038 let beacon_chain_info =
1040 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1041
1042 let (child_shard_blocks, remainder) =
1043 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1044
1045 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1046
1047 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1048
1049 let shared = SharedBlockHeader {
1050 prefix,
1051 result,
1052 consensus_info,
1053 seal,
1054 };
1055
1056 let header = Self {
1057 shared,
1058 beacon_chain_info,
1059 child_shard_blocks,
1060 pre_seal_bytes,
1061 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1062 cached_block_root: rclite::Arc::default(),
1063 };
1064
1065 if !header.is_internally_consistent() {
1066 return None;
1067 }
1068
1069 Some((header, remainder))
1070 }
1071
1072 #[inline]
1077 pub fn is_internally_consistent(&self) -> bool {
1078 let public_key_hash = match self.seal {
1079 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1080 };
1081 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1082 }
1083
1084 #[inline]
1087 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1088 let (prefix, consensus_info, result, mut remainder) =
1097 BlockHeader::try_from_bytes_shared(bytes)?;
1098
1099 if prefix.shard_index.shard_kind() != ShardKind::IntermediateShard {
1100 return None;
1101 }
1102
1103 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1104 let beacon_chain_info =
1106 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1107
1108 let (child_shard_blocks, remainder) =
1109 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1110
1111 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1112
1113 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1114
1115 let shared = SharedBlockHeader {
1116 prefix,
1117 result,
1118 consensus_info,
1119 seal,
1120 };
1121
1122 Some((
1123 Self {
1124 shared,
1125 beacon_chain_info,
1126 child_shard_blocks,
1127 pre_seal_bytes,
1128 #[cfg(any(
1129 feature = "alloc",
1130 not(any(target_os = "none", target_os = "unknown"))
1131 ))]
1132 cached_block_root: rclite::Arc::default(),
1133 },
1134 remainder,
1135 ))
1136 }
1137
1138 #[cfg(feature = "alloc")]
1140 #[inline(always)]
1141 pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1142 let unsealed = OwnedIntermediateShardHeader::from_parts(
1143 self.shared.prefix,
1144 self.shared.result,
1145 self.shared.consensus_info,
1146 self.beacon_chain_info,
1147 &self.child_shard_blocks,
1148 )
1149 .expect("`self` is always a valid invariant; qed");
1150
1151 unsealed.with_seal(self.shared.seal)
1152 }
1153
1154 #[inline(always)]
1156 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1157 &self.shared
1158 }
1159
1160 #[inline(always)]
1162 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1163 self.beacon_chain_info
1164 }
1165
1166 #[inline(always)]
1168 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1169 &self.child_shard_blocks
1170 }
1171
1172 #[inline]
1174 pub fn pre_seal_hash(&self) -> Blake3Hash {
1175 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1177 }
1178
1179 #[inline]
1182 pub fn is_sealed_correctly(&self) -> bool {
1183 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1184 && self.seal.is_seal_valid(&self.pre_seal_hash())
1185 }
1186
1187 #[inline]
1195 pub fn root(&self) -> impl Deref<Target = BlockRoot> {
1196 let Self {
1197 shared,
1198 beacon_chain_info,
1199 child_shard_blocks,
1200 pre_seal_bytes: _,
1201 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1202 cached_block_root,
1203 } = self;
1204
1205 let compute_root = || {
1206 let SharedBlockHeader {
1207 prefix,
1208 result,
1209 consensus_info,
1210 seal,
1211 } = shared;
1212
1213 const MAX_N: usize = 6;
1214 let leaves: [_; MAX_N] = [
1215 prefix.hash(),
1216 result.hash(),
1217 consensus_info.hash(),
1218 seal.hash(),
1219 beacon_chain_info.hash(),
1220 child_shard_blocks.root().unwrap_or_default(),
1221 ];
1222 let block_root =
1223 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1224 .expect("The list is not empty; qed");
1225
1226 BlockRoot::new(Blake3Hash::new(block_root))
1227 };
1228
1229 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1230 {
1231 cached_block_root.get_or_init(compute_root)
1232 }
1233 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1234 {
1235 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1236 }
1237 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1238 {
1239 struct Wrapper(BlockRoot);
1240
1241 impl Deref for Wrapper {
1242 type Target = BlockRoot;
1243
1244 #[inline(always)]
1245 fn deref(&self) -> &Self::Target {
1246 &self.0
1247 }
1248 }
1249
1250 Wrapper(compute_root())
1251 }
1252 }
1253}
1254
1255#[derive(Debug, Clone, Yokeable)]
1257#[non_exhaustive]
1259pub struct LeafShardHeader<'a> {
1260 shared: SharedBlockHeader<'a>,
1262 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1264 pre_seal_bytes: &'a [u8],
1266 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1267 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1268 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1269 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1270}
1271
1272impl<'a> Deref for LeafShardHeader<'a> {
1273 type Target = SharedBlockHeader<'a>;
1274
1275 #[inline(always)]
1276 fn deref(&self) -> &Self::Target {
1277 &self.shared
1278 }
1279}
1280
1281impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1282 #[cfg(feature = "alloc")]
1283 type Owned = OwnedLeafShardHeader;
1284
1285 #[cfg(feature = "alloc")]
1286 #[inline(always)]
1287 fn to_owned(self) -> Self::Owned {
1288 self.to_owned()
1289 }
1290
1291 #[inline(always)]
1292 fn root(&self) -> impl Deref<Target = BlockRoot> {
1293 self.root()
1294 }
1295}
1296
1297impl<'a> LeafShardHeader<'a> {
1298 #[inline]
1305 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1306 let (prefix, consensus_info, result, mut remainder) =
1314 BlockHeader::try_from_bytes_shared(bytes)?;
1315
1316 if prefix.shard_index.shard_kind() != ShardKind::LeafShard {
1317 return None;
1318 }
1319
1320 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1321 let beacon_chain_info =
1323 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1324
1325 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1326
1327 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1328
1329 let shared = SharedBlockHeader {
1330 prefix,
1331 result,
1332 consensus_info,
1333 seal,
1334 };
1335
1336 let header = Self {
1337 shared,
1338 beacon_chain_info,
1339 pre_seal_bytes,
1340 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1341 cached_block_root: rclite::Arc::default(),
1342 };
1343
1344 if !header.is_internally_consistent() {
1345 return None;
1346 }
1347
1348 Some((header, remainder))
1349 }
1350
1351 #[inline]
1356 pub fn is_internally_consistent(&self) -> bool {
1357 let public_key_hash = match self.seal {
1358 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1359 };
1360 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1361 }
1362
1363 #[inline]
1366 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1367 let (prefix, consensus_info, result, mut remainder) =
1375 BlockHeader::try_from_bytes_shared(bytes)?;
1376
1377 if prefix.shard_index.shard_kind() != ShardKind::LeafShard {
1378 return None;
1379 }
1380
1381 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1382 let beacon_chain_info =
1384 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1385
1386 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1387
1388 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1389
1390 let shared = SharedBlockHeader {
1391 prefix,
1392 result,
1393 consensus_info,
1394 seal,
1395 };
1396
1397 Some((
1398 Self {
1399 shared,
1400 beacon_chain_info,
1401 pre_seal_bytes,
1402 #[cfg(any(
1403 feature = "alloc",
1404 not(any(target_os = "none", target_os = "unknown"))
1405 ))]
1406 cached_block_root: rclite::Arc::default(),
1407 },
1408 remainder,
1409 ))
1410 }
1411
1412 #[cfg(feature = "alloc")]
1414 #[inline(always)]
1415 pub fn to_owned(self) -> OwnedLeafShardHeader {
1416 let unsealed = OwnedLeafShardHeader::from_parts(
1417 self.shared.prefix,
1418 self.shared.result,
1419 self.shared.consensus_info,
1420 self.beacon_chain_info,
1421 );
1422
1423 unsealed.with_seal(self.shared.seal)
1424 }
1425
1426 #[inline(always)]
1428 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1429 &self.shared
1430 }
1431
1432 #[inline(always)]
1434 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1435 self.beacon_chain_info
1436 }
1437
1438 #[inline]
1440 pub fn pre_seal_hash(&self) -> Blake3Hash {
1441 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1443 }
1444
1445 #[inline]
1448 pub fn is_sealed_correctly(&self) -> bool {
1449 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1450 && self.seal.is_seal_valid(&self.pre_seal_hash())
1451 }
1452
1453 #[inline]
1461 pub fn root(&self) -> impl Deref<Target = BlockRoot> {
1462 let Self {
1463 shared,
1464 beacon_chain_info,
1465 pre_seal_bytes: _,
1466 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1467 cached_block_root,
1468 } = self;
1469
1470 let compute_root = || {
1471 let SharedBlockHeader {
1472 prefix,
1473 result,
1474 consensus_info,
1475 seal,
1476 } = shared;
1477
1478 const MAX_N: usize = 5;
1479 let leaves: [_; MAX_N] = [
1480 prefix.hash(),
1481 result.hash(),
1482 consensus_info.hash(),
1483 seal.hash(),
1484 beacon_chain_info.hash(),
1485 ];
1486 let block_root =
1487 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1488 .expect("The list is not empty; qed");
1489
1490 BlockRoot::new(Blake3Hash::new(block_root))
1491 };
1492
1493 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1494 {
1495 cached_block_root.get_or_init(compute_root)
1496 }
1497 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1498 {
1499 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1500 }
1501 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1502 {
1503 struct Wrapper(BlockRoot);
1504
1505 impl Deref for Wrapper {
1506 type Target = BlockRoot;
1507
1508 #[inline(always)]
1509 fn deref(&self) -> &Self::Target {
1510 &self.0
1511 }
1512 }
1513
1514 Wrapper(compute_root())
1515 }
1516 }
1517}
1518
1519#[derive(Debug, Clone, From)]
1524pub enum BlockHeader<'a> {
1525 BeaconChain(BeaconChainHeader<'a>),
1527 IntermediateShard(IntermediateShardHeader<'a>),
1529 LeafShard(LeafShardHeader<'a>),
1531}
1532
1533impl<'a> Deref for BlockHeader<'a> {
1534 type Target = SharedBlockHeader<'a>;
1535
1536 #[inline(always)]
1537 fn deref(&self) -> &Self::Target {
1538 match self {
1539 Self::BeaconChain(header) => header,
1540 Self::IntermediateShard(header) => header,
1541 Self::LeafShard(header) => header,
1542 }
1543 }
1544}
1545
1546impl<'a> BlockHeader<'a> {
1547 #[inline]
1554 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: ShardKind) -> Option<(Self, &'a [u8])> {
1555 match shard_kind {
1556 ShardKind::BeaconChain => {
1557 let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1558 Some((Self::BeaconChain(header), remainder))
1559 }
1560 ShardKind::IntermediateShard => {
1561 let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1562 Some((Self::IntermediateShard(header), remainder))
1563 }
1564 ShardKind::LeafShard => {
1565 let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1566 Some((Self::LeafShard(header), remainder))
1567 }
1568 ShardKind::Phantom | ShardKind::Invalid => {
1569 None
1571 }
1572 }
1573 }
1574
1575 #[inline]
1580 pub fn is_internally_consistent(&self) -> bool {
1581 match self {
1582 Self::BeaconChain(header) => header.is_internally_consistent(),
1583 Self::IntermediateShard(header) => header.is_internally_consistent(),
1584 Self::LeafShard(header) => header.is_internally_consistent(),
1585 }
1586 }
1587
1588 #[inline]
1591 pub fn try_from_bytes_unchecked(
1592 bytes: &'a [u8],
1593 shard_kind: ShardKind,
1594 ) -> Option<(Self, &'a [u8])> {
1595 match shard_kind {
1596 ShardKind::BeaconChain => {
1597 let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1598 Some((Self::BeaconChain(header), remainder))
1599 }
1600 ShardKind::IntermediateShard => {
1601 let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1602 Some((Self::IntermediateShard(header), remainder))
1603 }
1604 ShardKind::LeafShard => {
1605 let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1606 Some((Self::LeafShard(header), remainder))
1607 }
1608 ShardKind::Phantom | ShardKind::Invalid => {
1609 None
1611 }
1612 }
1613 }
1614
1615 #[inline]
1616 fn try_from_bytes_shared(
1617 mut bytes: &'a [u8],
1618 ) -> Option<(
1619 &'a BlockHeaderPrefix,
1620 &'a BlockHeaderConsensusInfo,
1621 &'a BlockHeaderResult,
1622 &'a [u8],
1623 )> {
1624 let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1625 let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1627
1628 if !(prefix.padding_0 == [0; _]
1629 && prefix.shard_index.as_u32() <= ShardIndex::MAX_SHARD_INDEX)
1630 {
1631 return None;
1632 }
1633
1634 let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1635 let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1637
1638 let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1639 let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1641
1642 if consensus_info.solution.padding != [0; _] {
1643 return None;
1644 }
1645
1646 Some((prefix, consensus_info, result, bytes))
1647 }
1648
1649 #[cfg(feature = "alloc")]
1651 #[inline(always)]
1652 pub fn to_owned(self) -> OwnedBlockHeader {
1653 match self {
1654 Self::BeaconChain(header) => header.to_owned().into(),
1655 Self::IntermediateShard(header) => header.to_owned().into(),
1656 Self::LeafShard(header) => header.to_owned().into(),
1657 }
1658 }
1659
1660 #[inline]
1662 pub fn pre_seal_hash(&self) -> Blake3Hash {
1663 match self {
1664 Self::BeaconChain(header) => header.pre_seal_hash(),
1665 Self::IntermediateShard(header) => header.pre_seal_hash(),
1666 Self::LeafShard(header) => header.pre_seal_hash(),
1667 }
1668 }
1669
1670 #[inline]
1673 pub fn is_sealed_correctly(&self) -> bool {
1674 match self {
1675 Self::BeaconChain(header) => header.is_sealed_correctly(),
1676 Self::IntermediateShard(header) => header.is_sealed_correctly(),
1677 Self::LeafShard(header) => header.is_sealed_correctly(),
1678 }
1679 }
1680
1681 #[inline]
1689 pub fn root(&self) -> impl Deref<Target = BlockRoot> {
1690 enum Wrapper<B, I, L> {
1691 BeaconChain(B),
1692 IntermediateShard(I),
1693 LeafShard(L),
1694 }
1695
1696 impl<B, I, L> Deref for Wrapper<B, I, L>
1697 where
1698 B: Deref<Target = BlockRoot>,
1699 I: Deref<Target = BlockRoot>,
1700 L: Deref<Target = BlockRoot>,
1701 {
1702 type Target = BlockRoot;
1703
1704 #[inline(always)]
1705 fn deref(&self) -> &Self::Target {
1706 match self {
1707 Wrapper::BeaconChain(block_root) => block_root,
1708 Wrapper::IntermediateShard(block_root) => block_root,
1709 Wrapper::LeafShard(block_root) => block_root,
1710 }
1711 }
1712 }
1713
1714 match self {
1716 Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1717 Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1718 Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1719 }
1720 }
1721}