Skip to main content

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::{LocalSegmentIndex, SegmentRoot};
23use crate::shard::RealShardKind;
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: RealShardKind;
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: RealShardKind = RealShardKind::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, OS, ISB>(
112        own_segments: OS,
113        intermediate_shard_blocks: ISB,
114        pot_checkpoints: &[PotCheckpoints],
115    ) -> Result<OwnedBeaconChainBlockBuilder, OwnedBeaconChainBodyError>
116    where
117        OS: TrustedLen<Item = (LocalSegmentIndex, SegmentRoot)>,
118        ISB: TrustedLen<Item = IntermediateShardBlockInfo<'a>> + Clone + 'a,
119    {
120        Ok(OwnedBeaconChainBlockBuilder {
121            body: OwnedBeaconChainBody::new(
122                own_segments,
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: RealShardKind = RealShardKind::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, OS, LSB>(
276        own_segments: OS,
277        leaf_shard_blocks: LSB,
278    ) -> Result<OwnedIntermediateShardBlockBuilder, OwnedIntermediateShardBodyError>
279    where
280        OS: TrustedLen<Item = (LocalSegmentIndex, SegmentRoot)>,
281        LSB: TrustedLen<Item = LeafShardBlockInfo<'a>> + Clone + 'a,
282    {
283        Ok(OwnedIntermediateShardBlockBuilder {
284            body: OwnedIntermediateShardBody::new(own_segments, 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: RealShardKind = RealShardKind::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<OS>(own_segments: OS) -> Result<OwnedLeafShardBlockBuilder, OwnedLeafShardBodyError>
424    where
425        OS: TrustedLen<Item = (LocalSegmentIndex, SegmentRoot)>,
426    {
427        Ok(OwnedLeafShardBlockBuilder {
428            body_builder: OwnedLeafShardBody::init(own_segments)?,
429        })
430    }
431
432    /// Create owned block from buffers
433    #[inline]
434    pub fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
435        let block = Self {
436            header: OwnedLeafShardHeader::from_buffer(header).ok()?,
437            body: OwnedLeafShardBody::from_buffer(body).ok()?,
438        };
439
440        // TODO: This duplicates parsing done in above constructors
441        if !block.block().is_internally_consistent() {
442            return None;
443        }
444
445        Some(block)
446    }
447
448    /// Get [`LeafShardBlock`] out of [`OwnedLeafShardBlock`]
449    pub fn block(&self) -> LeafShardBlock<'_> {
450        LeafShardBlock {
451            header: self.header.header().clone(),
452            body: *self.body.body(),
453        }
454    }
455}
456
457/// Builder for [`OwnedLeafShardBlock`]
458#[derive(Debug, Clone)]
459pub struct OwnedLeafShardBlockBuilder {
460    body_builder: OwnedLeafShardBlockBodyBuilder,
461}
462
463impl OwnedLeafShardBlockBuilder {
464    /// Add transaction to the body
465    #[inline(always)]
466    pub fn add_transaction<T>(&mut self, transaction: T) -> Result<(), OwnedLeafShardBodyError>
467    where
468        T: WritableBodyTransaction,
469    {
470        self.body_builder.add_transaction(transaction)?;
471
472        Ok(())
473    }
474
475    /// Add header
476    pub fn with_header(
477        self,
478        prefix: &BlockHeaderPrefix,
479        state_root: Blake3Hash,
480        consensus_info: &BlockHeaderConsensusInfo,
481        beacon_chain_info: &BlockHeaderBeaconChainInfo,
482    ) -> OwnedLeafShardBlockUnsealed {
483        let body = self.body_builder.finish();
484        let header = OwnedLeafShardHeader::from_parts(
485            prefix,
486            &BlockHeaderResult {
487                body_root: body.body().root(),
488                state_root,
489            },
490            consensus_info,
491            beacon_chain_info,
492        );
493        OwnedLeafShardBlockUnsealed { body, header }
494    }
495}
496
497/// Owned leaf shard block header, which is not sealed yet
498#[derive(Debug, Clone)]
499pub struct OwnedLeafShardBlockUnsealed {
500    body: OwnedLeafShardBody,
501    header: OwnedLeafShardHeaderUnsealed,
502}
503
504impl OwnedLeafShardBlockUnsealed {
505    /// Hash of the block before seal is applied to it
506    #[inline(always)]
507    pub fn pre_seal_hash(&self) -> Blake3Hash {
508        self.header.pre_seal_hash()
509    }
510
511    /// Add seal and return [`OwnedLeafShardBlock`]
512    pub fn with_seal(self, seal: BlockHeaderSeal<'_>) -> OwnedLeafShardBlock {
513        let header = self.header.with_seal(seal);
514
515        OwnedLeafShardBlock {
516            header,
517            body: self.body,
518        }
519    }
520}
521
522// TODO: A variant that holds both header and body in the same allocation?
523/// An owned version of [`Block`].
524///
525/// It is correctly aligned in memory and well suited for sending and receiving over the network
526/// efficiently or storing in memory or on disk.
527#[derive(Debug, Clone, From)]
528pub enum OwnedBlock {
529    /// Block corresponds to the beacon chain
530    BeaconChain(OwnedBeaconChainBlock),
531    /// Block corresponds to an intermediate shard
532    IntermediateShard(OwnedIntermediateShardBlock),
533    /// Block corresponds to a leaf shard
534    LeafShard(OwnedLeafShardBlock),
535}
536
537impl OwnedBlock {
538    /// Split into header and body
539    #[inline]
540    pub fn split(self) -> (OwnedBlockHeader, OwnedBlockBody) {
541        match self {
542            Self::BeaconChain(block) => {
543                let (header, body) = block.split();
544                (header.into(), body.into())
545            }
546            Self::IntermediateShard(block) => {
547                let (header, body) = block.split();
548                (header.into(), body.into())
549            }
550            Self::LeafShard(block) => {
551                let (header, body) = block.split();
552                (header.into(), body.into())
553            }
554        }
555    }
556
557    /// Block header
558    #[inline(always)]
559    pub fn header(&self) -> BlockHeader<'_> {
560        match self {
561            Self::BeaconChain(block) => BlockHeader::BeaconChain(block.header.header().clone()),
562            Self::IntermediateShard(block) => {
563                BlockHeader::IntermediateShard(block.header.header().clone())
564            }
565            Self::LeafShard(block) => BlockHeader::LeafShard(block.header.header().clone()),
566        }
567    }
568
569    /// Block body
570    #[inline(always)]
571    pub fn body(&self) -> BlockBody<'_> {
572        match self {
573            Self::BeaconChain(block) => BlockBody::BeaconChain(*block.body.body()),
574            Self::IntermediateShard(block) => BlockBody::IntermediateShard(*block.body.body()),
575            Self::LeafShard(block) => BlockBody::LeafShard(*block.body.body()),
576        }
577    }
578
579    // TODO: Unchecked versions of methods that create instances from buffers (here and in
580    //  header/block)?
581    /// Create owned block from buffers
582    #[inline]
583    pub fn from_buffers(
584        header: SharedAlignedBuffer,
585        body: SharedAlignedBuffer,
586        shard_kind: RealShardKind,
587    ) -> Option<Self> {
588        Some(match shard_kind {
589            RealShardKind::BeaconChain => {
590                Self::BeaconChain(OwnedBeaconChainBlock::from_buffers(header, body)?)
591            }
592            RealShardKind::IntermediateShard => {
593                Self::IntermediateShard(OwnedIntermediateShardBlock::from_buffers(header, body)?)
594            }
595            RealShardKind::LeafShard => {
596                Self::LeafShard(OwnedLeafShardBlock::from_buffers(header, body)?)
597            }
598        })
599    }
600
601    /// Get block
602    #[inline(always)]
603    pub fn block(&self) -> Block<'_> {
604        match self {
605            Self::BeaconChain(block) => Block::BeaconChain(block.block()),
606            Self::IntermediateShard(block) => Block::IntermediateShard(block.block()),
607            Self::LeafShard(block) => Block::LeafShard(block.block()),
608        }
609    }
610}