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