ab_core_primitives/block/
owned.rs

1//! Data structures related to the owned version of [`Block`]
2
3use crate::block::body::owned::{
4    GenericOwnedBlockBody, OwnedBeaconChainBody, OwnedBeaconChainBodyError, OwnedBlockBody,
5    OwnedIntermediateShardBody, OwnedIntermediateShardBodyError, OwnedLeafShardBlockBodyBuilder,
6    OwnedLeafShardBody, OwnedLeafShardBodyError, WritableBodyTransaction,
7};
8use crate::block::body::{BlockBody, IntermediateShardBlockInfo, LeafShardBlockInfo};
9use crate::block::header::owned::{
10    GenericOwnedBlockHeader, OwnedBeaconChainHeader, OwnedBeaconChainHeaderError,
11    OwnedBeaconChainHeaderUnsealed, OwnedBlockHeader, OwnedIntermediateShardHeader,
12    OwnedIntermediateShardHeaderError, OwnedIntermediateShardHeaderUnsealed, OwnedLeafShardHeader,
13    OwnedLeafShardHeaderUnsealed,
14};
15use crate::block::header::{
16    BlockHeader, BlockHeaderBeaconChainInfo, BlockHeaderConsensusInfo,
17    BlockHeaderConsensusParameters, BlockHeaderPrefix, BlockHeaderResult, BlockHeaderSeal,
18};
19use crate::block::{BeaconChainBlock, Block, GenericBlock, IntermediateShardBlock, LeafShardBlock};
20use crate::hashes::Blake3Hash;
21use crate::pot::PotCheckpoints;
22use crate::segments::SegmentRoot;
23use crate::shard::ShardKind;
24use ab_aligned_buffer::SharedAlignedBuffer;
25use alloc::vec::Vec;
26use core::fmt;
27use core::iter::TrustedLen;
28use derive_more::From;
29
30/// Generic owned block
31pub trait GenericOwnedBlock: Clone + fmt::Debug + Send + Sync + Into<OwnedBlock> + 'static {
32    /// Shard kind
33    const SHARD_KIND: ShardKind;
34
35    /// Block header type
36    type Header: GenericOwnedBlockHeader;
37    /// Block body type
38    type Body: GenericOwnedBlockBody;
39    /// Block
40    type Block<'a>: GenericBlock<'a>
41    where
42        Self: 'a;
43
44    /// Split into header and body
45    fn split(self) -> (Self::Header, Self::Body);
46
47    /// Block header
48    fn header(&self) -> &Self::Header;
49
50    /// Block body
51    fn body(&self) -> &Self::Body;
52
53    // TODO: Unchecked versions of methods that create instances from buffers (here and in
54    //  header/block)?
55    /// Create owned block from buffers
56    fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self>;
57
58    /// Get regular block out of the owned version
59    fn block(&self) -> Self::Block<'_>;
60}
61
62/// An owned version of [`BeaconChainBlock`].
63///
64/// It is correctly aligned in memory and well suited for sending and receiving over the network
65/// efficiently or storing in memory or on disk.
66#[derive(Debug, Clone)]
67// Prevent creation of potentially broken invariants externally
68#[non_exhaustive]
69pub struct OwnedBeaconChainBlock {
70    /// Block header
71    pub header: OwnedBeaconChainHeader,
72    /// Block body
73    pub body: OwnedBeaconChainBody,
74}
75
76impl GenericOwnedBlock for OwnedBeaconChainBlock {
77    const SHARD_KIND: ShardKind = ShardKind::BeaconChain;
78
79    type Header = OwnedBeaconChainHeader;
80    type Body = OwnedBeaconChainBody;
81    type Block<'a> = BeaconChainBlock<'a>;
82
83    #[inline(always)]
84    fn split(self) -> (Self::Header, Self::Body) {
85        (self.header, self.body)
86    }
87
88    #[inline(always)]
89    fn header(&self) -> &Self::Header {
90        &self.header
91    }
92
93    #[inline(always)]
94    fn body(&self) -> &Self::Body {
95        &self.body
96    }
97
98    #[inline(always)]
99    fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
100        Self::from_buffers(header, body)
101    }
102
103    #[inline(always)]
104    fn block(&self) -> Self::Block<'_> {
105        self.block()
106    }
107}
108
109impl OwnedBeaconChainBlock {
110    /// Initialize building of [`OwnedBeaconChainBlock`]
111    pub fn init<'a, OSR, ISB>(
112        own_segment_roots: OSR,
113        intermediate_shard_blocks: ISB,
114        pot_checkpoints: &[PotCheckpoints],
115    ) -> Result<OwnedBeaconChainBlockBuilder, OwnedBeaconChainBodyError>
116    where
117        OSR: TrustedLen<Item = SegmentRoot>,
118        ISB: TrustedLen<Item = IntermediateShardBlockInfo<'a>> + Clone + 'a,
119    {
120        Ok(OwnedBeaconChainBlockBuilder {
121            body: OwnedBeaconChainBody::new(
122                own_segment_roots,
123                intermediate_shard_blocks,
124                pot_checkpoints,
125            )?,
126        })
127    }
128
129    /// Create owned block from buffers
130    #[inline]
131    pub fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
132        let block = Self {
133            header: OwnedBeaconChainHeader::from_buffer(header).ok()?,
134            body: OwnedBeaconChainBody::from_buffer(body).ok()?,
135        };
136
137        // TODO: This duplicates parsing done in above constructors
138        if !block.block().is_internally_consistent() {
139            return None;
140        }
141
142        Some(block)
143    }
144
145    /// Get [`BeaconChainBlock`] out of [`OwnedBeaconChainBlock`]
146    pub fn block(&self) -> BeaconChainBlock<'_> {
147        BeaconChainBlock {
148            header: self.header.header().clone(),
149            body: *self.body.body(),
150        }
151    }
152}
153
154/// Builder for [`OwnedBeaconChainBlock`]
155#[derive(Debug, Clone)]
156pub struct OwnedBeaconChainBlockBuilder {
157    body: OwnedBeaconChainBody,
158}
159
160impl OwnedBeaconChainBlockBuilder {
161    /// Add header
162    pub fn with_header(
163        self,
164        prefix: &BlockHeaderPrefix,
165        state_root: Blake3Hash,
166        consensus_info: &BlockHeaderConsensusInfo,
167        consensus_parameters: BlockHeaderConsensusParameters<'_>,
168    ) -> Result<OwnedBeaconChainBlockUnsealed, OwnedBeaconChainHeaderError> {
169        let body = self.body;
170        let header = OwnedBeaconChainHeader::from_parts(
171            prefix,
172            &BlockHeaderResult {
173                body_root: body.body().root(),
174                state_root,
175            },
176            consensus_info,
177            &body
178                .body()
179                .intermediate_shard_blocks()
180                .iter()
181                .map(|block| *block.header.root())
182                .collect::<Vec<_>>(),
183            consensus_parameters,
184        )?;
185
186        Ok(OwnedBeaconChainBlockUnsealed { body, header })
187    }
188}
189
190/// Owned beacon chain block header, which is not sealed yet
191#[derive(Debug, Clone)]
192pub struct OwnedBeaconChainBlockUnsealed {
193    body: OwnedBeaconChainBody,
194    header: OwnedBeaconChainHeaderUnsealed,
195}
196
197impl OwnedBeaconChainBlockUnsealed {
198    /// Hash of the block before seal is applied to it
199    #[inline(always)]
200    pub fn pre_seal_hash(&self) -> Blake3Hash {
201        self.header.pre_seal_hash()
202    }
203
204    /// Add seal and return [`OwnedBeaconChainBlock`]
205    pub fn with_seal(self, seal: BlockHeaderSeal<'_>) -> OwnedBeaconChainBlock {
206        let header = self.header.with_seal(seal);
207
208        OwnedBeaconChainBlock {
209            header,
210            body: self.body,
211        }
212    }
213}
214
215/// Errors for [`OwnedIntermediateShardBlock`]
216#[derive(Debug, thiserror::Error)]
217pub enum OwnedIntermediateShardBlockError {
218    /// Intermediate shard block header error
219    #[error("Intermediate shard block header error: {0}")]
220    Header(#[from] OwnedIntermediateShardHeaderError),
221    /// Intermediate shard block body error
222    #[error("Intermediate shard block body error: {0}")]
223    Body(#[from] OwnedIntermediateShardBodyError),
224}
225
226/// An owned version of [`IntermediateShardBlock`].
227///
228/// It is correctly aligned in memory and well suited for sending and receiving over the network
229/// efficiently or storing in memory or on disk.
230#[derive(Debug, Clone)]
231// Prevent creation of potentially broken invariants externally
232#[non_exhaustive]
233pub struct OwnedIntermediateShardBlock {
234    /// Block header
235    pub header: OwnedIntermediateShardHeader,
236    /// Block body
237    pub body: OwnedIntermediateShardBody,
238}
239
240impl GenericOwnedBlock for OwnedIntermediateShardBlock {
241    const SHARD_KIND: ShardKind = ShardKind::IntermediateShard;
242
243    type Header = OwnedIntermediateShardHeader;
244    type Body = OwnedIntermediateShardBody;
245    type Block<'a> = IntermediateShardBlock<'a>;
246
247    #[inline(always)]
248    fn split(self) -> (Self::Header, Self::Body) {
249        (self.header, self.body)
250    }
251
252    #[inline(always)]
253    fn header(&self) -> &Self::Header {
254        &self.header
255    }
256
257    #[inline(always)]
258    fn body(&self) -> &Self::Body {
259        &self.body
260    }
261
262    #[inline(always)]
263    fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
264        Self::from_buffers(header, body)
265    }
266
267    #[inline(always)]
268    fn block(&self) -> Self::Block<'_> {
269        self.block()
270    }
271}
272
273impl OwnedIntermediateShardBlock {
274    /// Initialize building of [`OwnedIntermediateShardBlock`]
275    pub fn init<'a, OSR, LSB>(
276        own_segment_roots: OSR,
277        leaf_shard_blocks: LSB,
278    ) -> Result<OwnedIntermediateShardBlockBuilder, OwnedIntermediateShardBodyError>
279    where
280        OSR: TrustedLen<Item = SegmentRoot>,
281        LSB: TrustedLen<Item = LeafShardBlockInfo<'a>> + Clone + 'a,
282    {
283        Ok(OwnedIntermediateShardBlockBuilder {
284            body: OwnedIntermediateShardBody::new(own_segment_roots, leaf_shard_blocks)?,
285        })
286    }
287
288    /// Create owned block from buffers
289    #[inline]
290    pub fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
291        let block = Self {
292            header: OwnedIntermediateShardHeader::from_buffer(header).ok()?,
293            body: OwnedIntermediateShardBody::from_buffer(body).ok()?,
294        };
295
296        // TODO: This duplicates parsing done in above constructors
297        if !block.block().is_internally_consistent() {
298            return None;
299        }
300
301        Some(block)
302    }
303
304    /// Get [`IntermediateShardBlock`] out of [`OwnedIntermediateShardBlock`]
305    pub fn block(&self) -> IntermediateShardBlock<'_> {
306        IntermediateShardBlock {
307            header: self.header.header().clone(),
308            body: *self.body.body(),
309        }
310    }
311}
312
313/// Builder for [`OwnedIntermediateShardBlock`]
314#[derive(Debug, Clone)]
315pub struct OwnedIntermediateShardBlockBuilder {
316    body: OwnedIntermediateShardBody,
317}
318
319impl OwnedIntermediateShardBlockBuilder {
320    /// Add header
321    pub fn with_header(
322        self,
323        prefix: &BlockHeaderPrefix,
324        state_root: Blake3Hash,
325        consensus_info: &BlockHeaderConsensusInfo,
326        beacon_chain_info: &BlockHeaderBeaconChainInfo,
327    ) -> Result<OwnedIntermediateShardBlockUnsealed, OwnedIntermediateShardHeaderError> {
328        let body = self.body;
329        let header = OwnedIntermediateShardHeader::from_parts(
330            prefix,
331            &BlockHeaderResult {
332                body_root: body.body().root(),
333                state_root,
334            },
335            consensus_info,
336            beacon_chain_info,
337            &body
338                .body()
339                .leaf_shard_blocks()
340                .iter()
341                .map(|block| *block.header.root())
342                .collect::<Vec<_>>(),
343        )?;
344
345        Ok(OwnedIntermediateShardBlockUnsealed { body, header })
346    }
347}
348
349/// Owned intermediate shard block header, which is not sealed yet
350#[derive(Debug, Clone)]
351pub struct OwnedIntermediateShardBlockUnsealed {
352    body: OwnedIntermediateShardBody,
353    header: OwnedIntermediateShardHeaderUnsealed,
354}
355
356impl OwnedIntermediateShardBlockUnsealed {
357    /// Hash of the block before seal is applied to it
358    #[inline(always)]
359    pub fn pre_seal_hash(&self) -> Blake3Hash {
360        self.header.pre_seal_hash()
361    }
362
363    /// Add seal and return [`OwnedIntermediateShardBlock`]
364    pub fn with_seal(self, seal: BlockHeaderSeal<'_>) -> OwnedIntermediateShardBlock {
365        let header = self.header.with_seal(seal);
366
367        OwnedIntermediateShardBlock {
368            header,
369            body: self.body,
370        }
371    }
372}
373
374/// An owned version of [`LeafShardBlock`].
375///
376/// It is correctly aligned in memory and well suited for sending and receiving over the network
377/// efficiently or storing in memory or on disk.
378#[derive(Debug, Clone)]
379// Prevent creation of potentially broken invariants externally
380#[non_exhaustive]
381pub struct OwnedLeafShardBlock {
382    /// Block header
383    pub header: OwnedLeafShardHeader,
384    /// Block body
385    pub body: OwnedLeafShardBody,
386}
387
388impl GenericOwnedBlock for OwnedLeafShardBlock {
389    const SHARD_KIND: ShardKind = ShardKind::LeafShard;
390
391    type Header = OwnedLeafShardHeader;
392    type Body = OwnedLeafShardBody;
393    type Block<'a> = LeafShardBlock<'a>;
394
395    #[inline(always)]
396    fn split(self) -> (Self::Header, Self::Body) {
397        (self.header, self.body)
398    }
399
400    #[inline(always)]
401    fn header(&self) -> &Self::Header {
402        &self.header
403    }
404
405    #[inline(always)]
406    fn body(&self) -> &Self::Body {
407        &self.body
408    }
409
410    #[inline(always)]
411    fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
412        Self::from_buffers(header, body)
413    }
414
415    #[inline(always)]
416    fn block(&self) -> Self::Block<'_> {
417        self.block()
418    }
419}
420
421impl OwnedLeafShardBlock {
422    /// Initialize building of [`OwnedLeafShardBlock`]
423    pub fn init<OSR>(
424        own_segment_roots: OSR,
425    ) -> Result<OwnedLeafShardBlockBuilder, OwnedLeafShardBodyError>
426    where
427        OSR: TrustedLen<Item = SegmentRoot>,
428    {
429        Ok(OwnedLeafShardBlockBuilder {
430            body_builder: OwnedLeafShardBody::init(own_segment_roots)?,
431        })
432    }
433
434    /// Create owned block from buffers
435    #[inline]
436    pub fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
437        let block = Self {
438            header: OwnedLeafShardHeader::from_buffer(header).ok()?,
439            body: OwnedLeafShardBody::from_buffer(body).ok()?,
440        };
441
442        // TODO: This duplicates parsing done in above constructors
443        if !block.block().is_internally_consistent() {
444            return None;
445        }
446
447        Some(block)
448    }
449
450    /// Get [`LeafShardBlock`] out of [`OwnedLeafShardBlock`]
451    pub fn block(&self) -> LeafShardBlock<'_> {
452        LeafShardBlock {
453            header: self.header.header().clone(),
454            body: *self.body.body(),
455        }
456    }
457}
458
459/// Builder for [`OwnedLeafShardBlock`]
460#[derive(Debug, Clone)]
461pub struct OwnedLeafShardBlockBuilder {
462    body_builder: OwnedLeafShardBlockBodyBuilder,
463}
464
465impl OwnedLeafShardBlockBuilder {
466    /// Add transaction to the body
467    #[inline(always)]
468    pub fn add_transaction<T>(&mut self, transaction: T) -> Result<(), OwnedLeafShardBodyError>
469    where
470        T: WritableBodyTransaction,
471    {
472        self.body_builder.add_transaction(transaction)?;
473
474        Ok(())
475    }
476
477    /// Add header
478    pub fn with_header(
479        self,
480        prefix: &BlockHeaderPrefix,
481        state_root: Blake3Hash,
482        consensus_info: &BlockHeaderConsensusInfo,
483        beacon_chain_info: &BlockHeaderBeaconChainInfo,
484    ) -> OwnedLeafShardBlockUnsealed {
485        let body = self.body_builder.finish();
486        let header = OwnedLeafShardHeader::from_parts(
487            prefix,
488            &BlockHeaderResult {
489                body_root: body.body().root(),
490                state_root,
491            },
492            consensus_info,
493            beacon_chain_info,
494        );
495        OwnedLeafShardBlockUnsealed { body, header }
496    }
497}
498
499/// Owned leaf shard block header, which is not sealed yet
500#[derive(Debug, Clone)]
501pub struct OwnedLeafShardBlockUnsealed {
502    body: OwnedLeafShardBody,
503    header: OwnedLeafShardHeaderUnsealed,
504}
505
506impl OwnedLeafShardBlockUnsealed {
507    /// Hash of the block before seal is applied to it
508    #[inline(always)]
509    pub fn pre_seal_hash(&self) -> Blake3Hash {
510        self.header.pre_seal_hash()
511    }
512
513    /// Add seal and return [`OwnedLeafShardBlock`]
514    pub fn with_seal(self, seal: BlockHeaderSeal<'_>) -> OwnedLeafShardBlock {
515        let header = self.header.with_seal(seal);
516
517        OwnedLeafShardBlock {
518            header,
519            body: self.body,
520        }
521    }
522}
523
524// TODO: A variant that holds both header and body in the same allocation?
525/// An owned version of [`Block`].
526///
527/// It is correctly aligned in memory and well suited for sending and receiving over the network
528/// efficiently or storing in memory or on disk.
529#[derive(Debug, Clone, From)]
530pub enum OwnedBlock {
531    /// Block corresponds to the beacon chain
532    BeaconChain(OwnedBeaconChainBlock),
533    /// Block corresponds to an intermediate shard
534    IntermediateShard(OwnedIntermediateShardBlock),
535    /// Block corresponds to a leaf shard
536    LeafShard(OwnedLeafShardBlock),
537}
538
539impl OwnedBlock {
540    /// Split into header and body
541    #[inline]
542    pub fn split(self) -> (OwnedBlockHeader, OwnedBlockBody) {
543        match self {
544            Self::BeaconChain(block) => {
545                let (header, body) = block.split();
546                (header.into(), body.into())
547            }
548            Self::IntermediateShard(block) => {
549                let (header, body) = block.split();
550                (header.into(), body.into())
551            }
552            Self::LeafShard(block) => {
553                let (header, body) = block.split();
554                (header.into(), body.into())
555            }
556        }
557    }
558
559    /// Block header
560    #[inline(always)]
561    pub fn header(&self) -> BlockHeader<'_> {
562        match self {
563            Self::BeaconChain(block) => BlockHeader::BeaconChain(block.header.header().clone()),
564            Self::IntermediateShard(block) => {
565                BlockHeader::IntermediateShard(block.header.header().clone())
566            }
567            Self::LeafShard(block) => BlockHeader::LeafShard(block.header.header().clone()),
568        }
569    }
570
571    /// Block body
572    #[inline(always)]
573    pub fn body(&self) -> BlockBody<'_> {
574        match self {
575            Self::BeaconChain(block) => BlockBody::BeaconChain(*block.body.body()),
576            Self::IntermediateShard(block) => BlockBody::IntermediateShard(*block.body.body()),
577            Self::LeafShard(block) => BlockBody::LeafShard(*block.body.body()),
578        }
579    }
580
581    // TODO: Unchecked versions of methods that create instances from buffers (here and in
582    //  header/block)?
583    /// Create owned block from buffers
584    #[inline]
585    pub fn from_buffers(
586        header: SharedAlignedBuffer,
587        body: SharedAlignedBuffer,
588        shard_kind: ShardKind,
589    ) -> Option<Self> {
590        Some(match shard_kind {
591            ShardKind::BeaconChain => {
592                Self::BeaconChain(OwnedBeaconChainBlock::from_buffers(header, body)?)
593            }
594            ShardKind::IntermediateShard => {
595                Self::IntermediateShard(OwnedIntermediateShardBlock::from_buffers(header, body)?)
596            }
597            ShardKind::LeafShard => {
598                Self::LeafShard(OwnedLeafShardBlock::from_buffers(header, body)?)
599            }
600            ShardKind::Phantom | ShardKind::Invalid => {
601                // Blocks for such shards do not exist
602                return None;
603            }
604        })
605    }
606
607    /// Get block
608    #[inline(always)]
609    pub fn block(&self) -> Block<'_> {
610        match self {
611            Self::BeaconChain(block) => Block::BeaconChain(block.block()),
612            Self::IntermediateShard(block) => Block::IntermediateShard(block.block()),
613            Self::LeafShard(block) => Block::LeafShard(block.block()),
614        }
615    }
616}