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