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