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 crate::trees::{
19 BeaconChainHeaderMerkleTree, IntermediateShardHeaderMerkleTree, LeafShardHeaderMerkleTree,
20};
21#[cfg(feature = "alloc")]
22use ab_aligned_buffer::SharedAlignedBuffer;
23use ab_blake3::{BLOCK_LEN, single_block_hash, single_chunk_hash};
24use ab_io_type::trivial_type::TrivialType;
25use ab_io_type::unaligned::Unaligned;
26use blake3::CHUNK_LEN;
27use core::fmt;
28use core::num::NonZeroU32;
29use core::ops::Deref;
30use derive_more::From;
31#[cfg(feature = "scale-codec")]
32use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
33#[cfg(feature = "serde")]
34use serde::{Deserialize, Serialize};
35use yoke::Yokeable;
36
37pub trait GenericBlockHeader<'a>
39where
40 Self: Clone
41 + fmt::Debug
42 + Deref<Target = SharedBlockHeader<'a>>
43 + Into<BlockHeader<'a>>
44 + Send
45 + Sync,
46{
47 const SHARD_KIND: RealShardKind;
49
50 #[cfg(feature = "alloc")]
52 type Owned: GenericOwnedBlockHeader<Header<'a> = Self>
53 where
54 Self: 'a;
55
56 #[cfg(feature = "alloc")]
58 fn to_owned(self) -> Self::Owned;
59
60 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync;
67
68 fn pre_seal_hash(&self) -> Blake3Hash;
70}
71
72#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
76#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
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(
103 single_chunk_hash(self.as_bytes())
104 .expect("Less than a single chunk worth of bytes; qed"),
105 )
106 }
107}
108
109#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
111#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
112#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
113#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
114#[repr(C)]
115pub struct BlockHeaderConsensusInfo {
116 pub slot: SlotNumber,
118 pub proof_of_time: PotOutput,
120 pub future_proof_of_time: PotOutput,
122 pub solution: Solution,
124}
125
126impl BlockHeaderConsensusInfo {
127 pub fn hash(&self) -> Blake3Hash {
129 Blake3Hash::from(blake3::hash(self.as_bytes()))
130 }
131}
132
133#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, TrivialType)]
135#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
136#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
137#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
138#[repr(C)]
139pub struct BlockHeaderBeaconChainInfo {
140 pub number: BlockNumber,
142 pub root: BlockRoot,
144}
145
146impl BlockHeaderBeaconChainInfo {
147 pub fn hash(&self) -> Blake3Hash {
149 const {
150 assert!(size_of::<Self>() <= BLOCK_LEN);
151 }
152 Blake3Hash::new(
153 single_block_hash(self.as_bytes())
154 .expect("Less than a single block worth of bytes; qed"),
155 )
156 }
157}
158
159#[derive(Debug, Copy, Clone, Eq, PartialEq)]
161#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
162#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
163#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
164pub struct BlockHeaderFixedConsensusParameters {
165 pub solution_range: SolutionRange,
167 pub slot_iterations: NonZeroU32,
172 pub num_shards: NumShards,
174}
175
176impl BlockHeaderFixedConsensusParameters {
177 #[inline]
183 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(Self, &[u8])> {
184 let solution_range = bytes.split_off(..size_of::<SolutionRange>())?;
190 let solution_range = SolutionRange::from_bytes([
191 solution_range[0],
192 solution_range[1],
193 solution_range[2],
194 solution_range[3],
195 solution_range[4],
196 solution_range[5],
197 solution_range[6],
198 solution_range[7],
199 ]);
200
201 let pot_slot_iterations = bytes.split_off(..size_of::<u32>())?;
202 let slot_iterations = u32::from_le_bytes([
203 pot_slot_iterations[0],
204 pot_slot_iterations[1],
205 pot_slot_iterations[2],
206 pot_slot_iterations[3],
207 ]);
208 let slot_iterations = NonZeroU32::new(slot_iterations)?;
209 let num_shards;
210 (num_shards, bytes) = Unaligned::<NumShardsUnchecked>::from_bytes(bytes)?;
211 let num_shards = NumShards::try_from(num_shards.as_inner()).ok()?;
212
213 Some((
214 Self {
215 solution_range,
216 slot_iterations,
217 num_shards,
218 },
219 bytes,
220 ))
221 }
222}
223
224#[derive(Debug, Copy, Clone, Eq, PartialEq)]
228#[repr(C, packed)]
229pub struct BlockHeaderPotParametersChange {
230 slot: SlotNumber,
234 slot_iterations: NonZeroU32,
236 entropy: Blake3Hash,
238}
239
240impl From<BlockHeaderPotParametersChange> for PotParametersChange {
241 #[inline(always)]
242 fn from(value: BlockHeaderPotParametersChange) -> Self {
243 let BlockHeaderPotParametersChange {
244 slot,
245 slot_iterations,
246 entropy,
247 } = value;
248
249 PotParametersChange {
250 slot,
251 slot_iterations,
252 entropy,
253 }
254 }
255}
256
257impl From<PotParametersChange> for BlockHeaderPotParametersChange {
258 #[inline(always)]
259 fn from(value: PotParametersChange) -> Self {
260 let PotParametersChange {
261 slot,
262 slot_iterations,
263 entropy,
264 } = value;
265
266 BlockHeaderPotParametersChange {
267 slot,
268 slot_iterations,
269 entropy,
270 }
271 }
272}
273
274impl BlockHeaderPotParametersChange {
275 #[inline]
281 pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(&Self, &[u8])> {
282 let pot_parameters_change_ptr = bytes.as_ptr().cast::<Self>();
288
289 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 { pot_parameters_change_ptr.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 =
346 <SolutionRange as TrivialType>::SIZE
348 + u32::SIZE
350 + <NumShardsUnchecked as TrivialType>::SIZE
352 + u8::SIZE
354 + <SuperSegmentRoot as TrivialType>::SIZE
356 + <SolutionRange as TrivialType>::SIZE
358 + size_of::<BlockHeaderPotParametersChange>() as u32;
360 pub const SUPER_SEGMENT_ROOT_MASK: u8 = 0b0000_0001;
362 pub const NEXT_SOLUTION_RANGE_MASK: u8 = 0b0000_0010;
364 pub const POT_PARAMETERS_CHANGE_MASK: u8 = 0b0000_0100;
366 pub const MASK_ALL: u8 = Self::SUPER_SEGMENT_ROOT_MASK
368 | Self::NEXT_SOLUTION_RANGE_MASK
369 | Self::POT_PARAMETERS_CHANGE_MASK;
370
371 #[inline]
377 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
378 let (fixed_parameters, mut remainder) =
386 BlockHeaderFixedConsensusParameters::try_from_bytes(bytes)?;
387
388 let bitflags = remainder.split_off(..size_of::<u8>())?;
389 let bitflags = bitflags[0];
390
391 if (bitflags & Self::MASK_ALL) != bitflags {
392 return None;
394 }
395
396 let super_segment_root = if bitflags & Self::SUPER_SEGMENT_ROOT_MASK != 0 {
397 let super_segment_root;
398 (super_segment_root, remainder) = SuperSegmentRoot::from_bytes(remainder)?;
399
400 Some(super_segment_root)
401 } else {
402 None
403 };
404
405 let next_solution_range = if bitflags & Self::NEXT_SOLUTION_RANGE_MASK != 0 {
406 let next_solution_range = remainder.split_off(..size_of::<SolutionRange>())?;
407 let next_solution_range = SolutionRange::from_bytes([
409 next_solution_range[0],
410 next_solution_range[1],
411 next_solution_range[2],
412 next_solution_range[3],
413 next_solution_range[4],
414 next_solution_range[5],
415 next_solution_range[6],
416 next_solution_range[7],
417 ]);
418
419 Some(next_solution_range)
420 } else {
421 None
422 };
423
424 let pot_parameters_change = if bitflags & Self::POT_PARAMETERS_CHANGE_MASK != 0 {
425 let pot_parameters_change;
426 (pot_parameters_change, remainder) =
427 BlockHeaderPotParametersChange::try_from_bytes(remainder)?;
428
429 Some(pot_parameters_change)
430 } else {
431 None
432 };
433
434 Some((
435 Self {
436 fixed_parameters,
437 super_segment_root,
438 next_solution_range,
439 pot_parameters_change,
440 },
441 remainder,
442 ))
443 }
444
445 pub fn hash(&self) -> Blake3Hash {
447 let Self {
448 super_segment_root,
449 fixed_parameters,
450 next_solution_range,
451 pot_parameters_change,
452 } = self;
453 let BlockHeaderFixedConsensusParameters {
454 solution_range,
455 slot_iterations,
456 num_shards,
457 } = fixed_parameters;
458
459 let mut hasher = blake3::Hasher::new();
460 hasher.update(solution_range.as_bytes());
461 hasher.update(&slot_iterations.get().to_le_bytes());
462 hasher.update(NumShardsUnchecked::from(*num_shards).as_bytes());
463
464 if let Some(super_segment_root) = super_segment_root {
465 hasher.update(super_segment_root.as_bytes());
466 }
467 if let Some(next_solution_range) = next_solution_range {
468 hasher.update(next_solution_range.as_bytes());
469 }
470 if let Some(pot_parameters_change) = pot_parameters_change.copied() {
471 let BlockHeaderPotParametersChange {
472 slot,
473 slot_iterations,
474 entropy,
475 } = pot_parameters_change;
476 hasher.update(slot.as_bytes());
477 hasher.update(&slot_iterations.get().to_le_bytes());
478 hasher.update(entropy.as_bytes());
479 }
480
481 Blake3Hash::from(hasher.finalize())
482 }
483}
484
485#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
489#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
490#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
491#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
492#[repr(C)]
493pub struct BlockHeaderResult {
494 pub body_root: Blake3Hash,
497 pub state_root: Blake3Hash,
500}
501
502impl BlockHeaderResult {
503 pub fn hash(&self) -> Blake3Hash {
505 const {
506 assert!(size_of::<Self>() <= BLOCK_LEN);
507 }
508 Blake3Hash::new(
509 single_block_hash(self.as_bytes())
510 .expect("Less than a single block worth of bytes; qed"),
511 )
512 }
513}
514
515#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
517#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
518#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
519#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
520#[repr(u8)]
521#[non_exhaustive]
522pub enum BlockHeaderSealType {
523 #[cfg_attr(feature = "scale-codec", codec(index = 0))]
525 Ed25519 = 0,
526}
527
528impl BlockHeaderSealType {
529 #[inline(always)]
531 pub const fn try_from_byte(byte: u8) -> Option<Self> {
532 if byte == Self::Ed25519 as u8 {
533 Some(Self::Ed25519)
534 } else {
535 None
536 }
537 }
538}
539
540#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
542#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
543#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
544#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
545#[repr(C)]
546pub struct BlockHeaderEd25519Seal {
547 pub public_key: Ed25519PublicKey,
549 pub signature: Ed25519Signature,
551}
552
553#[derive(Debug, Copy, Clone)]
555#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
556#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
557#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
558#[non_exhaustive]
559pub enum OwnedBlockHeaderSeal {
560 Ed25519(BlockHeaderEd25519Seal),
562}
563
564impl OwnedBlockHeaderSeal {
565 #[inline(always)]
567 pub fn as_ref(&self) -> BlockHeaderSeal<'_> {
568 match self {
569 Self::Ed25519(seal) => BlockHeaderSeal::Ed25519(seal),
570 }
571 }
572}
573
574#[derive(Debug, Copy, Clone)]
576#[non_exhaustive]
577pub enum BlockHeaderSeal<'a> {
578 Ed25519(&'a BlockHeaderEd25519Seal),
580}
581
582impl<'a> BlockHeaderSeal<'a> {
583 pub const MAX_SIZE: u32 = 1 + BlockHeaderEd25519Seal::SIZE;
585 #[inline]
591 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
592 let seal_type = bytes.split_off(..size_of::<u8>())?;
597 let seal_type = BlockHeaderSealType::try_from_byte(seal_type[0])?;
598
599 match seal_type {
600 BlockHeaderSealType::Ed25519 => {
601 let (seal, bytes) = BlockHeaderEd25519Seal::from_bytes(bytes)?;
602 Some((Self::Ed25519(seal), bytes))
603 }
604 }
605 }
606
607 #[cfg(feature = "ed25519")]
609 #[inline]
610 pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
611 match self {
612 BlockHeaderSeal::Ed25519(seal) => seal
613 .public_key
614 .verify(&seal.signature, pre_seal_hash.as_bytes())
615 .is_ok(),
616 }
617 }
618
619 #[inline]
621 pub fn public_key_hash(&self) -> Blake3Hash {
622 match self {
623 BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
624 }
625 }
626
627 #[inline]
629 pub fn hash(&self) -> Blake3Hash {
630 match self {
631 BlockHeaderSeal::Ed25519(seal) => {
632 let mut hasher = blake3::Hasher::new();
633 hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
634 hasher.update(seal.as_bytes());
635
636 Blake3Hash::from(hasher.finalize())
637 }
638 }
639 }
640}
641
642#[derive(Debug, Copy, Clone, Eq, PartialEq, thiserror::Error)]
648pub enum BlockHeaderConsistencyError {
649 #[error("Prefix padding is not all zeroes")]
651 NonZeroPrefixPadding,
652 #[error("Shard index {shard_index} is not a valid {shard_kind:?} shard index")]
654 InvalidShardIndex {
655 shard_index: ShardIndex,
657 shard_kind: RealShardKind,
659 },
660 #[error("Solution padding is not all zeroes")]
662 NonZeroSolutionPadding,
663 #[error(
665 "Seal public key hash {seal_public_key_hash} doesn't match solution public key hash \
666 {solution_public_key_hash}"
667 )]
668 SealPublicKeyHashMismatch {
669 solution_public_key_hash: Blake3Hash,
671 seal_public_key_hash: Blake3Hash,
673 },
674}
675
676#[derive(Debug, Copy, Clone)]
678pub struct SharedBlockHeader<'a> {
679 pub prefix: &'a BlockHeaderPrefix,
681 pub result: &'a BlockHeaderResult,
683 pub consensus_info: &'a BlockHeaderConsensusInfo,
685 pub seal: BlockHeaderSeal<'a>,
687}
688
689#[derive(Debug, Clone, Yokeable)]
691#[non_exhaustive]
693pub struct BeaconChainHeader<'a> {
694 shared: SharedBlockHeader<'a>,
696 intermediate_shard_blocks_root: &'a Blake3Hash,
698 consensus_parameters: BlockHeaderConsensusParameters<'a>,
700 pre_seal_bytes: &'a [u8],
702 #[cfg(feature = "alloc")]
704 bytes: &'a [u8],
705 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
706 cached_block_root: once_cell::race::OnceBox<BlockRoot>,
707 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
708 cached_block_root: std::sync::OnceLock<BlockRoot>,
709}
710
711impl<'a> Deref for BeaconChainHeader<'a> {
712 type Target = SharedBlockHeader<'a>;
713
714 #[inline(always)]
715 fn deref(&self) -> &Self::Target {
716 &self.shared
717 }
718}
719
720impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
721 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
722
723 #[cfg(feature = "alloc")]
724 type Owned = OwnedBeaconChainHeader;
725
726 #[cfg(feature = "alloc")]
727 #[inline(always)]
728 fn to_owned(self) -> Self::Owned {
729 self.to_owned()
730 }
731
732 #[inline(always)]
733 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
734 self.root()
735 }
736
737 #[inline(always)]
738 fn pre_seal_hash(&self) -> Blake3Hash {
739 self.pre_seal_hash()
740 }
741}
742
743impl<'a> BeaconChainHeader<'a> {
744 #[inline]
751 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
752 let (prefix, consensus_info, result, remainder) =
761 BlockHeader::try_from_bytes_shared(bytes, RealShardKind::BeaconChain)?;
762
763 let (intermediate_shard_blocks_root, remainder) = Blake3Hash::from_bytes(remainder)?;
764
765 let (consensus_parameters, remainder) =
766 BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
767
768 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
769
770 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
771 BlockHeader::check_seal(&consensus_info.solution.public_key_hash, seal).ok()?;
772
773 let shared = SharedBlockHeader {
774 prefix,
775 result,
776 consensus_info,
777 seal,
778 };
779
780 let header = Self {
781 shared,
782 intermediate_shard_blocks_root,
783 consensus_parameters,
784 pre_seal_bytes,
785 #[cfg(feature = "alloc")]
786 bytes: &bytes[..bytes.len() - remainder.len()],
787 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
788 cached_block_root: once_cell::race::OnceBox::new(),
789 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
790 cached_block_root: std::sync::OnceLock::new(),
791 };
792
793 Some((header, remainder))
794 }
795
796 #[cfg(feature = "alloc")]
798 #[inline(always)]
799 pub fn to_owned(self) -> OwnedBeaconChainHeader {
800 let buffer = SharedAlignedBuffer::from_bytes(self.bytes);
801 OwnedBeaconChainHeader::from_buffer(buffer).expect(
802 "The same bytes were already parsed with all checks, which only depend on the address \
803 being 8-byte aligned, and owned buffers are 16-byte aligned and hold headers, which \
804 are far smaller than `u32::MAX` bytes; qed",
805 )
806 }
807
808 #[inline(always)]
810 pub fn shared(&self) -> &SharedBlockHeader<'a> {
811 &self.shared
812 }
813
814 #[inline(always)]
819 pub fn intermediate_shard_blocks_root(&self) -> &'a Blake3Hash {
820 self.intermediate_shard_blocks_root
821 }
822
823 #[inline(always)]
825 pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
826 &self.consensus_parameters
827 }
828
829 #[inline]
831 pub fn pre_seal_hash(&self) -> Blake3Hash {
832 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
834 }
835
836 #[cfg(feature = "ed25519")]
839 #[inline]
840 pub fn is_sealed_correctly(&self) -> bool {
841 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
842 && self.seal.is_seal_valid(&self.pre_seal_hash())
843 }
844
845 #[inline]
853 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
854 let Self {
855 shared,
856 intermediate_shard_blocks_root,
857 consensus_parameters,
858 pre_seal_bytes: _,
859 #[cfg(feature = "alloc")]
860 bytes: _,
861 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
862 cached_block_root,
863 } = self;
864
865 let compute_root = || {
866 let SharedBlockHeader {
867 prefix,
868 result,
869 consensus_info,
870 seal,
871 } = shared;
872
873 let block_root = BeaconChainHeaderMerkleTree::compute_root_only_array(&[
874 prefix.hash(),
875 result.hash(),
876 consensus_info.hash(),
877 seal.hash(),
878 **intermediate_shard_blocks_root,
879 consensus_parameters.hash(),
880 ]);
881
882 BlockRoot::new(Blake3Hash::new(block_root))
883 };
884
885 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
886 {
887 cached_block_root.get_or_init(compute_root)
888 }
889 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
890 {
891 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
892 }
893 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
894 {
895 struct Wrapper(BlockRoot);
896
897 impl Deref for Wrapper {
898 type Target = BlockRoot;
899
900 #[inline(always)]
901 fn deref(&self) -> &Self::Target {
902 &self.0
903 }
904 }
905
906 Wrapper(compute_root())
907 }
908 }
909}
910
911#[derive(Debug, Clone, Yokeable)]
913#[non_exhaustive]
915pub struct IntermediateShardHeader<'a> {
916 shared: SharedBlockHeader<'a>,
918 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
920 leaf_shard_blocks_root: &'a Blake3Hash,
922 pre_seal_bytes: &'a [u8],
924 #[cfg(feature = "alloc")]
926 bytes: &'a [u8],
927 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
928 cached_block_root: once_cell::race::OnceBox<BlockRoot>,
929 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
930 cached_block_root: std::sync::OnceLock<BlockRoot>,
931}
932
933impl<'a> Deref for IntermediateShardHeader<'a> {
934 type Target = SharedBlockHeader<'a>;
935
936 #[inline(always)]
937 fn deref(&self) -> &Self::Target {
938 &self.shared
939 }
940}
941
942impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
943 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
944
945 #[cfg(feature = "alloc")]
946 type Owned = OwnedIntermediateShardHeader;
947
948 #[cfg(feature = "alloc")]
949 #[inline(always)]
950 fn to_owned(self) -> Self::Owned {
951 self.to_owned()
952 }
953
954 #[inline(always)]
955 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
956 self.root()
957 }
958
959 #[inline(always)]
960 fn pre_seal_hash(&self) -> Blake3Hash {
961 self.pre_seal_hash()
962 }
963}
964
965impl<'a> IntermediateShardHeader<'a> {
966 #[inline]
973 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
974 let (prefix, consensus_info, result, remainder) =
983 BlockHeader::try_from_bytes_shared(bytes, RealShardKind::IntermediateShard)?;
984
985 let (beacon_chain_info, remainder) = BlockHeaderBeaconChainInfo::from_bytes(remainder)?;
986
987 let (leaf_shard_blocks_root, remainder) = Blake3Hash::from_bytes(remainder)?;
988
989 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
990
991 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
992 BlockHeader::check_seal(&consensus_info.solution.public_key_hash, seal).ok()?;
993
994 let shared = SharedBlockHeader {
995 prefix,
996 result,
997 consensus_info,
998 seal,
999 };
1000
1001 let header = Self {
1002 shared,
1003 beacon_chain_info,
1004 leaf_shard_blocks_root,
1005 pre_seal_bytes,
1006 #[cfg(feature = "alloc")]
1007 bytes: &bytes[..bytes.len() - remainder.len()],
1008 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1009 cached_block_root: once_cell::race::OnceBox::new(),
1010 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1011 cached_block_root: std::sync::OnceLock::new(),
1012 };
1013
1014 Some((header, remainder))
1015 }
1016
1017 #[cfg(feature = "alloc")]
1019 #[inline(always)]
1020 pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1021 let buffer = SharedAlignedBuffer::from_bytes(self.bytes);
1022 OwnedIntermediateShardHeader::from_buffer(buffer).expect(
1023 "The same bytes were already parsed with all checks, which only depend on the address \
1024 being 8-byte aligned, and owned buffers are 16-byte aligned and hold headers, which \
1025 are far smaller than `u32::MAX` bytes; qed",
1026 )
1027 }
1028
1029 #[inline(always)]
1031 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1032 &self.shared
1033 }
1034
1035 #[inline(always)]
1037 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1038 self.beacon_chain_info
1039 }
1040
1041 #[inline(always)]
1047 pub fn leaf_shard_blocks_root(&self) -> &'a Blake3Hash {
1048 self.leaf_shard_blocks_root
1049 }
1050
1051 #[inline]
1053 pub fn pre_seal_hash(&self) -> Blake3Hash {
1054 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1056 }
1057
1058 #[cfg(feature = "ed25519")]
1061 #[inline]
1062 pub fn is_sealed_correctly(&self) -> bool {
1063 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1064 && self.seal.is_seal_valid(&self.pre_seal_hash())
1065 }
1066
1067 #[inline]
1075 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1076 let Self {
1077 shared,
1078 beacon_chain_info,
1079 leaf_shard_blocks_root,
1080 pre_seal_bytes: _,
1081 #[cfg(feature = "alloc")]
1082 bytes: _,
1083 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1084 cached_block_root,
1085 } = self;
1086
1087 let compute_root = || {
1088 let SharedBlockHeader {
1089 prefix,
1090 result,
1091 consensus_info,
1092 seal,
1093 } = shared;
1094
1095 let block_root = IntermediateShardHeaderMerkleTree::compute_root_only_array(&[
1096 prefix.hash(),
1097 result.hash(),
1098 consensus_info.hash(),
1099 seal.hash(),
1100 beacon_chain_info.hash(),
1101 **leaf_shard_blocks_root,
1102 ]);
1103
1104 BlockRoot::new(Blake3Hash::new(block_root))
1105 };
1106
1107 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1108 {
1109 cached_block_root.get_or_init(compute_root)
1110 }
1111 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1112 {
1113 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1114 }
1115 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1116 {
1117 struct Wrapper(BlockRoot);
1118
1119 impl Deref for Wrapper {
1120 type Target = BlockRoot;
1121
1122 #[inline(always)]
1123 fn deref(&self) -> &Self::Target {
1124 &self.0
1125 }
1126 }
1127
1128 Wrapper(compute_root())
1129 }
1130 }
1131}
1132
1133#[derive(Debug, Clone, Yokeable)]
1135#[non_exhaustive]
1137pub struct LeafShardHeader<'a> {
1138 shared: SharedBlockHeader<'a>,
1140 beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1142 pre_seal_bytes: &'a [u8],
1144 #[cfg(feature = "alloc")]
1146 bytes: &'a [u8],
1147 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1148 cached_block_root: once_cell::race::OnceBox<BlockRoot>,
1149 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1150 cached_block_root: std::sync::OnceLock<BlockRoot>,
1151}
1152
1153impl<'a> Deref for LeafShardHeader<'a> {
1154 type Target = SharedBlockHeader<'a>;
1155
1156 #[inline(always)]
1157 fn deref(&self) -> &Self::Target {
1158 &self.shared
1159 }
1160}
1161
1162impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1163 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1164
1165 #[cfg(feature = "alloc")]
1166 type Owned = OwnedLeafShardHeader;
1167
1168 #[cfg(feature = "alloc")]
1169 #[inline(always)]
1170 fn to_owned(self) -> Self::Owned {
1171 self.to_owned()
1172 }
1173
1174 #[inline(always)]
1175 fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1176 self.root()
1177 }
1178
1179 #[inline(always)]
1180 fn pre_seal_hash(&self) -> Blake3Hash {
1181 self.pre_seal_hash()
1182 }
1183}
1184
1185impl<'a> LeafShardHeader<'a> {
1186 #[inline]
1193 pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1194 let (prefix, consensus_info, result, remainder) =
1202 BlockHeader::try_from_bytes_shared(bytes, RealShardKind::LeafShard)?;
1203
1204 let (beacon_chain_info, remainder) = BlockHeaderBeaconChainInfo::from_bytes(remainder)?;
1205
1206 let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1207
1208 let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1209 BlockHeader::check_seal(&consensus_info.solution.public_key_hash, seal).ok()?;
1210
1211 let shared = SharedBlockHeader {
1212 prefix,
1213 result,
1214 consensus_info,
1215 seal,
1216 };
1217
1218 let header = Self {
1219 shared,
1220 beacon_chain_info,
1221 pre_seal_bytes,
1222 #[cfg(feature = "alloc")]
1223 bytes: &bytes[..bytes.len() - remainder.len()],
1224 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1225 cached_block_root: once_cell::race::OnceBox::new(),
1226 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1227 cached_block_root: std::sync::OnceLock::new(),
1228 };
1229
1230 Some((header, remainder))
1231 }
1232
1233 #[cfg(feature = "alloc")]
1235 #[inline(always)]
1236 pub fn to_owned(self) -> OwnedLeafShardHeader {
1237 let buffer = SharedAlignedBuffer::from_bytes(self.bytes);
1238 OwnedLeafShardHeader::from_buffer(buffer).expect(
1239 "The same bytes were already parsed with all checks, which only depend on the address \
1240 being 8-byte aligned, and owned buffers are 16-byte aligned and hold headers, which \
1241 are far smaller than `u32::MAX` bytes; qed",
1242 )
1243 }
1244
1245 #[inline(always)]
1247 pub fn shared(&self) -> &SharedBlockHeader<'a> {
1248 &self.shared
1249 }
1250
1251 #[inline(always)]
1253 pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1254 self.beacon_chain_info
1255 }
1256
1257 #[inline]
1259 pub fn pre_seal_hash(&self) -> Blake3Hash {
1260 Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1262 }
1263
1264 #[cfg(feature = "ed25519")]
1267 #[inline]
1268 pub fn is_sealed_correctly(&self) -> bool {
1269 self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1270 && self.seal.is_seal_valid(&self.pre_seal_hash())
1271 }
1272
1273 #[inline]
1281 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1282 let Self {
1283 shared,
1284 beacon_chain_info,
1285 pre_seal_bytes: _,
1286 #[cfg(feature = "alloc")]
1287 bytes: _,
1288 #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1289 cached_block_root,
1290 } = self;
1291
1292 let compute_root = || {
1293 let SharedBlockHeader {
1294 prefix,
1295 result,
1296 consensus_info,
1297 seal,
1298 } = shared;
1299
1300 let block_root = LeafShardHeaderMerkleTree::compute_root_only_array(&[
1301 prefix.hash(),
1302 result.hash(),
1303 consensus_info.hash(),
1304 seal.hash(),
1305 beacon_chain_info.hash(),
1306 ]);
1307
1308 BlockRoot::new(Blake3Hash::new(block_root))
1309 };
1310
1311 #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1312 {
1313 cached_block_root.get_or_init(compute_root)
1314 }
1315 #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1316 {
1317 cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1318 }
1319 #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1320 {
1321 struct Wrapper(BlockRoot);
1322
1323 impl Deref for Wrapper {
1324 type Target = BlockRoot;
1325
1326 #[inline(always)]
1327 fn deref(&self) -> &Self::Target {
1328 &self.0
1329 }
1330 }
1331
1332 Wrapper(compute_root())
1333 }
1334 }
1335}
1336
1337#[derive(Debug, Clone, From)]
1342pub enum BlockHeader<'a> {
1343 BeaconChain(BeaconChainHeader<'a>),
1345 IntermediateShard(IntermediateShardHeader<'a>),
1347 LeafShard(LeafShardHeader<'a>),
1349}
1350
1351impl<'a> Deref for BlockHeader<'a> {
1352 type Target = SharedBlockHeader<'a>;
1353
1354 #[inline(always)]
1355 fn deref(&self) -> &Self::Target {
1356 match self {
1357 Self::BeaconChain(header) => header,
1358 Self::IntermediateShard(header) => header,
1359 Self::LeafShard(header) => header,
1360 }
1361 }
1362}
1363
1364impl<'a> BlockHeader<'a> {
1365 #[inline]
1372 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1373 match shard_kind {
1374 RealShardKind::BeaconChain => {
1375 let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1376 Some((Self::BeaconChain(header), remainder))
1377 }
1378 RealShardKind::IntermediateShard => {
1379 let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1380 Some((Self::IntermediateShard(header), remainder))
1381 }
1382 RealShardKind::LeafShard => {
1383 let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1384 Some((Self::LeafShard(header), remainder))
1385 }
1386 }
1387 }
1388
1389 #[inline]
1390 fn try_from_bytes_shared(
1391 mut bytes: &'a [u8],
1392 shard_kind: RealShardKind,
1393 ) -> Option<(
1394 &'a BlockHeaderPrefix,
1395 &'a BlockHeaderConsensusInfo,
1396 &'a BlockHeaderResult,
1397 &'a [u8],
1398 )> {
1399 let prefix;
1400 (prefix, bytes) = BlockHeaderPrefix::from_bytes(bytes)?;
1401
1402 let result;
1403 (result, bytes) = BlockHeaderResult::from_bytes(bytes)?;
1404
1405 let consensus_info;
1406 (consensus_info, bytes) = BlockHeaderConsensusInfo::from_bytes(bytes)?;
1407
1408 Self::check_shared_parts(prefix, consensus_info, shard_kind).ok()?;
1409
1410 Some((prefix, consensus_info, result, bytes))
1411 }
1412
1413 #[inline]
1417 fn check_shared_parts(
1418 prefix: &BlockHeaderPrefix,
1419 consensus_info: &BlockHeaderConsensusInfo,
1420 shard_kind: RealShardKind,
1421 ) -> Result<(), BlockHeaderConsistencyError> {
1422 if prefix.padding_0 != [0; _] {
1423 return Err(BlockHeaderConsistencyError::NonZeroPrefixPadding);
1424 }
1425
1426 if prefix.shard_index.shard_kind() != Some(ShardKind::from(shard_kind)) {
1428 return Err(BlockHeaderConsistencyError::InvalidShardIndex {
1429 shard_index: prefix.shard_index,
1430 shard_kind,
1431 });
1432 }
1433
1434 if consensus_info.solution.padding != [0; _] {
1435 return Err(BlockHeaderConsistencyError::NonZeroSolutionPadding);
1436 }
1437
1438 Ok(())
1439 }
1440
1441 #[inline]
1445 fn check_seal(
1446 solution_public_key_hash: &Blake3Hash,
1447 seal: BlockHeaderSeal<'_>,
1448 ) -> Result<(), BlockHeaderConsistencyError> {
1449 let seal_public_key_hash = seal.public_key_hash();
1450
1451 if seal_public_key_hash != *solution_public_key_hash {
1452 return Err(BlockHeaderConsistencyError::SealPublicKeyHashMismatch {
1453 solution_public_key_hash: *solution_public_key_hash,
1454 seal_public_key_hash,
1455 });
1456 }
1457
1458 Ok(())
1459 }
1460
1461 #[cfg(feature = "alloc")]
1463 #[inline(always)]
1464 pub fn to_owned(self) -> OwnedBlockHeader {
1465 match self {
1466 Self::BeaconChain(header) => header.to_owned().into(),
1467 Self::IntermediateShard(header) => header.to_owned().into(),
1468 Self::LeafShard(header) => header.to_owned().into(),
1469 }
1470 }
1471
1472 #[inline]
1474 pub fn pre_seal_hash(&self) -> Blake3Hash {
1475 match self {
1476 Self::BeaconChain(header) => header.pre_seal_hash(),
1477 Self::IntermediateShard(header) => header.pre_seal_hash(),
1478 Self::LeafShard(header) => header.pre_seal_hash(),
1479 }
1480 }
1481
1482 #[cfg(feature = "ed25519")]
1485 #[inline]
1486 pub fn is_sealed_correctly(&self) -> bool {
1487 match self {
1488 Self::BeaconChain(header) => header.is_sealed_correctly(),
1489 Self::IntermediateShard(header) => header.is_sealed_correctly(),
1490 Self::LeafShard(header) => header.is_sealed_correctly(),
1491 }
1492 }
1493
1494 #[inline]
1502 pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1503 enum Wrapper<B, I, L> {
1504 BeaconChain(B),
1505 IntermediateShard(I),
1506 LeafShard(L),
1507 }
1508
1509 impl<B, I, L> Deref for Wrapper<B, I, L>
1510 where
1511 B: Deref<Target = BlockRoot>,
1512 I: Deref<Target = BlockRoot>,
1513 L: Deref<Target = BlockRoot>,
1514 {
1515 type Target = BlockRoot;
1516
1517 #[inline(always)]
1518 fn deref(&self) -> &Self::Target {
1519 match self {
1520 Wrapper::BeaconChain(block_root) => block_root,
1521 Wrapper::IntermediateShard(block_root) => block_root,
1522 Wrapper::LeafShard(block_root) => block_root,
1523 }
1524 }
1525 }
1526
1527 match self {
1528 Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1529 Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1530 Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1531 }
1532 }
1533}