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