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
36 + fmt::Debug
37 + Deref<Target = SharedBlockHeader<'a>>
38 + Into<BlockHeader<'a>>
39 + Send
40 + Sync,
41{
42 const SHARD_KIND: ShardKind;
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
64#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
68#[cfg_attr(
69 feature = "scale-codec",
70 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
71)]
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 Blake3Hash::from(blake3::hash(self.as_bytes()))
96 }
97}
98
99#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
101#[cfg_attr(
102 feature = "scale-codec",
103 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
104)]
105#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
106#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
107#[repr(C)]
108pub struct BlockHeaderConsensusInfo {
109 pub slot: SlotNumber,
111 pub proof_of_time: PotOutput,
113 pub future_proof_of_time: PotOutput,
115 pub solution: Solution,
117}
118
119impl BlockHeaderConsensusInfo {
120 pub fn hash(&self) -> Blake3Hash {
122 Blake3Hash::from(blake3::hash(self.as_bytes()))
124 }
125}
126
127#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, TrivialType)]
129#[cfg_attr(
130 feature = "scale-codec",
131 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
132)]
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 Blake3Hash::from(blake3::hash(self.as_bytes()))
148 }
149}
150
151#[derive(Debug, Copy, Clone, Eq, PartialEq)]
153#[cfg_attr(
154 feature = "scale-codec",
155 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
156)]
157#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
158#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
159pub struct BlockHeaderFixedConsensusParameters {
160 pub solution_range: SolutionRange,
162 pub slot_iterations: NonZeroU32,
167}
168
169impl BlockHeaderFixedConsensusParameters {
170 #[inline]
176 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(Self, &[u8])> {
177 let solution_range = bytes.split_off(..size_of::<SolutionRange>())?;
182 let solution_range = SolutionRange::from_bytes([
183 solution_range[0],
184 solution_range[1],
185 solution_range[2],
186 solution_range[3],
187 solution_range[4],
188 solution_range[5],
189 solution_range[6],
190 solution_range[7],
191 ]);
192
193 let pot_slot_iterations = bytes.split_off(..size_of::<u32>())?;
194 let slot_iterations = u32::from_le_bytes([
195 pot_slot_iterations[0],
196 pot_slot_iterations[1],
197 pot_slot_iterations[2],
198 pot_slot_iterations[3],
199 ]);
200 let slot_iterations = NonZeroU32::new(slot_iterations)?;
201
202 Some((
203 Self {
204 solution_range,
205 slot_iterations,
206 },
207 bytes,
208 ))
209 }
210}
211
212#[derive(Debug, Copy, Clone, Eq, PartialEq)]
216#[repr(C, packed)]
217pub struct BlockHeaderPotParametersChange {
218 slot: SlotNumber,
222 slot_iterations: NonZeroU32,
224 entropy: Blake3Hash,
226}
227
228impl From<BlockHeaderPotParametersChange> for PotParametersChange {
229 #[inline(always)]
230 fn from(value: BlockHeaderPotParametersChange) -> Self {
231 let BlockHeaderPotParametersChange {
232 slot,
233 slot_iterations,
234 entropy,
235 } = value;
236
237 PotParametersChange {
238 slot,
239 slot_iterations,
240 entropy,
241 }
242 }
243}
244
245impl From<PotParametersChange> for BlockHeaderPotParametersChange {
246 #[inline(always)]
247 fn from(value: PotParametersChange) -> Self {
248 let PotParametersChange {
249 slot,
250 slot_iterations,
251 entropy,
252 } = value;
253
254 BlockHeaderPotParametersChange {
255 slot,
256 slot_iterations,
257 entropy,
258 }
259 }
260}
261
262impl BlockHeaderPotParametersChange {
263 #[inline]
269 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(&Self, &[u8])> {
270 let _slot = bytes.split_off(..size_of::<SlotNumber>())?;
276
277 let slot_iterations = bytes.split_off(..size_of::<u32>())?;
278 if slot_iterations == [0, 0, 0, 0] {
279 return None;
280 }
281 let _entropy = bytes.split_off(..size_of::<Blake3Hash>())?;
282
283 let pot_parameters_change = unsafe { bytes.as_ptr().cast::<Self>().as_ref_unchecked() };
285
286 Some((pot_parameters_change, bytes))
287 }
288}
289
290#[derive(Debug, Copy, Clone)]
292pub struct OwnedBlockHeaderConsensusParameters {
293 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
295 pub super_segment_root: Option<SuperSegmentRoot>,
297 pub next_solution_range: Option<SolutionRange>,
299 pub pot_parameters_change: Option<BlockHeaderPotParametersChange>,
301}
302
303impl OwnedBlockHeaderConsensusParameters {
304 #[inline]
306 pub fn as_ref(&self) -> BlockHeaderConsensusParameters<'_> {
307 BlockHeaderConsensusParameters {
308 fixed_parameters: self.fixed_parameters,
309 super_segment_root: self.super_segment_root.as_ref(),
310 next_solution_range: self.next_solution_range,
311 pot_parameters_change: self.pot_parameters_change.as_ref(),
312 }
313 }
314}
315
316#[derive(Debug, Copy, Clone, Eq, PartialEq)]
318pub struct BlockHeaderConsensusParameters<'a> {
319 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
321 pub super_segment_root: Option<&'a SuperSegmentRoot>,
323 pub next_solution_range: Option<SolutionRange>,
325 pub pot_parameters_change: Option<&'a BlockHeaderPotParametersChange>,
327}
328
329impl<'a> BlockHeaderConsensusParameters<'a> {
330 pub const MAX_SIZE: u32 = size_of::<BlockHeaderFixedConsensusParameters>() as u32
332 + u8::SIZE
333 + <SuperSegmentRoot as TrivialType>::SIZE
334 + <SolutionRange as TrivialType>::SIZE
335 + size_of::<BlockHeaderPotParametersChange>() as u32;
336 pub const SUPER_SEGMENT_ROOT_MASK: u8 = 0b_0000_0001;
338 pub const NEXT_SOLUTION_RANGE_MASK: u8 = 0b_0000_0010;
340 pub const POT_PARAMETERS_CHANGE_MASK: u8 = 0b_0000_0100;
342
343 #[inline]
349 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
350 let (fixed_parameters, mut remainder) =
358 BlockHeaderFixedConsensusParameters::try_from_bytes(bytes)?;
359
360 let bitflags = remainder.split_off(..size_of::<u8>())?;
361 let bitflags = bitflags[0];
362
363 let super_segment_root = if bitflags & Self::SUPER_SEGMENT_ROOT_MASK != 0 {
364 let super_segment_root = remainder.split_off(..size_of::<SuperSegmentRoot>())?;
365 let super_segment_root = unsafe { SuperSegmentRoot::from_bytes(super_segment_root) }?;
367
368 Some(super_segment_root)
369 } else {
370 None
371 };
372
373 let next_solution_range = if bitflags & Self::NEXT_SOLUTION_RANGE_MASK != 0 {
374 let next_solution_range = remainder.split_off(..size_of::<SolutionRange>())?;
375 let next_solution_range = SolutionRange::from_bytes([
377 next_solution_range[0],
378 next_solution_range[1],
379 next_solution_range[2],
380 next_solution_range[3],
381 next_solution_range[4],
382 next_solution_range[5],
383 next_solution_range[6],
384 next_solution_range[7],
385 ]);
386
387 Some(next_solution_range)
388 } else {
389 None
390 };
391
392 let pot_parameters_change = if bitflags & Self::POT_PARAMETERS_CHANGE_MASK != 0 {
393 let pot_parameters_change;
394 (pot_parameters_change, remainder) =
395 BlockHeaderPotParametersChange::try_from_bytes(remainder)?;
396
397 Some(pot_parameters_change)
398 } else {
399 None
400 };
401
402 Some((
403 Self {
404 super_segment_root,
405 fixed_parameters,
406 next_solution_range,
407 pot_parameters_change,
408 },
409 remainder,
410 ))
411 }
412
413 pub fn hash(&self) -> Blake3Hash {
415 let Self {
416 super_segment_root,
417 fixed_parameters,
418 next_solution_range,
419 pot_parameters_change,
420 } = self;
421 let BlockHeaderFixedConsensusParameters {
422 solution_range,
423 slot_iterations,
424 } = fixed_parameters;
425
426 let mut hasher = blake3::Hasher::new();
428 hasher.update(solution_range.as_bytes());
429 hasher.update(&slot_iterations.get().to_le_bytes());
430
431 if let Some(super_segment_root) = super_segment_root {
432 hasher.update(super_segment_root.as_bytes());
433 }
434 if let Some(next_solution_range) = next_solution_range {
435 hasher.update(next_solution_range.as_bytes());
436 }
437 if let Some(pot_parameters_change) = pot_parameters_change.copied() {
438 let BlockHeaderPotParametersChange {
439 slot,
440 slot_iterations,
441 entropy,
442 } = pot_parameters_change;
443 hasher.update(slot.as_bytes());
444 hasher.update(&slot_iterations.get().to_le_bytes());
445 hasher.update(entropy.as_bytes());
446 }
447
448 Blake3Hash::from(hasher.finalize())
449 }
450}
451
452#[derive(Debug, Copy, Clone, Deref)]
454pub struct BlockHeaderChildShardBlocks<'a> {
455 pub child_shard_blocks: &'a [BlockRoot],
457}
458
459impl<'a> BlockHeaderChildShardBlocks<'a> {
460 #[inline]
466 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
467 let length = bytes.split_off(..size_of::<u16>())?;
473 let num_blocks = usize::from(*unsafe { <u16 as TrivialType>::from_bytes(length) }?);
475
476 let padding = bytes.split_off(..size_of::<[u8; 2]>())?;
477
478 if padding != [0, 0] {
480 return None;
481 }
482
483 let child_shard_blocks = bytes.split_off(..num_blocks * BlockRoot::SIZE)?;
484 let child_shard_blocks = unsafe {
486 slice::from_raw_parts(
487 child_shard_blocks.as_ptr().cast::<[u8; BlockRoot::SIZE]>(),
488 num_blocks,
489 )
490 };
491 let child_shard_blocks = BlockRoot::slice_from_repr(child_shard_blocks);
492
493 Some((Self { child_shard_blocks }, bytes))
494 }
495
496 pub fn root(&self) -> Option<Blake3Hash> {
500 let root = UnbalancedMerkleTree::compute_root_only::<'_, { u32::MAX as u64 }, _, _>(
501 self.child_shard_blocks
503 .iter()
504 .map(|child_shard_block_root| {
505 blake3::hash(child_shard_block_root.as_ref())
510 }),
511 )?;
512 Some(Blake3Hash::new(root))
513 }
514}
515
516#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
520#[cfg_attr(
521 feature = "scale-codec",
522 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
523)]
524#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
525#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
526#[repr(C)]
527pub struct BlockHeaderResult {
528 pub body_root: Blake3Hash,
531 pub state_root: Blake3Hash,
534}
535
536impl BlockHeaderResult {
537 pub fn hash(&self) -> Blake3Hash {
539 Blake3Hash::from(blake3::hash(self.as_bytes()))
541 }
542}
543
544#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
546#[cfg_attr(
547 feature = "scale-codec",
548 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
549)]
550#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
551#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
552#[repr(u8)]
553#[non_exhaustive]
554pub enum BlockHeaderSealType {
555 #[cfg_attr(feature = "scale-codec", codec(index = 0))]
557 Ed25519 = 0,
558}
559
560impl BlockHeaderSealType {
561 #[inline(always)]
563 pub const fn try_from_byte(byte: u8) -> Option<Self> {
564 if byte == Self::Ed25519 as u8 {
565 Some(Self::Ed25519)
566 } else {
567 None
568 }
569 }
570}
571
572#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
574#[cfg_attr(
575 feature = "scale-codec",
576 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
577)]
578#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
579#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
580#[repr(C)]
581pub struct BlockHeaderEd25519Seal {
582 pub public_key: Ed25519PublicKey,
584 pub signature: Ed25519Signature,
586}
587
588#[derive(Debug, Copy, Clone)]
590#[cfg_attr(
591 feature = "scale-codec",
592 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
593)]
594#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
595#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
596#[non_exhaustive]
597pub enum OwnedBlockHeaderSeal {
598 Ed25519(BlockHeaderEd25519Seal),
600}
601
602impl OwnedBlockHeaderSeal {
603 #[inline(always)]
605 pub fn as_ref(&self) -> BlockHeaderSeal<'_> {
606 match self {
607 Self::Ed25519(seal) => BlockHeaderSeal::Ed25519(seal),
608 }
609 }
610}
611
612#[derive(Debug, Copy, Clone)]
614#[non_exhaustive]
615pub enum BlockHeaderSeal<'a> {
616 Ed25519(&'a BlockHeaderEd25519Seal),
618}
619
620impl<'a> BlockHeaderSeal<'a> {
621 pub const MAX_SIZE: u32 = 1 + BlockHeaderEd25519Seal::SIZE;
623 #[inline]
629 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
630 let seal_type = bytes.split_off(..size_of::<u8>())?;
635 let seal_type = BlockHeaderSealType::try_from_byte(seal_type[0])?;
636
637 match seal_type {
638 BlockHeaderSealType::Ed25519 => {
639 let seal = bytes.split_off(..size_of::<BlockHeaderEd25519Seal>())?;
640 let seal = unsafe { BlockHeaderEd25519Seal::from_bytes(seal) }?;
642 Some((Self::Ed25519(seal), bytes))
643 }
644 }
645 }
646
647 #[inline]
649 pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
650 match self {
651 BlockHeaderSeal::Ed25519(seal) => seal
652 .public_key
653 .verify(&seal.signature, pre_seal_hash.as_bytes())
654 .is_ok(),
655 }
656 }
657
658 #[inline]
660 pub fn public_key_hash(&self) -> Blake3Hash {
661 match self {
662 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
663 }
664 }
665
666 #[inline]
668 pub fn hash(&self) -> Blake3Hash {
669 match self {
670 BlockHeaderSeal::Ed25519(seal) => {
671 let mut hasher = blake3::Hasher::new();
673 hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
674 hasher.update(seal.as_bytes());
675
676 Blake3Hash::from(hasher.finalize())
677 }
678 }
679 }
680}
681
682#[derive(Debug, Copy, Clone)]
684pub struct SharedBlockHeader<'a> {
685 pub prefix: &'a BlockHeaderPrefix,
687 pub result: &'a BlockHeaderResult,
689 pub consensus_info: &'a BlockHeaderConsensusInfo,
691 pub seal: BlockHeaderSeal<'a>,
693}
694
695#[derive(Debug, Clone, Yokeable)]
697#[non_exhaustive]
699pub struct BeaconChainHeader<'a> {
700 shared: SharedBlockHeader<'a>,
702 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
704 consensus_parameters: BlockHeaderConsensusParameters<'a>,
706 pre_seal_bytes: &'a [u8],
708 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
709 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
710 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
711 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
712}
713
714impl<'a> Deref for BeaconChainHeader<'a> {
715 type Target = SharedBlockHeader<'a>;
716
717 #[inline(always)]
718 fn deref(&self) -> &Self::Target {
719 &self.shared
720 }
721}
722
723impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
724 const SHARD_KIND: ShardKind = ShardKind::BeaconChain;
725
726 #[cfg(feature = "alloc")]
727 type Owned = OwnedBeaconChainHeader;
728
729 #[cfg(feature = "alloc")]
730 #[inline(always)]
731 fn to_owned(self) -> Self::Owned {
732 self.to_owned()
733 }
734
735 #[inline(always)]
736 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
737 self.root()
738 }
739}
740
741impl<'a> BeaconChainHeader<'a> {
742 #[inline]
749 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
750 let (prefix, consensus_info, result, remainder) =
759 BlockHeader::try_from_bytes_shared(bytes)?;
760
761 if prefix.shard_index.shard_kind() != ShardKind::BeaconChain {
762 return None;
763 }
764
765 let (child_shard_blocks, remainder) =
766 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
767
768 let (consensus_parameters, remainder) =
769 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
770
771 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
772
773 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
774
775 let shared = SharedBlockHeader {
776 prefix,
777 result,
778 consensus_info,
779 seal,
780 };
781
782 let header = Self {
783 shared,
784 child_shard_blocks,
785 consensus_parameters,
786 pre_seal_bytes,
787 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
788 cached_block_root: rclite::Arc::default(),
789 };
790
791 if !header.is_internally_consistent() {
792 return None;
793 }
794
795 Some((header, remainder))
796 }
797
798 #[inline]
803 pub fn is_internally_consistent(&self) -> bool {
804 let public_key_hash = match self.seal {
805 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
806 };
807 public_key_hash == self.shared.consensus_info.solution.public_key_hash
808 }
809
810 #[inline]
813 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
814 let (prefix, consensus_info, result, remainder) =
823 BlockHeader::try_from_bytes_shared(bytes)?;
824
825 if prefix.shard_index.shard_kind() != ShardKind::BeaconChain {
826 return None;
827 }
828
829 let (child_shard_blocks, remainder) =
830 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
831
832 let (consensus_parameters, remainder) =
833 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
834
835 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
836
837 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
838
839 let shared = SharedBlockHeader {
840 prefix,
841 result,
842 consensus_info,
843 seal,
844 };
845
846 Some((
847 Self {
848 shared,
849 child_shard_blocks,
850 consensus_parameters,
851 pre_seal_bytes,
852 #[cfg(any(
853 feature = "alloc",
854 not(any(target_os = "none", target_os = "unknown"))
855 ))]
856 cached_block_root: rclite::Arc::default(),
857 },
858 remainder,
859 ))
860 }
861
862 #[cfg(feature = "alloc")]
864 #[inline(always)]
865 pub fn to_owned(self) -> OwnedBeaconChainHeader {
866 let unsealed = OwnedBeaconChainHeader::from_parts(
867 self.shared.prefix,
868 self.shared.result,
869 self.shared.consensus_info,
870 &self.child_shard_blocks,
871 self.consensus_parameters,
872 )
873 .expect("`self` is always a valid invariant; qed");
874
875 unsealed.with_seal(self.shared.seal)
876 }
877
878 #[inline(always)]
880 pub fn shared(&self) -> &SharedBlockHeader<'a> {
881 &self.shared
882 }
883
884 #[inline(always)]
886 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
887 &self.child_shard_blocks
888 }
889
890 #[inline(always)]
892 pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
893 &self.consensus_parameters
894 }
895
896 #[inline]
898 pub fn pre_seal_hash(&self) -> Blake3Hash {
899 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
901 }
902
903 #[inline]
906 pub fn is_sealed_correctly(&self) -> bool {
907 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
908 && self.seal.is_seal_valid(&self.pre_seal_hash())
909 }
910
911 #[inline]
919 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
920 let Self {
921 shared,
922 child_shard_blocks,
923 consensus_parameters,
924 pre_seal_bytes: _,
925 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
926 cached_block_root,
927 } = self;
928
929 let compute_root = || {
930 let SharedBlockHeader {
931 prefix,
932 result,
933 consensus_info,
934 seal,
935 } = shared;
936
937 const MAX_N: usize = 6;
938 let leaves: [_; MAX_N] = [
939 prefix.hash(),
940 result.hash(),
941 consensus_info.hash(),
942 seal.hash(),
943 child_shard_blocks.root().unwrap_or_default(),
944 consensus_parameters.hash(),
945 ];
946 let block_root =
947 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
948 .expect("The list is not empty; qed");
949
950 BlockRoot::new(Blake3Hash::new(block_root))
951 };
952
953 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
954 {
955 cached_block_root.get_or_init(compute_root)
956 }
957 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
958 {
959 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
960 }
961 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
962 {
963 struct Wrapper(BlockRoot);
964
965 impl Deref for Wrapper {
966 type Target = BlockRoot;
967
968 #[inline(always)]
969 fn deref(&self) -> &Self::Target {
970 &self.0
971 }
972 }
973
974 Wrapper(compute_root())
975 }
976 }
977}
978
979#[derive(Debug, Clone, Yokeable)]
981#[non_exhaustive]
983pub struct IntermediateShardHeader<'a> {
984 shared: SharedBlockHeader<'a>,
986 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
988 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
990 pre_seal_bytes: &'a [u8],
992 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
993 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
994 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
995 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
996}
997
998impl<'a> Deref for IntermediateShardHeader<'a> {
999 type Target = SharedBlockHeader<'a>;
1000
1001 #[inline(always)]
1002 fn deref(&self) -> &Self::Target {
1003 &self.shared
1004 }
1005}
1006
1007impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
1008 const SHARD_KIND: ShardKind = ShardKind::IntermediateShard;
1009
1010 #[cfg(feature = "alloc")]
1011 type Owned = OwnedIntermediateShardHeader;
1012
1013 #[cfg(feature = "alloc")]
1014 #[inline(always)]
1015 fn to_owned(self) -> Self::Owned {
1016 self.to_owned()
1017 }
1018
1019 #[inline(always)]
1020 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1021 self.root()
1022 }
1023}
1024
1025impl<'a> IntermediateShardHeader<'a> {
1026 #[inline]
1033 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1034 let (prefix, consensus_info, result, mut remainder) =
1043 BlockHeader::try_from_bytes_shared(bytes)?;
1044
1045 if prefix.shard_index.shard_kind() != ShardKind::IntermediateShard {
1046 return None;
1047 }
1048
1049 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1050 let beacon_chain_info =
1052 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1053
1054 let (child_shard_blocks, remainder) =
1055 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1056
1057 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1058
1059 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1060
1061 let shared = SharedBlockHeader {
1062 prefix,
1063 result,
1064 consensus_info,
1065 seal,
1066 };
1067
1068 let header = Self {
1069 shared,
1070 beacon_chain_info,
1071 child_shard_blocks,
1072 pre_seal_bytes,
1073 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1074 cached_block_root: rclite::Arc::default(),
1075 };
1076
1077 if !header.is_internally_consistent() {
1078 return None;
1079 }
1080
1081 Some((header, remainder))
1082 }
1083
1084 #[inline]
1089 pub fn is_internally_consistent(&self) -> bool {
1090 let public_key_hash = match self.seal {
1091 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1092 };
1093 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1094 }
1095
1096 #[inline]
1099 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1100 let (prefix, consensus_info, result, mut remainder) =
1109 BlockHeader::try_from_bytes_shared(bytes)?;
1110
1111 if prefix.shard_index.shard_kind() != ShardKind::IntermediateShard {
1112 return None;
1113 }
1114
1115 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1116 let beacon_chain_info =
1118 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1119
1120 let (child_shard_blocks, remainder) =
1121 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1122
1123 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1124
1125 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1126
1127 let shared = SharedBlockHeader {
1128 prefix,
1129 result,
1130 consensus_info,
1131 seal,
1132 };
1133
1134 Some((
1135 Self {
1136 shared,
1137 beacon_chain_info,
1138 child_shard_blocks,
1139 pre_seal_bytes,
1140 #[cfg(any(
1141 feature = "alloc",
1142 not(any(target_os = "none", target_os = "unknown"))
1143 ))]
1144 cached_block_root: rclite::Arc::default(),
1145 },
1146 remainder,
1147 ))
1148 }
1149
1150 #[cfg(feature = "alloc")]
1152 #[inline(always)]
1153 pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1154 let unsealed = OwnedIntermediateShardHeader::from_parts(
1155 self.shared.prefix,
1156 self.shared.result,
1157 self.shared.consensus_info,
1158 self.beacon_chain_info,
1159 &self.child_shard_blocks,
1160 )
1161 .expect("`self` is always a valid invariant; qed");
1162
1163 unsealed.with_seal(self.shared.seal)
1164 }
1165
1166 #[inline(always)]
1168 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1169 &self.shared
1170 }
1171
1172 #[inline(always)]
1174 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1175 self.beacon_chain_info
1176 }
1177
1178 #[inline(always)]
1180 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1181 &self.child_shard_blocks
1182 }
1183
1184 #[inline]
1186 pub fn pre_seal_hash(&self) -> Blake3Hash {
1187 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1189 }
1190
1191 #[inline]
1194 pub fn is_sealed_correctly(&self) -> bool {
1195 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1196 && self.seal.is_seal_valid(&self.pre_seal_hash())
1197 }
1198
1199 #[inline]
1207 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1208 let Self {
1209 shared,
1210 beacon_chain_info,
1211 child_shard_blocks,
1212 pre_seal_bytes: _,
1213 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1214 cached_block_root,
1215 } = self;
1216
1217 let compute_root = || {
1218 let SharedBlockHeader {
1219 prefix,
1220 result,
1221 consensus_info,
1222 seal,
1223 } = shared;
1224
1225 const MAX_N: usize = 6;
1226 let leaves: [_; MAX_N] = [
1227 prefix.hash(),
1228 result.hash(),
1229 consensus_info.hash(),
1230 seal.hash(),
1231 beacon_chain_info.hash(),
1232 child_shard_blocks.root().unwrap_or_default(),
1233 ];
1234 let block_root =
1235 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1236 .expect("The list is not empty; qed");
1237
1238 BlockRoot::new(Blake3Hash::new(block_root))
1239 };
1240
1241 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1242 {
1243 cached_block_root.get_or_init(compute_root)
1244 }
1245 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1246 {
1247 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1248 }
1249 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1250 {
1251 struct Wrapper(BlockRoot);
1252
1253 impl Deref for Wrapper {
1254 type Target = BlockRoot;
1255
1256 #[inline(always)]
1257 fn deref(&self) -> &Self::Target {
1258 &self.0
1259 }
1260 }
1261
1262 Wrapper(compute_root())
1263 }
1264 }
1265}
1266
1267#[derive(Debug, Clone, Yokeable)]
1269#[non_exhaustive]
1271pub struct LeafShardHeader<'a> {
1272 shared: SharedBlockHeader<'a>,
1274 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1276 pre_seal_bytes: &'a [u8],
1278 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1279 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1280 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1281 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1282}
1283
1284impl<'a> Deref for LeafShardHeader<'a> {
1285 type Target = SharedBlockHeader<'a>;
1286
1287 #[inline(always)]
1288 fn deref(&self) -> &Self::Target {
1289 &self.shared
1290 }
1291}
1292
1293impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1294 const SHARD_KIND: ShardKind = ShardKind::LeafShard;
1295
1296 #[cfg(feature = "alloc")]
1297 type Owned = OwnedLeafShardHeader;
1298
1299 #[cfg(feature = "alloc")]
1300 #[inline(always)]
1301 fn to_owned(self) -> Self::Owned {
1302 self.to_owned()
1303 }
1304
1305 #[inline(always)]
1306 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1307 self.root()
1308 }
1309}
1310
1311impl<'a> LeafShardHeader<'a> {
1312 #[inline]
1319 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1320 let (prefix, consensus_info, result, mut remainder) =
1328 BlockHeader::try_from_bytes_shared(bytes)?;
1329
1330 if prefix.shard_index.shard_kind() != ShardKind::LeafShard {
1331 return None;
1332 }
1333
1334 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1335 let beacon_chain_info =
1337 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1338
1339 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1340
1341 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1342
1343 let shared = SharedBlockHeader {
1344 prefix,
1345 result,
1346 consensus_info,
1347 seal,
1348 };
1349
1350 let header = Self {
1351 shared,
1352 beacon_chain_info,
1353 pre_seal_bytes,
1354 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1355 cached_block_root: rclite::Arc::default(),
1356 };
1357
1358 if !header.is_internally_consistent() {
1359 return None;
1360 }
1361
1362 Some((header, remainder))
1363 }
1364
1365 #[inline]
1370 pub fn is_internally_consistent(&self) -> bool {
1371 let public_key_hash = match self.seal {
1372 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1373 };
1374 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1375 }
1376
1377 #[inline]
1380 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1381 let (prefix, consensus_info, result, mut remainder) =
1389 BlockHeader::try_from_bytes_shared(bytes)?;
1390
1391 if prefix.shard_index.shard_kind() != ShardKind::LeafShard {
1392 return None;
1393 }
1394
1395 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1396 let beacon_chain_info =
1398 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1399
1400 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1401
1402 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1403
1404 let shared = SharedBlockHeader {
1405 prefix,
1406 result,
1407 consensus_info,
1408 seal,
1409 };
1410
1411 Some((
1412 Self {
1413 shared,
1414 beacon_chain_info,
1415 pre_seal_bytes,
1416 #[cfg(any(
1417 feature = "alloc",
1418 not(any(target_os = "none", target_os = "unknown"))
1419 ))]
1420 cached_block_root: rclite::Arc::default(),
1421 },
1422 remainder,
1423 ))
1424 }
1425
1426 #[cfg(feature = "alloc")]
1428 #[inline(always)]
1429 pub fn to_owned(self) -> OwnedLeafShardHeader {
1430 let unsealed = OwnedLeafShardHeader::from_parts(
1431 self.shared.prefix,
1432 self.shared.result,
1433 self.shared.consensus_info,
1434 self.beacon_chain_info,
1435 );
1436
1437 unsealed.with_seal(self.shared.seal)
1438 }
1439
1440 #[inline(always)]
1442 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1443 &self.shared
1444 }
1445
1446 #[inline(always)]
1448 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1449 self.beacon_chain_info
1450 }
1451
1452 #[inline]
1454 pub fn pre_seal_hash(&self) -> Blake3Hash {
1455 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1457 }
1458
1459 #[inline]
1462 pub fn is_sealed_correctly(&self) -> bool {
1463 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1464 && self.seal.is_seal_valid(&self.pre_seal_hash())
1465 }
1466
1467 #[inline]
1475 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1476 let Self {
1477 shared,
1478 beacon_chain_info,
1479 pre_seal_bytes: _,
1480 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1481 cached_block_root,
1482 } = self;
1483
1484 let compute_root = || {
1485 let SharedBlockHeader {
1486 prefix,
1487 result,
1488 consensus_info,
1489 seal,
1490 } = shared;
1491
1492 const MAX_N: usize = 5;
1493 let leaves: [_; MAX_N] = [
1494 prefix.hash(),
1495 result.hash(),
1496 consensus_info.hash(),
1497 seal.hash(),
1498 beacon_chain_info.hash(),
1499 ];
1500 let block_root =
1501 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1502 .expect("The list is not empty; qed");
1503
1504 BlockRoot::new(Blake3Hash::new(block_root))
1505 };
1506
1507 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1508 {
1509 cached_block_root.get_or_init(compute_root)
1510 }
1511 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1512 {
1513 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1514 }
1515 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1516 {
1517 struct Wrapper(BlockRoot);
1518
1519 impl Deref for Wrapper {
1520 type Target = BlockRoot;
1521
1522 #[inline(always)]
1523 fn deref(&self) -> &Self::Target {
1524 &self.0
1525 }
1526 }
1527
1528 Wrapper(compute_root())
1529 }
1530 }
1531}
1532
1533#[derive(Debug, Clone, From)]
1538pub enum BlockHeader<'a> {
1539 BeaconChain(BeaconChainHeader<'a>),
1541 IntermediateShard(IntermediateShardHeader<'a>),
1543 LeafShard(LeafShardHeader<'a>),
1545}
1546
1547impl<'a> Deref for BlockHeader<'a> {
1548 type Target = SharedBlockHeader<'a>;
1549
1550 #[inline(always)]
1551 fn deref(&self) -> &Self::Target {
1552 match self {
1553 Self::BeaconChain(header) => header,
1554 Self::IntermediateShard(header) => header,
1555 Self::LeafShard(header) => header,
1556 }
1557 }
1558}
1559
1560impl<'a> BlockHeader<'a> {
1561 #[inline]
1568 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: ShardKind) -> Option<(Self, &'a [u8])> {
1569 match shard_kind {
1570 ShardKind::BeaconChain => {
1571 let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1572 Some((Self::BeaconChain(header), remainder))
1573 }
1574 ShardKind::IntermediateShard => {
1575 let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1576 Some((Self::IntermediateShard(header), remainder))
1577 }
1578 ShardKind::LeafShard => {
1579 let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1580 Some((Self::LeafShard(header), remainder))
1581 }
1582 ShardKind::Phantom | ShardKind::Invalid => {
1583 None
1585 }
1586 }
1587 }
1588
1589 #[inline]
1594 pub fn is_internally_consistent(&self) -> bool {
1595 match self {
1596 Self::BeaconChain(header) => header.is_internally_consistent(),
1597 Self::IntermediateShard(header) => header.is_internally_consistent(),
1598 Self::LeafShard(header) => header.is_internally_consistent(),
1599 }
1600 }
1601
1602 #[inline]
1605 pub fn try_from_bytes_unchecked(
1606 bytes: &'a [u8],
1607 shard_kind: ShardKind,
1608 ) -> Option<(Self, &'a [u8])> {
1609 match shard_kind {
1610 ShardKind::BeaconChain => {
1611 let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1612 Some((Self::BeaconChain(header), remainder))
1613 }
1614 ShardKind::IntermediateShard => {
1615 let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1616 Some((Self::IntermediateShard(header), remainder))
1617 }
1618 ShardKind::LeafShard => {
1619 let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1620 Some((Self::LeafShard(header), remainder))
1621 }
1622 ShardKind::Phantom | ShardKind::Invalid => {
1623 None
1625 }
1626 }
1627 }
1628
1629 #[inline]
1630 fn try_from_bytes_shared(
1631 mut bytes: &'a [u8],
1632 ) -> Option<(
1633 &'a BlockHeaderPrefix,
1634 &'a BlockHeaderConsensusInfo,
1635 &'a BlockHeaderResult,
1636 &'a [u8],
1637 )> {
1638 let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1639 let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1641
1642 if !(prefix.padding_0 == [0; _]
1643 && prefix.shard_index.as_u32() <= ShardIndex::MAX_SHARD_INDEX)
1644 {
1645 return None;
1646 }
1647
1648 let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1649 let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1651
1652 let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1653 let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1655
1656 if consensus_info.solution.padding != [0; _] {
1657 return None;
1658 }
1659
1660 Some((prefix, consensus_info, result, bytes))
1661 }
1662
1663 #[cfg(feature = "alloc")]
1665 #[inline(always)]
1666 pub fn to_owned(self) -> OwnedBlockHeader {
1667 match self {
1668 Self::BeaconChain(header) => header.to_owned().into(),
1669 Self::IntermediateShard(header) => header.to_owned().into(),
1670 Self::LeafShard(header) => header.to_owned().into(),
1671 }
1672 }
1673
1674 #[inline]
1676 pub fn pre_seal_hash(&self) -> Blake3Hash {
1677 match self {
1678 Self::BeaconChain(header) => header.pre_seal_hash(),
1679 Self::IntermediateShard(header) => header.pre_seal_hash(),
1680 Self::LeafShard(header) => header.pre_seal_hash(),
1681 }
1682 }
1683
1684 #[inline]
1687 pub fn is_sealed_correctly(&self) -> bool {
1688 match self {
1689 Self::BeaconChain(header) => header.is_sealed_correctly(),
1690 Self::IntermediateShard(header) => header.is_sealed_correctly(),
1691 Self::LeafShard(header) => header.is_sealed_correctly(),
1692 }
1693 }
1694
1695 #[inline]
1703 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1704 enum Wrapper<B, I, L> {
1705 BeaconChain(B),
1706 IntermediateShard(I),
1707 LeafShard(L),
1708 }
1709
1710 impl<B, I, L> Deref for Wrapper<B, I, L>
1711 where
1712 B: Deref<Target = BlockRoot>,
1713 I: Deref<Target = BlockRoot>,
1714 L: Deref<Target = BlockRoot>,
1715 {
1716 type Target = BlockRoot;
1717
1718 #[inline(always)]
1719 fn deref(&self) -> &Self::Target {
1720 match self {
1721 Wrapper::BeaconChain(block_root) => block_root,
1722 Wrapper::IntermediateShard(block_root) => block_root,
1723 Wrapper::LeafShard(block_root) => block_root,
1724 }
1725 }
1726 }
1727
1728 match self {
1730 Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1731 Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1732 Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1733 }
1734 }
1735}