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::{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 = "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: RealShardKind;
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 fn pre_seal_hash(&self) -> Blake3Hash;
67}
68
69#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
73#[cfg_attr(
74 feature = "scale-codec",
75 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
76)]
77#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
78#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
79#[repr(C)]
80pub struct BlockHeaderPrefix {
81 pub number: BlockNumber,
83 pub shard_index: ShardIndex,
85 pub padding_0: [u8; 4],
87 pub timestamp: BlockTimestamp,
89 pub parent_root: BlockRoot,
91 pub mmr_root: Blake3Hash,
94}
95
96impl BlockHeaderPrefix {
97 pub fn hash(&self) -> Blake3Hash {
99 const {
100 assert!(size_of::<Self>() <= CHUNK_LEN);
101 }
102 Blake3Hash::new(
104 single_chunk_hash(self.as_bytes())
105 .expect("Less than a single chunk worth of bytes; qed"),
106 )
107 }
108}
109
110#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
112#[cfg_attr(
113 feature = "scale-codec",
114 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
115)]
116#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
117#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
118#[repr(C)]
119pub struct BlockHeaderConsensusInfo {
120 pub slot: SlotNumber,
122 pub proof_of_time: PotOutput,
124 pub future_proof_of_time: PotOutput,
126 pub solution: Solution,
128}
129
130impl BlockHeaderConsensusInfo {
131 pub fn hash(&self) -> Blake3Hash {
133 Blake3Hash::from(blake3::hash(self.as_bytes()))
135 }
136}
137
138#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, TrivialType)]
140#[cfg_attr(
141 feature = "scale-codec",
142 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
143)]
144#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
145#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
146#[repr(C)]
147pub struct BlockHeaderBeaconChainInfo {
148 pub number: BlockNumber,
150 pub root: BlockRoot,
152}
153
154impl BlockHeaderBeaconChainInfo {
155 pub fn hash(&self) -> Blake3Hash {
157 const {
158 assert!(size_of::<Self>() <= BLOCK_LEN);
159 }
160 Blake3Hash::new(
162 single_block_hash(self.as_bytes())
163 .expect("Less than a single block worth of bytes; qed"),
164 )
165 }
166}
167
168#[derive(Debug, Copy, Clone, Eq, PartialEq)]
170#[cfg_attr(
171 feature = "scale-codec",
172 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
173)]
174#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
175#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
176pub struct BlockHeaderFixedConsensusParameters {
177 pub solution_range: SolutionRange,
179 pub slot_iterations: NonZeroU32,
184}
185
186impl BlockHeaderFixedConsensusParameters {
187 #[inline]
193 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(Self, &[u8])> {
194 let solution_range = bytes.split_off(..size_of::<SolutionRange>())?;
199 let solution_range = SolutionRange::from_bytes([
200 solution_range[0],
201 solution_range[1],
202 solution_range[2],
203 solution_range[3],
204 solution_range[4],
205 solution_range[5],
206 solution_range[6],
207 solution_range[7],
208 ]);
209
210 let pot_slot_iterations = bytes.split_off(..size_of::<u32>())?;
211 let slot_iterations = u32::from_le_bytes([
212 pot_slot_iterations[0],
213 pot_slot_iterations[1],
214 pot_slot_iterations[2],
215 pot_slot_iterations[3],
216 ]);
217 let slot_iterations = NonZeroU32::new(slot_iterations)?;
218
219 Some((
220 Self {
221 solution_range,
222 slot_iterations,
223 },
224 bytes,
225 ))
226 }
227}
228
229#[derive(Debug, Copy, Clone, Eq, PartialEq)]
233#[repr(C, packed)]
234pub struct BlockHeaderPotParametersChange {
235 slot: SlotNumber,
239 slot_iterations: NonZeroU32,
241 entropy: Blake3Hash,
243}
244
245impl From<BlockHeaderPotParametersChange> for PotParametersChange {
246 #[inline(always)]
247 fn from(value: BlockHeaderPotParametersChange) -> Self {
248 let BlockHeaderPotParametersChange {
249 slot,
250 slot_iterations,
251 entropy,
252 } = value;
253
254 PotParametersChange {
255 slot,
256 slot_iterations,
257 entropy,
258 }
259 }
260}
261
262impl From<PotParametersChange> for BlockHeaderPotParametersChange {
263 #[inline(always)]
264 fn from(value: PotParametersChange) -> Self {
265 let PotParametersChange {
266 slot,
267 slot_iterations,
268 entropy,
269 } = value;
270
271 BlockHeaderPotParametersChange {
272 slot,
273 slot_iterations,
274 entropy,
275 }
276 }
277}
278
279impl BlockHeaderPotParametersChange {
280 #[inline]
286 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(&Self, &[u8])> {
287 let pot_parameters_change_ptr = bytes.as_ptr().cast::<Self>();
293
294 let _slot = bytes.split_off(..size_of::<SlotNumber>())?;
295
296 let slot_iterations = bytes.split_off(..size_of::<u32>())?;
297 if slot_iterations == [0, 0, 0, 0] {
298 return None;
299 }
300 let _entropy = bytes.split_off(..size_of::<Blake3Hash>())?;
301
302 let pot_parameters_change = unsafe { pot_parameters_change_ptr.as_ref_unchecked() };
304
305 Some((pot_parameters_change, bytes))
306 }
307}
308
309#[derive(Debug, Copy, Clone)]
311pub struct OwnedBlockHeaderConsensusParameters {
312 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
314 pub super_segment_root: Option<SuperSegmentRoot>,
316 pub next_solution_range: Option<SolutionRange>,
318 pub pot_parameters_change: Option<BlockHeaderPotParametersChange>,
320}
321
322impl OwnedBlockHeaderConsensusParameters {
323 #[inline]
325 pub fn as_ref(&self) -> BlockHeaderConsensusParameters<'_> {
326 BlockHeaderConsensusParameters {
327 fixed_parameters: self.fixed_parameters,
328 super_segment_root: self.super_segment_root.as_ref(),
329 next_solution_range: self.next_solution_range,
330 pot_parameters_change: self.pot_parameters_change.as_ref(),
331 }
332 }
333}
334
335#[derive(Debug, Copy, Clone, Eq, PartialEq)]
337pub struct BlockHeaderConsensusParameters<'a> {
338 pub fixed_parameters: BlockHeaderFixedConsensusParameters,
340 pub super_segment_root: Option<&'a SuperSegmentRoot>,
342 pub next_solution_range: Option<SolutionRange>,
344 pub pot_parameters_change: Option<&'a BlockHeaderPotParametersChange>,
346}
347
348impl<'a> BlockHeaderConsensusParameters<'a> {
349 pub const MAX_SIZE: u32 = size_of::<BlockHeaderFixedConsensusParameters>() as u32
351 + u8::SIZE
352 + <SuperSegmentRoot as TrivialType>::SIZE
353 + <SolutionRange 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 } = fixed_parameters;
453
454 let mut hasher = blake3::Hasher::new();
456 hasher.update(solution_range.as_bytes());
457 hasher.update(&slot_iterations.get().to_le_bytes());
458
459 if let Some(super_segment_root) = super_segment_root {
460 hasher.update(super_segment_root.as_bytes());
461 }
462 if let Some(next_solution_range) = next_solution_range {
463 hasher.update(next_solution_range.as_bytes());
464 }
465 if let Some(pot_parameters_change) = pot_parameters_change.copied() {
466 let BlockHeaderPotParametersChange {
467 slot,
468 slot_iterations,
469 entropy,
470 } = pot_parameters_change;
471 hasher.update(slot.as_bytes());
472 hasher.update(&slot_iterations.get().to_le_bytes());
473 hasher.update(entropy.as_bytes());
474 }
475
476 Blake3Hash::from(hasher.finalize())
477 }
478}
479
480#[derive(Debug, Copy, Clone, Deref)]
482pub struct BlockHeaderChildShardBlocks<'a> {
483 pub child_shard_blocks: &'a [BlockRoot],
485}
486
487impl<'a> BlockHeaderChildShardBlocks<'a> {
488 #[inline]
494 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
495 let length = bytes.split_off(..size_of::<u16>())?;
501 let num_blocks = usize::from(*unsafe { <u16 as TrivialType>::from_bytes(length) }?);
503
504 let padding = bytes.split_off(..size_of::<[u8; 2]>())?;
505
506 if padding != [0, 0] {
508 return None;
509 }
510
511 let child_shard_blocks = bytes.split_off(..num_blocks * BlockRoot::SIZE)?;
512 let child_shard_blocks = unsafe {
514 slice::from_raw_parts(
515 child_shard_blocks.as_ptr().cast::<[u8; BlockRoot::SIZE]>(),
516 num_blocks,
517 )
518 };
519 let child_shard_blocks = BlockRoot::slice_from_repr(child_shard_blocks);
520
521 Some((Self { child_shard_blocks }, bytes))
522 }
523
524 pub fn root(&self) -> Option<Blake3Hash> {
528 let root = UnbalancedMerkleTree::compute_root_only::<'_, { u32::MAX as u64 }, _, _>(
529 self.child_shard_blocks
531 .iter()
532 .map(|child_shard_block_root| {
533 single_block_hash(child_shard_block_root.as_ref())
537 .expect("Less than a single block worth of bytes; qed")
538 }),
539 )?;
540 Some(Blake3Hash::new(root))
541 }
542}
543
544#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
548#[cfg_attr(
549 feature = "scale-codec",
550 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
551)]
552#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
553#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
554#[repr(C)]
555pub struct BlockHeaderResult {
556 pub body_root: Blake3Hash,
559 pub state_root: Blake3Hash,
562}
563
564impl BlockHeaderResult {
565 pub fn hash(&self) -> Blake3Hash {
567 const {
568 assert!(size_of::<Self>() <= BLOCK_LEN);
569 }
570 Blake3Hash::new(
572 single_block_hash(self.as_bytes())
573 .expect("Less than a single block worth of bytes; qed"),
574 )
575 }
576}
577
578#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
580#[cfg_attr(
581 feature = "scale-codec",
582 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
583)]
584#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
585#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
586#[repr(u8)]
587#[non_exhaustive]
588pub enum BlockHeaderSealType {
589 #[cfg_attr(feature = "scale-codec", codec(index = 0))]
591 Ed25519 = 0,
592}
593
594impl BlockHeaderSealType {
595 #[inline(always)]
597 pub const fn try_from_byte(byte: u8) -> Option<Self> {
598 if byte == Self::Ed25519 as u8 {
599 Some(Self::Ed25519)
600 } else {
601 None
602 }
603 }
604}
605
606#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
608#[cfg_attr(
609 feature = "scale-codec",
610 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
611)]
612#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
613#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
614#[repr(C)]
615pub struct BlockHeaderEd25519Seal {
616 pub public_key: Ed25519PublicKey,
618 pub signature: Ed25519Signature,
620}
621
622#[derive(Debug, Copy, Clone)]
624#[cfg_attr(
625 feature = "scale-codec",
626 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
627)]
628#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
629#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
630#[non_exhaustive]
631pub enum OwnedBlockHeaderSeal {
632 Ed25519(BlockHeaderEd25519Seal),
634}
635
636impl OwnedBlockHeaderSeal {
637 #[inline(always)]
639 pub fn as_ref(&self) -> BlockHeaderSeal<'_> {
640 match self {
641 Self::Ed25519(seal) => BlockHeaderSeal::Ed25519(seal),
642 }
643 }
644}
645
646#[derive(Debug, Copy, Clone)]
648#[non_exhaustive]
649pub enum BlockHeaderSeal<'a> {
650 Ed25519(&'a BlockHeaderEd25519Seal),
652}
653
654impl<'a> BlockHeaderSeal<'a> {
655 pub const MAX_SIZE: u32 = 1 + BlockHeaderEd25519Seal::SIZE;
657 #[inline]
663 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
664 let seal_type = bytes.split_off(..size_of::<u8>())?;
669 let seal_type = BlockHeaderSealType::try_from_byte(seal_type[0])?;
670
671 match seal_type {
672 BlockHeaderSealType::Ed25519 => {
673 let seal = bytes.split_off(..size_of::<BlockHeaderEd25519Seal>())?;
674 let seal = unsafe { BlockHeaderEd25519Seal::from_bytes(seal) }?;
676 Some((Self::Ed25519(seal), bytes))
677 }
678 }
679 }
680
681 #[inline]
683 pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
684 match self {
685 BlockHeaderSeal::Ed25519(seal) => seal
686 .public_key
687 .verify(&seal.signature, pre_seal_hash.as_bytes())
688 .is_ok(),
689 }
690 }
691
692 #[inline]
694 pub fn public_key_hash(&self) -> Blake3Hash {
695 match self {
696 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
697 }
698 }
699
700 #[inline]
702 pub fn hash(&self) -> Blake3Hash {
703 match self {
704 BlockHeaderSeal::Ed25519(seal) => {
705 let mut hasher = blake3::Hasher::new();
707 hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
708 hasher.update(seal.as_bytes());
709
710 Blake3Hash::from(hasher.finalize())
711 }
712 }
713 }
714}
715
716#[derive(Debug, Copy, Clone)]
718pub struct SharedBlockHeader<'a> {
719 pub prefix: &'a BlockHeaderPrefix,
721 pub result: &'a BlockHeaderResult,
723 pub consensus_info: &'a BlockHeaderConsensusInfo,
725 pub seal: BlockHeaderSeal<'a>,
727}
728
729#[derive(Debug, Clone, Yokeable)]
731#[non_exhaustive]
733pub struct BeaconChainHeader<'a> {
734 shared: SharedBlockHeader<'a>,
736 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
738 consensus_parameters: BlockHeaderConsensusParameters<'a>,
740 pre_seal_bytes: &'a [u8],
742 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
743 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
744 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
745 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
746}
747
748impl<'a> Deref for BeaconChainHeader<'a> {
749 type Target = SharedBlockHeader<'a>;
750
751 #[inline(always)]
752 fn deref(&self) -> &Self::Target {
753 &self.shared
754 }
755}
756
757impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
758 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
759
760 #[cfg(feature = "alloc")]
761 type Owned = OwnedBeaconChainHeader;
762
763 #[cfg(feature = "alloc")]
764 #[inline(always)]
765 fn to_owned(self) -> Self::Owned {
766 self.to_owned()
767 }
768
769 #[inline(always)]
770 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
771 self.root()
772 }
773
774 #[inline(always)]
775 fn pre_seal_hash(&self) -> Blake3Hash {
776 self.pre_seal_hash()
777 }
778}
779
780impl<'a> BeaconChainHeader<'a> {
781 #[inline]
788 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
789 let (prefix, consensus_info, result, remainder) =
798 BlockHeader::try_from_bytes_shared(bytes)?;
799
800 if prefix.shard_index.shard_kind() != Some(ShardKind::BeaconChain) {
801 return None;
802 }
803
804 let (child_shard_blocks, remainder) =
805 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
806
807 let (consensus_parameters, remainder) =
808 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
809
810 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
811
812 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
813
814 let shared = SharedBlockHeader {
815 prefix,
816 result,
817 consensus_info,
818 seal,
819 };
820
821 let header = Self {
822 shared,
823 child_shard_blocks,
824 consensus_parameters,
825 pre_seal_bytes,
826 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
827 cached_block_root: rclite::Arc::default(),
828 };
829
830 if !header.is_internally_consistent() {
831 return None;
832 }
833
834 Some((header, remainder))
835 }
836
837 #[inline]
842 pub fn is_internally_consistent(&self) -> bool {
843 let public_key_hash = match self.seal {
844 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
845 };
846 public_key_hash == self.shared.consensus_info.solution.public_key_hash
847 }
848
849 #[inline]
852 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
853 let (prefix, consensus_info, result, remainder) =
862 BlockHeader::try_from_bytes_shared(bytes)?;
863
864 if prefix.shard_index.shard_kind() != Some(ShardKind::BeaconChain) {
865 return None;
866 }
867
868 let (child_shard_blocks, remainder) =
869 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
870
871 let (consensus_parameters, remainder) =
872 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
873
874 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
875
876 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
877
878 let shared = SharedBlockHeader {
879 prefix,
880 result,
881 consensus_info,
882 seal,
883 };
884
885 Some((
886 Self {
887 shared,
888 child_shard_blocks,
889 consensus_parameters,
890 pre_seal_bytes,
891 #[cfg(any(
892 feature = "alloc",
893 not(any(target_os = "none", target_os = "unknown"))
894 ))]
895 cached_block_root: rclite::Arc::default(),
896 },
897 remainder,
898 ))
899 }
900
901 #[cfg(feature = "alloc")]
903 #[inline(always)]
904 pub fn to_owned(self) -> OwnedBeaconChainHeader {
905 let unsealed = OwnedBeaconChainHeader::from_parts(
906 self.shared.prefix,
907 self.shared.result,
908 self.shared.consensus_info,
909 &self.child_shard_blocks,
910 self.consensus_parameters,
911 )
912 .expect("`self` is always a valid invariant; qed");
913
914 unsealed.with_seal(self.shared.seal)
915 }
916
917 #[inline(always)]
919 pub fn shared(&self) -> &SharedBlockHeader<'a> {
920 &self.shared
921 }
922
923 #[inline(always)]
925 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
926 &self.child_shard_blocks
927 }
928
929 #[inline(always)]
931 pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
932 &self.consensus_parameters
933 }
934
935 #[inline]
937 pub fn pre_seal_hash(&self) -> Blake3Hash {
938 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
940 }
941
942 #[inline]
945 pub fn is_sealed_correctly(&self) -> bool {
946 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
947 && self.seal.is_seal_valid(&self.pre_seal_hash())
948 }
949
950 #[inline]
958 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
959 let Self {
960 shared,
961 child_shard_blocks,
962 consensus_parameters,
963 pre_seal_bytes: _,
964 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
965 cached_block_root,
966 } = self;
967
968 let compute_root = || {
969 let SharedBlockHeader {
970 prefix,
971 result,
972 consensus_info,
973 seal,
974 } = shared;
975
976 const MAX_N: usize = 6;
977 let leaves: [_; MAX_N] = [
978 prefix.hash(),
979 result.hash(),
980 consensus_info.hash(),
981 seal.hash(),
982 child_shard_blocks.root().unwrap_or_default(),
983 consensus_parameters.hash(),
984 ];
985 let block_root =
986 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
987 .expect("The list is not empty; qed");
988
989 BlockRoot::new(Blake3Hash::new(block_root))
990 };
991
992 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
993 {
994 cached_block_root.get_or_init(compute_root)
995 }
996 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
997 {
998 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
999 }
1000 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1001 {
1002 struct Wrapper(BlockRoot);
1003
1004 impl Deref for Wrapper {
1005 type Target = BlockRoot;
1006
1007 #[inline(always)]
1008 fn deref(&self) -> &Self::Target {
1009 &self.0
1010 }
1011 }
1012
1013 Wrapper(compute_root())
1014 }
1015 }
1016}
1017
1018#[derive(Debug, Clone, Yokeable)]
1020#[non_exhaustive]
1022pub struct IntermediateShardHeader<'a> {
1023 shared: SharedBlockHeader<'a>,
1025 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1027 child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
1029 pre_seal_bytes: &'a [u8],
1031 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1032 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1033 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1034 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1035}
1036
1037impl<'a> Deref for IntermediateShardHeader<'a> {
1038 type Target = SharedBlockHeader<'a>;
1039
1040 #[inline(always)]
1041 fn deref(&self) -> &Self::Target {
1042 &self.shared
1043 }
1044}
1045
1046impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
1047 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
1048
1049 #[cfg(feature = "alloc")]
1050 type Owned = OwnedIntermediateShardHeader;
1051
1052 #[cfg(feature = "alloc")]
1053 #[inline(always)]
1054 fn to_owned(self) -> Self::Owned {
1055 self.to_owned()
1056 }
1057
1058 #[inline(always)]
1059 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1060 self.root()
1061 }
1062
1063 #[inline(always)]
1064 fn pre_seal_hash(&self) -> Blake3Hash {
1065 self.pre_seal_hash()
1066 }
1067}
1068
1069impl<'a> IntermediateShardHeader<'a> {
1070 #[inline]
1077 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1078 let (prefix, consensus_info, result, mut remainder) =
1087 BlockHeader::try_from_bytes_shared(bytes)?;
1088
1089 if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1090 return None;
1091 }
1092
1093 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1094 let beacon_chain_info =
1096 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1097
1098 let (child_shard_blocks, remainder) =
1099 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1100
1101 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1102
1103 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1104
1105 let shared = SharedBlockHeader {
1106 prefix,
1107 result,
1108 consensus_info,
1109 seal,
1110 };
1111
1112 let header = Self {
1113 shared,
1114 beacon_chain_info,
1115 child_shard_blocks,
1116 pre_seal_bytes,
1117 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1118 cached_block_root: rclite::Arc::default(),
1119 };
1120
1121 if !header.is_internally_consistent() {
1122 return None;
1123 }
1124
1125 Some((header, remainder))
1126 }
1127
1128 #[inline]
1133 pub fn is_internally_consistent(&self) -> bool {
1134 let public_key_hash = match self.seal {
1135 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1136 };
1137 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1138 }
1139
1140 #[inline]
1143 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1144 let (prefix, consensus_info, result, mut remainder) =
1153 BlockHeader::try_from_bytes_shared(bytes)?;
1154
1155 if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1156 return None;
1157 }
1158
1159 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1160 let beacon_chain_info =
1162 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1163
1164 let (child_shard_blocks, remainder) =
1165 BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1166
1167 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1168
1169 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1170
1171 let shared = SharedBlockHeader {
1172 prefix,
1173 result,
1174 consensus_info,
1175 seal,
1176 };
1177
1178 Some((
1179 Self {
1180 shared,
1181 beacon_chain_info,
1182 child_shard_blocks,
1183 pre_seal_bytes,
1184 #[cfg(any(
1185 feature = "alloc",
1186 not(any(target_os = "none", target_os = "unknown"))
1187 ))]
1188 cached_block_root: rclite::Arc::default(),
1189 },
1190 remainder,
1191 ))
1192 }
1193
1194 #[cfg(feature = "alloc")]
1196 #[inline(always)]
1197 pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1198 let unsealed = OwnedIntermediateShardHeader::from_parts(
1199 self.shared.prefix,
1200 self.shared.result,
1201 self.shared.consensus_info,
1202 self.beacon_chain_info,
1203 &self.child_shard_blocks,
1204 )
1205 .expect("`self` is always a valid invariant; qed");
1206
1207 unsealed.with_seal(self.shared.seal)
1208 }
1209
1210 #[inline(always)]
1212 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1213 &self.shared
1214 }
1215
1216 #[inline(always)]
1218 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1219 self.beacon_chain_info
1220 }
1221
1222 #[inline(always)]
1224 pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1225 &self.child_shard_blocks
1226 }
1227
1228 #[inline]
1230 pub fn pre_seal_hash(&self) -> Blake3Hash {
1231 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1233 }
1234
1235 #[inline]
1238 pub fn is_sealed_correctly(&self) -> bool {
1239 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1240 && self.seal.is_seal_valid(&self.pre_seal_hash())
1241 }
1242
1243 #[inline]
1251 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1252 let Self {
1253 shared,
1254 beacon_chain_info,
1255 child_shard_blocks,
1256 pre_seal_bytes: _,
1257 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1258 cached_block_root,
1259 } = self;
1260
1261 let compute_root = || {
1262 let SharedBlockHeader {
1263 prefix,
1264 result,
1265 consensus_info,
1266 seal,
1267 } = shared;
1268
1269 const MAX_N: usize = 6;
1270 let leaves: [_; MAX_N] = [
1271 prefix.hash(),
1272 result.hash(),
1273 consensus_info.hash(),
1274 seal.hash(),
1275 beacon_chain_info.hash(),
1276 child_shard_blocks.root().unwrap_or_default(),
1277 ];
1278 let block_root =
1279 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1280 .expect("The list is not empty; qed");
1281
1282 BlockRoot::new(Blake3Hash::new(block_root))
1283 };
1284
1285 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1286 {
1287 cached_block_root.get_or_init(compute_root)
1288 }
1289 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1290 {
1291 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1292 }
1293 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1294 {
1295 struct Wrapper(BlockRoot);
1296
1297 impl Deref for Wrapper {
1298 type Target = BlockRoot;
1299
1300 #[inline(always)]
1301 fn deref(&self) -> &Self::Target {
1302 &self.0
1303 }
1304 }
1305
1306 Wrapper(compute_root())
1307 }
1308 }
1309}
1310
1311#[derive(Debug, Clone, Yokeable)]
1313#[non_exhaustive]
1315pub struct LeafShardHeader<'a> {
1316 shared: SharedBlockHeader<'a>,
1318 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1320 pre_seal_bytes: &'a [u8],
1322 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1323 cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1324 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1325 cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1326}
1327
1328impl<'a> Deref for LeafShardHeader<'a> {
1329 type Target = SharedBlockHeader<'a>;
1330
1331 #[inline(always)]
1332 fn deref(&self) -> &Self::Target {
1333 &self.shared
1334 }
1335}
1336
1337impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1338 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1339
1340 #[cfg(feature = "alloc")]
1341 type Owned = OwnedLeafShardHeader;
1342
1343 #[cfg(feature = "alloc")]
1344 #[inline(always)]
1345 fn to_owned(self) -> Self::Owned {
1346 self.to_owned()
1347 }
1348
1349 #[inline(always)]
1350 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1351 self.root()
1352 }
1353
1354 #[inline(always)]
1355 fn pre_seal_hash(&self) -> Blake3Hash {
1356 self.pre_seal_hash()
1357 }
1358}
1359
1360impl<'a> LeafShardHeader<'a> {
1361 #[inline]
1368 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1369 let (prefix, consensus_info, result, mut remainder) =
1377 BlockHeader::try_from_bytes_shared(bytes)?;
1378
1379 if prefix.shard_index.shard_kind() != Some(ShardKind::LeafShard) {
1380 return None;
1381 }
1382
1383 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1384 let beacon_chain_info =
1386 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1387
1388 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1389
1390 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1391
1392 let shared = SharedBlockHeader {
1393 prefix,
1394 result,
1395 consensus_info,
1396 seal,
1397 };
1398
1399 let header = Self {
1400 shared,
1401 beacon_chain_info,
1402 pre_seal_bytes,
1403 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1404 cached_block_root: rclite::Arc::default(),
1405 };
1406
1407 if !header.is_internally_consistent() {
1408 return None;
1409 }
1410
1411 Some((header, remainder))
1412 }
1413
1414 #[inline]
1419 pub fn is_internally_consistent(&self) -> bool {
1420 let public_key_hash = match self.seal {
1421 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1422 };
1423 public_key_hash == self.shared.consensus_info.solution.public_key_hash
1424 }
1425
1426 #[inline]
1429 pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1430 let (prefix, consensus_info, result, mut remainder) =
1438 BlockHeader::try_from_bytes_shared(bytes)?;
1439
1440 if prefix.shard_index.shard_kind() != Some(ShardKind::LeafShard) {
1441 return None;
1442 }
1443
1444 let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1445 let beacon_chain_info =
1447 unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1448
1449 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1450
1451 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1452
1453 let shared = SharedBlockHeader {
1454 prefix,
1455 result,
1456 consensus_info,
1457 seal,
1458 };
1459
1460 Some((
1461 Self {
1462 shared,
1463 beacon_chain_info,
1464 pre_seal_bytes,
1465 #[cfg(any(
1466 feature = "alloc",
1467 not(any(target_os = "none", target_os = "unknown"))
1468 ))]
1469 cached_block_root: rclite::Arc::default(),
1470 },
1471 remainder,
1472 ))
1473 }
1474
1475 #[cfg(feature = "alloc")]
1477 #[inline(always)]
1478 pub fn to_owned(self) -> OwnedLeafShardHeader {
1479 let unsealed = OwnedLeafShardHeader::from_parts(
1480 self.shared.prefix,
1481 self.shared.result,
1482 self.shared.consensus_info,
1483 self.beacon_chain_info,
1484 );
1485
1486 unsealed.with_seal(self.shared.seal)
1487 }
1488
1489 #[inline(always)]
1491 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1492 &self.shared
1493 }
1494
1495 #[inline(always)]
1497 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1498 self.beacon_chain_info
1499 }
1500
1501 #[inline]
1503 pub fn pre_seal_hash(&self) -> Blake3Hash {
1504 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1506 }
1507
1508 #[inline]
1511 pub fn is_sealed_correctly(&self) -> bool {
1512 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1513 && self.seal.is_seal_valid(&self.pre_seal_hash())
1514 }
1515
1516 #[inline]
1524 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1525 let Self {
1526 shared,
1527 beacon_chain_info,
1528 pre_seal_bytes: _,
1529 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1530 cached_block_root,
1531 } = self;
1532
1533 let compute_root = || {
1534 let SharedBlockHeader {
1535 prefix,
1536 result,
1537 consensus_info,
1538 seal,
1539 } = shared;
1540
1541 const MAX_N: usize = 5;
1542 let leaves: [_; MAX_N] = [
1543 prefix.hash(),
1544 result.hash(),
1545 consensus_info.hash(),
1546 seal.hash(),
1547 beacon_chain_info.hash(),
1548 ];
1549 let block_root =
1550 UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1551 .expect("The list is not empty; qed");
1552
1553 BlockRoot::new(Blake3Hash::new(block_root))
1554 };
1555
1556 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1557 {
1558 cached_block_root.get_or_init(compute_root)
1559 }
1560 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1561 {
1562 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1563 }
1564 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1565 {
1566 struct Wrapper(BlockRoot);
1567
1568 impl Deref for Wrapper {
1569 type Target = BlockRoot;
1570
1571 #[inline(always)]
1572 fn deref(&self) -> &Self::Target {
1573 &self.0
1574 }
1575 }
1576
1577 Wrapper(compute_root())
1578 }
1579 }
1580}
1581
1582#[derive(Debug, Clone, From)]
1587pub enum BlockHeader<'a> {
1588 BeaconChain(BeaconChainHeader<'a>),
1590 IntermediateShard(IntermediateShardHeader<'a>),
1592 LeafShard(LeafShardHeader<'a>),
1594}
1595
1596impl<'a> Deref for BlockHeader<'a> {
1597 type Target = SharedBlockHeader<'a>;
1598
1599 #[inline(always)]
1600 fn deref(&self) -> &Self::Target {
1601 match self {
1602 Self::BeaconChain(header) => header,
1603 Self::IntermediateShard(header) => header,
1604 Self::LeafShard(header) => header,
1605 }
1606 }
1607}
1608
1609impl<'a> BlockHeader<'a> {
1610 #[inline]
1617 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1618 match shard_kind {
1619 RealShardKind::BeaconChain => {
1620 let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1621 Some((Self::BeaconChain(header), remainder))
1622 }
1623 RealShardKind::IntermediateShard => {
1624 let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1625 Some((Self::IntermediateShard(header), remainder))
1626 }
1627 RealShardKind::LeafShard => {
1628 let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1629 Some((Self::LeafShard(header), remainder))
1630 }
1631 }
1632 }
1633
1634 #[inline]
1639 pub fn is_internally_consistent(&self) -> bool {
1640 match self {
1641 Self::BeaconChain(header) => header.is_internally_consistent(),
1642 Self::IntermediateShard(header) => header.is_internally_consistent(),
1643 Self::LeafShard(header) => header.is_internally_consistent(),
1644 }
1645 }
1646
1647 #[inline]
1650 pub fn try_from_bytes_unchecked(
1651 bytes: &'a [u8],
1652 shard_kind: RealShardKind,
1653 ) -> Option<(Self, &'a [u8])> {
1654 match shard_kind {
1655 RealShardKind::BeaconChain => {
1656 let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1657 Some((Self::BeaconChain(header), remainder))
1658 }
1659 RealShardKind::IntermediateShard => {
1660 let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1661 Some((Self::IntermediateShard(header), remainder))
1662 }
1663 RealShardKind::LeafShard => {
1664 let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1665 Some((Self::LeafShard(header), remainder))
1666 }
1667 }
1668 }
1669
1670 #[inline]
1671 fn try_from_bytes_shared(
1672 mut bytes: &'a [u8],
1673 ) -> Option<(
1674 &'a BlockHeaderPrefix,
1675 &'a BlockHeaderConsensusInfo,
1676 &'a BlockHeaderResult,
1677 &'a [u8],
1678 )> {
1679 let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1680 let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1682
1683 if !(prefix.padding_0 == [0; _]
1684 && prefix.shard_index.as_u32() <= ShardIndex::MAX_SHARD_INDEX)
1685 {
1686 return None;
1687 }
1688
1689 let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1690 let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1692
1693 let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1694 let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1696
1697 if consensus_info.solution.padding != [0; _] {
1698 return None;
1699 }
1700
1701 Some((prefix, consensus_info, result, bytes))
1702 }
1703
1704 #[cfg(feature = "alloc")]
1706 #[inline(always)]
1707 pub fn to_owned(self) -> OwnedBlockHeader {
1708 match self {
1709 Self::BeaconChain(header) => header.to_owned().into(),
1710 Self::IntermediateShard(header) => header.to_owned().into(),
1711 Self::LeafShard(header) => header.to_owned().into(),
1712 }
1713 }
1714
1715 #[inline]
1717 pub fn pre_seal_hash(&self) -> Blake3Hash {
1718 match self {
1719 Self::BeaconChain(header) => header.pre_seal_hash(),
1720 Self::IntermediateShard(header) => header.pre_seal_hash(),
1721 Self::LeafShard(header) => header.pre_seal_hash(),
1722 }
1723 }
1724
1725 #[inline]
1728 pub fn is_sealed_correctly(&self) -> bool {
1729 match self {
1730 Self::BeaconChain(header) => header.is_sealed_correctly(),
1731 Self::IntermediateShard(header) => header.is_sealed_correctly(),
1732 Self::LeafShard(header) => header.is_sealed_correctly(),
1733 }
1734 }
1735
1736 #[inline]
1744 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1745 enum Wrapper<B, I, L> {
1746 BeaconChain(B),
1747 IntermediateShard(I),
1748 LeafShard(L),
1749 }
1750
1751 impl<B, I, L> Deref for Wrapper<B, I, L>
1752 where
1753 B: Deref<Target = BlockRoot>,
1754 I: Deref<Target = BlockRoot>,
1755 L: Deref<Target = BlockRoot>,
1756 {
1757 type Target = BlockRoot;
1758
1759 #[inline(always)]
1760 fn deref(&self) -> &Self::Target {
1761 match self {
1762 Wrapper::BeaconChain(block_root) => block_root,
1763 Wrapper::IntermediateShard(block_root) => block_root,
1764 Wrapper::LeafShard(block_root) => block_root,
1765 }
1766 }
1767 }
1768
1769 match self {
1771 Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1772 Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1773 Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1774 }
1775 }
1776}