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>> + Into<BlockHeader<'a>>,
36{
37 const SHARD_KIND: ShardKind;
39
40 #[cfg(feature = "alloc")]
42 type Owned: GenericOwnedBlockHeader<Header<'a> = Self>
43 where
44 Self: 'a;
45
46 #[cfg(feature = "alloc")]
48 fn to_owned(self) -> Self::Owned;
49
50 fn root(&self) -> impl Deref<Target = BlockRoot>;
57}
58
59#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
63#[cfg_attr(
64 feature = "scale-codec",
65 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
66)]
67#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
68#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
69#[repr(C)]
70pub struct BlockHeaderPrefix {
71 pub number: BlockNumber,
73 pub shard_index: ShardIndex,
75 pub padding_0: [u8; 4],
77 pub timestamp: BlockTimestamp,
79 pub parent_root: BlockRoot,
81 pub mmr_root: Blake3Hash,
84}
85
86impl BlockHeaderPrefix {
87 pub fn hash(&self) -> Blake3Hash {
89 Blake3Hash::from(blake3::hash(self.as_bytes()))
91 }
92}
93
94#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
96#[cfg_attr(
97 feature = "scale-codec",
98 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
99)]
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
102#[repr(C)]
103pub struct BlockHeaderConsensusInfo {
104 pub slot: SlotNumber,
106 pub proof_of_time: PotOutput,
108 pub future_proof_of_time: PotOutput,
110 pub solution: Solution,
112}
113
114impl BlockHeaderConsensusInfo {
115 pub fn hash(&self) -> Blake3Hash {
117 Blake3Hash::from(blake3::hash(self.as_bytes()))
119 }
120}
121
122#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, TrivialType)]
124#[cfg_attr(
125 feature = "scale-codec",
126 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
127)]
128#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
129#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
130#[repr(C)]
131pub struct BlockHeaderBeaconChainInfo {
132 pub number: BlockNumber,
134 pub root: BlockRoot,
136}
137
138impl BlockHeaderBeaconChainInfo {
139 pub fn hash(&self) -> Blake3Hash {
141 Blake3Hash::from(blake3::hash(self.as_bytes()))
143 }
144}
145
146#[derive(Debug, Copy, Clone, Eq, PartialEq)]
148#[cfg_attr(
149 feature = "scale-codec",
150 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
151)]
152#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
153#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
154pub struct BlockHeaderFixedConsensusParameters {
155 pub solution_range: SolutionRange,
157 pub slot_iterations: NonZeroU32,
162}
163
164impl BlockHeaderFixedConsensusParameters {
165 #[inline]
171 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(Self, &[u8])> {
172 let solution_range = bytes.split_off(..size_of::<SolutionRange>())?;
177 let solution_range = SolutionRange::from_bytes([
178 solution_range[0],
179 solution_range[1],
180 solution_range[2],
181 solution_range[3],
182 solution_range[4],
183 solution_range[5],
184 solution_range[6],
185 solution_range[7],
186 ]);
187
188 let pot_slot_iterations = bytes.split_off(..size_of::<u32>())?;
189 let slot_iterations = u32::from_le_bytes([
190 pot_slot_iterations[0],
191 pot_slot_iterations[1],
192 pot_slot_iterations[2],
193 pot_slot_iterations[3],
194 ]);
195 let slot_iterations = NonZeroU32::new(slot_iterations)?;
196
197 Some((
198 Self {
199 solution_range,
200 slot_iterations,
201 },
202 bytes,
203 ))
204 }
205}
206
207#[derive(Debug, Copy, Clone, Eq, PartialEq)]
211#[repr(C, packed)]
212pub struct BlockHeaderPotParametersChange {
213 slot: SlotNumber,
217 slot_iterations: NonZeroU32,
219 entropy: Blake3Hash,
221}
222
223impl From<BlockHeaderPotParametersChange> for PotParametersChange {
224 #[inline(always)]
225 fn from(value: BlockHeaderPotParametersChange) -> Self {
226 let BlockHeaderPotParametersChange {
227 slot,
228 slot_iterations,
229 entropy,
230 } = value;
231
232 PotParametersChange {
233 slot,
234 slot_iterations,
235 entropy,
236 }
237 }
238}
239
240impl From<PotParametersChange> for BlockHeaderPotParametersChange {
241 #[inline(always)]
242 fn from(value: PotParametersChange) -> Self {
243 let PotParametersChange {
244 slot,
245 slot_iterations,
246 entropy,
247 } = value;
248
249 BlockHeaderPotParametersChange {
250 slot,
251 slot_iterations,
252 entropy,
253 }
254 }
255}
256
257impl BlockHeaderPotParametersChange {
258 #[inline]
264 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(&Self, &[u8])> {
265 let _slot = bytes.split_off(..size_of::<SlotNumber>())?;
271
272 let slot_iterations = bytes.split_off(..size_of::<u32>())?;
273 if slot_iterations == [0, 0, 0, 0] {
274 return None;
275 }
276 let _entropy = bytes.split_off(..size_of::<Blake3Hash>())?;
277
278 let pot_parameters_change = unsafe { bytes.as_ptr().cast::<Self>().as_ref_unchecked() };
280
281 Some((pot_parameters_change, bytes))
282 }
283}
284
285#[derive(Debug, Copy, Clone)]
287pub struct OwnedBlockHeaderConsensusParameters {
288 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
290 pub super_segment_root: Option<SuperSegmentRoot>,
292 pub next_solution_range: Option<SolutionRange>,
294 pub pot_parameters_change: Option<BlockHeaderPotParametersChange>,
296}
297
298impl OwnedBlockHeaderConsensusParameters {
299 #[inline]
301 pub fn as_ref(&self) -> BlockHeaderConsensusParameters<'_> {
302 BlockHeaderConsensusParameters {
303 fixed_parameters: self.fixed_parameters,
304 super_segment_root: self.super_segment_root.as_ref(),
305 next_solution_range: self.next_solution_range,
306 pot_parameters_change: self.pot_parameters_change.as_ref(),
307 }
308 }
309}
310
311#[derive(Debug, Copy, Clone, Eq, PartialEq)]
313pub struct BlockHeaderConsensusParameters<'a> {
314 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
316 pub super_segment_root: Option<&'a SuperSegmentRoot>,
318 pub next_solution_range: Option<SolutionRange>,
320 pub pot_parameters_change: Option<&'a BlockHeaderPotParametersChange>,
322}
323
324impl<'a> BlockHeaderConsensusParameters<'a> {
325 pub const MAX_SIZE: u32 = size_of::<BlockHeaderFixedConsensusParameters>() as u32
327 + u8::SIZE
328 + <SuperSegmentRoot as TrivialType>::SIZE
329 + <SolutionRange as TrivialType>::SIZE
330 + size_of::<BlockHeaderPotParametersChange>() as u32;
331 pub const SUPER_SEGMENT_ROOT_MASK: u8 = 0b_0000_0001;
333 pub const NEXT_SOLUTION_RANGE_MASK: u8 = 0b_0000_0010;
335 pub const POT_PARAMETERS_CHANGE_MASK: u8 = 0b_0000_0100;
337
338 #[inline]
344 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
345 let (fixed_parameters, mut remainder) =
353 BlockHeaderFixedConsensusParameters::try_from_bytes(bytes)?;
354
355 let bitflags = remainder.split_off(..size_of::<u8>())?;
356 let bitflags = bitflags[0];
357
358 let super_segment_root = if bitflags & Self::SUPER_SEGMENT_ROOT_MASK != 0 {
359 let super_segment_root = remainder.split_off(..size_of::<SuperSegmentRoot>())?;
360 let super_segment_root = unsafe { SuperSegmentRoot::from_bytes(super_segment_root) }?;
362
363 Some(super_segment_root)
364 } else {
365 None
366 };
367
368 let next_solution_range = if bitflags & Self::NEXT_SOLUTION_RANGE_MASK != 0 {
369 let next_solution_range = remainder.split_off(..size_of::<SolutionRange>())?;
370 let next_solution_range = SolutionRange::from_bytes([
372 next_solution_range[0],
373 next_solution_range[1],
374 next_solution_range[2],
375 next_solution_range[3],
376 next_solution_range[4],
377 next_solution_range[5],
378 next_solution_range[6],
379 next_solution_range[7],
380 ]);
381
382 Some(next_solution_range)
383 } else {
384 None
385 };
386
387 let pot_parameters_change = if bitflags & Self::POT_PARAMETERS_CHANGE_MASK != 0 {
388 let pot_parameters_change;
389 (pot_parameters_change, remainder) =
390 BlockHeaderPotParametersChange::try_from_bytes(remainder)?;
391
392 Some(pot_parameters_change)
393 } else {
394 None
395 };
396
397 Some((
398 Self {
399 super_segment_root,
400 fixed_parameters,
401 next_solution_range,
402 pot_parameters_change,
403 },
404 remainder,
405 ))
406 }
407
408 pub fn hash(&self) -> Blake3Hash {
410 let Self {
411 super_segment_root,
412 fixed_parameters,
413 next_solution_range,
414 pot_parameters_change,
415 } = self;
416 let BlockHeaderFixedConsensusParameters {
417 solution_range,
418 slot_iterations,
419 } = fixed_parameters;
420
421 let mut hasher = blake3::Hasher::new();
423 hasher.update(solution_range.as_bytes());
424 hasher.update(&slot_iterations.get().to_le_bytes());
425
426 if let Some(super_segment_root) = super_segment_root {
427 hasher.update(super_segment_root.as_bytes());
428 }
429 if let Some(next_solution_range) = next_solution_range {
430 hasher.update(next_solution_range.as_bytes());
431 }
432 if let Some(pot_parameters_change) = pot_parameters_change.copied() {
433 let BlockHeaderPotParametersChange {
434 slot,
435 slot_iterations,
436 entropy,
437 } = pot_parameters_change;
438 hasher.update(slot.as_bytes());
439 hasher.update(&slot_iterations.get().to_le_bytes());
440 hasher.update(entropy.as_bytes());
441 }
442
443 Blake3Hash::from(hasher.finalize())
444 }
445}
446
447#[derive(Debug, Copy, Clone, Deref)]
449pub struct BlockHeaderChildShardBlocks<'a> {
450 pub child_shard_blocks: &'a [BlockRoot],
452}
453
454impl<'a> BlockHeaderChildShardBlocks<'a> {
455 #[inline]
461 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
462 let length = bytes.split_off(..size_of::<u16>())?;
468 let num_blocks = usize::from(*unsafe { <u16 as TrivialType>::from_bytes(length) }?);
470
471 let padding = bytes.split_off(..size_of::<[u8; 2]>())?;
472
473 if padding != [0, 0] {
475 return None;
476 }
477
478 let child_shard_blocks = bytes.split_off(..num_blocks * BlockRoot::SIZE)?;
479 let child_shard_blocks = unsafe {
481 slice::from_raw_parts(
482 child_shard_blocks.as_ptr().cast::<[u8; BlockRoot::SIZE]>(),
483 num_blocks,
484 )
485 };
486 let child_shard_blocks = BlockRoot::slice_from_repr(child_shard_blocks);
487
488 Some((Self { child_shard_blocks }, bytes))
489 }
490
491 pub fn root(&self) -> Option<Blake3Hash> {
495 let root = UnbalancedMerkleTree::compute_root_only::<'_, { u32::MAX as u64 }, _, _>(
496 self.child_shard_blocks
498 .iter()
499 .map(|child_shard_block_root| {
500 blake3::hash(child_shard_block_root.as_ref())
505 }),
506 )?;
507 Some(Blake3Hash::new(root))
508 }
509}
510
511#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
515#[cfg_attr(
516 feature = "scale-codec",
517 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
518)]
519#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
520#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
521#[repr(C)]
522pub struct BlockHeaderResult {
523 pub body_root: Blake3Hash,
526 pub state_root: Blake3Hash,
529}
530
531impl BlockHeaderResult {
532 pub fn hash(&self) -> Blake3Hash {
534 Blake3Hash::from(blake3::hash(self.as_bytes()))
536 }
537}
538
539#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
541#[cfg_attr(
542 feature = "scale-codec",
543 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
544)]
545#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
546#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
547#[repr(u8)]
548#[non_exhaustive]
549pub enum BlockHeaderSealType {
550 #[cfg_attr(feature = "scale-codec", codec(index = 0))]
552 Ed25519 = 0,
553}
554
555impl BlockHeaderSealType {
556 #[inline(always)]
558 pub const fn try_from_byte(byte: u8) -> Option<Self> {
559 if byte == Self::Ed25519 as u8 {
560 Some(Self::Ed25519)
561 } else {
562 None
563 }
564 }
565}
566
567#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
569#[cfg_attr(
570 feature = "scale-codec",
571 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
572)]
573#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
574#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
575#[repr(C)]
576pub struct BlockHeaderEd25519Seal {
577 pub public_key: Ed25519PublicKey,
579 pub signature: Ed25519Signature,
581}
582
583#[derive(Debug, Copy, Clone)]
585#[cfg_attr(
586 feature = "scale-codec",
587 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
588)]
589#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
590#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
591#[non_exhaustive]
592pub enum OwnedBlockHeaderSeal {
593 Ed25519(BlockHeaderEd25519Seal),
595}
596
597impl OwnedBlockHeaderSeal {
598 #[inline(always)]
600 pub fn as_ref(&self) -> BlockHeaderSeal<'_> {
601 match self {
602 Self::Ed25519(seal) => BlockHeaderSeal::Ed25519(seal),
603 }
604 }
605}
606
607#[derive(Debug, Copy, Clone)]
609#[non_exhaustive]
610pub enum BlockHeaderSeal<'a> {
611 Ed25519(&'a BlockHeaderEd25519Seal),
613}
614
615impl<'a> BlockHeaderSeal<'a> {
616 pub const MAX_SIZE: u32 = 1 + BlockHeaderEd25519Seal::SIZE;
618 #[inline]
624 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
625 let seal_type = bytes.split_off(..size_of::<u8>())?;
630 let seal_type = BlockHeaderSealType::try_from_byte(seal_type[0])?;
631
632 match seal_type {
633 BlockHeaderSealType::Ed25519 => {
634 let seal = bytes.split_off(..size_of::<BlockHeaderEd25519Seal>())?;
635 let seal = unsafe { BlockHeaderEd25519Seal::from_bytes(seal) }?;
637 Some((Self::Ed25519(seal), bytes))
638 }
639 }
640 }
641
642 #[inline]
644 pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
645 match self {
646 BlockHeaderSeal::Ed25519(seal) => seal
647 .public_key
648 .verify(&seal.signature, pre_seal_hash.as_bytes())
649 .is_ok(),
650 }
651 }
652
653 #[inline]
655 pub fn public_key_hash(&self) -> Blake3Hash {
656 match self {
657 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
658 }
659 }
660
661 #[inline]
663 pub fn hash(&self) -> Blake3Hash {
664 match self {
665 BlockHeaderSeal::Ed25519(seal) => {
666 let mut hasher = blake3::Hasher::new();
668 hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
669 hasher.update(seal.as_bytes());
670
671 Blake3Hash::from(hasher.finalize())
672 }
673 }
674 }
675}
676
677#[derive(Debug, Copy, Clone)]
679pub struct SharedBlockHeader<'a> {
680 pub prefix: &'a BlockHeaderPrefix,
682 pub result: &'a BlockHeaderResult,
684 pub consensus_info: &'a BlockHeaderConsensusInfo,
686 pub seal: BlockHeaderSeal<'a>,
688}
689
690#[derive(Debug, Clone, Yokeable)]
692#[non_exhaustive]
694pub struct BeaconChainHeader<'a> {
695 shared: SharedBlockHeader<'a>,
697 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
699 consensus_parameters: BlockHeaderConsensusParameters<'a>,
701 pre_seal_bytes: &'a [u8],
703 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
704 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
705 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
706 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
707}
708
709impl<'a> Deref for BeaconChainHeader<'a> {
710 type Target = SharedBlockHeader<'a>;
711
712 #[inline(always)]
713 fn deref(&self) -> &Self::Target {
714 &self.shared
715 }
716}
717
718impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
719 const SHARD_KIND: ShardKind = ShardKind::BeaconChain;
720
721 #[cfg(feature = "alloc")]
722 type Owned = OwnedBeaconChainHeader;
723
724 #[cfg(feature = "alloc")]
725 #[inline(always)]
726 fn to_owned(self) -> Self::Owned {
727 self.to_owned()
728 }
729
730 #[inline(always)]
731 fn root(&self) -> impl Deref<Target = BlockRoot> {
732 self.root()
733 }
734}
735
736impl<'a> BeaconChainHeader<'a> {
737 #[inline]
744 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
745 let (prefix, consensus_info, result, remainder) =
754 BlockHeader::try_from_bytes_shared(bytes)?;
755
756 if prefix.shard_index.shard_kind() != ShardKind::BeaconChain {
757 return None;
758 }
759
760 let (child_shard_blocks, remainder) =
761 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
762
763 let (consensus_parameters, remainder) =
764 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
765
766 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
767
768 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
769
770 let shared = SharedBlockHeader {
771 prefix,
772 result,
773 consensus_info,
774 seal,
775 };
776
777 let header = Self {
778 shared,
779 child_shard_blocks,
780 consensus_parameters,
781 pre_seal_bytes,
782 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
783 cached_block_root: rclite::Arc::default(),
784 };
785
786 if !header.is_internally_consistent() {
787 return None;
788 }
789
790 Some((header, remainder))
791 }
792
793 #[inline]
798 pub fn is_internally_consistent(&self) -> bool {
799 let public_key_hash = match self.seal {
800 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
801 };
802 public_key_hash == self.shared.consensus_info.solution.public_key_hash
803 }
804
805 #[inline]
808 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
809 let (prefix, consensus_info, result, remainder) =
818 BlockHeader::try_from_bytes_shared(bytes)?;
819
820 if prefix.shard_index.shard_kind() != ShardKind::BeaconChain {
821 return None;
822 }
823
824 let (child_shard_blocks, remainder) =
825 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
826
827 let (consensus_parameters, remainder) =
828 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
829
830 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
831
832 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
833
834 let shared = SharedBlockHeader {
835 prefix,
836 result,
837 consensus_info,
838 seal,
839 };
840
841 Some((
842 Self {
843 shared,
844 child_shard_blocks,
845 consensus_parameters,
846 pre_seal_bytes,
847 #[cfg(any(
848 feature = "alloc",
849 not(any(target_os = "none", target_os = "unknown"))
850 ))]
851 cached_block_root: rclite::Arc::default(),
852 },
853 remainder,
854 ))
855 }
856
857 #[cfg(feature = "alloc")]
859 #[inline(always)]
860 pub fn to_owned(self) -> OwnedBeaconChainHeader {
861 let unsealed = OwnedBeaconChainHeader::from_parts(
862 self.shared.prefix,
863 self.shared.result,
864 self.shared.consensus_info,
865 &self.child_shard_blocks,
866 self.consensus_parameters,
867 )
868 .expect("`self` is always a valid invariant; qed");
869
870 unsealed.with_seal(self.shared.seal)
871 }
872
873 #[inline(always)]
875 pub fn shared(&self) -> &SharedBlockHeader<'a> {
876 &self.shared
877 }
878
879 #[inline(always)]
881 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
882 &self.child_shard_blocks
883 }
884
885 #[inline(always)]
887 pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
888 &self.consensus_parameters
889 }
890
891 #[inline]
893 pub fn pre_seal_hash(&self) -> Blake3Hash {
894 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
896 }
897
898 #[inline]
901 pub fn is_sealed_correctly(&self) -> bool {
902 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
903 && self.seal.is_seal_valid(&self.pre_seal_hash())
904 }
905
906 #[inline]
914 pub fn root(&self) -> impl Deref<Target = BlockRoot> {
915 let Self {
916 shared,
917 child_shard_blocks,
918 consensus_parameters,
919 pre_seal_bytes: _,
920 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
921 cached_block_root,
922 } = self;
923
924 let compute_root = || {
925 let SharedBlockHeader {
926 prefix,
927 result,
928 consensus_info,
929 seal,
930 } = shared;
931
932 const MAX_N: usize = 6;
933 let leaves: [_; MAX_N] = [
934 prefix.hash(),
935 result.hash(),
936 consensus_info.hash(),
937 seal.hash(),
938 child_shard_blocks.root().unwrap_or_default(),
939 consensus_parameters.hash(),
940 ];
941 let block_root =
942 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
943 .expect("The list is not empty; qed");
944
945 BlockRoot::new(Blake3Hash::new(block_root))
946 };
947
948 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
949 {
950 cached_block_root.get_or_init(compute_root)
951 }
952 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
953 {
954 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
955 }
956 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
957 {
958 struct Wrapper(BlockRoot);
959
960 impl Deref for Wrapper {
961 type Target = BlockRoot;
962
963 #[inline(always)]
964 fn deref(&self) -> &Self::Target {
965 &self.0
966 }
967 }
968
969 Wrapper(compute_root())
970 }
971 }
972}
973
974#[derive(Debug, Clone, Yokeable)]
976#[non_exhaustive]
978pub struct IntermediateShardHeader<'a> {
979 shared: SharedBlockHeader<'a>,
981 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
983 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
985 pre_seal_bytes: &'a [u8],
987 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
988 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
989 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
990 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
991}
992
993impl<'a> Deref for IntermediateShardHeader<'a> {
994 type Target = SharedBlockHeader<'a>;
995
996 #[inline(always)]
997 fn deref(&self) -> &Self::Target {
998 &self.shared
999 }
1000}
1001
1002impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
1003 const SHARD_KIND: ShardKind = ShardKind::IntermediateShard;
1004
1005 #[cfg(feature = "alloc")]
1006 type Owned = OwnedIntermediateShardHeader;
1007
1008 #[cfg(feature = "alloc")]
1009 #[inline(always)]
1010 fn to_owned(self) -> Self::Owned {
1011 self.to_owned()
1012 }
1013
1014 #[inline(always)]
1015 fn root(&self) -> impl Deref<Target = BlockRoot> {
1016 self.root()
1017 }
1018}
1019
1020impl<'a> IntermediateShardHeader<'a> {
1021 #[inline]
1028 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1029 let (prefix, consensus_info, result, mut remainder) =
1038 BlockHeader::try_from_bytes_shared(bytes)?;
1039
1040 if prefix.shard_index.shard_kind() != ShardKind::IntermediateShard {
1041 return None;
1042 }
1043
1044 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1045 let beacon_chain_info =
1047 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1048
1049 let (child_shard_blocks, remainder) =
1050 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1051
1052 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1053
1054 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1055
1056 let shared = SharedBlockHeader {
1057 prefix,
1058 result,
1059 consensus_info,
1060 seal,
1061 };
1062
1063 let header = Self {
1064 shared,
1065 beacon_chain_info,
1066 child_shard_blocks,
1067 pre_seal_bytes,
1068 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1069 cached_block_root: rclite::Arc::default(),
1070 };
1071
1072 if !header.is_internally_consistent() {
1073 return None;
1074 }
1075
1076 Some((header, remainder))
1077 }
1078
1079 #[inline]
1084 pub fn is_internally_consistent(&self) -> bool {
1085 let public_key_hash = match self.seal {
1086 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1087 };
1088 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1089 }
1090
1091 #[inline]
1094 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1095 let (prefix, consensus_info, result, mut remainder) =
1104 BlockHeader::try_from_bytes_shared(bytes)?;
1105
1106 if prefix.shard_index.shard_kind() != ShardKind::IntermediateShard {
1107 return None;
1108 }
1109
1110 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1111 let beacon_chain_info =
1113 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1114
1115 let (child_shard_blocks, remainder) =
1116 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1117
1118 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1119
1120 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1121
1122 let shared = SharedBlockHeader {
1123 prefix,
1124 result,
1125 consensus_info,
1126 seal,
1127 };
1128
1129 Some((
1130 Self {
1131 shared,
1132 beacon_chain_info,
1133 child_shard_blocks,
1134 pre_seal_bytes,
1135 #[cfg(any(
1136 feature = "alloc",
1137 not(any(target_os = "none", target_os = "unknown"))
1138 ))]
1139 cached_block_root: rclite::Arc::default(),
1140 },
1141 remainder,
1142 ))
1143 }
1144
1145 #[cfg(feature = "alloc")]
1147 #[inline(always)]
1148 pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1149 let unsealed = OwnedIntermediateShardHeader::from_parts(
1150 self.shared.prefix,
1151 self.shared.result,
1152 self.shared.consensus_info,
1153 self.beacon_chain_info,
1154 &self.child_shard_blocks,
1155 )
1156 .expect("`self` is always a valid invariant; qed");
1157
1158 unsealed.with_seal(self.shared.seal)
1159 }
1160
1161 #[inline(always)]
1163 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1164 &self.shared
1165 }
1166
1167 #[inline(always)]
1169 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1170 self.beacon_chain_info
1171 }
1172
1173 #[inline(always)]
1175 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1176 &self.child_shard_blocks
1177 }
1178
1179 #[inline]
1181 pub fn pre_seal_hash(&self) -> Blake3Hash {
1182 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1184 }
1185
1186 #[inline]
1189 pub fn is_sealed_correctly(&self) -> bool {
1190 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1191 && self.seal.is_seal_valid(&self.pre_seal_hash())
1192 }
1193
1194 #[inline]
1202 pub fn root(&self) -> impl Deref<Target = BlockRoot> {
1203 let Self {
1204 shared,
1205 beacon_chain_info,
1206 child_shard_blocks,
1207 pre_seal_bytes: _,
1208 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1209 cached_block_root,
1210 } = self;
1211
1212 let compute_root = || {
1213 let SharedBlockHeader {
1214 prefix,
1215 result,
1216 consensus_info,
1217 seal,
1218 } = shared;
1219
1220 const MAX_N: usize = 6;
1221 let leaves: [_; MAX_N] = [
1222 prefix.hash(),
1223 result.hash(),
1224 consensus_info.hash(),
1225 seal.hash(),
1226 beacon_chain_info.hash(),
1227 child_shard_blocks.root().unwrap_or_default(),
1228 ];
1229 let block_root =
1230 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1231 .expect("The list is not empty; qed");
1232
1233 BlockRoot::new(Blake3Hash::new(block_root))
1234 };
1235
1236 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1237 {
1238 cached_block_root.get_or_init(compute_root)
1239 }
1240 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1241 {
1242 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1243 }
1244 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1245 {
1246 struct Wrapper(BlockRoot);
1247
1248 impl Deref for Wrapper {
1249 type Target = BlockRoot;
1250
1251 #[inline(always)]
1252 fn deref(&self) -> &Self::Target {
1253 &self.0
1254 }
1255 }
1256
1257 Wrapper(compute_root())
1258 }
1259 }
1260}
1261
1262#[derive(Debug, Clone, Yokeable)]
1264#[non_exhaustive]
1266pub struct LeafShardHeader<'a> {
1267 shared: SharedBlockHeader<'a>,
1269 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1271 pre_seal_bytes: &'a [u8],
1273 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1274 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1275 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1276 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1277}
1278
1279impl<'a> Deref for LeafShardHeader<'a> {
1280 type Target = SharedBlockHeader<'a>;
1281
1282 #[inline(always)]
1283 fn deref(&self) -> &Self::Target {
1284 &self.shared
1285 }
1286}
1287
1288impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1289 const SHARD_KIND: ShardKind = ShardKind::LeafShard;
1290
1291 #[cfg(feature = "alloc")]
1292 type Owned = OwnedLeafShardHeader;
1293
1294 #[cfg(feature = "alloc")]
1295 #[inline(always)]
1296 fn to_owned(self) -> Self::Owned {
1297 self.to_owned()
1298 }
1299
1300 #[inline(always)]
1301 fn root(&self) -> impl Deref<Target = BlockRoot> {
1302 self.root()
1303 }
1304}
1305
1306impl<'a> LeafShardHeader<'a> {
1307 #[inline]
1314 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1315 let (prefix, consensus_info, result, mut remainder) =
1323 BlockHeader::try_from_bytes_shared(bytes)?;
1324
1325 if prefix.shard_index.shard_kind() != ShardKind::LeafShard {
1326 return None;
1327 }
1328
1329 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1330 let beacon_chain_info =
1332 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1333
1334 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1335
1336 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1337
1338 let shared = SharedBlockHeader {
1339 prefix,
1340 result,
1341 consensus_info,
1342 seal,
1343 };
1344
1345 let header = Self {
1346 shared,
1347 beacon_chain_info,
1348 pre_seal_bytes,
1349 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1350 cached_block_root: rclite::Arc::default(),
1351 };
1352
1353 if !header.is_internally_consistent() {
1354 return None;
1355 }
1356
1357 Some((header, remainder))
1358 }
1359
1360 #[inline]
1365 pub fn is_internally_consistent(&self) -> bool {
1366 let public_key_hash = match self.seal {
1367 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1368 };
1369 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1370 }
1371
1372 #[inline]
1375 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1376 let (prefix, consensus_info, result, mut remainder) =
1384 BlockHeader::try_from_bytes_shared(bytes)?;
1385
1386 if prefix.shard_index.shard_kind() != ShardKind::LeafShard {
1387 return None;
1388 }
1389
1390 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1391 let beacon_chain_info =
1393 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1394
1395 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1396
1397 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1398
1399 let shared = SharedBlockHeader {
1400 prefix,
1401 result,
1402 consensus_info,
1403 seal,
1404 };
1405
1406 Some((
1407 Self {
1408 shared,
1409 beacon_chain_info,
1410 pre_seal_bytes,
1411 #[cfg(any(
1412 feature = "alloc",
1413 not(any(target_os = "none", target_os = "unknown"))
1414 ))]
1415 cached_block_root: rclite::Arc::default(),
1416 },
1417 remainder,
1418 ))
1419 }
1420
1421 #[cfg(feature = "alloc")]
1423 #[inline(always)]
1424 pub fn to_owned(self) -> OwnedLeafShardHeader {
1425 let unsealed = OwnedLeafShardHeader::from_parts(
1426 self.shared.prefix,
1427 self.shared.result,
1428 self.shared.consensus_info,
1429 self.beacon_chain_info,
1430 );
1431
1432 unsealed.with_seal(self.shared.seal)
1433 }
1434
1435 #[inline(always)]
1437 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1438 &self.shared
1439 }
1440
1441 #[inline(always)]
1443 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1444 self.beacon_chain_info
1445 }
1446
1447 #[inline]
1449 pub fn pre_seal_hash(&self) -> Blake3Hash {
1450 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1452 }
1453
1454 #[inline]
1457 pub fn is_sealed_correctly(&self) -> bool {
1458 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1459 && self.seal.is_seal_valid(&self.pre_seal_hash())
1460 }
1461
1462 #[inline]
1470 pub fn root(&self) -> impl Deref<Target = BlockRoot> {
1471 let Self {
1472 shared,
1473 beacon_chain_info,
1474 pre_seal_bytes: _,
1475 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1476 cached_block_root,
1477 } = self;
1478
1479 let compute_root = || {
1480 let SharedBlockHeader {
1481 prefix,
1482 result,
1483 consensus_info,
1484 seal,
1485 } = shared;
1486
1487 const MAX_N: usize = 5;
1488 let leaves: [_; MAX_N] = [
1489 prefix.hash(),
1490 result.hash(),
1491 consensus_info.hash(),
1492 seal.hash(),
1493 beacon_chain_info.hash(),
1494 ];
1495 let block_root =
1496 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1497 .expect("The list is not empty; qed");
1498
1499 BlockRoot::new(Blake3Hash::new(block_root))
1500 };
1501
1502 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1503 {
1504 cached_block_root.get_or_init(compute_root)
1505 }
1506 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1507 {
1508 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1509 }
1510 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1511 {
1512 struct Wrapper(BlockRoot);
1513
1514 impl Deref for Wrapper {
1515 type Target = BlockRoot;
1516
1517 #[inline(always)]
1518 fn deref(&self) -> &Self::Target {
1519 &self.0
1520 }
1521 }
1522
1523 Wrapper(compute_root())
1524 }
1525 }
1526}
1527
1528#[derive(Debug, Clone, From)]
1533pub enum BlockHeader<'a> {
1534 BeaconChain(BeaconChainHeader<'a>),
1536 IntermediateShard(IntermediateShardHeader<'a>),
1538 LeafShard(LeafShardHeader<'a>),
1540}
1541
1542impl<'a> Deref for BlockHeader<'a> {
1543 type Target = SharedBlockHeader<'a>;
1544
1545 #[inline(always)]
1546 fn deref(&self) -> &Self::Target {
1547 match self {
1548 Self::BeaconChain(header) => header,
1549 Self::IntermediateShard(header) => header,
1550 Self::LeafShard(header) => header,
1551 }
1552 }
1553}
1554
1555impl<'a> BlockHeader<'a> {
1556 #[inline]
1563 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: ShardKind) -> Option<(Self, &'a [u8])> {
1564 match shard_kind {
1565 ShardKind::BeaconChain => {
1566 let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1567 Some((Self::BeaconChain(header), remainder))
1568 }
1569 ShardKind::IntermediateShard => {
1570 let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1571 Some((Self::IntermediateShard(header), remainder))
1572 }
1573 ShardKind::LeafShard => {
1574 let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1575 Some((Self::LeafShard(header), remainder))
1576 }
1577 ShardKind::Phantom | ShardKind::Invalid => {
1578 None
1580 }
1581 }
1582 }
1583
1584 #[inline]
1589 pub fn is_internally_consistent(&self) -> bool {
1590 match self {
1591 Self::BeaconChain(header) => header.is_internally_consistent(),
1592 Self::IntermediateShard(header) => header.is_internally_consistent(),
1593 Self::LeafShard(header) => header.is_internally_consistent(),
1594 }
1595 }
1596
1597 #[inline]
1600 pub fn try_from_bytes_unchecked(
1601 bytes: &'a [u8],
1602 shard_kind: ShardKind,
1603 ) -> Option<(Self, &'a [u8])> {
1604 match shard_kind {
1605 ShardKind::BeaconChain => {
1606 let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1607 Some((Self::BeaconChain(header), remainder))
1608 }
1609 ShardKind::IntermediateShard => {
1610 let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1611 Some((Self::IntermediateShard(header), remainder))
1612 }
1613 ShardKind::LeafShard => {
1614 let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1615 Some((Self::LeafShard(header), remainder))
1616 }
1617 ShardKind::Phantom | ShardKind::Invalid => {
1618 None
1620 }
1621 }
1622 }
1623
1624 #[inline]
1625 fn try_from_bytes_shared(
1626 mut bytes: &'a [u8],
1627 ) -> Option<(
1628 &'a BlockHeaderPrefix,
1629 &'a BlockHeaderConsensusInfo,
1630 &'a BlockHeaderResult,
1631 &'a [u8],
1632 )> {
1633 let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1634 let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1636
1637 if !(prefix.padding_0 == [0; _]
1638 && prefix.shard_index.as_u32() <= ShardIndex::MAX_SHARD_INDEX)
1639 {
1640 return None;
1641 }
1642
1643 let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1644 let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1646
1647 let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1648 let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1650
1651 if consensus_info.solution.padding != [0; _] {
1652 return None;
1653 }
1654
1655 Some((prefix, consensus_info, result, bytes))
1656 }
1657
1658 #[cfg(feature = "alloc")]
1660 #[inline(always)]
1661 pub fn to_owned(self) -> OwnedBlockHeader {
1662 match self {
1663 Self::BeaconChain(header) => header.to_owned().into(),
1664 Self::IntermediateShard(header) => header.to_owned().into(),
1665 Self::LeafShard(header) => header.to_owned().into(),
1666 }
1667 }
1668
1669 #[inline]
1671 pub fn pre_seal_hash(&self) -> Blake3Hash {
1672 match self {
1673 Self::BeaconChain(header) => header.pre_seal_hash(),
1674 Self::IntermediateShard(header) => header.pre_seal_hash(),
1675 Self::LeafShard(header) => header.pre_seal_hash(),
1676 }
1677 }
1678
1679 #[inline]
1682 pub fn is_sealed_correctly(&self) -> bool {
1683 match self {
1684 Self::BeaconChain(header) => header.is_sealed_correctly(),
1685 Self::IntermediateShard(header) => header.is_sealed_correctly(),
1686 Self::LeafShard(header) => header.is_sealed_correctly(),
1687 }
1688 }
1689
1690 #[inline]
1698 pub fn root(&self) -> impl Deref<Target = BlockRoot> {
1699 enum Wrapper<B, I, L> {
1700 BeaconChain(B),
1701 IntermediateShard(I),
1702 LeafShard(L),
1703 }
1704
1705 impl<B, I, L> Deref for Wrapper<B, I, L>
1706 where
1707 B: Deref<Target = BlockRoot>,
1708 I: Deref<Target = BlockRoot>,
1709 L: Deref<Target = BlockRoot>,
1710 {
1711 type Target = BlockRoot;
1712
1713 #[inline(always)]
1714 fn deref(&self) -> &Self::Target {
1715 match self {
1716 Wrapper::BeaconChain(block_root) => block_root,
1717 Wrapper::IntermediateShard(block_root) => block_root,
1718 Wrapper::LeafShard(block_root) => block_root,
1719 }
1720 }
1721 }
1722
1723 match self {
1725 Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1726 Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1727 Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1728 }
1729 }
1730}