1#[cfg(feature = "alloc")]
4pub mod owned;
5
6#[cfg(feature = "alloc")]
7use crate::block::header::owned::{
8 GenericOwnedBlockHeader, OwnedBeaconChainHeader, OwnedBlockHeader,
9 OwnedIntermediateShardHeader, OwnedLeafShardHeader,
10};
11use crate::block::{BlockNumber, BlockRoot, BlockTimestamp};
12use crate::ed25519::{Ed25519PublicKey, Ed25519Signature};
13use crate::hashes::Blake3Hash;
14use crate::pot::{PotOutput, PotParametersChange, SlotNumber};
15use crate::segments::SuperSegmentRoot;
16use crate::shard::{NumShards, NumShardsUnchecked, RealShardKind, ShardIndex, ShardKind};
17use crate::solutions::{Solution, SolutionRange};
18use ab_blake3::{BLOCK_LEN, single_block_hash, single_chunk_hash};
19use ab_io_type::trivial_type::TrivialType;
20use ab_merkle_tree::unbalanced::UnbalancedMerkleTree;
21use blake3::CHUNK_LEN;
22use core::num::NonZeroU32;
23use core::ops::Deref;
24use core::{fmt, slice};
25use derive_more::{Deref, From};
26#[cfg(feature = "scale-codec")]
27use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
28#[cfg(feature = "serde")]
29use serde::{Deserialize, Serialize};
30use yoke::Yokeable;
31
32pub trait GenericBlockHeader<'a>
34where
35 Self: Clone
36 + fmt::Debug
37 + Deref<Target = SharedBlockHeader<'a>>
38 + Into<BlockHeader<'a>>
39 + Send
40 + Sync,
41{
42 const SHARD_KIND: RealShardKind;
44
45 #[cfg(feature = "alloc")]
47 type Owned: GenericOwnedBlockHeader<Header<'a> = Self>
48 where
49 Self: 'a;
50
51 #[cfg(feature = "alloc")]
53 fn to_owned(self) -> Self::Owned;
54
55 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync;
62
63 fn pre_seal_hash(&self) -> Blake3Hash;
65}
66
67#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
71#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
72#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
73#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
74#[repr(C)]
75pub struct BlockHeaderPrefix {
76 pub number: BlockNumber,
78 pub shard_index: ShardIndex,
80 pub padding_0: [u8; 4],
82 pub timestamp: BlockTimestamp,
84 pub parent_root: BlockRoot,
86 pub mmr_root: Blake3Hash,
89}
90
91impl BlockHeaderPrefix {
92 pub fn hash(&self) -> Blake3Hash {
94 const {
95 assert!(size_of::<Self>() <= CHUNK_LEN);
96 }
97 Blake3Hash::new(
99 single_chunk_hash(self.as_bytes())
100 .expect("Less than a single chunk worth of bytes; qed"),
101 )
102 }
103}
104
105#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
107#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
108#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
109#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
110#[repr(C)]
111pub struct BlockHeaderConsensusInfo {
112 pub slot: SlotNumber,
114 pub proof_of_time: PotOutput,
116 pub future_proof_of_time: PotOutput,
118 pub solution: Solution,
120}
121
122impl BlockHeaderConsensusInfo {
123 pub fn hash(&self) -> Blake3Hash {
125 Blake3Hash::from(blake3::hash(self.as_bytes()))
127 }
128}
129
130#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, TrivialType)]
132#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
135#[repr(C)]
136pub struct BlockHeaderBeaconChainInfo {
137 pub number: BlockNumber,
139 pub root: BlockRoot,
141}
142
143impl BlockHeaderBeaconChainInfo {
144 pub fn hash(&self) -> Blake3Hash {
146 const {
147 assert!(size_of::<Self>() <= BLOCK_LEN);
148 }
149 Blake3Hash::new(
151 single_block_hash(self.as_bytes())
152 .expect("Less than a single block worth of bytes; qed"),
153 )
154 }
155}
156
157#[derive(Debug, Copy, Clone, Eq, PartialEq)]
159#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
160#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
161#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
162pub struct BlockHeaderFixedConsensusParameters {
163 pub solution_range: SolutionRange,
165 pub slot_iterations: NonZeroU32,
170 pub num_shards: NumShards,
172}
173
174impl BlockHeaderFixedConsensusParameters {
175 #[inline]
181 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(Self, &[u8])> {
182 let solution_range = bytes.split_off(..size_of::<SolutionRange>())?;
188 let solution_range = SolutionRange::from_bytes([
189 solution_range[0],
190 solution_range[1],
191 solution_range[2],
192 solution_range[3],
193 solution_range[4],
194 solution_range[5],
195 solution_range[6],
196 solution_range[7],
197 ]);
198
199 let pot_slot_iterations = bytes.split_off(..size_of::<u32>())?;
200 let slot_iterations = u32::from_le_bytes([
201 pot_slot_iterations[0],
202 pot_slot_iterations[1],
203 pot_slot_iterations[2],
204 pot_slot_iterations[3],
205 ]);
206 let slot_iterations = NonZeroU32::new(slot_iterations)?;
207 let num_shards = unsafe {
209 bytes
210 .split_off(..size_of::<NumShardsUnchecked>())?
211 .as_ptr()
212 .cast::<NumShardsUnchecked>()
213 .read_unaligned()
214 };
215 let num_shards = NumShards::try_from(num_shards).ok()?;
216
217 Some((
218 Self {
219 solution_range,
220 slot_iterations,
221 num_shards,
222 },
223 bytes,
224 ))
225 }
226}
227
228#[derive(Debug, Copy, Clone, Eq, PartialEq)]
232#[repr(C, packed)]
233pub struct BlockHeaderPotParametersChange {
234 slot: SlotNumber,
238 slot_iterations: NonZeroU32,
240 entropy: Blake3Hash,
242}
243
244impl From<BlockHeaderPotParametersChange> for PotParametersChange {
245 #[inline(always)]
246 fn from(value: BlockHeaderPotParametersChange) -> Self {
247 let BlockHeaderPotParametersChange {
248 slot,
249 slot_iterations,
250 entropy,
251 } = value;
252
253 PotParametersChange {
254 slot,
255 slot_iterations,
256 entropy,
257 }
258 }
259}
260
261impl From<PotParametersChange> for BlockHeaderPotParametersChange {
262 #[inline(always)]
263 fn from(value: PotParametersChange) -> Self {
264 let PotParametersChange {
265 slot,
266 slot_iterations,
267 entropy,
268 } = value;
269
270 BlockHeaderPotParametersChange {
271 slot,
272 slot_iterations,
273 entropy,
274 }
275 }
276}
277
278impl BlockHeaderPotParametersChange {
279 #[inline]
285 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(&Self, &[u8])> {
286 let pot_parameters_change_ptr = bytes.as_ptr().cast::<Self>();
292
293 let _slot = bytes.split_off(..size_of::<SlotNumber>())?;
294
295 let slot_iterations = bytes.split_off(..size_of::<u32>())?;
296 if slot_iterations == [0, 0, 0, 0] {
297 return None;
298 }
299 let _entropy = bytes.split_off(..size_of::<Blake3Hash>())?;
300
301 let pot_parameters_change = unsafe { pot_parameters_change_ptr.as_ref_unchecked() };
303
304 Some((pot_parameters_change, bytes))
305 }
306}
307
308#[derive(Debug, Copy, Clone)]
310pub struct OwnedBlockHeaderConsensusParameters {
311 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
313 pub super_segment_root: Option<SuperSegmentRoot>,
315 pub next_solution_range: Option<SolutionRange>,
317 pub pot_parameters_change: Option<BlockHeaderPotParametersChange>,
319}
320
321impl OwnedBlockHeaderConsensusParameters {
322 #[inline]
324 pub fn as_ref(&self) -> BlockHeaderConsensusParameters<'_> {
325 BlockHeaderConsensusParameters {
326 fixed_parameters: self.fixed_parameters,
327 super_segment_root: self.super_segment_root.as_ref(),
328 next_solution_range: self.next_solution_range,
329 pot_parameters_change: self.pot_parameters_change.as_ref(),
330 }
331 }
332}
333
334#[derive(Debug, Copy, Clone, Eq, PartialEq)]
336pub struct BlockHeaderConsensusParameters<'a> {
337 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
339 pub super_segment_root: Option<&'a SuperSegmentRoot>,
341 pub next_solution_range: Option<SolutionRange>,
343 pub pot_parameters_change: Option<&'a BlockHeaderPotParametersChange>,
345}
346
347impl<'a> BlockHeaderConsensusParameters<'a> {
348 pub const MAX_SIZE: u32 = size_of::<BlockHeaderFixedConsensusParameters>() as u32
350 + u8::SIZE
351 + <SuperSegmentRoot as TrivialType>::SIZE
352 + <SolutionRange as TrivialType>::SIZE
353 + <NumShardsUnchecked as TrivialType>::SIZE
354 + size_of::<BlockHeaderPotParametersChange>() as u32;
355 pub const SUPER_SEGMENT_ROOT_MASK: u8 = 0b_0000_0001;
357 pub const NEXT_SOLUTION_RANGE_MASK: u8 = 0b_0000_0010;
359 pub const POT_PARAMETERS_CHANGE_MASK: u8 = 0b_0000_0100;
361 pub const MASK_ALL: u8 = Self::SUPER_SEGMENT_ROOT_MASK
363 | Self::NEXT_SOLUTION_RANGE_MASK
364 | Self::POT_PARAMETERS_CHANGE_MASK;
365
366 #[inline]
372 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
373 let (fixed_parameters, mut remainder) =
381 BlockHeaderFixedConsensusParameters::try_from_bytes(bytes)?;
382
383 let bitflags = remainder.split_off(..size_of::<u8>())?;
384 let bitflags = bitflags[0];
385
386 if (bitflags & Self::MASK_ALL) != bitflags {
387 return None;
389 }
390
391 let super_segment_root = if bitflags & Self::SUPER_SEGMENT_ROOT_MASK != 0 {
392 let super_segment_root = remainder.split_off(..size_of::<SuperSegmentRoot>())?;
393 let super_segment_root = unsafe { SuperSegmentRoot::from_bytes(super_segment_root) }?;
395
396 Some(super_segment_root)
397 } else {
398 None
399 };
400
401 let next_solution_range = if bitflags & Self::NEXT_SOLUTION_RANGE_MASK != 0 {
402 let next_solution_range = remainder.split_off(..size_of::<SolutionRange>())?;
403 let next_solution_range = SolutionRange::from_bytes([
405 next_solution_range[0],
406 next_solution_range[1],
407 next_solution_range[2],
408 next_solution_range[3],
409 next_solution_range[4],
410 next_solution_range[5],
411 next_solution_range[6],
412 next_solution_range[7],
413 ]);
414
415 Some(next_solution_range)
416 } else {
417 None
418 };
419
420 let pot_parameters_change = if bitflags & Self::POT_PARAMETERS_CHANGE_MASK != 0 {
421 let pot_parameters_change;
422 (pot_parameters_change, remainder) =
423 BlockHeaderPotParametersChange::try_from_bytes(remainder)?;
424
425 Some(pot_parameters_change)
426 } else {
427 None
428 };
429
430 Some((
431 Self {
432 super_segment_root,
433 fixed_parameters,
434 next_solution_range,
435 pot_parameters_change,
436 },
437 remainder,
438 ))
439 }
440
441 pub fn hash(&self) -> Blake3Hash {
443 let Self {
444 super_segment_root,
445 fixed_parameters,
446 next_solution_range,
447 pot_parameters_change,
448 } = self;
449 let BlockHeaderFixedConsensusParameters {
450 solution_range,
451 slot_iterations,
452 num_shards,
453 } = fixed_parameters;
454
455 let mut hasher = blake3::Hasher::new();
457 hasher.update(solution_range.as_bytes());
458 hasher.update(&slot_iterations.get().to_le_bytes());
459 hasher.update(NumShardsUnchecked::from(*num_shards).as_bytes());
460
461 if let Some(super_segment_root) = super_segment_root {
462 hasher.update(super_segment_root.as_bytes());
463 }
464 if let Some(next_solution_range) = next_solution_range {
465 hasher.update(next_solution_range.as_bytes());
466 }
467 if let Some(pot_parameters_change) = pot_parameters_change.copied() {
468 let BlockHeaderPotParametersChange {
469 slot,
470 slot_iterations,
471 entropy,
472 } = pot_parameters_change;
473 hasher.update(slot.as_bytes());
474 hasher.update(&slot_iterations.get().to_le_bytes());
475 hasher.update(entropy.as_bytes());
476 }
477
478 Blake3Hash::from(hasher.finalize())
479 }
480}
481
482#[derive(Debug, Copy, Clone, Deref)]
484pub struct BlockHeaderChildShardBlocks<'a> {
485 pub child_shard_blocks: &'a [BlockRoot],
487}
488
489impl<'a> BlockHeaderChildShardBlocks<'a> {
490 #[inline]
496 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
497 let length = bytes.split_off(..size_of::<u16>())?;
503 let num_blocks = usize::from(*unsafe { <u16 as TrivialType>::from_bytes(length) }?);
505
506 let padding = bytes.split_off(..size_of::<[u8; 2]>())?;
507
508 if padding != [0, 0] {
510 return None;
511 }
512
513 let child_shard_blocks = bytes.split_off(..num_blocks * BlockRoot::SIZE)?;
514 let child_shard_blocks = unsafe {
516 slice::from_raw_parts(
517 child_shard_blocks.as_ptr().cast::<[u8; BlockRoot::SIZE]>(),
518 num_blocks,
519 )
520 };
521 let child_shard_blocks = BlockRoot::slice_from_repr(child_shard_blocks);
522
523 Some((Self { child_shard_blocks }, bytes))
524 }
525
526 pub fn root(&self) -> Option<Blake3Hash> {
530 let root = UnbalancedMerkleTree::compute_root_only::<'_, { u32::MAX as u64 }, _, _>(
531 self.child_shard_blocks
533 .iter()
534 .map(|child_shard_block_root| {
535 single_block_hash(child_shard_block_root.as_ref())
539 .expect("Less than a single block worth of bytes; qed")
540 }),
541 )?;
542 Some(Blake3Hash::new(root))
543 }
544}
545
546#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
550#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
551#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
552#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
553#[repr(C)]
554pub struct BlockHeaderResult {
555 pub body_root: Blake3Hash,
558 pub state_root: Blake3Hash,
561}
562
563impl BlockHeaderResult {
564 pub fn hash(&self) -> Blake3Hash {
566 const {
567 assert!(size_of::<Self>() <= BLOCK_LEN);
568 }
569 Blake3Hash::new(
571 single_block_hash(self.as_bytes())
572 .expect("Less than a single block worth of bytes; qed"),
573 )
574 }
575}
576
577#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
579#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
580#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
581#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
582#[repr(u8)]
583#[non_exhaustive]
584pub enum BlockHeaderSealType {
585 #[cfg_attr(feature = "scale-codec", codec(index = 0))]
587 Ed25519 = 0,
588}
589
590impl BlockHeaderSealType {
591 #[inline(always)]
593 pub const fn try_from_byte(byte: u8) -> Option<Self> {
594 if byte == Self::Ed25519 as u8 {
595 Some(Self::Ed25519)
596 } else {
597 None
598 }
599 }
600}
601
602#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
604#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
605#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
606#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
607#[repr(C)]
608pub struct BlockHeaderEd25519Seal {
609 pub public_key: Ed25519PublicKey,
611 pub signature: Ed25519Signature,
613}
614
615#[derive(Debug, Copy, Clone)]
617#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
618#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
619#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
620#[non_exhaustive]
621pub enum OwnedBlockHeaderSeal {
622 Ed25519(BlockHeaderEd25519Seal),
624}
625
626impl OwnedBlockHeaderSeal {
627 #[inline(always)]
629 pub fn as_ref(&self) -> BlockHeaderSeal<'_> {
630 match self {
631 Self::Ed25519(seal) => BlockHeaderSeal::Ed25519(seal),
632 }
633 }
634}
635
636#[derive(Debug, Copy, Clone)]
638#[non_exhaustive]
639pub enum BlockHeaderSeal<'a> {
640 Ed25519(&'a BlockHeaderEd25519Seal),
642}
643
644impl<'a> BlockHeaderSeal<'a> {
645 pub const MAX_SIZE: u32 = 1 + BlockHeaderEd25519Seal::SIZE;
647 #[inline]
653 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
654 let seal_type = bytes.split_off(..size_of::<u8>())?;
659 let seal_type = BlockHeaderSealType::try_from_byte(seal_type[0])?;
660
661 match seal_type {
662 BlockHeaderSealType::Ed25519 => {
663 let seal = bytes.split_off(..size_of::<BlockHeaderEd25519Seal>())?;
664 let seal = unsafe { BlockHeaderEd25519Seal::from_bytes(seal) }?;
666 Some((Self::Ed25519(seal), bytes))
667 }
668 }
669 }
670
671 #[inline]
673 pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
674 match self {
675 BlockHeaderSeal::Ed25519(seal) => seal
676 .public_key
677 .verify(&seal.signature, pre_seal_hash.as_bytes())
678 .is_ok(),
679 }
680 }
681
682 #[inline]
684 pub fn public_key_hash(&self) -> Blake3Hash {
685 match self {
686 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
687 }
688 }
689
690 #[inline]
692 pub fn hash(&self) -> Blake3Hash {
693 match self {
694 BlockHeaderSeal::Ed25519(seal) => {
695 let mut hasher = blake3::Hasher::new();
697 hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
698 hasher.update(seal.as_bytes());
699
700 Blake3Hash::from(hasher.finalize())
701 }
702 }
703 }
704}
705
706#[derive(Debug, Copy, Clone)]
708pub struct SharedBlockHeader<'a> {
709 pub prefix: &'a BlockHeaderPrefix,
711 pub result: &'a BlockHeaderResult,
713 pub consensus_info: &'a BlockHeaderConsensusInfo,
715 pub seal: BlockHeaderSeal<'a>,
717}
718
719#[derive(Debug, Clone, Yokeable)]
721#[non_exhaustive]
723pub struct BeaconChainHeader<'a> {
724 shared: SharedBlockHeader<'a>,
726 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
728 consensus_parameters: BlockHeaderConsensusParameters<'a>,
730 pre_seal_bytes: &'a [u8],
732 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
733 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
734 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
735 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
736}
737
738impl<'a> Deref for BeaconChainHeader<'a> {
739 type Target = SharedBlockHeader<'a>;
740
741 #[inline(always)]
742 fn deref(&self) -> &Self::Target {
743 &self.shared
744 }
745}
746
747impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
748 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
749
750 #[cfg(feature = "alloc")]
751 type Owned = OwnedBeaconChainHeader;
752
753 #[cfg(feature = "alloc")]
754 #[inline(always)]
755 fn to_owned(self) -> Self::Owned {
756 self.to_owned()
757 }
758
759 #[inline(always)]
760 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
761 self.root()
762 }
763
764 #[inline(always)]
765 fn pre_seal_hash(&self) -> Blake3Hash {
766 self.pre_seal_hash()
767 }
768}
769
770impl<'a> BeaconChainHeader<'a> {
771 #[inline]
778 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
779 let (prefix, consensus_info, result, remainder) =
788 BlockHeader::try_from_bytes_shared(bytes)?;
789
790 if prefix.shard_index.shard_kind() != Some(ShardKind::BeaconChain) {
791 return None;
792 }
793
794 let (child_shard_blocks, remainder) =
795 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
796
797 let (consensus_parameters, remainder) =
798 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
799
800 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
801
802 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
803
804 let shared = SharedBlockHeader {
805 prefix,
806 result,
807 consensus_info,
808 seal,
809 };
810
811 let header = Self {
812 shared,
813 child_shard_blocks,
814 consensus_parameters,
815 pre_seal_bytes,
816 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
817 cached_block_root: rclite::Arc::default(),
818 };
819
820 if !header.is_internally_consistent() {
821 return None;
822 }
823
824 Some((header, remainder))
825 }
826
827 #[inline]
832 pub fn is_internally_consistent(&self) -> bool {
833 let public_key_hash = match self.seal {
834 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
835 };
836 public_key_hash == self.shared.consensus_info.solution.public_key_hash
837 }
838
839 #[inline]
842 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
843 let (prefix, consensus_info, result, remainder) =
852 BlockHeader::try_from_bytes_shared(bytes)?;
853
854 if prefix.shard_index.shard_kind() != Some(ShardKind::BeaconChain) {
855 return None;
856 }
857
858 let (child_shard_blocks, remainder) =
859 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
860
861 let (consensus_parameters, remainder) =
862 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
863
864 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
865
866 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
867
868 let shared = SharedBlockHeader {
869 prefix,
870 result,
871 consensus_info,
872 seal,
873 };
874
875 Some((
876 Self {
877 shared,
878 child_shard_blocks,
879 consensus_parameters,
880 pre_seal_bytes,
881 #[cfg(any(
882 feature = "alloc",
883 not(any(target_os = "none", target_os = "unknown"))
884 ))]
885 cached_block_root: rclite::Arc::default(),
886 },
887 remainder,
888 ))
889 }
890
891 #[cfg(feature = "alloc")]
893 #[inline(always)]
894 pub fn to_owned(self) -> OwnedBeaconChainHeader {
895 let unsealed = OwnedBeaconChainHeader::from_parts(
896 self.shared.prefix,
897 self.shared.result,
898 self.shared.consensus_info,
899 &self.child_shard_blocks,
900 &self.consensus_parameters,
901 )
902 .expect("`self` is always a valid invariant; qed");
903
904 unsealed.with_seal(self.shared.seal)
905 }
906
907 #[inline(always)]
909 pub fn shared(&self) -> &SharedBlockHeader<'a> {
910 &self.shared
911 }
912
913 #[inline(always)]
915 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
916 &self.child_shard_blocks
917 }
918
919 #[inline(always)]
921 pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
922 &self.consensus_parameters
923 }
924
925 #[inline]
927 pub fn pre_seal_hash(&self) -> Blake3Hash {
928 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
930 }
931
932 #[inline]
935 pub fn is_sealed_correctly(&self) -> bool {
936 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
937 && self.seal.is_seal_valid(&self.pre_seal_hash())
938 }
939
940 #[inline]
948 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
949 let Self {
950 shared,
951 child_shard_blocks,
952 consensus_parameters,
953 pre_seal_bytes: _,
954 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
955 cached_block_root,
956 } = self;
957
958 let compute_root = || {
959 let SharedBlockHeader {
960 prefix,
961 result,
962 consensus_info,
963 seal,
964 } = shared;
965
966 const MAX_N: usize = 6;
967 const MAX_N_U64: u64 = 6;
970 let leaves: [_; MAX_N] = [
971 prefix.hash(),
972 result.hash(),
973 consensus_info.hash(),
974 seal.hash(),
975 child_shard_blocks.root().unwrap_or_default(),
976 consensus_parameters.hash(),
977 ];
978 let block_root = UnbalancedMerkleTree::compute_root_only::<MAX_N_U64, _, _>(leaves)
979 .expect("The list is not empty; qed");
980
981 BlockRoot::new(Blake3Hash::new(block_root))
982 };
983
984 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
985 {
986 cached_block_root.get_or_init(compute_root)
987 }
988 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
989 {
990 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
991 }
992 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
993 {
994 struct Wrapper(BlockRoot);
995
996 impl Deref for Wrapper {
997 type Target = BlockRoot;
998
999 #[inline(always)]
1000 fn deref(&self) -> &Self::Target {
1001 &self.0
1002 }
1003 }
1004
1005 Wrapper(compute_root())
1006 }
1007 }
1008}
1009
1010#[derive(Debug, Clone, Yokeable)]
1012#[non_exhaustive]
1014pub struct IntermediateShardHeader<'a> {
1015 shared: SharedBlockHeader<'a>,
1017 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1019 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
1021 pre_seal_bytes: &'a [u8],
1023 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1024 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1025 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1026 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1027}
1028
1029impl<'a> Deref for IntermediateShardHeader<'a> {
1030 type Target = SharedBlockHeader<'a>;
1031
1032 #[inline(always)]
1033 fn deref(&self) -> &Self::Target {
1034 &self.shared
1035 }
1036}
1037
1038impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
1039 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
1040
1041 #[cfg(feature = "alloc")]
1042 type Owned = OwnedIntermediateShardHeader;
1043
1044 #[cfg(feature = "alloc")]
1045 #[inline(always)]
1046 fn to_owned(self) -> Self::Owned {
1047 self.to_owned()
1048 }
1049
1050 #[inline(always)]
1051 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1052 self.root()
1053 }
1054
1055 #[inline(always)]
1056 fn pre_seal_hash(&self) -> Blake3Hash {
1057 self.pre_seal_hash()
1058 }
1059}
1060
1061impl<'a> IntermediateShardHeader<'a> {
1062 #[inline]
1069 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1070 let (prefix, consensus_info, result, mut remainder) =
1079 BlockHeader::try_from_bytes_shared(bytes)?;
1080
1081 if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1082 return None;
1083 }
1084
1085 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1086 let beacon_chain_info =
1088 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1089
1090 let (child_shard_blocks, remainder) =
1091 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1092
1093 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1094
1095 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1096
1097 let shared = SharedBlockHeader {
1098 prefix,
1099 result,
1100 consensus_info,
1101 seal,
1102 };
1103
1104 let header = Self {
1105 shared,
1106 beacon_chain_info,
1107 child_shard_blocks,
1108 pre_seal_bytes,
1109 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1110 cached_block_root: rclite::Arc::default(),
1111 };
1112
1113 if !header.is_internally_consistent() {
1114 return None;
1115 }
1116
1117 Some((header, remainder))
1118 }
1119
1120 #[inline]
1125 pub fn is_internally_consistent(&self) -> bool {
1126 let public_key_hash = match self.seal {
1127 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1128 };
1129 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1130 }
1131
1132 #[inline]
1135 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1136 let (prefix, consensus_info, result, mut remainder) =
1145 BlockHeader::try_from_bytes_shared(bytes)?;
1146
1147 if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1148 return None;
1149 }
1150
1151 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1152 let beacon_chain_info =
1154 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1155
1156 let (child_shard_blocks, remainder) =
1157 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1158
1159 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1160
1161 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1162
1163 let shared = SharedBlockHeader {
1164 prefix,
1165 result,
1166 consensus_info,
1167 seal,
1168 };
1169
1170 Some((
1171 Self {
1172 shared,
1173 beacon_chain_info,
1174 child_shard_blocks,
1175 pre_seal_bytes,
1176 #[cfg(any(
1177 feature = "alloc",
1178 not(any(target_os = "none", target_os = "unknown"))
1179 ))]
1180 cached_block_root: rclite::Arc::default(),
1181 },
1182 remainder,
1183 ))
1184 }
1185
1186 #[cfg(feature = "alloc")]
1188 #[inline(always)]
1189 pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1190 let unsealed = OwnedIntermediateShardHeader::from_parts(
1191 self.shared.prefix,
1192 self.shared.result,
1193 self.shared.consensus_info,
1194 self.beacon_chain_info,
1195 &self.child_shard_blocks,
1196 )
1197 .expect("`self` is always a valid invariant; qed");
1198
1199 unsealed.with_seal(self.shared.seal)
1200 }
1201
1202 #[inline(always)]
1204 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1205 &self.shared
1206 }
1207
1208 #[inline(always)]
1210 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1211 self.beacon_chain_info
1212 }
1213
1214 #[inline(always)]
1216 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1217 &self.child_shard_blocks
1218 }
1219
1220 #[inline]
1222 pub fn pre_seal_hash(&self) -> Blake3Hash {
1223 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1225 }
1226
1227 #[inline]
1230 pub fn is_sealed_correctly(&self) -> bool {
1231 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1232 && self.seal.is_seal_valid(&self.pre_seal_hash())
1233 }
1234
1235 #[inline]
1243 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1244 let Self {
1245 shared,
1246 beacon_chain_info,
1247 child_shard_blocks,
1248 pre_seal_bytes: _,
1249 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1250 cached_block_root,
1251 } = self;
1252
1253 let compute_root = || {
1254 let SharedBlockHeader {
1255 prefix,
1256 result,
1257 consensus_info,
1258 seal,
1259 } = shared;
1260
1261 const MAX_N: usize = 6;
1262 const MAX_N_U64: u64 = 6;
1265 let leaves: [_; MAX_N] = [
1266 prefix.hash(),
1267 result.hash(),
1268 consensus_info.hash(),
1269 seal.hash(),
1270 beacon_chain_info.hash(),
1271 child_shard_blocks.root().unwrap_or_default(),
1272 ];
1273 let block_root = UnbalancedMerkleTree::compute_root_only::<MAX_N_U64, _, _>(leaves)
1274 .expect("The list is not empty; qed");
1275
1276 BlockRoot::new(Blake3Hash::new(block_root))
1277 };
1278
1279 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1280 {
1281 cached_block_root.get_or_init(compute_root)
1282 }
1283 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1284 {
1285 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1286 }
1287 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1288 {
1289 struct Wrapper(BlockRoot);
1290
1291 impl Deref for Wrapper {
1292 type Target = BlockRoot;
1293
1294 #[inline(always)]
1295 fn deref(&self) -> &Self::Target {
1296 &self.0
1297 }
1298 }
1299
1300 Wrapper(compute_root())
1301 }
1302 }
1303}
1304
1305#[derive(Debug, Clone, Yokeable)]
1307#[non_exhaustive]
1309pub struct LeafShardHeader<'a> {
1310 shared: SharedBlockHeader<'a>,
1312 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1314 pre_seal_bytes: &'a [u8],
1316 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1317 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1318 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1319 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1320}
1321
1322impl<'a> Deref for LeafShardHeader<'a> {
1323 type Target = SharedBlockHeader<'a>;
1324
1325 #[inline(always)]
1326 fn deref(&self) -> &Self::Target {
1327 &self.shared
1328 }
1329}
1330
1331impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1332 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1333
1334 #[cfg(feature = "alloc")]
1335 type Owned = OwnedLeafShardHeader;
1336
1337 #[cfg(feature = "alloc")]
1338 #[inline(always)]
1339 fn to_owned(self) -> Self::Owned {
1340 self.to_owned()
1341 }
1342
1343 #[inline(always)]
1344 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1345 self.root()
1346 }
1347
1348 #[inline(always)]
1349 fn pre_seal_hash(&self) -> Blake3Hash {
1350 self.pre_seal_hash()
1351 }
1352}
1353
1354impl<'a> LeafShardHeader<'a> {
1355 #[inline]
1362 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1363 let (prefix, consensus_info, result, mut remainder) =
1371 BlockHeader::try_from_bytes_shared(bytes)?;
1372
1373 if prefix.shard_index.shard_kind() != Some(ShardKind::LeafShard) {
1374 return None;
1375 }
1376
1377 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1378 let beacon_chain_info =
1380 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1381
1382 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1383
1384 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1385
1386 let shared = SharedBlockHeader {
1387 prefix,
1388 result,
1389 consensus_info,
1390 seal,
1391 };
1392
1393 let header = Self {
1394 shared,
1395 beacon_chain_info,
1396 pre_seal_bytes,
1397 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1398 cached_block_root: rclite::Arc::default(),
1399 };
1400
1401 if !header.is_internally_consistent() {
1402 return None;
1403 }
1404
1405 Some((header, remainder))
1406 }
1407
1408 #[inline]
1413 pub fn is_internally_consistent(&self) -> bool {
1414 let public_key_hash = match self.seal {
1415 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1416 };
1417 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1418 }
1419
1420 #[inline]
1423 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1424 let (prefix, consensus_info, result, mut remainder) =
1432 BlockHeader::try_from_bytes_shared(bytes)?;
1433
1434 if prefix.shard_index.shard_kind() != Some(ShardKind::LeafShard) {
1435 return None;
1436 }
1437
1438 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1439 let beacon_chain_info =
1441 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1442
1443 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1444
1445 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1446
1447 let shared = SharedBlockHeader {
1448 prefix,
1449 result,
1450 consensus_info,
1451 seal,
1452 };
1453
1454 Some((
1455 Self {
1456 shared,
1457 beacon_chain_info,
1458 pre_seal_bytes,
1459 #[cfg(any(
1460 feature = "alloc",
1461 not(any(target_os = "none", target_os = "unknown"))
1462 ))]
1463 cached_block_root: rclite::Arc::default(),
1464 },
1465 remainder,
1466 ))
1467 }
1468
1469 #[cfg(feature = "alloc")]
1471 #[inline(always)]
1472 pub fn to_owned(self) -> OwnedLeafShardHeader {
1473 let unsealed = OwnedLeafShardHeader::from_parts(
1474 self.shared.prefix,
1475 self.shared.result,
1476 self.shared.consensus_info,
1477 self.beacon_chain_info,
1478 );
1479
1480 unsealed.with_seal(self.shared.seal)
1481 }
1482
1483 #[inline(always)]
1485 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1486 &self.shared
1487 }
1488
1489 #[inline(always)]
1491 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1492 self.beacon_chain_info
1493 }
1494
1495 #[inline]
1497 pub fn pre_seal_hash(&self) -> Blake3Hash {
1498 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1500 }
1501
1502 #[inline]
1505 pub fn is_sealed_correctly(&self) -> bool {
1506 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1507 && self.seal.is_seal_valid(&self.pre_seal_hash())
1508 }
1509
1510 #[inline]
1518 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1519 let Self {
1520 shared,
1521 beacon_chain_info,
1522 pre_seal_bytes: _,
1523 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1524 cached_block_root,
1525 } = self;
1526
1527 let compute_root = || {
1528 let SharedBlockHeader {
1529 prefix,
1530 result,
1531 consensus_info,
1532 seal,
1533 } = shared;
1534
1535 const MAX_N: usize = 5;
1536 const MAX_N_U64: u64 = 5;
1539 let leaves: [_; MAX_N] = [
1540 prefix.hash(),
1541 result.hash(),
1542 consensus_info.hash(),
1543 seal.hash(),
1544 beacon_chain_info.hash(),
1545 ];
1546 let block_root = UnbalancedMerkleTree::compute_root_only::<MAX_N_U64, _, _>(leaves)
1547 .expect("The list is not empty; qed");
1548
1549 BlockRoot::new(Blake3Hash::new(block_root))
1550 };
1551
1552 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1553 {
1554 cached_block_root.get_or_init(compute_root)
1555 }
1556 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1557 {
1558 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1559 }
1560 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1561 {
1562 struct Wrapper(BlockRoot);
1563
1564 impl Deref for Wrapper {
1565 type Target = BlockRoot;
1566
1567 #[inline(always)]
1568 fn deref(&self) -> &Self::Target {
1569 &self.0
1570 }
1571 }
1572
1573 Wrapper(compute_root())
1574 }
1575 }
1576}
1577
1578#[derive(Debug, Clone, From)]
1583pub enum BlockHeader<'a> {
1584 BeaconChain(BeaconChainHeader<'a>),
1586 IntermediateShard(IntermediateShardHeader<'a>),
1588 LeafShard(LeafShardHeader<'a>),
1590}
1591
1592impl<'a> Deref for BlockHeader<'a> {
1593 type Target = SharedBlockHeader<'a>;
1594
1595 #[inline(always)]
1596 fn deref(&self) -> &Self::Target {
1597 match self {
1598 Self::BeaconChain(header) => header,
1599 Self::IntermediateShard(header) => header,
1600 Self::LeafShard(header) => header,
1601 }
1602 }
1603}
1604
1605impl<'a> BlockHeader<'a> {
1606 #[inline]
1613 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1614 match shard_kind {
1615 RealShardKind::BeaconChain => {
1616 let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1617 Some((Self::BeaconChain(header), remainder))
1618 }
1619 RealShardKind::IntermediateShard => {
1620 let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1621 Some((Self::IntermediateShard(header), remainder))
1622 }
1623 RealShardKind::LeafShard => {
1624 let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1625 Some((Self::LeafShard(header), remainder))
1626 }
1627 }
1628 }
1629
1630 #[inline]
1635 pub fn is_internally_consistent(&self) -> bool {
1636 match self {
1637 Self::BeaconChain(header) => header.is_internally_consistent(),
1638 Self::IntermediateShard(header) => header.is_internally_consistent(),
1639 Self::LeafShard(header) => header.is_internally_consistent(),
1640 }
1641 }
1642
1643 #[inline]
1646 pub fn try_from_bytes_unchecked(
1647 bytes: &'a [u8],
1648 shard_kind: RealShardKind,
1649 ) -> Option<(Self, &'a [u8])> {
1650 match shard_kind {
1651 RealShardKind::BeaconChain => {
1652 let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1653 Some((Self::BeaconChain(header), remainder))
1654 }
1655 RealShardKind::IntermediateShard => {
1656 let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1657 Some((Self::IntermediateShard(header), remainder))
1658 }
1659 RealShardKind::LeafShard => {
1660 let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1661 Some((Self::LeafShard(header), remainder))
1662 }
1663 }
1664 }
1665
1666 #[inline]
1667 fn try_from_bytes_shared(
1668 mut bytes: &'a [u8],
1669 ) -> Option<(
1670 &'a BlockHeaderPrefix,
1671 &'a BlockHeaderConsensusInfo,
1672 &'a BlockHeaderResult,
1673 &'a [u8],
1674 )> {
1675 let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1676 let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1678
1679 if !(prefix.padding_0 == [0; _]
1680 && prefix.shard_index.as_u32() <= ShardIndex::MAX_SHARD_INDEX)
1681 {
1682 return None;
1683 }
1684
1685 let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1686 let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1688
1689 let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1690 let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1692
1693 if consensus_info.solution.padding != [0; _] {
1694 return None;
1695 }
1696
1697 Some((prefix, consensus_info, result, bytes))
1698 }
1699
1700 #[cfg(feature = "alloc")]
1702 #[inline(always)]
1703 pub fn to_owned(self) -> OwnedBlockHeader {
1704 match self {
1705 Self::BeaconChain(header) => header.to_owned().into(),
1706 Self::IntermediateShard(header) => header.to_owned().into(),
1707 Self::LeafShard(header) => header.to_owned().into(),
1708 }
1709 }
1710
1711 #[inline]
1713 pub fn pre_seal_hash(&self) -> Blake3Hash {
1714 match self {
1715 Self::BeaconChain(header) => header.pre_seal_hash(),
1716 Self::IntermediateShard(header) => header.pre_seal_hash(),
1717 Self::LeafShard(header) => header.pre_seal_hash(),
1718 }
1719 }
1720
1721 #[inline]
1724 pub fn is_sealed_correctly(&self) -> bool {
1725 match self {
1726 Self::BeaconChain(header) => header.is_sealed_correctly(),
1727 Self::IntermediateShard(header) => header.is_sealed_correctly(),
1728 Self::LeafShard(header) => header.is_sealed_correctly(),
1729 }
1730 }
1731
1732 #[inline]
1740 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1741 enum Wrapper<B, I, L> {
1742 BeaconChain(B),
1743 IntermediateShard(I),
1744 LeafShard(L),
1745 }
1746
1747 impl<B, I, L> Deref for Wrapper<B, I, L>
1748 where
1749 B: Deref<Target = BlockRoot>,
1750 I: Deref<Target = BlockRoot>,
1751 L: Deref<Target = BlockRoot>,
1752 {
1753 type Target = BlockRoot;
1754
1755 #[inline(always)]
1756 fn deref(&self) -> &Self::Target {
1757 match self {
1758 Wrapper::BeaconChain(block_root) => block_root,
1759 Wrapper::IntermediateShard(block_root) => block_root,
1760 Wrapper::LeafShard(block_root) => block_root,
1761 }
1762 }
1763 }
1764
1765 match self {
1767 Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1768 Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1769 Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1770 }
1771 }
1772}