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_blake3::{BLOCK_LEN, single_block_hash, single_chunk_hash};
19use ab_io_type::trivial_type::TrivialType;
20use ab_merkle_tree::unbalanced::UnbalancedMerkleTree;
21use blake3::CHUNK_LEN;
22use core::num::NonZeroU32;
23use core::ops::Deref;
24use core::{fmt, slice};
25use derive_more::{Deref, From};
26#[cfg(feature = "scale-codec")]
27use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
28#[cfg(feature = "scale-codec")]
29use scale_info::TypeInfo;
30#[cfg(feature = "serde")]
31use serde::{Deserialize, Serialize};
32use yoke::Yokeable;
33
34pub trait GenericBlockHeader<'a>
36where
37 Self: Clone
38 + fmt::Debug
39 + Deref<Target = SharedBlockHeader<'a>>
40 + Into<BlockHeader<'a>>
41 + Send
42 + Sync,
43{
44 const SHARD_KIND: ShardKind;
46
47 #[cfg(feature = "alloc")]
49 type Owned: GenericOwnedBlockHeader<Header<'a> = Self>
50 where
51 Self: 'a;
52
53 #[cfg(feature = "alloc")]
55 fn to_owned(self) -> Self::Owned;
56
57 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync;
64}
65
66#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
70#[cfg_attr(
71 feature = "scale-codec",
72 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
73)]
74#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
75#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
76#[repr(C)]
77pub struct BlockHeaderPrefix {
78 pub number: BlockNumber,
80 pub shard_index: ShardIndex,
82 pub padding_0: [u8; 4],
84 pub timestamp: BlockTimestamp,
86 pub parent_root: BlockRoot,
88 pub mmr_root: Blake3Hash,
91}
92
93impl BlockHeaderPrefix {
94 pub fn hash(&self) -> Blake3Hash {
96 const {
97 assert!(size_of::<Self>() <= CHUNK_LEN);
98 }
99 Blake3Hash::new(
101 single_chunk_hash(self.as_bytes())
102 .expect("Less than a single chunk worth of bytes; qed"),
103 )
104 }
105}
106
107#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
109#[cfg_attr(
110 feature = "scale-codec",
111 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
112)]
113#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
114#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
115#[repr(C)]
116pub struct BlockHeaderConsensusInfo {
117 pub slot: SlotNumber,
119 pub proof_of_time: PotOutput,
121 pub future_proof_of_time: PotOutput,
123 pub solution: Solution,
125}
126
127impl BlockHeaderConsensusInfo {
128 pub fn hash(&self) -> Blake3Hash {
130 Blake3Hash::from(blake3::hash(self.as_bytes()))
132 }
133}
134
135#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, TrivialType)]
137#[cfg_attr(
138 feature = "scale-codec",
139 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
140)]
141#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
142#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
143#[repr(C)]
144pub struct BlockHeaderBeaconChainInfo {
145 pub number: BlockNumber,
147 pub root: BlockRoot,
149}
150
151impl BlockHeaderBeaconChainInfo {
152 pub fn hash(&self) -> Blake3Hash {
154 const {
155 assert!(size_of::<Self>() <= BLOCK_LEN);
156 }
157 Blake3Hash::new(
159 single_block_hash(self.as_bytes())
160 .expect("Less than a single block worth of bytes; qed"),
161 )
162 }
163}
164
165#[derive(Debug, Copy, Clone, Eq, PartialEq)]
167#[cfg_attr(
168 feature = "scale-codec",
169 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
170)]
171#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
172#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
173pub struct BlockHeaderFixedConsensusParameters {
174 pub solution_range: SolutionRange,
176 pub slot_iterations: NonZeroU32,
181}
182
183impl BlockHeaderFixedConsensusParameters {
184 #[inline]
190 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(Self, &[u8])> {
191 let solution_range = bytes.split_off(..size_of::<SolutionRange>())?;
196 let solution_range = SolutionRange::from_bytes([
197 solution_range[0],
198 solution_range[1],
199 solution_range[2],
200 solution_range[3],
201 solution_range[4],
202 solution_range[5],
203 solution_range[6],
204 solution_range[7],
205 ]);
206
207 let pot_slot_iterations = bytes.split_off(..size_of::<u32>())?;
208 let slot_iterations = u32::from_le_bytes([
209 pot_slot_iterations[0],
210 pot_slot_iterations[1],
211 pot_slot_iterations[2],
212 pot_slot_iterations[3],
213 ]);
214 let slot_iterations = NonZeroU32::new(slot_iterations)?;
215
216 Some((
217 Self {
218 solution_range,
219 slot_iterations,
220 },
221 bytes,
222 ))
223 }
224}
225
226#[derive(Debug, Copy, Clone, Eq, PartialEq)]
230#[repr(C, packed)]
231pub struct BlockHeaderPotParametersChange {
232 slot: SlotNumber,
236 slot_iterations: NonZeroU32,
238 entropy: Blake3Hash,
240}
241
242impl From<BlockHeaderPotParametersChange> for PotParametersChange {
243 #[inline(always)]
244 fn from(value: BlockHeaderPotParametersChange) -> Self {
245 let BlockHeaderPotParametersChange {
246 slot,
247 slot_iterations,
248 entropy,
249 } = value;
250
251 PotParametersChange {
252 slot,
253 slot_iterations,
254 entropy,
255 }
256 }
257}
258
259impl From<PotParametersChange> for BlockHeaderPotParametersChange {
260 #[inline(always)]
261 fn from(value: PotParametersChange) -> Self {
262 let PotParametersChange {
263 slot,
264 slot_iterations,
265 entropy,
266 } = value;
267
268 BlockHeaderPotParametersChange {
269 slot,
270 slot_iterations,
271 entropy,
272 }
273 }
274}
275
276impl BlockHeaderPotParametersChange {
277 #[inline]
283 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(&Self, &[u8])> {
284 let _slot = bytes.split_off(..size_of::<SlotNumber>())?;
290
291 let slot_iterations = bytes.split_off(..size_of::<u32>())?;
292 if slot_iterations == [0, 0, 0, 0] {
293 return None;
294 }
295 let _entropy = bytes.split_off(..size_of::<Blake3Hash>())?;
296
297 let pot_parameters_change = unsafe { bytes.as_ptr().cast::<Self>().as_ref_unchecked() };
299
300 Some((pot_parameters_change, bytes))
301 }
302}
303
304#[derive(Debug, Copy, Clone)]
306pub struct OwnedBlockHeaderConsensusParameters {
307 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
309 pub super_segment_root: Option<SuperSegmentRoot>,
311 pub next_solution_range: Option<SolutionRange>,
313 pub pot_parameters_change: Option<BlockHeaderPotParametersChange>,
315}
316
317impl OwnedBlockHeaderConsensusParameters {
318 #[inline]
320 pub fn as_ref(&self) -> BlockHeaderConsensusParameters<'_> {
321 BlockHeaderConsensusParameters {
322 fixed_parameters: self.fixed_parameters,
323 super_segment_root: self.super_segment_root.as_ref(),
324 next_solution_range: self.next_solution_range,
325 pot_parameters_change: self.pot_parameters_change.as_ref(),
326 }
327 }
328}
329
330#[derive(Debug, Copy, Clone, Eq, PartialEq)]
332pub struct BlockHeaderConsensusParameters<'a> {
333 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
335 pub super_segment_root: Option<&'a SuperSegmentRoot>,
337 pub next_solution_range: Option<SolutionRange>,
339 pub pot_parameters_change: Option<&'a BlockHeaderPotParametersChange>,
341}
342
343impl<'a> BlockHeaderConsensusParameters<'a> {
344 pub const MAX_SIZE: u32 = size_of::<BlockHeaderFixedConsensusParameters>() as u32
346 + u8::SIZE
347 + <SuperSegmentRoot as TrivialType>::SIZE
348 + <SolutionRange as TrivialType>::SIZE
349 + size_of::<BlockHeaderPotParametersChange>() as u32;
350 pub const SUPER_SEGMENT_ROOT_MASK: u8 = 0b_0000_0001;
352 pub const NEXT_SOLUTION_RANGE_MASK: u8 = 0b_0000_0010;
354 pub const POT_PARAMETERS_CHANGE_MASK: u8 = 0b_0000_0100;
356
357 #[inline]
363 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
364 let (fixed_parameters, mut remainder) =
372 BlockHeaderFixedConsensusParameters::try_from_bytes(bytes)?;
373
374 let bitflags = remainder.split_off(..size_of::<u8>())?;
375 let bitflags = bitflags[0];
376
377 let super_segment_root = if bitflags & Self::SUPER_SEGMENT_ROOT_MASK != 0 {
378 let super_segment_root = remainder.split_off(..size_of::<SuperSegmentRoot>())?;
379 let super_segment_root = unsafe { SuperSegmentRoot::from_bytes(super_segment_root) }?;
381
382 Some(super_segment_root)
383 } else {
384 None
385 };
386
387 let next_solution_range = if bitflags & Self::NEXT_SOLUTION_RANGE_MASK != 0 {
388 let next_solution_range = remainder.split_off(..size_of::<SolutionRange>())?;
389 let next_solution_range = SolutionRange::from_bytes([
391 next_solution_range[0],
392 next_solution_range[1],
393 next_solution_range[2],
394 next_solution_range[3],
395 next_solution_range[4],
396 next_solution_range[5],
397 next_solution_range[6],
398 next_solution_range[7],
399 ]);
400
401 Some(next_solution_range)
402 } else {
403 None
404 };
405
406 let pot_parameters_change = if bitflags & Self::POT_PARAMETERS_CHANGE_MASK != 0 {
407 let pot_parameters_change;
408 (pot_parameters_change, remainder) =
409 BlockHeaderPotParametersChange::try_from_bytes(remainder)?;
410
411 Some(pot_parameters_change)
412 } else {
413 None
414 };
415
416 Some((
417 Self {
418 super_segment_root,
419 fixed_parameters,
420 next_solution_range,
421 pot_parameters_change,
422 },
423 remainder,
424 ))
425 }
426
427 pub fn hash(&self) -> Blake3Hash {
429 let Self {
430 super_segment_root,
431 fixed_parameters,
432 next_solution_range,
433 pot_parameters_change,
434 } = self;
435 let BlockHeaderFixedConsensusParameters {
436 solution_range,
437 slot_iterations,
438 } = fixed_parameters;
439
440 let mut hasher = blake3::Hasher::new();
442 hasher.update(solution_range.as_bytes());
443 hasher.update(&slot_iterations.get().to_le_bytes());
444
445 if let Some(super_segment_root) = super_segment_root {
446 hasher.update(super_segment_root.as_bytes());
447 }
448 if let Some(next_solution_range) = next_solution_range {
449 hasher.update(next_solution_range.as_bytes());
450 }
451 if let Some(pot_parameters_change) = pot_parameters_change.copied() {
452 let BlockHeaderPotParametersChange {
453 slot,
454 slot_iterations,
455 entropy,
456 } = pot_parameters_change;
457 hasher.update(slot.as_bytes());
458 hasher.update(&slot_iterations.get().to_le_bytes());
459 hasher.update(entropy.as_bytes());
460 }
461
462 Blake3Hash::from(hasher.finalize())
463 }
464}
465
466#[derive(Debug, Copy, Clone, Deref)]
468pub struct BlockHeaderChildShardBlocks<'a> {
469 pub child_shard_blocks: &'a [BlockRoot],
471}
472
473impl<'a> BlockHeaderChildShardBlocks<'a> {
474 #[inline]
480 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
481 let length = bytes.split_off(..size_of::<u16>())?;
487 let num_blocks = usize::from(*unsafe { <u16 as TrivialType>::from_bytes(length) }?);
489
490 let padding = bytes.split_off(..size_of::<[u8; 2]>())?;
491
492 if padding != [0, 0] {
494 return None;
495 }
496
497 let child_shard_blocks = bytes.split_off(..num_blocks * BlockRoot::SIZE)?;
498 let child_shard_blocks = unsafe {
500 slice::from_raw_parts(
501 child_shard_blocks.as_ptr().cast::<[u8; BlockRoot::SIZE]>(),
502 num_blocks,
503 )
504 };
505 let child_shard_blocks = BlockRoot::slice_from_repr(child_shard_blocks);
506
507 Some((Self { child_shard_blocks }, bytes))
508 }
509
510 pub fn root(&self) -> Option<Blake3Hash> {
514 let root = UnbalancedMerkleTree::compute_root_only::<'_, { u32::MAX as u64 }, _, _>(
515 self.child_shard_blocks
517 .iter()
518 .map(|child_shard_block_root| {
519 single_block_hash(child_shard_block_root.as_ref())
523 .expect("Less than a single block worth of bytes; qed")
524 }),
525 )?;
526 Some(Blake3Hash::new(root))
527 }
528}
529
530#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
534#[cfg_attr(
535 feature = "scale-codec",
536 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
537)]
538#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
539#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
540#[repr(C)]
541pub struct BlockHeaderResult {
542 pub body_root: Blake3Hash,
545 pub state_root: Blake3Hash,
548}
549
550impl BlockHeaderResult {
551 pub fn hash(&self) -> Blake3Hash {
553 const {
554 assert!(size_of::<Self>() <= BLOCK_LEN);
555 }
556 Blake3Hash::new(
558 single_block_hash(self.as_bytes())
559 .expect("Less than a single block worth of bytes; qed"),
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(u8)]
573#[non_exhaustive]
574pub enum BlockHeaderSealType {
575 #[cfg_attr(feature = "scale-codec", codec(index = 0))]
577 Ed25519 = 0,
578}
579
580impl BlockHeaderSealType {
581 #[inline(always)]
583 pub const fn try_from_byte(byte: u8) -> Option<Self> {
584 if byte == Self::Ed25519 as u8 {
585 Some(Self::Ed25519)
586 } else {
587 None
588 }
589 }
590}
591
592#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
594#[cfg_attr(
595 feature = "scale-codec",
596 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
597)]
598#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
599#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
600#[repr(C)]
601pub struct BlockHeaderEd25519Seal {
602 pub public_key: Ed25519PublicKey,
604 pub signature: Ed25519Signature,
606}
607
608#[derive(Debug, Copy, Clone)]
610#[cfg_attr(
611 feature = "scale-codec",
612 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
613)]
614#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
615#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
616#[non_exhaustive]
617pub enum OwnedBlockHeaderSeal {
618 Ed25519(BlockHeaderEd25519Seal),
620}
621
622impl OwnedBlockHeaderSeal {
623 #[inline(always)]
625 pub fn as_ref(&self) -> BlockHeaderSeal<'_> {
626 match self {
627 Self::Ed25519(seal) => BlockHeaderSeal::Ed25519(seal),
628 }
629 }
630}
631
632#[derive(Debug, Copy, Clone)]
634#[non_exhaustive]
635pub enum BlockHeaderSeal<'a> {
636 Ed25519(&'a BlockHeaderEd25519Seal),
638}
639
640impl<'a> BlockHeaderSeal<'a> {
641 pub const MAX_SIZE: u32 = 1 + BlockHeaderEd25519Seal::SIZE;
643 #[inline]
649 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
650 let seal_type = bytes.split_off(..size_of::<u8>())?;
655 let seal_type = BlockHeaderSealType::try_from_byte(seal_type[0])?;
656
657 match seal_type {
658 BlockHeaderSealType::Ed25519 => {
659 let seal = bytes.split_off(..size_of::<BlockHeaderEd25519Seal>())?;
660 let seal = unsafe { BlockHeaderEd25519Seal::from_bytes(seal) }?;
662 Some((Self::Ed25519(seal), bytes))
663 }
664 }
665 }
666
667 #[inline]
669 pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
670 match self {
671 BlockHeaderSeal::Ed25519(seal) => seal
672 .public_key
673 .verify(&seal.signature, pre_seal_hash.as_bytes())
674 .is_ok(),
675 }
676 }
677
678 #[inline]
680 pub fn public_key_hash(&self) -> Blake3Hash {
681 match self {
682 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
683 }
684 }
685
686 #[inline]
688 pub fn hash(&self) -> Blake3Hash {
689 match self {
690 BlockHeaderSeal::Ed25519(seal) => {
691 let mut hasher = blake3::Hasher::new();
693 hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
694 hasher.update(seal.as_bytes());
695
696 Blake3Hash::from(hasher.finalize())
697 }
698 }
699 }
700}
701
702#[derive(Debug, Copy, Clone)]
704pub struct SharedBlockHeader<'a> {
705 pub prefix: &'a BlockHeaderPrefix,
707 pub result: &'a BlockHeaderResult,
709 pub consensus_info: &'a BlockHeaderConsensusInfo,
711 pub seal: BlockHeaderSeal<'a>,
713}
714
715#[derive(Debug, Clone, Yokeable)]
717#[non_exhaustive]
719pub struct BeaconChainHeader<'a> {
720 shared: SharedBlockHeader<'a>,
722 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
724 consensus_parameters: BlockHeaderConsensusParameters<'a>,
726 pre_seal_bytes: &'a [u8],
728 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
729 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
730 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
731 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
732}
733
734impl<'a> Deref for BeaconChainHeader<'a> {
735 type Target = SharedBlockHeader<'a>;
736
737 #[inline(always)]
738 fn deref(&self) -> &Self::Target {
739 &self.shared
740 }
741}
742
743impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
744 const SHARD_KIND: ShardKind = ShardKind::BeaconChain;
745
746 #[cfg(feature = "alloc")]
747 type Owned = OwnedBeaconChainHeader;
748
749 #[cfg(feature = "alloc")]
750 #[inline(always)]
751 fn to_owned(self) -> Self::Owned {
752 self.to_owned()
753 }
754
755 #[inline(always)]
756 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
757 self.root()
758 }
759}
760
761impl<'a> BeaconChainHeader<'a> {
762 #[inline]
769 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
770 let (prefix, consensus_info, result, remainder) =
779 BlockHeader::try_from_bytes_shared(bytes)?;
780
781 if prefix.shard_index.shard_kind() != ShardKind::BeaconChain {
782 return None;
783 }
784
785 let (child_shard_blocks, remainder) =
786 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
787
788 let (consensus_parameters, remainder) =
789 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
790
791 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
792
793 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
794
795 let shared = SharedBlockHeader {
796 prefix,
797 result,
798 consensus_info,
799 seal,
800 };
801
802 let header = Self {
803 shared,
804 child_shard_blocks,
805 consensus_parameters,
806 pre_seal_bytes,
807 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
808 cached_block_root: rclite::Arc::default(),
809 };
810
811 if !header.is_internally_consistent() {
812 return None;
813 }
814
815 Some((header, remainder))
816 }
817
818 #[inline]
823 pub fn is_internally_consistent(&self) -> bool {
824 let public_key_hash = match self.seal {
825 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
826 };
827 public_key_hash == self.shared.consensus_info.solution.public_key_hash
828 }
829
830 #[inline]
833 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
834 let (prefix, consensus_info, result, remainder) =
843 BlockHeader::try_from_bytes_shared(bytes)?;
844
845 if prefix.shard_index.shard_kind() != ShardKind::BeaconChain {
846 return None;
847 }
848
849 let (child_shard_blocks, remainder) =
850 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
851
852 let (consensus_parameters, remainder) =
853 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
854
855 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
856
857 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
858
859 let shared = SharedBlockHeader {
860 prefix,
861 result,
862 consensus_info,
863 seal,
864 };
865
866 Some((
867 Self {
868 shared,
869 child_shard_blocks,
870 consensus_parameters,
871 pre_seal_bytes,
872 #[cfg(any(
873 feature = "alloc",
874 not(any(target_os = "none", target_os = "unknown"))
875 ))]
876 cached_block_root: rclite::Arc::default(),
877 },
878 remainder,
879 ))
880 }
881
882 #[cfg(feature = "alloc")]
884 #[inline(always)]
885 pub fn to_owned(self) -> OwnedBeaconChainHeader {
886 let unsealed = OwnedBeaconChainHeader::from_parts(
887 self.shared.prefix,
888 self.shared.result,
889 self.shared.consensus_info,
890 &self.child_shard_blocks,
891 self.consensus_parameters,
892 )
893 .expect("`self` is always a valid invariant; qed");
894
895 unsealed.with_seal(self.shared.seal)
896 }
897
898 #[inline(always)]
900 pub fn shared(&self) -> &SharedBlockHeader<'a> {
901 &self.shared
902 }
903
904 #[inline(always)]
906 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
907 &self.child_shard_blocks
908 }
909
910 #[inline(always)]
912 pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
913 &self.consensus_parameters
914 }
915
916 #[inline]
918 pub fn pre_seal_hash(&self) -> Blake3Hash {
919 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
921 }
922
923 #[inline]
926 pub fn is_sealed_correctly(&self) -> bool {
927 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
928 && self.seal.is_seal_valid(&self.pre_seal_hash())
929 }
930
931 #[inline]
939 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
940 let Self {
941 shared,
942 child_shard_blocks,
943 consensus_parameters,
944 pre_seal_bytes: _,
945 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
946 cached_block_root,
947 } = self;
948
949 let compute_root = || {
950 let SharedBlockHeader {
951 prefix,
952 result,
953 consensus_info,
954 seal,
955 } = shared;
956
957 const MAX_N: usize = 6;
958 let leaves: [_; MAX_N] = [
959 prefix.hash(),
960 result.hash(),
961 consensus_info.hash(),
962 seal.hash(),
963 child_shard_blocks.root().unwrap_or_default(),
964 consensus_parameters.hash(),
965 ];
966 let block_root =
967 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
968 .expect("The list is not empty; qed");
969
970 BlockRoot::new(Blake3Hash::new(block_root))
971 };
972
973 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
974 {
975 cached_block_root.get_or_init(compute_root)
976 }
977 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
978 {
979 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
980 }
981 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
982 {
983 struct Wrapper(BlockRoot);
984
985 impl Deref for Wrapper {
986 type Target = BlockRoot;
987
988 #[inline(always)]
989 fn deref(&self) -> &Self::Target {
990 &self.0
991 }
992 }
993
994 Wrapper(compute_root())
995 }
996 }
997}
998
999#[derive(Debug, Clone, Yokeable)]
1001#[non_exhaustive]
1003pub struct IntermediateShardHeader<'a> {
1004 shared: SharedBlockHeader<'a>,
1006 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1008 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
1010 pre_seal_bytes: &'a [u8],
1012 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1013 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1014 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1015 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1016}
1017
1018impl<'a> Deref for IntermediateShardHeader<'a> {
1019 type Target = SharedBlockHeader<'a>;
1020
1021 #[inline(always)]
1022 fn deref(&self) -> &Self::Target {
1023 &self.shared
1024 }
1025}
1026
1027impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
1028 const SHARD_KIND: ShardKind = ShardKind::IntermediateShard;
1029
1030 #[cfg(feature = "alloc")]
1031 type Owned = OwnedIntermediateShardHeader;
1032
1033 #[cfg(feature = "alloc")]
1034 #[inline(always)]
1035 fn to_owned(self) -> Self::Owned {
1036 self.to_owned()
1037 }
1038
1039 #[inline(always)]
1040 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1041 self.root()
1042 }
1043}
1044
1045impl<'a> IntermediateShardHeader<'a> {
1046 #[inline]
1053 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1054 let (prefix, consensus_info, result, mut remainder) =
1063 BlockHeader::try_from_bytes_shared(bytes)?;
1064
1065 if prefix.shard_index.shard_kind() != ShardKind::IntermediateShard {
1066 return None;
1067 }
1068
1069 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1070 let beacon_chain_info =
1072 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1073
1074 let (child_shard_blocks, remainder) =
1075 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1076
1077 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1078
1079 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1080
1081 let shared = SharedBlockHeader {
1082 prefix,
1083 result,
1084 consensus_info,
1085 seal,
1086 };
1087
1088 let header = Self {
1089 shared,
1090 beacon_chain_info,
1091 child_shard_blocks,
1092 pre_seal_bytes,
1093 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1094 cached_block_root: rclite::Arc::default(),
1095 };
1096
1097 if !header.is_internally_consistent() {
1098 return None;
1099 }
1100
1101 Some((header, remainder))
1102 }
1103
1104 #[inline]
1109 pub fn is_internally_consistent(&self) -> bool {
1110 let public_key_hash = match self.seal {
1111 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1112 };
1113 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1114 }
1115
1116 #[inline]
1119 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1120 let (prefix, consensus_info, result, mut remainder) =
1129 BlockHeader::try_from_bytes_shared(bytes)?;
1130
1131 if prefix.shard_index.shard_kind() != ShardKind::IntermediateShard {
1132 return None;
1133 }
1134
1135 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1136 let beacon_chain_info =
1138 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1139
1140 let (child_shard_blocks, remainder) =
1141 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1142
1143 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1144
1145 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1146
1147 let shared = SharedBlockHeader {
1148 prefix,
1149 result,
1150 consensus_info,
1151 seal,
1152 };
1153
1154 Some((
1155 Self {
1156 shared,
1157 beacon_chain_info,
1158 child_shard_blocks,
1159 pre_seal_bytes,
1160 #[cfg(any(
1161 feature = "alloc",
1162 not(any(target_os = "none", target_os = "unknown"))
1163 ))]
1164 cached_block_root: rclite::Arc::default(),
1165 },
1166 remainder,
1167 ))
1168 }
1169
1170 #[cfg(feature = "alloc")]
1172 #[inline(always)]
1173 pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1174 let unsealed = OwnedIntermediateShardHeader::from_parts(
1175 self.shared.prefix,
1176 self.shared.result,
1177 self.shared.consensus_info,
1178 self.beacon_chain_info,
1179 &self.child_shard_blocks,
1180 )
1181 .expect("`self` is always a valid invariant; qed");
1182
1183 unsealed.with_seal(self.shared.seal)
1184 }
1185
1186 #[inline(always)]
1188 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1189 &self.shared
1190 }
1191
1192 #[inline(always)]
1194 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1195 self.beacon_chain_info
1196 }
1197
1198 #[inline(always)]
1200 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1201 &self.child_shard_blocks
1202 }
1203
1204 #[inline]
1206 pub fn pre_seal_hash(&self) -> Blake3Hash {
1207 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1209 }
1210
1211 #[inline]
1214 pub fn is_sealed_correctly(&self) -> bool {
1215 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1216 && self.seal.is_seal_valid(&self.pre_seal_hash())
1217 }
1218
1219 #[inline]
1227 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1228 let Self {
1229 shared,
1230 beacon_chain_info,
1231 child_shard_blocks,
1232 pre_seal_bytes: _,
1233 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1234 cached_block_root,
1235 } = self;
1236
1237 let compute_root = || {
1238 let SharedBlockHeader {
1239 prefix,
1240 result,
1241 consensus_info,
1242 seal,
1243 } = shared;
1244
1245 const MAX_N: usize = 6;
1246 let leaves: [_; MAX_N] = [
1247 prefix.hash(),
1248 result.hash(),
1249 consensus_info.hash(),
1250 seal.hash(),
1251 beacon_chain_info.hash(),
1252 child_shard_blocks.root().unwrap_or_default(),
1253 ];
1254 let block_root =
1255 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1256 .expect("The list is not empty; qed");
1257
1258 BlockRoot::new(Blake3Hash::new(block_root))
1259 };
1260
1261 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1262 {
1263 cached_block_root.get_or_init(compute_root)
1264 }
1265 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1266 {
1267 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1268 }
1269 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1270 {
1271 struct Wrapper(BlockRoot);
1272
1273 impl Deref for Wrapper {
1274 type Target = BlockRoot;
1275
1276 #[inline(always)]
1277 fn deref(&self) -> &Self::Target {
1278 &self.0
1279 }
1280 }
1281
1282 Wrapper(compute_root())
1283 }
1284 }
1285}
1286
1287#[derive(Debug, Clone, Yokeable)]
1289#[non_exhaustive]
1291pub struct LeafShardHeader<'a> {
1292 shared: SharedBlockHeader<'a>,
1294 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1296 pre_seal_bytes: &'a [u8],
1298 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1299 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1300 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1301 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1302}
1303
1304impl<'a> Deref for LeafShardHeader<'a> {
1305 type Target = SharedBlockHeader<'a>;
1306
1307 #[inline(always)]
1308 fn deref(&self) -> &Self::Target {
1309 &self.shared
1310 }
1311}
1312
1313impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1314 const SHARD_KIND: ShardKind = ShardKind::LeafShard;
1315
1316 #[cfg(feature = "alloc")]
1317 type Owned = OwnedLeafShardHeader;
1318
1319 #[cfg(feature = "alloc")]
1320 #[inline(always)]
1321 fn to_owned(self) -> Self::Owned {
1322 self.to_owned()
1323 }
1324
1325 #[inline(always)]
1326 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1327 self.root()
1328 }
1329}
1330
1331impl<'a> LeafShardHeader<'a> {
1332 #[inline]
1339 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1340 let (prefix, consensus_info, result, mut remainder) =
1348 BlockHeader::try_from_bytes_shared(bytes)?;
1349
1350 if prefix.shard_index.shard_kind() != ShardKind::LeafShard {
1351 return None;
1352 }
1353
1354 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1355 let beacon_chain_info =
1357 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1358
1359 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1360
1361 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1362
1363 let shared = SharedBlockHeader {
1364 prefix,
1365 result,
1366 consensus_info,
1367 seal,
1368 };
1369
1370 let header = Self {
1371 shared,
1372 beacon_chain_info,
1373 pre_seal_bytes,
1374 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1375 cached_block_root: rclite::Arc::default(),
1376 };
1377
1378 if !header.is_internally_consistent() {
1379 return None;
1380 }
1381
1382 Some((header, remainder))
1383 }
1384
1385 #[inline]
1390 pub fn is_internally_consistent(&self) -> bool {
1391 let public_key_hash = match self.seal {
1392 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1393 };
1394 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1395 }
1396
1397 #[inline]
1400 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1401 let (prefix, consensus_info, result, mut remainder) =
1409 BlockHeader::try_from_bytes_shared(bytes)?;
1410
1411 if prefix.shard_index.shard_kind() != ShardKind::LeafShard {
1412 return None;
1413 }
1414
1415 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1416 let beacon_chain_info =
1418 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1419
1420 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1421
1422 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1423
1424 let shared = SharedBlockHeader {
1425 prefix,
1426 result,
1427 consensus_info,
1428 seal,
1429 };
1430
1431 Some((
1432 Self {
1433 shared,
1434 beacon_chain_info,
1435 pre_seal_bytes,
1436 #[cfg(any(
1437 feature = "alloc",
1438 not(any(target_os = "none", target_os = "unknown"))
1439 ))]
1440 cached_block_root: rclite::Arc::default(),
1441 },
1442 remainder,
1443 ))
1444 }
1445
1446 #[cfg(feature = "alloc")]
1448 #[inline(always)]
1449 pub fn to_owned(self) -> OwnedLeafShardHeader {
1450 let unsealed = OwnedLeafShardHeader::from_parts(
1451 self.shared.prefix,
1452 self.shared.result,
1453 self.shared.consensus_info,
1454 self.beacon_chain_info,
1455 );
1456
1457 unsealed.with_seal(self.shared.seal)
1458 }
1459
1460 #[inline(always)]
1462 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1463 &self.shared
1464 }
1465
1466 #[inline(always)]
1468 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1469 self.beacon_chain_info
1470 }
1471
1472 #[inline]
1474 pub fn pre_seal_hash(&self) -> Blake3Hash {
1475 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1477 }
1478
1479 #[inline]
1482 pub fn is_sealed_correctly(&self) -> bool {
1483 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1484 && self.seal.is_seal_valid(&self.pre_seal_hash())
1485 }
1486
1487 #[inline]
1495 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1496 let Self {
1497 shared,
1498 beacon_chain_info,
1499 pre_seal_bytes: _,
1500 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1501 cached_block_root,
1502 } = self;
1503
1504 let compute_root = || {
1505 let SharedBlockHeader {
1506 prefix,
1507 result,
1508 consensus_info,
1509 seal,
1510 } = shared;
1511
1512 const MAX_N: usize = 5;
1513 let leaves: [_; MAX_N] = [
1514 prefix.hash(),
1515 result.hash(),
1516 consensus_info.hash(),
1517 seal.hash(),
1518 beacon_chain_info.hash(),
1519 ];
1520 let block_root =
1521 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1522 .expect("The list is not empty; qed");
1523
1524 BlockRoot::new(Blake3Hash::new(block_root))
1525 };
1526
1527 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1528 {
1529 cached_block_root.get_or_init(compute_root)
1530 }
1531 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1532 {
1533 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1534 }
1535 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1536 {
1537 struct Wrapper(BlockRoot);
1538
1539 impl Deref for Wrapper {
1540 type Target = BlockRoot;
1541
1542 #[inline(always)]
1543 fn deref(&self) -> &Self::Target {
1544 &self.0
1545 }
1546 }
1547
1548 Wrapper(compute_root())
1549 }
1550 }
1551}
1552
1553#[derive(Debug, Clone, From)]
1558pub enum BlockHeader<'a> {
1559 BeaconChain(BeaconChainHeader<'a>),
1561 IntermediateShard(IntermediateShardHeader<'a>),
1563 LeafShard(LeafShardHeader<'a>),
1565}
1566
1567impl<'a> Deref for BlockHeader<'a> {
1568 type Target = SharedBlockHeader<'a>;
1569
1570 #[inline(always)]
1571 fn deref(&self) -> &Self::Target {
1572 match self {
1573 Self::BeaconChain(header) => header,
1574 Self::IntermediateShard(header) => header,
1575 Self::LeafShard(header) => header,
1576 }
1577 }
1578}
1579
1580impl<'a> BlockHeader<'a> {
1581 #[inline]
1588 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: ShardKind) -> Option<(Self, &'a [u8])> {
1589 match shard_kind {
1590 ShardKind::BeaconChain => {
1591 let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1592 Some((Self::BeaconChain(header), remainder))
1593 }
1594 ShardKind::IntermediateShard => {
1595 let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1596 Some((Self::IntermediateShard(header), remainder))
1597 }
1598 ShardKind::LeafShard => {
1599 let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1600 Some((Self::LeafShard(header), remainder))
1601 }
1602 ShardKind::Phantom | ShardKind::Invalid => {
1603 None
1605 }
1606 }
1607 }
1608
1609 #[inline]
1614 pub fn is_internally_consistent(&self) -> bool {
1615 match self {
1616 Self::BeaconChain(header) => header.is_internally_consistent(),
1617 Self::IntermediateShard(header) => header.is_internally_consistent(),
1618 Self::LeafShard(header) => header.is_internally_consistent(),
1619 }
1620 }
1621
1622 #[inline]
1625 pub fn try_from_bytes_unchecked(
1626 bytes: &'a [u8],
1627 shard_kind: ShardKind,
1628 ) -> Option<(Self, &'a [u8])> {
1629 match shard_kind {
1630 ShardKind::BeaconChain => {
1631 let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1632 Some((Self::BeaconChain(header), remainder))
1633 }
1634 ShardKind::IntermediateShard => {
1635 let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1636 Some((Self::IntermediateShard(header), remainder))
1637 }
1638 ShardKind::LeafShard => {
1639 let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1640 Some((Self::LeafShard(header), remainder))
1641 }
1642 ShardKind::Phantom | ShardKind::Invalid => {
1643 None
1645 }
1646 }
1647 }
1648
1649 #[inline]
1650 fn try_from_bytes_shared(
1651 mut bytes: &'a [u8],
1652 ) -> Option<(
1653 &'a BlockHeaderPrefix,
1654 &'a BlockHeaderConsensusInfo,
1655 &'a BlockHeaderResult,
1656 &'a [u8],
1657 )> {
1658 let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1659 let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1661
1662 if !(prefix.padding_0 == [0; _]
1663 && prefix.shard_index.as_u32() <= ShardIndex::MAX_SHARD_INDEX)
1664 {
1665 return None;
1666 }
1667
1668 let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1669 let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1671
1672 let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1673 let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1675
1676 if consensus_info.solution.padding != [0; _] {
1677 return None;
1678 }
1679
1680 Some((prefix, consensus_info, result, bytes))
1681 }
1682
1683 #[cfg(feature = "alloc")]
1685 #[inline(always)]
1686 pub fn to_owned(self) -> OwnedBlockHeader {
1687 match self {
1688 Self::BeaconChain(header) => header.to_owned().into(),
1689 Self::IntermediateShard(header) => header.to_owned().into(),
1690 Self::LeafShard(header) => header.to_owned().into(),
1691 }
1692 }
1693
1694 #[inline]
1696 pub fn pre_seal_hash(&self) -> Blake3Hash {
1697 match self {
1698 Self::BeaconChain(header) => header.pre_seal_hash(),
1699 Self::IntermediateShard(header) => header.pre_seal_hash(),
1700 Self::LeafShard(header) => header.pre_seal_hash(),
1701 }
1702 }
1703
1704 #[inline]
1707 pub fn is_sealed_correctly(&self) -> bool {
1708 match self {
1709 Self::BeaconChain(header) => header.is_sealed_correctly(),
1710 Self::IntermediateShard(header) => header.is_sealed_correctly(),
1711 Self::LeafShard(header) => header.is_sealed_correctly(),
1712 }
1713 }
1714
1715 #[inline]
1723 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1724 enum Wrapper<B, I, L> {
1725 BeaconChain(B),
1726 IntermediateShard(I),
1727 LeafShard(L),
1728 }
1729
1730 impl<B, I, L> Deref for Wrapper<B, I, L>
1731 where
1732 B: Deref<Target = BlockRoot>,
1733 I: Deref<Target = BlockRoot>,
1734 L: Deref<Target = BlockRoot>,
1735 {
1736 type Target = BlockRoot;
1737
1738 #[inline(always)]
1739 fn deref(&self) -> &Self::Target {
1740 match self {
1741 Wrapper::BeaconChain(block_root) => block_root,
1742 Wrapper::IntermediateShard(block_root) => block_root,
1743 Wrapper::LeafShard(block_root) => block_root,
1744 }
1745 }
1746 }
1747
1748 match self {
1750 Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1751 Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1752 Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1753 }
1754 }
1755}