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