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 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 = 0b_0000_0001;
357    /// Bitmask for presence of `next_solution_range` field
358    pub const NEXT_SOLUTION_RANGE_MASK: u8 = 0b_0000_0010;
359    /// Bitmask for presence of `pot_parameters_change` field
360    pub const POT_PARAMETERS_CHANGE_MASK: u8 = 0b_0000_0100;
361    /// All supported bitmask variants
362    pub const MASK_ALL: u8 = Self::SUPER_SEGMENT_ROOT_MASK
363        | Self::NEXT_SOLUTION_RANGE_MASK
364        | Self::POT_PARAMETERS_CHANGE_MASK;
365
366    /// Create an instance from provided bytes.
367    ///
368    /// `bytes` do not need to be aligned.
369    ///
370    /// Returns an instance and remaining bytes on success.
371    #[inline]
372    pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
373        // Layout here is as follows:
374        // * fixed parameters: BlockHeaderFixedConsensusParameters
375        // * bitflags: u8
376        // * (optional, depends on bitflags) super segment root: SuperSegmentRoot
377        // * (optional, depends on bitflags) next solution range: SolutionRange as unaligned bytes
378        // * (optional, depends on bitflags) PoT parameters change: BlockHeaderPotParametersChange
379
380        let (fixed_parameters, mut remainder) =
381            BlockHeaderFixedConsensusParameters::try_from_bytes(bytes)?;
382
383        let bitflags = remainder.split_off(..size_of::<u8>())?;
384        let bitflags = bitflags[0];
385
386        if (bitflags & Self::MASK_ALL) != bitflags {
387            // Unexpected bitflags were set
388            return None;
389        }
390
391        let super_segment_root = if bitflags & Self::SUPER_SEGMENT_ROOT_MASK != 0 {
392            let super_segment_root = remainder.split_off(..size_of::<SuperSegmentRoot>())?;
393            // SAFETY: All bit patterns are valid
394            let super_segment_root = unsafe { SuperSegmentRoot::from_bytes(super_segment_root) }?;
395
396            Some(super_segment_root)
397        } else {
398            None
399        };
400
401        let next_solution_range = if bitflags & Self::NEXT_SOLUTION_RANGE_MASK != 0 {
402            let next_solution_range = remainder.split_off(..size_of::<SolutionRange>())?;
403            // Not guaranteed to be aligned
404            let next_solution_range = SolutionRange::from_bytes([
405                next_solution_range[0],
406                next_solution_range[1],
407                next_solution_range[2],
408                next_solution_range[3],
409                next_solution_range[4],
410                next_solution_range[5],
411                next_solution_range[6],
412                next_solution_range[7],
413            ]);
414
415            Some(next_solution_range)
416        } else {
417            None
418        };
419
420        let pot_parameters_change = if bitflags & Self::POT_PARAMETERS_CHANGE_MASK != 0 {
421            let pot_parameters_change;
422            (pot_parameters_change, remainder) =
423                BlockHeaderPotParametersChange::try_from_bytes(remainder)?;
424
425            Some(pot_parameters_change)
426        } else {
427            None
428        };
429
430        Some((
431            Self {
432                super_segment_root,
433                fixed_parameters,
434                next_solution_range,
435                pot_parameters_change,
436            },
437            remainder,
438        ))
439    }
440
441    /// Hash of the block consensus parameters, part of the eventual block root
442    pub fn hash(&self) -> Blake3Hash {
443        let Self {
444            super_segment_root,
445            fixed_parameters,
446            next_solution_range,
447            pot_parameters_change,
448        } = self;
449        let BlockHeaderFixedConsensusParameters {
450            solution_range,
451            slot_iterations,
452            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::<'_, { u32::MAX as u64 }, _, _>(
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            const MAX_N: usize = 6;
967            // TODO: separate constant should not be necessary, but
968            //  https://github.com/rust-lang/rust/issues/148596
969            const MAX_N_U64: u64 = 6;
970            let leaves: [_; MAX_N] = [
971                prefix.hash(),
972                result.hash(),
973                consensus_info.hash(),
974                seal.hash(),
975                child_shard_blocks.root().unwrap_or_default(),
976                consensus_parameters.hash(),
977            ];
978            let block_root = UnbalancedMerkleTree::compute_root_only::<MAX_N_U64, _, _>(leaves)
979                .expect("The list is not empty; qed");
980
981            BlockRoot::new(Blake3Hash::new(block_root))
982        };
983
984        #[cfg(not(any(target_os = "none", target_os = "unknown")))]
985        {
986            cached_block_root.get_or_init(compute_root)
987        }
988        #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
989        {
990            cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
991        }
992        #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
993        {
994            struct Wrapper(BlockRoot);
995
996            impl Deref for Wrapper {
997                type Target = BlockRoot;
998
999                #[inline(always)]
1000                fn deref(&self) -> &Self::Target {
1001                    &self.0
1002                }
1003            }
1004
1005            Wrapper(compute_root())
1006        }
1007    }
1008}
1009
1010/// Block header that corresponds to an intermediate shard
1011#[derive(Debug, Clone, Yokeable)]
1012// Prevent creation of potentially broken invariants externally
1013#[non_exhaustive]
1014pub struct IntermediateShardHeader<'a> {
1015    /// Shared block header
1016    shared: SharedBlockHeader<'a>,
1017    /// Beacon chain info
1018    beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1019    /// Information about child shard blocks
1020    child_shard_blocks: BlockHeaderChildShardBlocks<'a>,
1021    /// All bytes of the header except the seal
1022    pre_seal_bytes: &'a [u8],
1023    #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1024    cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1025    #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1026    cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1027}
1028
1029impl<'a> Deref for IntermediateShardHeader<'a> {
1030    type Target = SharedBlockHeader<'a>;
1031
1032    #[inline(always)]
1033    fn deref(&self) -> &Self::Target {
1034        &self.shared
1035    }
1036}
1037
1038impl<'a> GenericBlockHeader<'a> for IntermediateShardHeader<'a> {
1039    const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
1040
1041    #[cfg(feature = "alloc")]
1042    type Owned = OwnedIntermediateShardHeader;
1043
1044    #[cfg(feature = "alloc")]
1045    #[inline(always)]
1046    fn to_owned(self) -> Self::Owned {
1047        self.to_owned()
1048    }
1049
1050    #[inline(always)]
1051    fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1052        self.root()
1053    }
1054
1055    #[inline(always)]
1056    fn pre_seal_hash(&self) -> Blake3Hash {
1057        self.pre_seal_hash()
1058    }
1059}
1060
1061impl<'a> IntermediateShardHeader<'a> {
1062    /// Try to create a new instance from provided bytes.
1063    ///
1064    /// `bytes` should be 8-bytes aligned.
1065    ///
1066    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
1067    /// bytes are not properly aligned or input is otherwise invalid.
1068    #[inline]
1069    pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1070        // The layout here is as follows:
1071        // * block header prefix: BlockHeaderPrefix
1072        // * block header result: BlockHeaderResult
1073        // * consensus info: BlockHeaderConsensusInfo
1074        // * beacon chain: BlockHeaderBeaconChainInfo
1075        // * child shard blocks: BlockHeaderBeaconChainInfo
1076        // * block header seal: BlockHeaderSeal
1077
1078        let (prefix, consensus_info, result, mut remainder) =
1079            BlockHeader::try_from_bytes_shared(bytes)?;
1080
1081        if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1082            return None;
1083        }
1084
1085        let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1086        // SAFETY: All bit patterns are valid
1087        let beacon_chain_info =
1088            unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1089
1090        let (child_shard_blocks, remainder) =
1091            BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1092
1093        let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1094
1095        let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1096
1097        let shared = SharedBlockHeader {
1098            prefix,
1099            result,
1100            consensus_info,
1101            seal,
1102        };
1103
1104        let header = Self {
1105            shared,
1106            beacon_chain_info,
1107            child_shard_blocks,
1108            pre_seal_bytes,
1109            #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1110            cached_block_root: rclite::Arc::default(),
1111        };
1112
1113        if !header.is_internally_consistent() {
1114            return None;
1115        }
1116
1117        Some((header, remainder))
1118    }
1119
1120    /// Check block header's internal consistency.
1121    ///
1122    /// This is usually not necessary to be called explicitly since internal consistency is checked
1123    /// by [`Self::try_from_bytes()`] internally.
1124    #[inline]
1125    pub fn is_internally_consistent(&self) -> bool {
1126        let public_key_hash = match self.seal {
1127            BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1128        };
1129        public_key_hash == self.shared.consensus_info.solution.public_key_hash
1130    }
1131
1132    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
1133    /// checks
1134    #[inline]
1135    pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1136        // The layout here is as follows:
1137        // * block header prefix: BlockHeaderPrefix
1138        // * block header result: BlockHeaderResult
1139        // * consensus info: BlockHeaderConsensusInfo
1140        // * beacon chain: BlockHeaderBeaconChainInfo
1141        // * child shard blocks: BlockHeaderBeaconChainInfo
1142        // * block header seal: BlockHeaderSeal
1143
1144        let (prefix, consensus_info, result, mut remainder) =
1145            BlockHeader::try_from_bytes_shared(bytes)?;
1146
1147        if prefix.shard_index.shard_kind() != Some(ShardKind::IntermediateShard) {
1148            return None;
1149        }
1150
1151        let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1152        // SAFETY: All bit patterns are valid
1153        let beacon_chain_info =
1154            unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1155
1156        let (child_shard_blocks, remainder) =
1157            BlockHeaderChildShardBlocks::try_from_bytes(remainder)?;
1158
1159        let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1160
1161        let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1162
1163        let shared = SharedBlockHeader {
1164            prefix,
1165            result,
1166            consensus_info,
1167            seal,
1168        };
1169
1170        Some((
1171            Self {
1172                shared,
1173                beacon_chain_info,
1174                child_shard_blocks,
1175                pre_seal_bytes,
1176                #[cfg(any(
1177                    feature = "alloc",
1178                    not(any(target_os = "none", target_os = "unknown"))
1179                ))]
1180                cached_block_root: rclite::Arc::default(),
1181            },
1182            remainder,
1183        ))
1184    }
1185
1186    /// Create an owned version of this header
1187    #[cfg(feature = "alloc")]
1188    #[inline(always)]
1189    pub fn to_owned(self) -> OwnedIntermediateShardHeader {
1190        let unsealed = OwnedIntermediateShardHeader::from_parts(
1191            self.shared.prefix,
1192            self.shared.result,
1193            self.shared.consensus_info,
1194            self.beacon_chain_info,
1195            &self.child_shard_blocks,
1196        )
1197        .expect("`self` is always a valid invariant; qed");
1198
1199        unsealed.with_seal(self.shared.seal)
1200    }
1201
1202    /// Shared block header
1203    #[inline(always)]
1204    pub fn shared(&self) -> &SharedBlockHeader<'a> {
1205        &self.shared
1206    }
1207
1208    /// Beacon chain info
1209    #[inline(always)]
1210    pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1211        self.beacon_chain_info
1212    }
1213
1214    /// Information about child shard blocks
1215    #[inline(always)]
1216    pub fn child_shard_blocks(&self) -> &BlockHeaderChildShardBlocks<'a> {
1217        &self.child_shard_blocks
1218    }
1219
1220    /// Hash of the block before seal is applied to it
1221    #[inline]
1222    pub fn pre_seal_hash(&self) -> Blake3Hash {
1223        // TODO: Keyed hash with `block_header_seal` as a key
1224        Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1225    }
1226
1227    /// Verify seal against [`IntermediateShardHeader::pre_seal_hash()`] and check that its public
1228    /// key hash corresponds to the solution
1229    #[inline]
1230    pub fn is_sealed_correctly(&self) -> bool {
1231        self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1232            && self.seal.is_seal_valid(&self.pre_seal_hash())
1233    }
1234
1235    /// Compute block root out of this header.
1236    ///
1237    /// Block root is a Merkle Tree Root. The leaves are derived from individual fields in
1238    /// [`SharedBlockHeader`] and other fields of this enum in the declaration order.
1239    ///
1240    /// Note that this method computes root by doing a bunch of hashing. The result is then cached
1241    /// if `alloc` feature is enabled or when compiled for OS target that is not `none`.
1242    #[inline]
1243    pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1244        let Self {
1245            shared,
1246            beacon_chain_info,
1247            child_shard_blocks,
1248            pre_seal_bytes: _,
1249            #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1250            cached_block_root,
1251        } = self;
1252
1253        let compute_root = || {
1254            let SharedBlockHeader {
1255                prefix,
1256                result,
1257                consensus_info,
1258                seal,
1259            } = shared;
1260
1261            const MAX_N: usize = 6;
1262            // TODO: separate constant should not be necessary, but
1263            //  https://github.com/rust-lang/rust/issues/148596
1264            const MAX_N_U64: u64 = 6;
1265            let leaves: [_; MAX_N] = [
1266                prefix.hash(),
1267                result.hash(),
1268                consensus_info.hash(),
1269                seal.hash(),
1270                beacon_chain_info.hash(),
1271                child_shard_blocks.root().unwrap_or_default(),
1272            ];
1273            let block_root = UnbalancedMerkleTree::compute_root_only::<MAX_N_U64, _, _>(leaves)
1274                .expect("The list is not empty; qed");
1275
1276            BlockRoot::new(Blake3Hash::new(block_root))
1277        };
1278
1279        #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1280        {
1281            cached_block_root.get_or_init(compute_root)
1282        }
1283        #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1284        {
1285            cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1286        }
1287        #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1288        {
1289            struct Wrapper(BlockRoot);
1290
1291            impl Deref for Wrapper {
1292                type Target = BlockRoot;
1293
1294                #[inline(always)]
1295                fn deref(&self) -> &Self::Target {
1296                    &self.0
1297                }
1298            }
1299
1300            Wrapper(compute_root())
1301        }
1302    }
1303}
1304
1305/// Block header that corresponds to a leaf shard
1306#[derive(Debug, Clone, Yokeable)]
1307// Prevent creation of potentially broken invariants externally
1308#[non_exhaustive]
1309pub struct LeafShardHeader<'a> {
1310    /// Shared block header
1311    shared: SharedBlockHeader<'a>,
1312    /// Beacon chain info
1313    beacon_chain_info: &'a BlockHeaderBeaconChainInfo,
1314    /// All bytes of the header except the seal
1315    pre_seal_bytes: &'a [u8],
1316    #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1317    cached_block_root: rclite::Arc<once_cell::race::OnceBox<BlockRoot>>,
1318    #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1319    cached_block_root: rclite::Arc<std::sync::OnceLock<BlockRoot>>,
1320}
1321
1322impl<'a> Deref for LeafShardHeader<'a> {
1323    type Target = SharedBlockHeader<'a>;
1324
1325    #[inline(always)]
1326    fn deref(&self) -> &Self::Target {
1327        &self.shared
1328    }
1329}
1330
1331impl<'a> GenericBlockHeader<'a> for LeafShardHeader<'a> {
1332    const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1333
1334    #[cfg(feature = "alloc")]
1335    type Owned = OwnedLeafShardHeader;
1336
1337    #[cfg(feature = "alloc")]
1338    #[inline(always)]
1339    fn to_owned(self) -> Self::Owned {
1340        self.to_owned()
1341    }
1342
1343    #[inline(always)]
1344    fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1345        self.root()
1346    }
1347
1348    #[inline(always)]
1349    fn pre_seal_hash(&self) -> Blake3Hash {
1350        self.pre_seal_hash()
1351    }
1352}
1353
1354impl<'a> LeafShardHeader<'a> {
1355    /// Try to create a new instance from provided bytes.
1356    ///
1357    /// `bytes` should be 8-bytes aligned.
1358    ///
1359    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
1360    /// bytes are not properly aligned or input is otherwise invalid.
1361    #[inline]
1362    pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1363        // The layout here is as follows:
1364        // * block header result: BlockHeaderResult
1365        // * block header prefix: BlockHeaderPrefix
1366        // * consensus info: BlockHeaderConsensusInfo
1367        // * beacon chain: BlockHeaderBeaconChainInfo
1368        // * block header seal: BlockHeaderSeal
1369
1370        let (prefix, consensus_info, result, mut remainder) =
1371            BlockHeader::try_from_bytes_shared(bytes)?;
1372
1373        if prefix.shard_index.shard_kind() != Some(ShardKind::LeafShard) {
1374            return None;
1375        }
1376
1377        let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1378        // SAFETY: All bit patterns are valid
1379        let beacon_chain_info =
1380            unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1381
1382        let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1383
1384        let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1385
1386        let shared = SharedBlockHeader {
1387            prefix,
1388            result,
1389            consensus_info,
1390            seal,
1391        };
1392
1393        let header = Self {
1394            shared,
1395            beacon_chain_info,
1396            pre_seal_bytes,
1397            #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1398            cached_block_root: rclite::Arc::default(),
1399        };
1400
1401        if !header.is_internally_consistent() {
1402            return None;
1403        }
1404
1405        Some((header, remainder))
1406    }
1407
1408    /// Check block header's internal consistency.
1409    ///
1410    /// This is usually not necessary to be called explicitly since internal consistency is checked
1411    /// by [`Self::try_from_bytes()`] internally.
1412    #[inline]
1413    pub fn is_internally_consistent(&self) -> bool {
1414        let public_key_hash = match self.seal {
1415            BlockHeaderSeal::Ed25519(seal) => seal.public_key.hash(),
1416        };
1417        public_key_hash == self.shared.consensus_info.solution.public_key_hash
1418    }
1419
1420    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
1421    /// checks
1422    #[inline]
1423    pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1424        // The layout here is as follows:
1425        // * block header result: BlockHeaderResult
1426        // * block header prefix: BlockHeaderPrefix
1427        // * consensus info: BlockHeaderConsensusInfo
1428        // * beacon chain: BlockHeaderBeaconChainInfo
1429        // * block header seal: BlockHeaderSeal
1430
1431        let (prefix, consensus_info, result, mut remainder) =
1432            BlockHeader::try_from_bytes_shared(bytes)?;
1433
1434        if prefix.shard_index.shard_kind() != Some(ShardKind::LeafShard) {
1435            return None;
1436        }
1437
1438        let beacon_chain_info = remainder.split_off(..size_of::<BlockHeaderBeaconChainInfo>())?;
1439        // SAFETY: All bit patterns are valid
1440        let beacon_chain_info =
1441            unsafe { BlockHeaderBeaconChainInfo::from_bytes(beacon_chain_info) }?;
1442
1443        let pre_seal_bytes = &bytes[..bytes.len() - remainder.len()];
1444
1445        let (seal, remainder) = BlockHeaderSeal::try_from_bytes(remainder)?;
1446
1447        let shared = SharedBlockHeader {
1448            prefix,
1449            result,
1450            consensus_info,
1451            seal,
1452        };
1453
1454        Some((
1455            Self {
1456                shared,
1457                beacon_chain_info,
1458                pre_seal_bytes,
1459                #[cfg(any(
1460                    feature = "alloc",
1461                    not(any(target_os = "none", target_os = "unknown"))
1462                ))]
1463                cached_block_root: rclite::Arc::default(),
1464            },
1465            remainder,
1466        ))
1467    }
1468
1469    /// Create an owned version of this header
1470    #[cfg(feature = "alloc")]
1471    #[inline(always)]
1472    pub fn to_owned(self) -> OwnedLeafShardHeader {
1473        let unsealed = OwnedLeafShardHeader::from_parts(
1474            self.shared.prefix,
1475            self.shared.result,
1476            self.shared.consensus_info,
1477            self.beacon_chain_info,
1478        );
1479
1480        unsealed.with_seal(self.shared.seal)
1481    }
1482
1483    /// Shared block header
1484    #[inline(always)]
1485    pub fn shared(&self) -> &SharedBlockHeader<'a> {
1486        &self.shared
1487    }
1488
1489    /// Beacon chain info
1490    #[inline(always)]
1491    pub fn beacon_chain_info(&self) -> &'a BlockHeaderBeaconChainInfo {
1492        self.beacon_chain_info
1493    }
1494
1495    /// Hash of the block before seal is applied to it
1496    #[inline]
1497    pub fn pre_seal_hash(&self) -> Blake3Hash {
1498        // TODO: Keyed hash with `block_header_seal` as a key
1499        Blake3Hash::from(blake3::hash(self.pre_seal_bytes))
1500    }
1501
1502    /// Verify seal against [`LeafShardHeader::pre_seal_hash()`] and check that its public key hash
1503    /// corresponds to the solution
1504    #[inline]
1505    pub fn is_sealed_correctly(&self) -> bool {
1506        self.consensus_info.solution.public_key_hash == self.seal.public_key_hash()
1507            && self.seal.is_seal_valid(&self.pre_seal_hash())
1508    }
1509
1510    /// Compute block root out of this header.
1511    ///
1512    /// Block root is a Merkle Tree Root. The leaves are derived from individual fields in
1513    /// [`SharedBlockHeader`] and other fields of this enum in the declaration order.
1514    ///
1515    /// Note that this method computes root by doing a bunch of hashing. The result is then cached
1516    /// if `alloc` feature is enabled or when compiled for OS target that is not `none`.
1517    #[inline]
1518    pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1519        let Self {
1520            shared,
1521            beacon_chain_info,
1522            pre_seal_bytes: _,
1523            #[cfg(any(feature = "alloc", not(any(target_os = "none", target_os = "unknown"))))]
1524            cached_block_root,
1525        } = self;
1526
1527        let compute_root = || {
1528            let SharedBlockHeader {
1529                prefix,
1530                result,
1531                consensus_info,
1532                seal,
1533            } = shared;
1534
1535            const MAX_N: usize = 5;
1536            // TODO: separate constant should not be necessary, but
1537            //  https://github.com/rust-lang/rust/issues/148596
1538            const MAX_N_U64: u64 = 5;
1539            let leaves: [_; MAX_N] = [
1540                prefix.hash(),
1541                result.hash(),
1542                consensus_info.hash(),
1543                seal.hash(),
1544                beacon_chain_info.hash(),
1545            ];
1546            let block_root = UnbalancedMerkleTree::compute_root_only::<MAX_N_U64, _, _>(leaves)
1547                .expect("The list is not empty; qed");
1548
1549            BlockRoot::new(Blake3Hash::new(block_root))
1550        };
1551
1552        #[cfg(not(any(target_os = "none", target_os = "unknown")))]
1553        {
1554            cached_block_root.get_or_init(compute_root)
1555        }
1556        #[cfg(all(feature = "alloc", any(target_os = "none", target_os = "unknown")))]
1557        {
1558            cached_block_root.get_or_init(|| alloc::boxed::Box::new(compute_root()))
1559        }
1560        #[cfg(all(not(feature = "alloc"), any(target_os = "none", target_os = "unknown")))]
1561        {
1562            struct Wrapper(BlockRoot);
1563
1564            impl Deref for Wrapper {
1565                type Target = BlockRoot;
1566
1567                #[inline(always)]
1568                fn deref(&self) -> &Self::Target {
1569                    &self.0
1570                }
1571            }
1572
1573            Wrapper(compute_root())
1574        }
1575    }
1576}
1577
1578/// Block header that together with [`BlockBody`] form a [`Block`]
1579///
1580/// [`BlockBody`]: crate::block::body::BlockBody
1581/// [`Block`]: crate::block::Block
1582#[derive(Debug, Clone, From)]
1583pub enum BlockHeader<'a> {
1584    /// Block header corresponds to the beacon chain
1585    BeaconChain(BeaconChainHeader<'a>),
1586    /// Block header corresponds to an intermediate shard
1587    IntermediateShard(IntermediateShardHeader<'a>),
1588    /// Block header corresponds to a leaf shard
1589    LeafShard(LeafShardHeader<'a>),
1590}
1591
1592impl<'a> Deref for BlockHeader<'a> {
1593    type Target = SharedBlockHeader<'a>;
1594
1595    #[inline(always)]
1596    fn deref(&self) -> &Self::Target {
1597        match self {
1598            Self::BeaconChain(header) => header,
1599            Self::IntermediateShard(header) => header,
1600            Self::LeafShard(header) => header,
1601        }
1602    }
1603}
1604
1605impl<'a> BlockHeader<'a> {
1606    /// Try to create a new instance from provided bytes for provided shard index.
1607    ///
1608    /// `bytes` should be 8-bytes aligned.
1609    ///
1610    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
1611    /// bytes are not properly aligned or input is otherwise invalid.
1612    #[inline]
1613    pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1614        match shard_kind {
1615            RealShardKind::BeaconChain => {
1616                let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
1617                Some((Self::BeaconChain(header), remainder))
1618            }
1619            RealShardKind::IntermediateShard => {
1620                let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
1621                Some((Self::IntermediateShard(header), remainder))
1622            }
1623            RealShardKind::LeafShard => {
1624                let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
1625                Some((Self::LeafShard(header), remainder))
1626            }
1627        }
1628    }
1629
1630    /// Check block header's internal consistency.
1631    ///
1632    /// This is usually not necessary to be called explicitly since internal consistency is checked
1633    /// by [`Self::try_from_bytes()`] internally.
1634    #[inline]
1635    pub fn is_internally_consistent(&self) -> bool {
1636        match self {
1637            Self::BeaconChain(header) => header.is_internally_consistent(),
1638            Self::IntermediateShard(header) => header.is_internally_consistent(),
1639            Self::LeafShard(header) => header.is_internally_consistent(),
1640        }
1641    }
1642
1643    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
1644    /// checks
1645    #[inline]
1646    pub fn try_from_bytes_unchecked(
1647        bytes: &'a [u8],
1648        shard_kind: RealShardKind,
1649    ) -> Option<(Self, &'a [u8])> {
1650        match shard_kind {
1651            RealShardKind::BeaconChain => {
1652                let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
1653                Some((Self::BeaconChain(header), remainder))
1654            }
1655            RealShardKind::IntermediateShard => {
1656                let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
1657                Some((Self::IntermediateShard(header), remainder))
1658            }
1659            RealShardKind::LeafShard => {
1660                let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
1661                Some((Self::LeafShard(header), remainder))
1662            }
1663        }
1664    }
1665
1666    #[inline]
1667    fn try_from_bytes_shared(
1668        mut bytes: &'a [u8],
1669    ) -> Option<(
1670        &'a BlockHeaderPrefix,
1671        &'a BlockHeaderConsensusInfo,
1672        &'a BlockHeaderResult,
1673        &'a [u8],
1674    )> {
1675        let prefix = bytes.split_off(..size_of::<BlockHeaderPrefix>())?;
1676        // SAFETY: All bit patterns are valid
1677        let prefix = unsafe { BlockHeaderPrefix::from_bytes(prefix) }?;
1678
1679        if !(prefix.padding_0 == [0; _]
1680            && prefix.shard_index.as_u32() <= ShardIndex::MAX_SHARD_INDEX)
1681        {
1682            return None;
1683        }
1684
1685        let result = bytes.split_off(..size_of::<BlockHeaderResult>())?;
1686        // SAFETY: All bit patterns are valid
1687        let result = unsafe { BlockHeaderResult::from_bytes(result) }?;
1688
1689        let consensus_info = bytes.split_off(..size_of::<BlockHeaderConsensusInfo>())?;
1690        // SAFETY: All bit patterns are valid
1691        let consensus_info = unsafe { BlockHeaderConsensusInfo::from_bytes(consensus_info) }?;
1692
1693        if consensus_info.solution.padding != [0; _] {
1694            return None;
1695        }
1696
1697        Some((prefix, consensus_info, result, bytes))
1698    }
1699
1700    /// Create an owned version of this header
1701    #[cfg(feature = "alloc")]
1702    #[inline(always)]
1703    pub fn to_owned(self) -> OwnedBlockHeader {
1704        match self {
1705            Self::BeaconChain(header) => header.to_owned().into(),
1706            Self::IntermediateShard(header) => header.to_owned().into(),
1707            Self::LeafShard(header) => header.to_owned().into(),
1708        }
1709    }
1710
1711    /// Hash of the block before seal is applied to it
1712    #[inline]
1713    pub fn pre_seal_hash(&self) -> Blake3Hash {
1714        match self {
1715            Self::BeaconChain(header) => header.pre_seal_hash(),
1716            Self::IntermediateShard(header) => header.pre_seal_hash(),
1717            Self::LeafShard(header) => header.pre_seal_hash(),
1718        }
1719    }
1720
1721    /// Verify seal against [`BlockHeader::pre_seal_hash()`] and check that its public key hash
1722    /// corresponds to the solution
1723    #[inline]
1724    pub fn is_sealed_correctly(&self) -> bool {
1725        match self {
1726            Self::BeaconChain(header) => header.is_sealed_correctly(),
1727            Self::IntermediateShard(header) => header.is_sealed_correctly(),
1728            Self::LeafShard(header) => header.is_sealed_correctly(),
1729        }
1730    }
1731
1732    /// Compute block root out of this header.
1733    ///
1734    /// Block root is a Merkle Tree Root. The leaves are derived from individual fields in
1735    /// [`SharedBlockHeader`] and other fields of this enum in the declaration order.
1736    ///
1737    /// Note that this method computes root by doing a bunch of hashing. The result is then cached
1738    /// if `alloc` feature is enabled.
1739    #[inline]
1740    pub fn root(&self) -> impl Deref<Target = BlockRoot> + Send + Sync {
1741        enum Wrapper<B, I, L> {
1742            BeaconChain(B),
1743            IntermediateShard(I),
1744            LeafShard(L),
1745        }
1746
1747        impl<B, I, L> Deref for Wrapper<B, I, L>
1748        where
1749            B: Deref<Target = BlockRoot>,
1750            I: Deref<Target = BlockRoot>,
1751            L: Deref<Target = BlockRoot>,
1752        {
1753            type Target = BlockRoot;
1754
1755            #[inline(always)]
1756            fn deref(&self) -> &Self::Target {
1757                match self {
1758                    Wrapper::BeaconChain(block_root) => block_root,
1759                    Wrapper::IntermediateShard(block_root) => block_root,
1760                    Wrapper::LeafShard(block_root) => block_root,
1761                }
1762            }
1763        }
1764
1765        // TODO: Should unique keyed hash be used for different kinds of shards?
1766        match self {
1767            Self::BeaconChain(header) => Wrapper::BeaconChain(header.root()),
1768            Self::IntermediateShard(header) => Wrapper::IntermediateShard(header.root()),
1769            Self::LeafShard(header) => Wrapper::LeafShard(header.root()),
1770        }
1771    }
1772}