Skip to main content

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