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