ab_core_primitives/
block.rs

1//! Block-related primitives
2
3pub mod body;
4pub mod header;
5#[cfg(feature = "alloc")]
6pub mod owned;
7
8use crate::block::body::{BeaconChainBody, GenericBlockBody, IntermediateShardBody, LeafShardBody};
9use crate::block::header::{
10    BeaconChainHeader, GenericBlockHeader, IntermediateShardHeader, LeafShardHeader,
11};
12#[cfg(feature = "alloc")]
13use crate::block::owned::{
14    GenericOwnedBlock, OwnedBeaconChainBlock, OwnedBlock, OwnedIntermediateShardBlock,
15    OwnedLeafShardBlock,
16};
17use crate::hashes::Blake3Hash;
18use crate::shard::ShardKind;
19use crate::solutions::SolutionRange;
20#[cfg(feature = "serde")]
21use ::serde::{Deserialize, Serialize};
22use ab_io_type::trivial_type::TrivialType;
23use core::iter::Step;
24use core::{fmt, mem};
25use derive_more::{
26    Add, AddAssign, AsMut, AsRef, Deref, DerefMut, Display, From, Into, Sub, SubAssign,
27};
28#[cfg(feature = "scale-codec")]
29use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
30#[cfg(feature = "scale-codec")]
31use scale_info::TypeInfo;
32
33/// Block number
34#[derive(
35    Debug,
36    Display,
37    Default,
38    Copy,
39    Clone,
40    Ord,
41    PartialOrd,
42    Eq,
43    PartialEq,
44    Hash,
45    From,
46    Into,
47    Add,
48    AddAssign,
49    Sub,
50    SubAssign,
51    TrivialType,
52)]
53#[cfg_attr(
54    feature = "scale-codec",
55    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
56)]
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58#[cfg_attr(feature = "serde", serde(transparent))]
59#[repr(C)]
60pub struct BlockNumber(u64);
61
62impl Step for BlockNumber {
63    #[inline(always)]
64    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
65        u64::steps_between(&start.0, &end.0)
66    }
67
68    #[inline(always)]
69    fn forward_checked(start: Self, count: usize) -> Option<Self> {
70        u64::forward_checked(start.0, count).map(Self)
71    }
72
73    #[inline(always)]
74    fn backward_checked(start: Self, count: usize) -> Option<Self> {
75        u64::backward_checked(start.0, count).map(Self)
76    }
77}
78
79impl BlockNumber {
80    /// Size in bytes
81    pub const SIZE: usize = size_of::<u64>();
82    /// Genesis block number
83    pub const ZERO: BlockNumber = BlockNumber(0);
84    /// First block number
85    pub const ONE: BlockNumber = BlockNumber(1);
86    /// Max block number
87    pub const MAX: BlockNumber = BlockNumber(u64::MAX);
88
89    /// Create new instance
90    #[inline(always)]
91    pub const fn new(n: u64) -> Self {
92        Self(n)
93    }
94
95    /// Get internal representation
96    #[inline(always)]
97    pub const fn as_u64(self) -> u64 {
98        self.0
99    }
100
101    /// Create block number from bytes
102    #[inline(always)]
103    pub const fn from_bytes(bytes: [u8; Self::SIZE]) -> Self {
104        Self(u64::from_le_bytes(bytes))
105    }
106
107    /// Convert block number to bytes
108    #[inline(always)]
109    pub const fn to_bytes(self) -> [u8; Self::SIZE] {
110        self.0.to_le_bytes()
111    }
112
113    /// Checked addition, returns `None` on overflow
114    #[inline(always)]
115    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
116        if let Some(n) = self.0.checked_add(rhs.0) {
117            Some(Self(n))
118        } else {
119            None
120        }
121    }
122
123    /// Saturating addition
124    #[inline(always)]
125    pub const fn saturating_add(self, rhs: Self) -> Self {
126        Self(self.0.saturating_add(rhs.0))
127    }
128
129    /// Checked subtraction, returns `None` on underflow
130    #[inline(always)]
131    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
132        if let Some(n) = self.0.checked_sub(rhs.0) {
133            Some(Self(n))
134        } else {
135            None
136        }
137    }
138
139    /// Saturating subtraction
140    #[inline(always)]
141    pub const fn saturating_sub(self, rhs: Self) -> Self {
142        Self(self.0.saturating_sub(rhs.0))
143    }
144}
145
146/// Block timestamp as Unix time in milliseconds
147#[derive(
148    Debug,
149    Display,
150    Default,
151    Copy,
152    Clone,
153    Ord,
154    PartialOrd,
155    Eq,
156    PartialEq,
157    Hash,
158    From,
159    Into,
160    Add,
161    AddAssign,
162    Sub,
163    SubAssign,
164    TrivialType,
165)]
166#[cfg_attr(
167    feature = "scale-codec",
168    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
169)]
170#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
171#[cfg_attr(feature = "serde", serde(transparent))]
172#[repr(C)]
173pub struct BlockTimestamp(u64);
174
175impl BlockTimestamp {
176    /// Size in bytes
177    pub const SIZE: usize = size_of::<u64>();
178
179    /// Create new instance
180    #[inline(always)]
181    pub const fn new(ms: u64) -> Self {
182        Self(ms)
183    }
184
185    /// Get internal representation
186    #[inline(always)]
187    pub const fn as_ms(self) -> u64 {
188        self.0
189    }
190
191    /// Checked addition, returns `None` on overflow
192    #[inline(always)]
193    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
194        if let Some(n) = self.0.checked_add(rhs.0) {
195            Some(Self(n))
196        } else {
197            None
198        }
199    }
200
201    /// Saturating addition
202    #[inline(always)]
203    pub const fn saturating_add(self, rhs: Self) -> Self {
204        Self(self.0.saturating_add(rhs.0))
205    }
206
207    /// Checked subtraction, returns `None` on underflow
208    #[inline(always)]
209    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
210        if let Some(n) = self.0.checked_sub(rhs.0) {
211            Some(Self(n))
212        } else {
213            None
214        }
215    }
216
217    /// Saturating subtraction
218    #[inline(always)]
219    pub const fn saturating_sub(self, rhs: Self) -> Self {
220        Self(self.0.saturating_sub(rhs.0))
221    }
222}
223
224/// Block root.
225///
226/// This is typically called block hash in other blockchains, but here it represents Merkle Tree
227/// root of the header rather than a single hash of its contents.
228#[derive(
229    Debug,
230    Display,
231    Default,
232    Copy,
233    Clone,
234    Eq,
235    PartialEq,
236    Ord,
237    PartialOrd,
238    Hash,
239    From,
240    Into,
241    AsRef,
242    AsMut,
243    Deref,
244    DerefMut,
245    TrivialType,
246)]
247#[cfg_attr(
248    feature = "scale-codec",
249    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
250)]
251#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
252#[cfg_attr(feature = "serde", serde(transparent))]
253#[repr(C)]
254pub struct BlockRoot(Blake3Hash);
255
256impl AsRef<[u8]> for BlockRoot {
257    #[inline(always)]
258    fn as_ref(&self) -> &[u8] {
259        self.0.as_ref()
260    }
261}
262
263impl AsMut<[u8]> for BlockRoot {
264    #[inline(always)]
265    fn as_mut(&mut self) -> &mut [u8] {
266        self.0.as_mut()
267    }
268}
269
270impl BlockRoot {
271    /// Size in bytes
272    pub const SIZE: usize = Blake3Hash::SIZE;
273
274    /// Create new instance
275    #[inline(always)]
276    pub const fn new(hash: Blake3Hash) -> Self {
277        Self(hash)
278    }
279
280    /// Convenient conversion from slice of underlying representation for efficiency purposes
281    #[inline(always)]
282    pub const fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
283        let value = Blake3Hash::slice_from_repr(value);
284        // SAFETY: `BlockHash` is `#[repr(C)]` and guaranteed to have the same memory layout
285        unsafe { mem::transmute(value) }
286    }
287
288    /// Convenient conversion to slice of underlying representation for efficiency purposes
289    #[inline(always)]
290    pub const fn repr_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
291        // SAFETY: `BlockHash` is `#[repr(C)]` and guaranteed to have the same memory layout
292        let value = unsafe { mem::transmute::<&[Self], &[Blake3Hash]>(value) };
293        Blake3Hash::repr_from_slice(value)
294    }
295}
296
297/// Generic block
298pub trait GenericBlock<'a>
299where
300    Self: Clone + fmt::Debug,
301{
302    /// Shard kind
303    const SHARD_KIND: ShardKind;
304
305    /// Block header type
306    type Header: GenericBlockHeader<'a>;
307    /// Block body type
308    type Body: GenericBlockBody<'a>;
309    /// Owned block
310    #[cfg(feature = "alloc")]
311    type Owned: GenericOwnedBlock<Block<'a> = Self>
312    where
313        Self: 'a;
314
315    /// Get block header
316    fn header(&self) -> &Self::Header;
317
318    /// Get block body
319    fn body(&self) -> &Self::Body;
320
321    /// Turn into owned version
322    #[cfg(feature = "alloc")]
323    fn to_owned(self) -> Self::Owned;
324}
325
326/// Block that corresponds to the beacon chain
327#[derive(Debug, Clone)]
328// Prevent creation of potentially broken invariants externally
329#[non_exhaustive]
330pub struct BeaconChainBlock<'a> {
331    /// Block header
332    header: BeaconChainHeader<'a>,
333    /// Block body
334    body: BeaconChainBody<'a>,
335}
336
337impl<'a> BeaconChainBlock<'a> {
338    /// Try to create a new instance from provided bytes for provided shard index.
339    ///
340    /// `bytes` should be 8-bytes aligned.
341    ///
342    /// Checks internal consistency of header, body, and block, but no consensus verification is
343    /// done. For unchecked version use [`Self::try_from_bytes_unchecked()`].
344    ///
345    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
346    /// bytes are not properly aligned or input is otherwise invalid.
347    #[inline]
348    pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
349        let (header, remainder) = BeaconChainHeader::try_from_bytes(bytes)?;
350        let remainder = align_to_and_ensure_zero_padding::<u128>(remainder)?;
351        let (body, remainder) = BeaconChainBody::try_from_bytes(remainder)?;
352
353        let block = Self { header, body };
354
355        // Check internal consistency
356        if !block.is_internally_consistent() {
357            return None;
358        }
359
360        Some((block, remainder))
361    }
362
363    /// Check block's internal consistency.
364    ///
365    /// This is usually not necessary to be called explicitly since full internal consistency is
366    /// checked by [`Self::try_from_bytes()`] internally.
367    ///
368    /// NOTE: This only checks block-level internal consistency, header and block level internal
369    /// consistency is checked separately.
370    #[inline]
371    pub fn is_internally_consistent(&self) -> bool {
372        self.body.root() == self.header.result.body_root
373            && self.header.child_shard_blocks().len() == self.body.intermediate_shard_blocks().len()
374            && self
375                .header
376                .child_shard_blocks()
377                .iter()
378                .zip(self.body.intermediate_shard_blocks().iter())
379                .all(|(child_shard_block_root, intermediate_shard_block)| {
380                    child_shard_block_root == &*intermediate_shard_block.header.root()
381                        && intermediate_shard_block
382                            .header
383                            .prefix
384                            .shard_index
385                            .is_child_of(self.header.prefix.shard_index)
386                })
387    }
388
389    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
390    /// checks
391    #[inline]
392    pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
393        let (header, remainder) = BeaconChainHeader::try_from_bytes_unchecked(bytes)?;
394        let remainder = align_to_and_ensure_zero_padding::<u128>(remainder)?;
395        let (body, remainder) = BeaconChainBody::try_from_bytes_unchecked(remainder)?;
396
397        Some((Self { header, body }, remainder))
398    }
399
400    /// Create an owned version of this block
401    #[cfg(feature = "alloc")]
402    #[inline(always)]
403    pub fn to_owned(self) -> OwnedBeaconChainBlock {
404        OwnedBeaconChainBlock {
405            header: self.header.to_owned(),
406            body: self.body.to_owned(),
407        }
408    }
409}
410
411impl<'a> GenericBlock<'a> for BeaconChainBlock<'a> {
412    const SHARD_KIND: ShardKind = ShardKind::BeaconChain;
413
414    type Header = BeaconChainHeader<'a>;
415    type Body = BeaconChainBody<'a>;
416    #[cfg(feature = "alloc")]
417    type Owned = OwnedBeaconChainBlock;
418
419    #[inline(always)]
420    fn header(&self) -> &Self::Header {
421        &self.header
422    }
423
424    #[inline(always)]
425    fn body(&self) -> &Self::Body {
426        &self.body
427    }
428
429    #[cfg(feature = "alloc")]
430    #[inline(always)]
431    fn to_owned(self) -> Self::Owned {
432        self.to_owned()
433    }
434}
435
436/// Block that corresponds to an intermediate shard
437#[derive(Debug, Clone)]
438// Prevent creation of potentially broken invariants externally
439#[non_exhaustive]
440pub struct IntermediateShardBlock<'a> {
441    /// Block header
442    header: IntermediateShardHeader<'a>,
443    /// Block body
444    body: IntermediateShardBody<'a>,
445}
446
447impl<'a> IntermediateShardBlock<'a> {
448    /// Try to create a new instance from provided bytes for provided shard index.
449    ///
450    /// `bytes` should be 8-bytes aligned.
451    ///
452    /// Checks internal consistency of header, body, and block, but no consensus verification is
453    /// done. For unchecked version use [`Self::try_from_bytes_unchecked()`].
454    ///
455    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
456    /// bytes are not properly aligned or input is otherwise invalid.
457    #[inline]
458    pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
459        let (header, remainder) = IntermediateShardHeader::try_from_bytes(bytes)?;
460        let remainder = align_to_and_ensure_zero_padding::<u128>(remainder)?;
461        let (body, remainder) = IntermediateShardBody::try_from_bytes(remainder)?;
462
463        let block = Self { header, body };
464
465        // Check internal consistency
466        if !block.is_internally_consistent() {
467            return None;
468        }
469
470        Some((block, remainder))
471    }
472
473    /// Check block's internal consistency.
474    ///
475    /// This is usually not necessary to be called explicitly since full internal consistency is
476    /// checked by [`Self::try_from_bytes()`] internally.
477    ///
478    /// NOTE: This only checks block-level internal consistency, header and block level internal
479    /// consistency is checked separately.
480    #[inline]
481    pub fn is_internally_consistent(&self) -> bool {
482        self.body.root() == self.header.result.body_root
483            && self.header.child_shard_blocks().len() == self.body.leaf_shard_blocks().len()
484            && self
485                .header
486                .child_shard_blocks()
487                .iter()
488                .zip(self.body.leaf_shard_blocks().iter())
489                .all(|(child_shard_block_root, leaf_shard_block)| {
490                    child_shard_block_root == &*leaf_shard_block.header.root()
491                        && leaf_shard_block
492                            .header
493                            .prefix
494                            .shard_index
495                            .is_child_of(self.header.prefix.shard_index)
496                })
497    }
498
499    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
500    /// checks
501    #[inline]
502    pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
503        let (header, remainder) = IntermediateShardHeader::try_from_bytes_unchecked(bytes)?;
504        let remainder = align_to_and_ensure_zero_padding::<u128>(remainder)?;
505        let (body, remainder) = IntermediateShardBody::try_from_bytes_unchecked(remainder)?;
506
507        Some((Self { header, body }, remainder))
508    }
509
510    /// Create an owned version of this block
511    #[cfg(feature = "alloc")]
512    #[inline(always)]
513    pub fn to_owned(self) -> OwnedIntermediateShardBlock {
514        OwnedIntermediateShardBlock {
515            header: self.header.to_owned(),
516            body: self.body.to_owned(),
517        }
518    }
519}
520
521impl<'a> GenericBlock<'a> for IntermediateShardBlock<'a> {
522    const SHARD_KIND: ShardKind = ShardKind::IntermediateShard;
523
524    type Header = IntermediateShardHeader<'a>;
525    type Body = IntermediateShardBody<'a>;
526    #[cfg(feature = "alloc")]
527    type Owned = OwnedIntermediateShardBlock;
528
529    #[inline(always)]
530    fn header(&self) -> &Self::Header {
531        &self.header
532    }
533
534    #[inline(always)]
535    fn body(&self) -> &Self::Body {
536        &self.body
537    }
538
539    #[cfg(feature = "alloc")]
540    #[inline(always)]
541    fn to_owned(self) -> Self::Owned {
542        self.to_owned()
543    }
544}
545
546/// Block that corresponds to a leaf shard
547#[derive(Debug, Clone)]
548// Prevent creation of potentially broken invariants externally
549#[non_exhaustive]
550pub struct LeafShardBlock<'a> {
551    /// Block header
552    header: LeafShardHeader<'a>,
553    /// Block body
554    body: LeafShardBody<'a>,
555}
556
557impl<'a> LeafShardBlock<'a> {
558    /// Try to create a new instance from provided bytes for provided shard index.
559    ///
560    /// `bytes` should be 8-bytes aligned.
561    ///
562    /// Checks internal consistency of header, body, and block, but no consensus verification is
563    /// done. For unchecked version use [`Self::try_from_bytes_unchecked()`].
564    ///
565    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
566    /// bytes are not properly aligned or input is otherwise invalid.
567    #[inline]
568    pub fn try_from_bytes(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
569        let (header, remainder) = LeafShardHeader::try_from_bytes(bytes)?;
570        let remainder = align_to_and_ensure_zero_padding::<u128>(remainder)?;
571        let (body, remainder) = LeafShardBody::try_from_bytes(remainder)?;
572
573        let block = Self { header, body };
574
575        // Check internal consistency
576        if !block.is_internally_consistent() {
577            return None;
578        }
579
580        Some((block, remainder))
581    }
582
583    /// Check block's internal consistency.
584    ///
585    /// This is usually not necessary to be called explicitly since full internal consistency is
586    /// checked by [`Self::try_from_bytes()`] internally.
587    ///
588    /// NOTE: This only checks block-level internal consistency, header and block level internal
589    /// consistency is checked separately.
590    #[inline]
591    pub fn is_internally_consistent(&self) -> bool {
592        self.body.root() == self.header.result.body_root
593    }
594
595    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
596    /// checks
597    #[inline]
598    pub fn try_from_bytes_unchecked(bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
599        let (header, remainder) = LeafShardHeader::try_from_bytes_unchecked(bytes)?;
600        let remainder = align_to_and_ensure_zero_padding::<u128>(remainder)?;
601        let (body, remainder) = LeafShardBody::try_from_bytes_unchecked(remainder)?;
602
603        Some((Self { header, body }, remainder))
604    }
605
606    /// Create an owned version of this block
607    #[cfg(feature = "alloc")]
608    #[inline(always)]
609    pub fn to_owned(self) -> OwnedLeafShardBlock {
610        OwnedLeafShardBlock {
611            header: self.header.to_owned(),
612            body: self.body.to_owned(),
613        }
614    }
615}
616
617impl<'a> GenericBlock<'a> for LeafShardBlock<'a> {
618    const SHARD_KIND: ShardKind = ShardKind::LeafShard;
619
620    type Header = LeafShardHeader<'a>;
621    type Body = LeafShardBody<'a>;
622    #[cfg(feature = "alloc")]
623    type Owned = OwnedLeafShardBlock;
624
625    #[inline(always)]
626    fn header(&self) -> &Self::Header {
627        &self.header
628    }
629
630    #[inline(always)]
631    fn body(&self) -> &Self::Body {
632        &self.body
633    }
634
635    #[cfg(feature = "alloc")]
636    #[inline(always)]
637    fn to_owned(self) -> Self::Owned {
638        self.to_owned()
639    }
640}
641
642/// Block that contains [`BlockHeader`] and [`BlockBody`]
643///
644/// [`BlockHeader`]: crate::block::header::BlockHeader
645/// [`BlockBody`]: crate::block::body::BlockBody
646#[derive(Debug, Clone, From)]
647pub enum Block<'a> {
648    /// Block corresponds to the beacon chain
649    BeaconChain(BeaconChainBlock<'a>),
650    /// Block corresponds to an intermediate shard
651    IntermediateShard(IntermediateShardBlock<'a>),
652    /// Block corresponds to a leaf shard
653    LeafShard(LeafShardBlock<'a>),
654}
655
656impl<'a> Block<'a> {
657    /// Try to create a new instance from provided bytes.
658    ///
659    /// `bytes` should be 16-byte aligned.
660    ///
661    /// Checks internal consistency of header, body, and block, but no consensus verification is
662    /// done. For unchecked version use [`Self::try_from_bytes_unchecked()`].
663    ///
664    /// Returns an instance and remaining bytes on success, `None` if too few bytes were given,
665    /// bytes are not properly aligned or input is otherwise invalid.
666    #[inline]
667    pub fn try_from_bytes(bytes: &'a [u8], shard_kind: ShardKind) -> Option<(Self, &'a [u8])> {
668        match shard_kind {
669            ShardKind::BeaconChain => {
670                let (block_header, remainder) = BeaconChainBlock::try_from_bytes(bytes)?;
671                Some((Self::BeaconChain(block_header), remainder))
672            }
673            ShardKind::IntermediateShard => {
674                let (block_header, remainder) = IntermediateShardBlock::try_from_bytes(bytes)?;
675                Some((Self::IntermediateShard(block_header), remainder))
676            }
677            ShardKind::LeafShard => {
678                let (block_header, remainder) = LeafShardBlock::try_from_bytes(bytes)?;
679                Some((Self::LeafShard(block_header), remainder))
680            }
681            ShardKind::Phantom | ShardKind::Invalid => {
682                // Blocks for such shards do not exist
683                None
684            }
685        }
686    }
687
688    /// Check block's internal consistency.
689    ///
690    /// This is usually not necessary to be called explicitly since full internal consistency is
691    /// checked by [`Self::try_from_bytes()`] internally.
692    ///
693    /// NOTE: This only checks block-level internal consistency, header and block level internal
694    /// consistency is checked separately.
695    #[inline]
696    pub fn is_internally_consistent(&self) -> bool {
697        match self {
698            Self::BeaconChain(block) => block.is_internally_consistent(),
699            Self::IntermediateShard(block) => block.is_internally_consistent(),
700            Self::LeafShard(block) => block.is_internally_consistent(),
701        }
702    }
703
704    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
705    /// checks
706    #[inline]
707    pub fn try_from_bytes_unchecked(
708        bytes: &'a [u8],
709        shard_kind: ShardKind,
710    ) -> Option<(Self, &'a [u8])> {
711        match shard_kind {
712            ShardKind::BeaconChain => {
713                let (block_header, remainder) = BeaconChainBlock::try_from_bytes_unchecked(bytes)?;
714                Some((Self::BeaconChain(block_header), remainder))
715            }
716            ShardKind::IntermediateShard => {
717                let (block_header, remainder) =
718                    IntermediateShardBlock::try_from_bytes_unchecked(bytes)?;
719                Some((Self::IntermediateShard(block_header), remainder))
720            }
721            ShardKind::LeafShard => {
722                let (block_header, remainder) = LeafShardBlock::try_from_bytes_unchecked(bytes)?;
723                Some((Self::LeafShard(block_header), remainder))
724            }
725            ShardKind::Phantom | ShardKind::Invalid => {
726                // Blocks for such shards do not exist
727                None
728            }
729        }
730    }
731
732    /// Create an owned version of this block
733    #[cfg(feature = "alloc")]
734    #[inline(always)]
735    pub fn to_owned(self) -> OwnedBlock {
736        match self {
737            Self::BeaconChain(block) => block.to_owned().into(),
738            Self::IntermediateShard(block) => block.to_owned().into(),
739            Self::LeafShard(block) => block.to_owned().into(),
740        }
741    }
742}
743
744/// BlockWeight type for fork choice rule.
745///
746/// The smaller the solution range is, the heavier is the block.
747#[derive(
748    Debug,
749    Display,
750    Default,
751    Copy,
752    Clone,
753    Ord,
754    PartialOrd,
755    Eq,
756    PartialEq,
757    Hash,
758    From,
759    Into,
760    Add,
761    AddAssign,
762    Sub,
763    SubAssign,
764)]
765#[cfg_attr(
766    feature = "scale-codec",
767    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
768)]
769#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
770#[repr(C)]
771pub struct BlockWeight(u128);
772
773impl BlockWeight {
774    /// Size in bytes
775    pub const SIZE: usize = size_of::<u128>();
776    /// Zero block weight
777    pub const ZERO: BlockWeight = BlockWeight(0);
778    /// Max block wright
779    pub const MAX: BlockWeight = BlockWeight(u128::MAX);
780
781    /// Create new instance
782    #[inline(always)]
783    pub const fn new(n: u128) -> Self {
784        Self(n)
785    }
786
787    /// Derive block weight from provided solution range
788    pub const fn from_solution_range(solution_range: SolutionRange) -> Self {
789        Self::new((SolutionRange::MAX.as_u64() - solution_range.as_u64()) as u128)
790    }
791
792    /// Get internal representation
793    #[inline(always)]
794    pub const fn as_u128(self) -> u128 {
795        self.0
796    }
797}
798
799/// Aligns bytes to `T` and ensures that all padding bytes (if any) are zero
800fn align_to_and_ensure_zero_padding<T>(bytes: &[u8]) -> Option<&[u8]> {
801    // SAFETY: We do not read `T`, so the contents don't really matter
802    let padding = unsafe { bytes.align_to::<T>() }.0;
803
804    // Padding must be zero
805    if padding.iter().any(|&byte| byte != 0) {
806        return None;
807    }
808
809    Some(&bytes[padding.len()..])
810}