ab_core_primitives/block/
header.rs

1//! Block header primitives
2
3#[cfg(feature = "alloc")]
4pub mod owned;
5
6#[cfg(feature = "alloc")]
7use crate::block::header::owned::{
8    GenericOwnedBlockHeader, OwnedBeaconChainHeader, OwnedBlockHeader,
9    OwnedIntermediateShardHeader, OwnedLeafShardHeader,
10};
11use crate::block::{BlockNumber, BlockRoot, BlockTimestamp};
12use crate::ed25519::{Ed25519PublicKey, Ed25519Signature};
13use crate::hashes::Blake3Hash;
14use crate::pot::{PotOutput, PotParametersChange, SlotNumber};
15use crate::segments::SuperSegmentRoot;
16use crate::shard::{ShardIndex, ShardKind};
17use crate::solutions::{Solution, SolutionRange};
18use ab_io_type::trivial_type::TrivialType;
19use ab_merkle_tree::unbalanced::UnbalancedMerkleTree;
20use core::num::NonZeroU32;
21use core::ops::Deref;
22use core::{fmt, slice};
23use derive_more::{Deref, From};
24#[cfg(feature = "scale-codec")]
25use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
26#[cfg(feature = "scale-codec")]
27use scale_info::TypeInfo;
28#[cfg(feature = "serde")]
29use serde::{Deserialize, Serialize};
30use yoke::Yokeable;
31
32/// Generic block header
33pub 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    /// Shard kind
43    const SHARD_KIND: ShardKind;
44
45    /// Owned block header
46    #[cfg(feature = "alloc")]
47    type Owned: GenericOwnedBlockHeader<Header<'a> = Self>
48    where
49        Self: 'a;
50
51    /// Turn into owned version
52    #[cfg(feature = "alloc")]
53    fn to_owned(self) -> Self::Owned;
54
55    /// Compute block root out of this header.
56    ///
57    /// Block root is a Merkle Tree Root. The leaves are derived from individual fields in
58    /// [`SharedBlockHeader`] and other fields of this enum in the declaration order.
59    ///
60    /// Note that this method does a bunch of hashing and if hash is needed often, should be cached.
61    fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync;
62}
63
64/// Block header prefix.
65///
66/// The prefix contains generic information known about the block before block creation starts.
67#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
68#[cfg_attr(
69    feature = "scale-codec",
70    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
71)]
72#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
73#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
74#[repr(C)]
75pub struct BlockHeaderPrefix {
76    /// Block number
77    pub number: BlockNumber,
78    /// Shard index
79    pub shard_index: ShardIndex,
80    /// Padding for data structure alignment, contents must be all zeroes
81    pub padding_0: [u8; 4],
82    /// Block timestamp
83    pub timestamp: BlockTimestamp,
84    /// Root of the parent block
85    pub parent_root: BlockRoot,
86    /// MMR root of all block roots, including `parent_root`
87    // TODO: New type?
88    pub mmr_root: Blake3Hash,
89}
90
91impl BlockHeaderPrefix {
92    /// Hash of the block header prefix, part of the eventual block root
93    pub fn hash(&self) -> Blake3Hash {
94        // TODO: Keyed hash
95        Blake3Hash::from(blake3::hash(self.as_bytes()))
96    }
97}
98
99/// Consensus information in the block header
100#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
101#[cfg_attr(
102    feature = "scale-codec",
103    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
104)]
105#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
106#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
107#[repr(C)]
108pub struct BlockHeaderConsensusInfo {
109    /// Slot number
110    pub slot: SlotNumber,
111    /// Proof of time for this slot
112    pub proof_of_time: PotOutput,
113    /// Future proof of time
114    pub future_proof_of_time: PotOutput,
115    /// Solution
116    pub solution: Solution,
117}
118
119impl BlockHeaderConsensusInfo {
120    /// Hash of the consensus info, part of the eventual block root
121    pub fn hash(&self) -> Blake3Hash {
122        // TODO: Keyed hash
123        Blake3Hash::from(blake3::hash(self.as_bytes()))
124    }
125}
126
127/// Beacon chain info
128#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, TrivialType)]
129#[cfg_attr(
130    feature = "scale-codec",
131    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
132)]
133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
135#[repr(C)]
136pub struct BlockHeaderBeaconChainInfo {
137    /// Beacon chain block number
138    pub number: BlockNumber,
139    /// Beacon chain block root
140    pub root: BlockRoot,
141}
142
143impl BlockHeaderBeaconChainInfo {
144    /// Hash of the beacon chain info, part of the eventual block root
145    pub fn hash(&self) -> Blake3Hash {
146        // TODO: Keyed hash
147        Blake3Hash::from(blake3::hash(self.as_bytes()))
148    }
149}
150
151/// Consensus parameters (on the beacon chain)
152#[derive(Debug, Copy, Clone, Eq, PartialEq)]
153#[cfg_attr(
154    feature = "scale-codec",
155    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
156)]
157#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
158#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
159pub struct BlockHeaderFixedConsensusParameters {
160    /// Solution range for this block/era
161    pub solution_range: SolutionRange,
162    /// The number of iterations for proof of time per slot.
163    ///
164    /// Corresponds to the slot that is right after the parent block's slot.
165    /// It can change before the slot of this block (see [`PotParametersChange`]).
166    pub slot_iterations: NonZeroU32,
167}
168
169impl BlockHeaderFixedConsensusParameters {
170    /// Create an instance from provided bytes.
171    ///
172    /// `bytes` do not need to be aligned.
173    ///
174    /// Returns an instance and remaining bytes on success.
175    #[inline]
176    pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(Self, &[u8])> {
177        // Layout here is as follows:
178        // * solution range: SolutionRange as unaligned bytes
179        // * PoT slot iterations: NonZeroU32 as unaligned little-endian bytes
180
181        let solution_range = bytes.split_off(..size_of::<SolutionRange>())?;
182        let solution_range = SolutionRange::from_bytes([
183            solution_range[0],
184            solution_range[1],
185            solution_range[2],
186            solution_range[3],
187            solution_range[4],
188            solution_range[5],
189            solution_range[6],
190            solution_range[7],
191        ]);
192
193        let pot_slot_iterations = bytes.split_off(..size_of::<u32>())?;
194        let slot_iterations = u32::from_le_bytes([
195            pot_slot_iterations[0],
196            pot_slot_iterations[1],
197            pot_slot_iterations[2],
198            pot_slot_iterations[3],
199        ]);
200        let slot_iterations = NonZeroU32::new(slot_iterations)?;
201
202        Some((
203            Self {
204                solution_range,
205                slot_iterations,
206            },
207            bytes,
208        ))
209    }
210}
211
212/// A mirror of [`PotParametersChange`] for block header purposes.
213///
214/// Use [`From`] or [`Into`] for converting into [`PotParametersChange`] before use.
215#[derive(Debug, Copy, Clone, Eq, PartialEq)]
216#[repr(C, packed)]
217pub struct BlockHeaderPotParametersChange {
218    // TODO: Reduce this to `u16` or even `u8` since it is always an offset relatively to current
219    //  block's slot number
220    /// At which slot change of parameters takes effect
221    slot: SlotNumber,
222    /// New number of slot iterations
223    slot_iterations: NonZeroU32,
224    /// Entropy that should be injected at this time
225    entropy: Blake3Hash,
226}
227
228impl From<BlockHeaderPotParametersChange> for PotParametersChange {
229    #[inline(always)]
230    fn from(value: BlockHeaderPotParametersChange) -> Self {
231        let BlockHeaderPotParametersChange {
232            slot,
233            slot_iterations,
234            entropy,
235        } = value;
236
237        PotParametersChange {
238            slot,
239            slot_iterations,
240            entropy,
241        }
242    }
243}
244
245impl From<PotParametersChange> for BlockHeaderPotParametersChange {
246    #[inline(always)]
247    fn from(value: PotParametersChange) -> Self {
248        let PotParametersChange {
249            slot,
250            slot_iterations,
251            entropy,
252        } = value;
253
254        BlockHeaderPotParametersChange {
255            slot,
256            slot_iterations,
257            entropy,
258        }
259    }
260}
261
262impl BlockHeaderPotParametersChange {
263    /// Get instance reference from provided bytes.
264    ///
265    /// `bytes` do not need to be aligned.
266    ///
267    /// Returns an instance and remaining bytes on success.
268    #[inline]
269    pub fn try_from_bytes(mut bytes: &[u8]) -> Option<(&Self, &[u8])> {
270        // Layout here is as follows:
271        // * slot number: SlotNumber as unaligned bytes
272        // * slot iterations: NonZeroU32 as unaligned little-endian bytes
273        // * entropy: Blake3Hash
274
275        let _slot = bytes.split_off(..size_of::<SlotNumber>())?;
276
277        let slot_iterations = bytes.split_off(..size_of::<u32>())?;
278        if slot_iterations == [0, 0, 0, 0] {
279            return None;
280        }
281        let _entropy = bytes.split_off(..size_of::<Blake3Hash>())?;
282
283        // SAFETY: Not null, packed, bit pattern for `NonZeroU32` checked above
284        let pot_parameters_change = unsafe { bytes.as_ptr().cast::<Self>().as_ref_unchecked() };
285
286        Some((pot_parameters_change, bytes))
287    }
288}
289
290/// Owned version of [`BlockHeaderConsensusParameters`]
291#[derive(Debug, Copy, Clone)]
292pub struct OwnedBlockHeaderConsensusParameters {
293    /// Consensus parameters that are always present
294    pub fixed_parameters: BlockHeaderFixedConsensusParameters,
295    /// Super segment root
296    pub super_segment_root: Option<SuperSegmentRoot>,
297    /// Solution range for the next block/era (if any)
298    pub next_solution_range: Option<SolutionRange>,
299    /// Change of parameters to apply to the proof of time chain (if any)
300    pub pot_parameters_change: Option<BlockHeaderPotParametersChange>,
301}
302
303impl OwnedBlockHeaderConsensusParameters {
304    /// Get a reference out of owned version
305    #[inline]
306    pub fn as_ref(&self) -> BlockHeaderConsensusParameters<'_> {
307        BlockHeaderConsensusParameters {
308            fixed_parameters: self.fixed_parameters,
309            super_segment_root: self.super_segment_root.as_ref(),
310            next_solution_range: self.next_solution_range,
311            pot_parameters_change: self.pot_parameters_change.as_ref(),
312        }
313    }
314}
315
316/// Consensus parameters (on the beacon chain)
317#[derive(Debug, Copy, Clone, Eq, PartialEq)]
318pub struct BlockHeaderConsensusParameters<'a> {
319    /// Consensus parameters that are always present
320    pub fixed_parameters: BlockHeaderFixedConsensusParameters,
321    /// Super segment root
322    pub super_segment_root: Option<&'a SuperSegmentRoot>,
323    /// Solution range for the next block/era (if any)
324    pub next_solution_range: Option<SolutionRange>,
325    /// Change of parameters to apply to the proof of time chain (if any)
326    pub pot_parameters_change: Option<&'a BlockHeaderPotParametersChange>,
327}
328
329impl<'a> BlockHeaderConsensusParameters<'a> {
330    /// Max size of the allocation necessary for this data structure
331    pub const MAX_SIZE: u32 = size_of::<BlockHeaderFixedConsensusParameters>() as u32
332        + u8::SIZE
333        + <SuperSegmentRoot as TrivialType>::SIZE
334        + <SolutionRange as TrivialType>::SIZE
335        + size_of::<BlockHeaderPotParametersChange>() as u32;
336    /// Bitmask for presence of `super_segment_root` field
337    pub const SUPER_SEGMENT_ROOT_MASK: u8 = 0b_0000_0001;
338    /// Bitmask for presence of `next_solution_range` field
339    pub const NEXT_SOLUTION_RANGE_MASK: u8 = 0b_0000_0010;
340    /// Bitmask for presence of `pot_parameters_change` field
341    pub const POT_PARAMETERS_CHANGE_MASK: u8 = 0b_0000_0100;
342
343    /// Create an instance from provided bytes.
344    ///
345    /// `bytes` do not need to be aligned.
346    ///
347    /// Returns an instance and remaining bytes on success.
348    #[inline]
349    pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
350        // Layout here is as follows:
351        // * fixed parameters: BlockHeaderFixedConsensusParameters
352        // * bitflags: u8
353        // * (optional, depends on bitflags) super segment root: SuperSegmentRoot
354        // * (optional, depends on bitflags) next solution range: SolutionRange as unaligned bytes
355        // * (optional, depends on bitflags) PoT parameters change: BlockHeaderPotParametersChange
356
357        let (fixed_parameters, mut remainder) =
358            BlockHeaderFixedConsensusParameters::try_from_bytes(bytes)?;
359
360        let bitflags = remainder.split_off(..size_of::<u8>())?;
361        let bitflags = bitflags[0];
362
363        let super_segment_root = if bitflags & Self::SUPER_SEGMENT_ROOT_MASK != 0 {
364            let super_segment_root = remainder.split_off(..size_of::<SuperSegmentRoot>())?;
365            // SAFETY: All bit patterns are valid
366            let super_segment_root = unsafe { SuperSegmentRoot::from_bytes(super_segment_root) }?;
367
368            Some(super_segment_root)
369        } else {
370            None
371        };
372
373        let next_solution_range = if bitflags & Self::NEXT_SOLUTION_RANGE_MASK != 0 {
374            let next_solution_range = remainder.split_off(..size_of::<SolutionRange>())?;
375            // Not guaranteed to be aligned
376            let next_solution_range = SolutionRange::from_bytes([
377                next_solution_range[0],
378                next_solution_range[1],
379                next_solution_range[2],
380                next_solution_range[3],
381                next_solution_range[4],
382                next_solution_range[5],
383                next_solution_range[6],
384                next_solution_range[7],
385            ]);
386
387            Some(next_solution_range)
388        } else {
389            None
390        };
391
392        let pot_parameters_change = if bitflags & Self::POT_PARAMETERS_CHANGE_MASK != 0 {
393            let pot_parameters_change;
394            (pot_parameters_change, remainder) =
395                BlockHeaderPotParametersChange::try_from_bytes(remainder)?;
396
397            Some(pot_parameters_change)
398        } else {
399            None
400        };
401
402        Some((
403            Self {
404                super_segment_root,
405                fixed_parameters,
406                next_solution_range,
407                pot_parameters_change,
408            },
409            remainder,
410        ))
411    }
412
413    /// Hash of the block consensus parameters, part of the eventual block root
414    pub fn hash(&self) -> Blake3Hash {
415        let Self {
416            super_segment_root,
417            fixed_parameters,
418            next_solution_range,
419            pot_parameters_change,
420        } = self;
421        let BlockHeaderFixedConsensusParameters {
422            solution_range,
423            slot_iterations,
424        } = fixed_parameters;
425
426        // TODO: Keyed hash
427        let mut hasher = blake3::Hasher::new();
428        hasher.update(solution_range.as_bytes());
429        hasher.update(&slot_iterations.get().to_le_bytes());
430
431        if let Some(super_segment_root) = super_segment_root {
432            hasher.update(super_segment_root.as_bytes());
433        }
434        if let Some(next_solution_range) = next_solution_range {
435            hasher.update(next_solution_range.as_bytes());
436        }
437        if let Some(pot_parameters_change) = pot_parameters_change.copied() {
438            let BlockHeaderPotParametersChange {
439                slot,
440                slot_iterations,
441                entropy,
442            } = pot_parameters_change;
443            hasher.update(slot.as_bytes());
444            hasher.update(&slot_iterations.get().to_le_bytes());
445            hasher.update(entropy.as_bytes());
446        }
447
448        Blake3Hash::from(hasher.finalize())
449    }
450}
451
452/// Information about child shard blocks
453#[derive(Debug, Copy, Clone, Deref)]
454pub struct BlockHeaderChildShardBlocks<'a> {
455    /// Child shards blocks
456    pub child_shard_blocks: &'a [BlockRoot],
457}
458
459impl<'a> BlockHeaderChildShardBlocks<'a> {
460    /// Create an instance from provided correctly aligned bytes.
461    ///
462    /// `bytes` should be 2-bytes aligned.
463    ///
464    /// Returns an instance and remaining bytes on success.
465    #[inline]
466    pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
467        // Layout here is as follows:
468        // * number of blocks: u16 as aligned little-endian bytes
469        // * for each block:
470        //   * child shard block: BlockHash
471
472        let length = bytes.split_off(..size_of::<u16>())?;
473        // SAFETY: All bit patterns are valid
474        let num_blocks = usize::from(*unsafe { <u16 as TrivialType>::from_bytes(length) }?);
475
476        let padding = bytes.split_off(..size_of::<[u8; 2]>())?;
477
478        // Padding must be zero
479        if padding != [0, 0] {
480            return None;
481        }
482
483        let child_shard_blocks = bytes.split_off(..num_blocks * BlockRoot::SIZE)?;
484        // SAFETY: Valid pointer and size, no alignment requirements
485        let child_shard_blocks = unsafe {
486            slice::from_raw_parts(
487                child_shard_blocks.as_ptr().cast::<[u8; BlockRoot::SIZE]>(),
488                num_blocks,
489            )
490        };
491        let child_shard_blocks = BlockRoot::slice_from_repr(child_shard_blocks);
492
493        Some((Self { child_shard_blocks }, bytes))
494    }
495
496    /// Compute Merkle Tree with child shard blocks, part of the eventual block root.
497    ///
498    /// `None` is returned if there are no child shard blocks.
499    pub fn root(&self) -> Option<Blake3Hash> {
500        let root = UnbalancedMerkleTree::compute_root_only::<'_, { u32::MAX as u64 }, _, _>(
501            // TODO: Keyed hash
502            self.child_shard_blocks
503                .iter()
504                .map(|child_shard_block_root| {
505                    // Hash the root again so we can prove it, otherwise headers root is
506                    // indistinguishable from individual block roots and can be used to confuse
507                    // verifier
508
509                    blake3::hash(child_shard_block_root.as_ref())
510                }),
511        )?;
512        Some(Blake3Hash::new(root))
513    }
514}
515
516/// Block header result.
517///
518/// The result contains information that can only be computed after the block was created.
519#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
520#[cfg_attr(
521    feature = "scale-codec",
522    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
523)]
524#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
525#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
526#[repr(C)]
527pub struct BlockHeaderResult {
528    /// Root of the block body
529    // TODO: New type
530    pub body_root: Blake3Hash,
531    /// Root of the state tree
532    // TODO: New type?
533    pub state_root: Blake3Hash,
534}
535
536impl BlockHeaderResult {
537    /// Hash of the block header result, part of the eventual block root
538    pub fn hash(&self) -> Blake3Hash {
539        // TODO: Keyed hash
540        Blake3Hash::from(blake3::hash(self.as_bytes()))
541    }
542}
543
544/// Block header seal type
545#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
546#[cfg_attr(
547    feature = "scale-codec",
548    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
549)]
550#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
551#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
552#[repr(u8)]
553#[non_exhaustive]
554pub enum BlockHeaderSealType {
555    /// Ed25519 signature
556    #[cfg_attr(feature = "scale-codec", codec(index = 0))]
557    Ed25519 = 0,
558}
559
560impl BlockHeaderSealType {
561    /// Create an instance from bytes if valid
562    #[inline(always)]
563    pub const fn try_from_byte(byte: u8) -> Option<Self> {
564        if byte == Self::Ed25519 as u8 {
565            Some(Self::Ed25519)
566        } else {
567            None
568        }
569    }
570}
571
572/// Ed25519 seal
573#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
574#[cfg_attr(
575    feature = "scale-codec",
576    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
577)]
578#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
579#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
580#[repr(C)]
581pub struct BlockHeaderEd25519Seal {
582    /// Ed25519 public key
583    pub public_key: Ed25519PublicKey,
584    /// Ed25519 signature
585    pub signature: Ed25519Signature,
586}
587
588/// Owned version of [`BlockHeaderSeal`]
589#[derive(Debug, Copy, Clone)]
590#[cfg_attr(
591    feature = "scale-codec",
592    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
593)]
594#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
595#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
596#[non_exhaustive]
597pub enum OwnedBlockHeaderSeal {
598    /// Ed25519 seal
599    Ed25519(BlockHeaderEd25519Seal),
600}
601
602impl OwnedBlockHeaderSeal {
603    /// Get a reference out of owned version
604    #[inline(always)]
605    pub fn as_ref(&self) -> BlockHeaderSeal<'_> {
606        match self {
607            Self::Ed25519(seal) => BlockHeaderSeal::Ed25519(seal),
608        }
609    }
610}
611
612/// Block header seal
613#[derive(Debug, Copy, Clone)]
614#[non_exhaustive]
615pub enum BlockHeaderSeal<'a> {
616    /// Ed25519 seal
617    Ed25519(&'a BlockHeaderEd25519Seal),
618}
619
620impl<'a> BlockHeaderSeal<'a> {
621    /// Max size of the allocation necessary for this data structure
622    pub const MAX_SIZE: u32 = 1 + BlockHeaderEd25519Seal::SIZE;
623    /// Create an instance from provided bytes.
624    ///
625    /// `bytes` do not need to be aligned.
626    ///
627    /// Returns an instance and remaining bytes on success.
628    #[inline]
629    pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
630        // The layout here is as follows:
631        // * seal type: u8
632        // * seal (depends on a seal type): BlockHeaderEd25519Seal
633
634        let seal_type = bytes.split_off(..size_of::<u8>())?;
635        let seal_type = BlockHeaderSealType::try_from_byte(seal_type[0])?;
636
637        match seal_type {
638            BlockHeaderSealType::Ed25519 => {
639                let seal = bytes.split_off(..size_of::<BlockHeaderEd25519Seal>())?;
640                // SAFETY: All bit patterns are valid
641                let seal = unsafe { BlockHeaderEd25519Seal::from_bytes(seal) }?;
642                Some((Self::Ed25519(seal), bytes))
643            }
644        }
645    }
646
647    /// Verify seal against [`BlockHeader::pre_seal_hash()`]
648    #[inline]
649    pub fn is_seal_valid(&self, pre_seal_hash: &Blake3Hash) -> bool {
650        match self {
651            BlockHeaderSeal::Ed25519(seal) => seal
652                .public_key
653                .verify(&seal.signature, pre_seal_hash.as_bytes())
654                .is_ok(),
655        }
656    }
657
658    /// Derive public key hash from this seal
659    #[inline]
660    pub fn public_key_hash(&self) -> Blake3Hash {
661        match self {
662            BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
663        }
664    }
665
666    /// Hash of the block header seal, part of the eventual block root
667    #[inline]
668    pub fn hash(&self) -> Blake3Hash {
669        match self {
670            BlockHeaderSeal::Ed25519(seal) => {
671                // TODO: Keyed hash
672                let mut hasher = blake3::Hasher::new();
673                hasher.update(&[BlockHeaderSealType::Ed25519 as u8]);
674                hasher.update(seal.as_bytes());
675
676                Blake3Hash::from(hasher.finalize())
677            }
678        }
679    }
680}
681
682/// Part of the block header, shared for different kinds of shards
683#[derive(Debug, Copy, Clone)]
684pub struct SharedBlockHeader<'a> {
685    /// Block header prefix
686    pub prefix: &'a BlockHeaderPrefix,
687    /// Block header result
688    pub result: &'a BlockHeaderResult,
689    /// Consensus information
690    pub consensus_info: &'a BlockHeaderConsensusInfo,
691    /// Block header seal
692    pub seal: BlockHeaderSeal<'a>,
693}
694
695/// Block header that corresponds to the beacon chain
696#[derive(Debug, Clone, Yokeable)]
697// Prevent creation of potentially broken invariants externally
698#[non_exhaustive]
699pub struct BeaconChainHeader<'a> {
700    /// Shared block header
701    shared: SharedBlockHeader<'a>,
702    /// Information about child shard blocks
703    child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
704    /// Consensus parameters (on the beacon chain)
705    consensus_parameters: BlockHeaderConsensusParameters<'a>,
706    /// All bytes of the header except the seal
707    pre_seal_bytes: &'a [u8],
708    #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
709    cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
710    #[cfg(not(any(target_os = "none", target_os = "unknown")))]
711    cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
712}
713
714impl<'a> Deref for BeaconChainHeader<'a> {
715    type Target = SharedBlockHeader<'a>;
716
717    #[inline(always)]
718    fn deref(&self) -> &Self::Target {
719        &self.shared
720    }
721}
722
723impl<'a> GenericBlockHeader<'a> for BeaconChainHeader<'a> {
724    const SHARD_KIND: ShardKind = ShardKind::BeaconChain;
725
726    #[cfg(feature = "alloc")]
727    type Owned = OwnedBeaconChainHeader;
728
729    #[cfg(feature = "alloc")]
730    #[inline(always)]
731    fn to_owned(self) -> Self::Owned {
732        self.to_owned()
733    }
734
735    #[inline(always)]
736    fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
737        self.root()
738    }
739}
740
741impl<'a> BeaconChainHeader<'a> {
742    /// Try to create a new instance from provided bytes.
743    ///
744    /// `bytes` should be 8-bytes aligned.
745    ///
746    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
747    /// bytes are not properly aligned or input is otherwise invalid.
748    #[inline]
749    pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
750        // The layout here is as follows:
751        // * block header prefix: BlockHeaderPrefix
752        // * block header result: BlockHeaderResult
753        // * consensus info: BlockHeaderConsensusInfo
754        // * child shard blocks: BlockHeaderChildShardBlocks
755        // * beacon chain parameters: BlockHeaderBeaconChainParameters
756        // * block header seal: BlockHeaderSeal
757
758        let (prefix, consensus_info, result, remainder) =
759            BlockHeader::try_from_bytes_shared(bytes)?;
760
761        if prefix.shard_index.shard_kind() != ShardKind::BeaconChain {
762            return None;
763        }
764
765        let (child_shard_blocks, remainder) =
766            BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
767
768        let (consensus_parameters, remainder) =
769            BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
770
771        let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
772
773        let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
774
775        let shared = SharedBlockHeader {
776            prefix,
777            result,
778            consensus_info,
779            seal,
780        };
781
782        let header = Self {
783            shared,
784            child_shard_blocks,
785            consensus_parameters,
786            pre_seal_bytes,
787            #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
788            cached_block_root: rclite::Arc::default(),
789        };
790
791        if !header.is_internally_consistent() {
792            return None;
793        }
794
795        Some((header, remainder))
796    }
797
798    /// Check block header's internal consistency.
799    ///
800    /// This is usually not necessary to be called explicitly since internal consistency is checked
801    /// by [`Self::try_from_bytes()`] internally.
802    #[inline]
803    pub fn is_internally_consistent(&self) -> bool {
804        let public_key_hash = match self.seal {
805            BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
806        };
807        public_key_hash == self.shared.consensus_info.solution.public_key_hash
808    }
809
810    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
811    /// checks
812    #[inline]
813    pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
814        // The layout here is as follows:
815        // * block header prefix: BlockHeaderPrefix
816        // * block header result: BlockHeaderResult
817        // * consensus info: BlockHeaderConsensusInfo
818        // * child shard blocks: BlockHeaderChildShardBlocks
819        // * beacon chain parameters: BlockHeaderBeaconChainParameters
820        // * block header seal: BlockHeaderSeal
821
822        let (prefix, consensus_info, result, remainder) =
823            BlockHeader::try_from_bytes_shared(bytes)?;
824
825        if prefix.shard_index.shard_kind() != ShardKind::BeaconChain {
826            return None;
827        }
828
829        let (child_shard_blocks, remainder) =
830            BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
831
832        let (consensus_parameters, remainder) =
833            BlockHeaderConsensusParameters::try_from_bytes(remainder)?;
834
835        let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
836
837        let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
838
839        let shared = SharedBlockHeader {
840            prefix,
841            result,
842            consensus_info,
843            seal,
844        };
845
846        Some((
847            Self {
848                shared,
849                child_shard_blocks,
850                consensus_parameters,
851                pre_seal_bytes,
852                #[cfg(any(
853                    feature = "alloc",
854                    not(any(target_os = "none", target_os = "unknown"))
855                ))]
856                cached_block_root: rclite::Arc::default(),
857            },
858            remainder,
859        ))
860    }
861
862    /// Create an owned version of this header
863    #[cfg(feature = "alloc")]
864    #[inline(always)]
865    pub fn to_owned(self) -> OwnedBeaconChainHeader {
866        let unsealed = OwnedBeaconChainHeader::from_parts(
867            self.shared.prefix,
868            self.shared.result,
869            self.shared.consensus_info,
870            &self.child_shard_blocks,
871            self.consensus_parameters,
872        )
873        .expect("`self` is always a valid invariant; qed");
874
875        unsealed.with_seal(self.shared.seal)
876    }
877
878    /// Shared block header
879    #[inline(always)]
880    pub fn shared(&self) -> &SharedBlockHeader<'a> {
881        &self.shared
882    }
883
884    /// Information about child shard blocks
885    #[inline(always)]
886    pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
887        &self.child_shard_blocks
888    }
889
890    /// Consensus parameters (on the beacon chain)
891    #[inline(always)]
892    pub fn consensus_parameters(&self) -> &BlockHeaderConsensusParameters<'a> {
893        &self.consensus_parameters
894    }
895
896    /// Hash of the block before seal is applied to it
897    #[inline]
898    pub fn pre_seal_hash(&self) -> Blake3Hash {
899        // TODO: Keyed hash with `block_header_seal` as a key
900        Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
901    }
902
903    /// Verify seal against [`BeaconChainHeader::pre_seal_hash()`] and check that its public key
904    /// hash corresponds to the solution
905    #[inline]
906    pub fn is_sealed_correctly(&self) -> bool {
907        self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
908            && self.seal.is_seal_valid(&self.pre_seal_hash())
909    }
910
911    /// Compute block root out of this header.
912    ///
913    /// Block root is a Merkle Tree Root. The leaves are derived from individual fields in
914    /// [`SharedBlockHeader`] and other fields of this enum in the declaration order.
915    ///
916    /// Note that this method computes root by doing a bunch of hashing. The result is then cached
917    /// if `alloc` feature is enabled or when compiled for OS target that is not `none`.
918    #[inline]
919    pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
920        let Self {
921            shared,
922            child_shard_blocks,
923            consensus_parameters,
924            pre_seal_bytes: _,
925            #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
926            cached_block_root,
927        } = self;
928
929        let compute_root = || {
930            let SharedBlockHeader {
931                prefix,
932                result,
933                consensus_info,
934                seal,
935            } = shared;
936
937            const MAX_N: usize = 6;
938            let leaves: [_; MAX_N] = [
939                prefix.hash(),
940                result.hash(),
941                consensus_info.hash(),
942                seal.hash(),
943                child_shard_blocks.root().unwrap_or_default(),
944                consensus_parameters.hash(),
945            ];
946            let block_root =
947                UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
948                    .expect("The list is not empty; qed");
949
950            BlockRoot::new(Blake3Hash::new(block_root))
951        };
952
953        #[cfg(not(any(target_os = "none", target_os = "unknown")))]
954        {
955            cached_block_root.get_or_init(compute_root)
956        }
957        #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
958        {
959            cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
960        }
961        #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
962        {
963            struct Wrapper(BlockRoot);
964
965            impl Deref for Wrapper {
966                type Target = BlockRoot;
967
968                #[inline(always)]
969                fn deref(&self) -> &Self::Target {
970                    &self.0
971                }
972            }
973
974            Wrapper(compute_root())
975        }
976    }
977}
978
979/// Block header that corresponds to an intermediate shard
980#[derive(Debug, Clone, Yokeable)]
981// Prevent creation of potentially broken invariants externally
982#[non_exhaustive]
983pub struct IntermediateShardHeader<'a> {
984    /// Shared block header
985    shared: SharedBlockHeader<'a>,
986    /// Beacon chain info
987    beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
988    /// Information about child shard blocks
989    child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
990    /// All bytes of the header except the seal
991    pre_seal_bytes: &'a [u8],
992    #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
993    cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
994    #[cfg(not(any(target_os = "none", target_os = "unknown")))]
995    cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
996}
997
998impl<'a> Deref for IntermediateShardHeader<'a> {
999    type Target = SharedBlockHeader<'a>;
1000
1001    #[inline(always)]
1002    fn deref(&self) -> &Self::Target {
1003        &self.shared
1004    }
1005}
1006
1007impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
1008    const SHARD_KIND: ShardKind = ShardKind::IntermediateShard;
1009
1010    #[cfg(feature = "alloc")]
1011    type Owned = OwnedIntermediateShardHeader;
1012
1013    #[cfg(feature = "alloc")]
1014    #[inline(always)]
1015    fn to_owned(self) -> Self::Owned {
1016        self.to_owned()
1017    }
1018
1019    #[inline(always)]
1020    fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1021        self.root()
1022    }
1023}
1024
1025impl<'a> IntermediateShardHeader<'a> {
1026    /// Try to create a new instance from provided bytes.
1027    ///
1028    /// `bytes` should be 8-bytes aligned.
1029    ///
1030    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
1031    /// bytes are not properly aligned or input is otherwise invalid.
1032    #[inline]
1033    pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1034        // The layout here is as follows:
1035        // * block header prefix: BlockHeaderPrefix
1036        // * block header result: BlockHeaderResult
1037        // * consensus info: BlockHeaderConsensusInfo
1038        // * beacon chain: BlockHeaderBeaconChainInfo
1039        // * child shard blocks: BlockHeaderBeaconChainInfo
1040        // * block header seal: BlockHeaderSeal
1041
1042        let (prefix, consensus_info, result, mut remainder) =
1043            BlockHeader::try_from_bytes_shared(bytes)?;
1044
1045        if prefix.shard_index.shard_kind() != ShardKind::IntermediateShard {
1046            return None;
1047        }
1048
1049        let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1050        // SAFETY: All bit patterns are valid
1051        let beacon_chain_info =
1052            unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1053
1054        let (child_shard_blocks, remainder) =
1055            BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1056
1057        let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1058
1059        let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1060
1061        let shared = SharedBlockHeader {
1062            prefix,
1063            result,
1064            consensus_info,
1065            seal,
1066        };
1067
1068        let header = Self {
1069            shared,
1070            beacon_chain_info,
1071            child_shard_blocks,
1072            pre_seal_bytes,
1073            #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1074            cached_block_root: rclite::Arc::default(),
1075        };
1076
1077        if !header.is_internally_consistent() {
1078            return None;
1079        }
1080
1081        Some((header, remainder))
1082    }
1083
1084    /// Check block header's internal consistency.
1085    ///
1086    /// This is usually not necessary to be called explicitly since internal consistency is checked
1087    /// by [`Self::try_from_bytes()`] internally.
1088    #[inline]
1089    pub fn is_internally_consistent(&self) -> bool {
1090        let public_key_hash = match self.seal {
1091            BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1092        };
1093        public_key_hash == self.shared.consensus_info.solution.public_key_hash
1094    }
1095
1096    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
1097    /// checks
1098    #[inline]
1099    pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1100        // The layout here is as follows:
1101        // * block header prefix: BlockHeaderPrefix
1102        // * block header result: BlockHeaderResult
1103        // * consensus info: BlockHeaderConsensusInfo
1104        // * beacon chain: BlockHeaderBeaconChainInfo
1105        // * child shard blocks: BlockHeaderBeaconChainInfo
1106        // * block header seal: BlockHeaderSeal
1107
1108        let (prefix, consensus_info, result, mut remainder) =
1109            BlockHeader::try_from_bytes_shared(bytes)?;
1110
1111        if prefix.shard_index.shard_kind() != ShardKind::IntermediateShard {
1112            return None;
1113        }
1114
1115        let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1116        // SAFETY: All bit patterns are valid
1117        let beacon_chain_info =
1118            unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1119
1120        let (child_shard_blocks, remainder) =
1121            BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1122
1123        let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1124
1125        let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1126
1127        let shared = SharedBlockHeader {
1128            prefix,
1129            result,
1130            consensus_info,
1131            seal,
1132        };
1133
1134        Some((
1135            Self {
1136                shared,
1137                beacon_chain_info,
1138                child_shard_blocks,
1139                pre_seal_bytes,
1140                #[cfg(any(
1141                    feature = "alloc",
1142                    not(any(target_os = "none", target_os = "unknown"))
1143                ))]
1144                cached_block_root: rclite::Arc::default(),
1145            },
1146            remainder,
1147        ))
1148    }
1149
1150    /// Create an owned version of this header
1151    #[cfg(feature = "alloc")]
1152    #[inline(always)]
1153    pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1154        let unsealed = OwnedIntermediateShardHeader::from_parts(
1155            self.shared.prefix,
1156            self.shared.result,
1157            self.shared.consensus_info,
1158            self.beacon_chain_info,
1159            &self.child_shard_blocks,
1160        )
1161        .expect("`self` is always a valid invariant; qed");
1162
1163        unsealed.with_seal(self.shared.seal)
1164    }
1165
1166    /// Shared block header
1167    #[inline(always)]
1168    pub fn shared(&self) -> &SharedBlockHeader<'a> {
1169        &self.shared
1170    }
1171
1172    /// Beacon chain info
1173    #[inline(always)]
1174    pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1175        self.beacon_chain_info
1176    }
1177
1178    /// Information about child shard blocks
1179    #[inline(always)]
1180    pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1181        &self.child_shard_blocks
1182    }
1183
1184    /// Hash of the block before seal is applied to it
1185    #[inline]
1186    pub fn pre_seal_hash(&self) -> Blake3Hash {
1187        // TODO: Keyed hash with `block_header_seal` as a key
1188        Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1189    }
1190
1191    /// Verify seal against [`IntermediateShardHeader::pre_seal_hash()`] and check that its public
1192    /// key hash corresponds to the solution
1193    #[inline]
1194    pub fn is_sealed_correctly(&self) -> bool {
1195        self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1196            && self.seal.is_seal_valid(&self.pre_seal_hash())
1197    }
1198
1199    /// Compute block root out of this header.
1200    ///
1201    /// Block root is a Merkle Tree Root. The leaves are derived from individual fields in
1202    /// [`SharedBlockHeader`] and other fields of this enum in the declaration order.
1203    ///
1204    /// Note that this method computes root by doing a bunch of hashing. The result is then cached
1205    /// if `alloc` feature is enabled or when compiled for OS target that is not `none`.
1206    #[inline]
1207    pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1208        let Self {
1209            shared,
1210            beacon_chain_info,
1211            child_shard_blocks,
1212            pre_seal_bytes: _,
1213            #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1214            cached_block_root,
1215        } = self;
1216
1217        let compute_root = || {
1218            let SharedBlockHeader {
1219                prefix,
1220                result,
1221                consensus_info,
1222                seal,
1223            } = shared;
1224
1225            const MAX_N: usize = 6;
1226            let leaves: [_; MAX_N] = [
1227                prefix.hash(),
1228                result.hash(),
1229                consensus_info.hash(),
1230                seal.hash(),
1231                beacon_chain_info.hash(),
1232                child_shard_blocks.root().unwrap_or_default(),
1233            ];
1234            let block_root =
1235                UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1236                    .expect("The list is not empty; qed");
1237
1238            BlockRoot::new(Blake3Hash::new(block_root))
1239        };
1240
1241        #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1242        {
1243            cached_block_root.get_or_init(compute_root)
1244        }
1245        #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1246        {
1247            cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1248        }
1249        #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1250        {
1251            struct Wrapper(BlockRoot);
1252
1253            impl Deref for Wrapper {
1254                type Target = BlockRoot;
1255
1256                #[inline(always)]
1257                fn deref(&self) -> &Self::Target {
1258                    &self.0
1259                }
1260            }
1261
1262            Wrapper(compute_root())
1263        }
1264    }
1265}
1266
1267/// Block header that corresponds to a leaf shard
1268#[derive(Debug, Clone, Yokeable)]
1269// Prevent creation of potentially broken invariants externally
1270#[non_exhaustive]
1271pub struct LeafShardHeader<'a> {
1272    /// Shared block header
1273    shared: SharedBlockHeader<'a>,
1274    /// Beacon chain info
1275    beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1276    /// All bytes of the header except the seal
1277    pre_seal_bytes: &'a [u8],
1278    #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1279    cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1280    #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1281    cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1282}
1283
1284impl<'a> Deref for LeafShardHeader<'a> {
1285    type Target = SharedBlockHeader<'a>;
1286
1287    #[inline(always)]
1288    fn deref(&self) -> &Self::Target {
1289        &self.shared
1290    }
1291}
1292
1293impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1294    const SHARD_KIND: ShardKind = ShardKind::LeafShard;
1295
1296    #[cfg(feature = "alloc")]
1297    type Owned = OwnedLeafShardHeader;
1298
1299    #[cfg(feature = "alloc")]
1300    #[inline(always)]
1301    fn to_owned(self) -> Self::Owned {
1302        self.to_owned()
1303    }
1304
1305    #[inline(always)]
1306    fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1307        self.root()
1308    }
1309}
1310
1311impl<'a> LeafShardHeader<'a> {
1312    /// Try to create a new instance from provided bytes.
1313    ///
1314    /// `bytes` should be 8-bytes aligned.
1315    ///
1316    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
1317    /// bytes are not properly aligned or input is otherwise invalid.
1318    #[inline]
1319    pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1320        // The layout here is as follows:
1321        // * block header result: BlockHeaderResult
1322        // * block header prefix: BlockHeaderPrefix
1323        // * consensus info: BlockHeaderConsensusInfo
1324        // * beacon chain: BlockHeaderBeaconChainInfo
1325        // * block header seal: BlockHeaderSeal
1326
1327        let (prefix, consensus_info, result, mut remainder) =
1328            BlockHeader::try_from_bytes_shared(bytes)?;
1329
1330        if prefix.shard_index.shard_kind() != ShardKind::LeafShard {
1331            return None;
1332        }
1333
1334        let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1335        // SAFETY: All bit patterns are valid
1336        let beacon_chain_info =
1337            unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1338
1339        let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1340
1341        let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1342
1343        let shared = SharedBlockHeader {
1344            prefix,
1345            result,
1346            consensus_info,
1347            seal,
1348        };
1349
1350        let header = Self {
1351            shared,
1352            beacon_chain_info,
1353            pre_seal_bytes,
1354            #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1355            cached_block_root: rclite::Arc::default(),
1356        };
1357
1358        if !header.is_internally_consistent() {
1359            return None;
1360        }
1361
1362        Some((header, remainder))
1363    }
1364
1365    /// Check block header's internal consistency.
1366    ///
1367    /// This is usually not necessary to be called explicitly since internal consistency is checked
1368    /// by [`Self::try_from_bytes()`] internally.
1369    #[inline]
1370    pub fn is_internally_consistent(&self) -> bool {
1371        let public_key_hash = match self.seal {
1372            BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1373        };
1374        public_key_hash == self.shared.consensus_info.solution.public_key_hash
1375    }
1376
1377    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
1378    /// checks
1379    #[inline]
1380    pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1381        // The layout here is as follows:
1382        // * block header result: BlockHeaderResult
1383        // * block header prefix: BlockHeaderPrefix
1384        // * consensus info: BlockHeaderConsensusInfo
1385        // * beacon chain: BlockHeaderBeaconChainInfo
1386        // * block header seal: BlockHeaderSeal
1387
1388        let (prefix, consensus_info, result, mut remainder) =
1389            BlockHeader::try_from_bytes_shared(bytes)?;
1390
1391        if prefix.shard_index.shard_kind() != ShardKind::LeafShard {
1392            return None;
1393        }
1394
1395        let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1396        // SAFETY: All bit patterns are valid
1397        let beacon_chain_info =
1398            unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1399
1400        let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1401
1402        let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1403
1404        let shared = SharedBlockHeader {
1405            prefix,
1406            result,
1407            consensus_info,
1408            seal,
1409        };
1410
1411        Some((
1412            Self {
1413                shared,
1414                beacon_chain_info,
1415                pre_seal_bytes,
1416                #[cfg(any(
1417                    feature = "alloc",
1418                    not(any(target_os = "none", target_os = "unknown"))
1419                ))]
1420                cached_block_root: rclite::Arc::default(),
1421            },
1422            remainder,
1423        ))
1424    }
1425
1426    /// Create an owned version of this header
1427    #[cfg(feature = "alloc")]
1428    #[inline(always)]
1429    pub fn to_owned(self) -> OwnedLeafShardHeader {
1430        let unsealed = OwnedLeafShardHeader::from_parts(
1431            self.shared.prefix,
1432            self.shared.result,
1433            self.shared.consensus_info,
1434            self.beacon_chain_info,
1435        );
1436
1437        unsealed.with_seal(self.shared.seal)
1438    }
1439
1440    /// Shared block header
1441    #[inline(always)]
1442    pub fn shared(&self) -> &SharedBlockHeader<'a> {
1443        &self.shared
1444    }
1445
1446    /// Beacon chain info
1447    #[inline(always)]
1448    pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1449        self.beacon_chain_info
1450    }
1451
1452    /// Hash of the block before seal is applied to it
1453    #[inline]
1454    pub fn pre_seal_hash(&self) -> Blake3Hash {
1455        // TODO: Keyed hash with `block_header_seal` as a key
1456        Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1457    }
1458
1459    /// Verify seal against [`LeafShardHeader::pre_seal_hash()`] and check that its public key hash
1460    /// corresponds to the solution
1461    #[inline]
1462    pub fn is_sealed_correctly(&self) -> bool {
1463        self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1464            && self.seal.is_seal_valid(&self.pre_seal_hash())
1465    }
1466
1467    /// Compute block root out of this header.
1468    ///
1469    /// Block root is a Merkle Tree Root. The leaves are derived from individual fields in
1470    /// [`SharedBlockHeader`] and other fields of this enum in the declaration order.
1471    ///
1472    /// Note that this method computes root by doing a bunch of hashing. The result is then cached
1473    /// if `alloc` feature is enabled or when compiled for OS target that is not `none`.
1474    #[inline]
1475    pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1476        let Self {
1477            shared,
1478            beacon_chain_info,
1479            pre_seal_bytes: _,
1480            #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1481            cached_block_root,
1482        } = self;
1483
1484        let compute_root = || {
1485            let SharedBlockHeader {
1486                prefix,
1487                result,
1488                consensus_info,
1489                seal,
1490            } = shared;
1491
1492            const MAX_N: usize = 5;
1493            let leaves: [_; MAX_N] = [
1494                prefix.hash(),
1495                result.hash(),
1496                consensus_info.hash(),
1497                seal.hash(),
1498                beacon_chain_info.hash(),
1499            ];
1500            let block_root =
1501                UnbalancedMerkleTree::compute_root_only::<{ MAX_N as u64 }, _, _>(leaves)
1502                    .expect("The list is not empty; qed");
1503
1504            BlockRoot::new(Blake3Hash::new(block_root))
1505        };
1506
1507        #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1508        {
1509            cached_block_root.get_or_init(compute_root)
1510        }
1511        #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1512        {
1513            cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1514        }
1515        #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1516        {
1517            struct Wrapper(BlockRoot);
1518
1519            impl Deref for Wrapper {
1520                type Target = BlockRoot;
1521
1522                #[inline(always)]
1523                fn deref(&self) -> &Self::Target {
1524                    &self.0
1525                }
1526            }
1527
1528            Wrapper(compute_root())
1529        }
1530    }
1531}
1532
1533/// Block header that together with [`BlockBody`] form a [`Block`]
1534///
1535/// [`BlockBody`]: crate::block::body::BlockBody
1536/// [`Block`]: crate::block::Block
1537#[derive(Debug, Clone, From)]
1538pub enum BlockHeader<'a> {
1539    /// Block header corresponds to the beacon chain
1540    BeaconChain(BeaconChainHeader<'a>),
1541    /// Block header corresponds to an intermediate shard
1542    IntermediateShard(IntermediateShardHeader<'a>),
1543    /// Block header corresponds to a leaf shard
1544    LeafShard(LeafShardHeader<'a>),
1545}
1546
1547impl<'a> Deref for BlockHeader<'a> {
1548    type Target = SharedBlockHeader<'a>;
1549
1550    #[inline(always)]
1551    fn deref(&self) -> &Self::Target {
1552        match self {
1553            Self::BeaconChain(header) => header,
1554            Self::IntermediateShard(header) => header,
1555            Self::LeafShard(header) => header,
1556        }
1557    }
1558}
1559
1560impl<'a> BlockHeader<'a> {
1561    /// Try to create a new instance from provided bytes for provided shard index.
1562    ///
1563    /// `bytes` should be 8-bytes aligned.
1564    ///
1565    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
1566    /// bytes are not properly aligned or input is otherwise invalid.
1567    #[inline]
1568    pub fn try_from_bytes(bytes: &'a [u8], shard_kind: ShardKind) -> Option<(Self, &'a [u8])> {
1569        match shard_kind {
1570            ShardKind::BeaconChain => {
1571                let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1572                Some((Self::BeaconChain(header), remainder))
1573            }
1574            ShardKind::IntermediateShard => {
1575                let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1576                Some((Self::IntermediateShard(header), remainder))
1577            }
1578            ShardKind::LeafShard => {
1579                let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1580                Some((Self::LeafShard(header), remainder))
1581            }
1582            ShardKind::Phantom | ShardKind::Invalid => {
1583                // Blocks for such shards do not exist
1584                None
1585            }
1586        }
1587    }
1588
1589    /// Check block header's internal consistency.
1590    ///
1591    /// This is usually not necessary to be called explicitly since internal consistency is checked
1592    /// by [`Self::try_from_bytes()`] internally.
1593    #[inline]
1594    pub fn is_internally_consistent(&self) -> bool {
1595        match self {
1596            Self::BeaconChain(header) => header.is_internally_consistent(),
1597            Self::IntermediateShard(header) => header.is_internally_consistent(),
1598            Self::LeafShard(header) => header.is_internally_consistent(),
1599        }
1600    }
1601
1602    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
1603    /// checks
1604    #[inline]
1605    pub fn try_from_bytes_unchecked(
1606        bytes: &'a [u8],
1607        shard_kind: ShardKind,
1608    ) -> Option<(Self, &'a [u8])> {
1609        match shard_kind {
1610            ShardKind::BeaconChain => {
1611                let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1612                Some((Self::BeaconChain(header), remainder))
1613            }
1614            ShardKind::IntermediateShard => {
1615                let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1616                Some((Self::IntermediateShard(header), remainder))
1617            }
1618            ShardKind::LeafShard => {
1619                let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1620                Some((Self::LeafShard(header), remainder))
1621            }
1622            ShardKind::Phantom | ShardKind::Invalid => {
1623                // Blocks for such shards do not exist
1624                None
1625            }
1626        }
1627    }
1628
1629    #[inline]
1630    fn try_from_bytes_shared(
1631        mut bytes: &'a [u8],
1632    ) -> Option<(
1633        &'a BlockHeaderPrefix,
1634        &'a BlockHeaderConsensusInfo,
1635        &'a BlockHeaderResult,
1636        &'a [u8],
1637    )> {
1638        let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1639        // SAFETY: All bit patterns are valid
1640        let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1641
1642        if !(prefix.padding_0 == [0; _]
1643            && prefix.shard_index.as_u32() <= ShardIndex::MAX_SHARD_INDEX)
1644        {
1645            return None;
1646        }
1647
1648        let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1649        // SAFETY: All bit patterns are valid
1650        let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1651
1652        let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1653        // SAFETY: All bit patterns are valid
1654        let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1655
1656        if consensus_info.solution.padding != [0; _] {
1657            return None;
1658        }
1659
1660        Some((prefix, consensus_info, result, bytes))
1661    }
1662
1663    /// Create an owned version of this header
1664    #[cfg(feature = "alloc")]
1665    #[inline(always)]
1666    pub fn to_owned(self) -> OwnedBlockHeader {
1667        match self {
1668            Self::BeaconChain(header) => header.to_owned().into(),
1669            Self::IntermediateShard(header) => header.to_owned().into(),
1670            Self::LeafShard(header) => header.to_owned().into(),
1671        }
1672    }
1673
1674    /// Hash of the block before seal is applied to it
1675    #[inline]
1676    pub fn pre_seal_hash(&self) -> Blake3Hash {
1677        match self {
1678            Self::BeaconChain(header) => header.pre_seal_hash(),
1679            Self::IntermediateShard(header) => header.pre_seal_hash(),
1680            Self::LeafShard(header) => header.pre_seal_hash(),
1681        }
1682    }
1683
1684    /// Verify seal against [`BlockHeader::pre_seal_hash()`] and check that its public key hash
1685    /// corresponds to the solution
1686    #[inline]
1687    pub fn is_sealed_correctly(&self) -> bool {
1688        match self {
1689            Self::BeaconChain(header) => header.is_sealed_correctly(),
1690            Self::IntermediateShard(header) => header.is_sealed_correctly(),
1691            Self::LeafShard(header) => header.is_sealed_correctly(),
1692        }
1693    }
1694
1695    /// Compute block root out of this header.
1696    ///
1697    /// Block root is a Merkle Tree Root. The leaves are derived from individual fields in
1698    /// [`SharedBlockHeader`] and other fields of this enum in the declaration order.
1699    ///
1700    /// Note that this method computes root by doing a bunch of hashing. The result is then cached
1701    /// if `alloc` feature is enabled.
1702    #[inline]
1703    pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1704        enum Wrapper<B, I, L> {
1705            BeaconChain(B),
1706            IntermediateShard(I),
1707            LeafShard(L),
1708        }
1709
1710        impl<B, I, L> Deref for Wrapper<B, I, L>
1711        where
1712            B: Deref<Target = BlockRoot>,
1713            I: Deref<Target = BlockRoot>,
1714            L: Deref<Target = BlockRoot>,
1715        {
1716            type Target = BlockRoot;
1717
1718            #[inline(always)]
1719            fn deref(&self) -> &Self::Target {
1720                match self {
1721                    Wrapper::BeaconChain(block_root) => block_root,
1722                    Wrapper::IntermediateShard(block_root) => block_root,
1723                    Wrapper::LeafShard(block_root) => block_root,
1724                }
1725            }
1726        }
1727
1728        // TODO: Should unique keyed hash be used for different kinds of shards?
1729        match self {
1730            Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1731            Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1732            Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1733        }
1734    }
1735}