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::alignment::Alignment;
23use ab_io_type::trivial_type::TrivialType;
24use core::fmt;
25use core::iter::Step;
26use derive_more::{
27    Add, AddAssign, AsMut, AsRef, Deref, DerefMut, Display, From, Into, Sub, SubAssign,
28};
29#[cfg(feature = "scale-codec")]
30use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
31use transparent_wrapper::TransparentWrapper;
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    Add,
46    AddAssign,
47    Sub,
48    SubAssign,
49    TrivialType,
50)]
51#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
52#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
53#[cfg_attr(feature = "serde", serde(transparent))]
54#[repr(C)]
55pub struct BlockNumber(u64);
56
57impl Step for BlockNumber {
58    #[inline(always)]
59    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
60        u64::steps_between(&start.0, &end.0)
61    }
62
63    #[inline(always)]
64    fn forward_checked(start: Self, count: usize) -> Option<Self> {
65        u64::forward_checked(start.0, count).map(Self)
66    }
67
68    #[inline(always)]
69    fn forward_overflowing(start: Self, count: usize) -> (Self, bool) {
70        let (n, overflowing) = u64::forward_overflowing(start.0, count);
71        (Self(n), overflowing)
72    }
73
74    #[inline(always)]
75    fn backward_checked(start: Self, count: usize) -> Option<Self> {
76        u64::backward_checked(start.0, count).map(Self)
77    }
78
79    #[inline(always)]
80    fn backward_overflowing(start: Self, count: usize) -> (Self, bool) {
81        let (n, overflowing) = u64::backward_overflowing(start.0, count);
82        (Self(n), overflowing)
83    }
84}
85
86const impl From<u64> for BlockNumber {
87    #[inline(always)]
88    fn from(value: u64) -> Self {
89        Self(value)
90    }
91}
92
93const impl From<BlockNumber> for u64 {
94    #[inline(always)]
95    fn from(value: BlockNumber) -> Self {
96        value.0
97    }
98}
99
100impl BlockNumber {
101    /// Size in bytes
102    pub const SIZE: usize = size_of::<u64>();
103    /// Genesis block number
104    pub const ZERO: BlockNumber = BlockNumber(0);
105    /// First block number
106    pub const ONE: BlockNumber = BlockNumber(1);
107    /// Max block number
108    pub const MAX: BlockNumber = BlockNumber(u64::MAX);
109
110    /// Create block number from bytes
111    #[inline(always)]
112    pub const fn from_bytes(bytes: [u8; Self::SIZE]) -> Self {
113        Self(u64::from_le_bytes(bytes))
114    }
115
116    /// Convert block number to bytes
117    #[inline(always)]
118    pub const fn to_bytes(self) -> [u8; Self::SIZE] {
119        self.0.to_le_bytes()
120    }
121
122    /// Checked addition, returns `None` on overflow
123    #[inline(always)]
124    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
125        if let Some(n) = self.0.checked_add(rhs.0) {
126            Some(Self(n))
127        } else {
128            None
129        }
130    }
131
132    /// Saturating addition
133    #[inline(always)]
134    pub const fn saturating_add(self, rhs: Self) -> Self {
135        Self(self.0.saturating_add(rhs.0))
136    }
137
138    /// Checked subtraction, returns `None` on underflow
139    #[inline(always)]
140    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
141        if let Some(n) = self.0.checked_sub(rhs.0) {
142            Some(Self(n))
143        } else {
144            None
145        }
146    }
147
148    /// Saturating subtraction
149    #[inline(always)]
150    pub const fn saturating_sub(self, rhs: Self) -> Self {
151        Self(self.0.saturating_sub(rhs.0))
152    }
153}
154
155/// Block timestamp as Unix time in milliseconds
156#[derive(
157    Debug,
158    Display,
159    Default,
160    Copy,
161    Clone,
162    Ord,
163    PartialOrd,
164    Eq,
165    PartialEq,
166    Hash,
167    From,
168    Into,
169    Add,
170    AddAssign,
171    Sub,
172    SubAssign,
173    TrivialType,
174)]
175#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
176#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
177#[cfg_attr(feature = "serde", serde(transparent))]
178#[repr(C)]
179pub struct BlockTimestamp(u64);
180
181impl BlockTimestamp {
182    /// Size in bytes
183    pub const SIZE: usize = size_of::<u64>();
184
185    /// Create a new instance
186    #[inline(always)]
187    pub const fn from_millis(ms: u64) -> Self {
188        Self(ms)
189    }
190
191    /// Get internal representation
192    #[inline(always)]
193    pub const fn as_millis(self) -> u64 {
194        self.0
195    }
196
197    /// Checked addition, returns `None` on overflow
198    #[inline(always)]
199    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
200        if let Some(n) = self.0.checked_add(rhs.0) {
201            Some(Self(n))
202        } else {
203            None
204        }
205    }
206
207    /// Saturating addition
208    #[inline(always)]
209    pub const fn saturating_add(self, rhs: Self) -> Self {
210        Self(self.0.saturating_add(rhs.0))
211    }
212
213    /// Checked subtraction, returns `None` on underflow
214    #[inline(always)]
215    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
216        if let Some(n) = self.0.checked_sub(rhs.0) {
217            Some(Self(n))
218        } else {
219            None
220        }
221    }
222
223    /// Saturating subtraction
224    #[inline(always)]
225    pub const fn saturating_sub(self, rhs: Self) -> Self {
226        Self(self.0.saturating_sub(rhs.0))
227    }
228}
229
230/// Block root.
231///
232/// This is typically called block hash in other blockchains, but here it represents Merkle Tree
233/// root of the header rather than a single hash of its contents.
234#[derive(
235    Debug,
236    Display,
237    Default,
238    Copy,
239    Clone,
240    Eq,
241    PartialEq,
242    Ord,
243    PartialOrd,
244    Hash,
245    From,
246    Into,
247    AsRef,
248    AsMut,
249    Deref,
250    DerefMut,
251    TrivialType,
252    TransparentWrapper,
253)]
254#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
255#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
256#[cfg_attr(feature = "serde", serde(transparent))]
257#[repr(C)]
258pub struct BlockRoot(Blake3Hash);
259
260impl AsRef<[u8]> for BlockRoot {
261    #[inline(always)]
262    fn as_ref(&self) -> &[u8] {
263        self.0.as_ref()
264    }
265}
266
267impl AsMut<[u8]> for BlockRoot {
268    #[inline(always)]
269    fn as_mut(&mut self) -> &mut [u8] {
270        self.0.as_mut()
271    }
272}
273
274impl BlockRoot {
275    /// Size in bytes
276    pub const SIZE: usize = Blake3Hash::SIZE;
277
278    /// Create a new instance
279    #[inline(always)]
280    pub const fn new(hash: Blake3Hash) -> Self {
281        Self(hash)
282    }
283
284    /// Convenient conversion from slice of underlying representation for efficiency purposes
285    #[inline(always)]
286    pub const fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
287        Self::wrap_slice(Blake3Hash::slice_from_repr(value))
288    }
289
290    /// Convenient conversion to slice of underlying representation for efficiency purposes
291    #[inline(always)]
292    pub const fn repr_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
293        Blake3Hash::repr_from_slice(Self::peel_slice(value))
294    }
295}
296
297/// Generic block
298pub trait GenericBlock<'a>
299where
300    Self: Clone + fmt::Debug + Send + Sync,
301{
302    /// Shard kind
303    const SHARD_KIND: RealShardKind;
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 an 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 16-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(remainder, Alignment::MAX)?;
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(remainder, Alignment::MAX)?;
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: RealShardKind = RealShardKind::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 16-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(remainder, Alignment::MAX)?;
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(remainder, Alignment::MAX)?;
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: RealShardKind = RealShardKind::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 16-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(remainder, Alignment::MAX)?;
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(remainder, Alignment::MAX)?;
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: RealShardKind = RealShardKind::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: RealShardKind) -> Option<(Self, &'a [u8])> {
668        match shard_kind {
669            RealShardKind::BeaconChain => {
670                let (block_header, remainder) = BeaconChainBlock::try_from_bytes(bytes)?;
671                Some((Self::BeaconChain(block_header), remainder))
672            }
673            RealShardKind::IntermediateShard => {
674                let (block_header, remainder) = IntermediateShardBlock::try_from_bytes(bytes)?;
675                Some((Self::IntermediateShard(block_header), remainder))
676            }
677            RealShardKind::LeafShard => {
678                let (block_header, remainder) = LeafShardBlock::try_from_bytes(bytes)?;
679                Some((Self::LeafShard(block_header), remainder))
680            }
681        }
682    }
683
684    /// Check block's internal consistency.
685    ///
686    /// This is usually not necessary to be called explicitly since full internal consistency is
687    /// checked by [`Self::try_from_bytes()`] internally.
688    ///
689    /// NOTE: This only checks block-level internal consistency, header and block level internal
690    /// consistency is checked separately.
691    #[inline]
692    pub fn is_internally_consistent(&self) -> bool {
693        match self {
694            Self::BeaconChain(block) => block.is_internally_consistent(),
695            Self::IntermediateShard(block) => block.is_internally_consistent(),
696            Self::LeafShard(block) => block.is_internally_consistent(),
697        }
698    }
699
700    /// The same as [`Self::try_from_bytes()`], but for trusted input that skips some consistency
701    /// checks
702    #[inline]
703    pub fn try_from_bytes_unchecked(
704        bytes: &'a [u8],
705        shard_kind: RealShardKind,
706    ) -> Option<(Self, &'a [u8])> {
707        match shard_kind {
708            RealShardKind::BeaconChain => {
709                let (block_header, remainder) = BeaconChainBlock::try_from_bytes_unchecked(bytes)?;
710                Some((Self::BeaconChain(block_header), remainder))
711            }
712            RealShardKind::IntermediateShard => {
713                let (block_header, remainder) =
714                    IntermediateShardBlock::try_from_bytes_unchecked(bytes)?;
715                Some((Self::IntermediateShard(block_header), remainder))
716            }
717            RealShardKind::LeafShard => {
718                let (block_header, remainder) = LeafShardBlock::try_from_bytes_unchecked(bytes)?;
719                Some((Self::LeafShard(block_header), remainder))
720            }
721        }
722    }
723
724    /// Create an owned version of this block
725    #[cfg(feature = "alloc")]
726    #[inline(always)]
727    pub fn to_owned(self) -> OwnedBlock {
728        match self {
729            Self::BeaconChain(block) => block.to_owned().into(),
730            Self::IntermediateShard(block) => block.to_owned().into(),
731            Self::LeafShard(block) => block.to_owned().into(),
732        }
733    }
734}
735
736/// BlockWeight type for fork choice rule.
737///
738/// The smaller the solution range is, the heavier is the block.
739#[derive(
740    Debug,
741    Display,
742    Default,
743    Copy,
744    Clone,
745    Ord,
746    PartialOrd,
747    Eq,
748    PartialEq,
749    Hash,
750    Add,
751    AddAssign,
752    Sub,
753    SubAssign,
754)]
755#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
756#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
757#[repr(C)]
758pub struct BlockWeight(u128);
759
760const impl From<u128> for BlockWeight {
761    #[inline(always)]
762    fn from(value: u128) -> Self {
763        Self(value)
764    }
765}
766
767const impl From<BlockWeight> for u128 {
768    #[inline(always)]
769    fn from(value: BlockWeight) -> Self {
770        value.0
771    }
772}
773
774impl BlockWeight {
775    /// Size in bytes
776    pub const SIZE: usize = size_of::<u128>();
777    /// Zero block weight
778    pub const ZERO: BlockWeight = BlockWeight(0);
779    /// Max block wright
780    pub const MAX: BlockWeight = BlockWeight(u128::MAX);
781
782    /// Derive block weight from provided solution range
783    pub const fn from_solution_range(solution_range: SolutionRange) -> Self {
784        Self::from(u128::from(
785            u64::from(SolutionRange::MAX) - u64::from(solution_range),
786        ))
787    }
788}
789
790/// Aligns bytes to `alignment` and ensures that all padding bytes (if any) are zero
791fn align_to_and_ensure_zero_padding(bytes: &[u8], alignment: Alignment) -> Option<&[u8]> {
792    let padding_len = bytes
793        .as_ptr()
794        .align_offset(usize::from(alignment.get()))
795        .min(bytes.len());
796    let (padding, remainder) = bytes.split_at(padding_len);
797
798    // Padding must be zero
799    if padding.iter().any(|&byte| byte != 0) {
800        return None;
801    }
802
803    Some(remainder)
804}