Skip to main content

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