1#[cfg(all(
6 test,
7 any(
8 not(miri),
9 not(any(
10 feature = "ed25519",
11 feature = "parallel",
12 feature = "scale-codec",
13 feature = "serde"
14 )),
15 all(
16 feature = "ed25519",
17 feature = "parallel",
18 feature = "scale-codec",
19 feature = "serde"
20 ),
21 ),
22))]
23mod tests;
24
25use crate::block::body::owned::{
26 GenericOwnedBlockBody, OwnedBeaconChainBody, OwnedBeaconChainBodyError, OwnedBlockBody,
27 OwnedIntermediateShardBody, OwnedIntermediateShardBodyError, OwnedLeafShardBlockBodyBuilder,
28 OwnedLeafShardBody, OwnedLeafShardBodyError, WritableBodyTransaction,
29};
30use crate::block::body::{BlockBody, IntermediateShardBlockInfo, LeafShardBlockInfo};
31use crate::block::header::owned::{
32 GenericOwnedBlockHeader, OwnedBeaconChainHeader, OwnedBeaconChainHeaderUnsealed,
33 OwnedBlockHeader, OwnedIntermediateShardHeader, OwnedIntermediateShardHeaderUnsealed,
34 OwnedLeafShardHeader, OwnedLeafShardHeaderUnsealed,
35};
36use crate::block::header::{
37 BlockHeader, BlockHeaderBeaconChainInfo, BlockHeaderConsensusInfo,
38 BlockHeaderConsensusParameters, BlockHeaderConsistencyError, BlockHeaderPrefix,
39 BlockHeaderResult, BlockHeaderSeal,
40};
41use crate::block::{BeaconChainBlock, Block, GenericBlock, IntermediateShardBlock, LeafShardBlock};
42use crate::hashes::Blake3Hash;
43use crate::pot::PotCheckpoints;
44use crate::segments::{LocalSegmentIndex, SegmentRoot};
45use crate::shard::{RealShardKind, ShardIndex};
46use ab_aligned_buffer::SharedAlignedBuffer;
47use core::any::Any;
48use core::fmt;
49use core::iter::TrustedLen;
50use derive_more::From;
51
52pub impl(self) trait GenericOwnedBlock:
57 Clone + fmt::Debug + Send + Sync + Into<OwnedBlock> + Any + 'static
58{
59 const SHARD_KIND: RealShardKind;
61
62 type Header: GenericOwnedBlockHeader;
64 type Body: GenericOwnedBlockBody;
66 type Block<'a>: GenericBlock<'a>
68 where
69 Self: 'a;
70
71 fn split(self) -> (Self::Header, Self::Body);
73
74 fn header(&self) -> &Self::Header;
76
77 fn body(&self) -> &Self::Body;
79
80 fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self>;
82
83 fn block(&self) -> Self::Block<'_>;
85}
86
87#[derive(Debug, Clone)]
95pub struct OwnedBeaconChainBlock {
96 pub mut(self) header: OwnedBeaconChainHeader,
98 pub mut(self) body: OwnedBeaconChainBody,
100}
101
102impl GenericOwnedBlock for OwnedBeaconChainBlock {
103 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
104
105 type Header = OwnedBeaconChainHeader;
106 type Body = OwnedBeaconChainBody;
107 type Block<'a> = BeaconChainBlock<'a>;
108
109 #[inline(always)]
110 fn split(self) -> (Self::Header, Self::Body) {
111 (self.header, self.body)
112 }
113
114 #[inline(always)]
115 fn header(&self) -> &Self::Header {
116 &self.header
117 }
118
119 #[inline(always)]
120 fn body(&self) -> &Self::Body {
121 &self.body
122 }
123
124 #[inline(always)]
125 fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
126 Self::from_buffers(header, body)
127 }
128
129 #[inline(always)]
130 fn block(&self) -> Self::Block<'_> {
131 self.block()
132 }
133}
134
135impl OwnedBeaconChainBlock {
136 pub fn init<'a, OS, ISB>(
138 own_segments: OS,
139 intermediate_shard_blocks: ISB,
140 pot_checkpoints: &[PotCheckpoints],
141 ) -> Result<OwnedBeaconChainBlockBuilder, OwnedBeaconChainBodyError>
142 where
143 OS: TrustedLen<Item = (LocalSegmentIndex, SegmentRoot)>,
144 ISB: TrustedLen<Item = IntermediateShardBlockInfo<'a>> + Clone + 'a,
145 {
146 Ok(OwnedBeaconChainBlockBuilder {
147 body: OwnedBeaconChainBody::new(
148 own_segments,
149 intermediate_shard_blocks,
150 pot_checkpoints,
151 )?,
152 })
153 }
154
155 #[inline]
157 pub fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
158 let block = Self {
159 header: OwnedBeaconChainHeader::from_buffer(header).ok()?,
160 body: OwnedBeaconChainBody::from_buffer(body).ok()?,
161 };
162
163 if !block.block().is_internally_consistent() {
164 return None;
165 }
166
167 Some(block)
168 }
169
170 #[inline(always)]
173 pub(super) fn from_block(block: BeaconChainBlock<'_>) -> Self {
174 Self {
175 header: block.header.to_owned(),
176 body: block.body.to_owned(),
177 }
178 }
179
180 pub fn block(&self) -> BeaconChainBlock<'_> {
182 BeaconChainBlock {
183 header: self.header.header().clone(),
184 body: *self.body.body(),
185 }
186 }
187}
188
189#[derive(Debug, Clone)]
191pub struct OwnedBeaconChainBlockBuilder {
192 body: OwnedBeaconChainBody,
193}
194
195impl OwnedBeaconChainBlockBuilder {
196 pub fn with_header(
201 self,
202 prefix: &BlockHeaderPrefix,
203 state_root: Blake3Hash,
204 consensus_info: &BlockHeaderConsensusInfo,
205 consensus_parameters: &BlockHeaderConsensusParameters<'_>,
206 ) -> Result<OwnedBeaconChainBlockUnsealed, BlockHeaderConsistencyError> {
207 let body = self.body;
208 let header = OwnedBeaconChainHeader::from_parts(
209 prefix,
210 &BlockHeaderResult {
211 body_root: body.body().root(),
212 state_root,
213 },
214 consensus_info,
215 &body.body().intermediate_shard_blocks().headers_root(),
216 consensus_parameters,
217 )?;
218
219 Ok(OwnedBeaconChainBlockUnsealed { body, header })
220 }
221}
222
223#[derive(Debug, Clone)]
225pub struct OwnedBeaconChainBlockUnsealed {
226 body: OwnedBeaconChainBody,
227 header: OwnedBeaconChainHeaderUnsealed,
228}
229
230impl OwnedBeaconChainBlockUnsealed {
231 #[inline(always)]
233 pub fn pre_seal_hash(&self) -> Blake3Hash {
234 self.header.pre_seal_hash()
235 }
236
237 pub fn with_seal(
241 self,
242 seal: BlockHeaderSeal<'_>,
243 ) -> Result<OwnedBeaconChainBlock, BlockHeaderConsistencyError> {
244 let header = self.header.with_seal(seal)?;
245
246 Ok(OwnedBeaconChainBlock {
247 header,
248 body: self.body,
249 })
250 }
251}
252
253#[derive(Debug, Clone)]
261pub struct OwnedIntermediateShardBlock {
262 pub mut(self) header: OwnedIntermediateShardHeader,
264 pub mut(self) body: OwnedIntermediateShardBody,
266}
267
268impl GenericOwnedBlock for OwnedIntermediateShardBlock {
269 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
270
271 type Header = OwnedIntermediateShardHeader;
272 type Body = OwnedIntermediateShardBody;
273 type Block<'a> = IntermediateShardBlock<'a>;
274
275 #[inline(always)]
276 fn split(self) -> (Self::Header, Self::Body) {
277 (self.header, self.body)
278 }
279
280 #[inline(always)]
281 fn header(&self) -> &Self::Header {
282 &self.header
283 }
284
285 #[inline(always)]
286 fn body(&self) -> &Self::Body {
287 &self.body
288 }
289
290 #[inline(always)]
291 fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
292 Self::from_buffers(header, body)
293 }
294
295 #[inline(always)]
296 fn block(&self) -> Self::Block<'_> {
297 self.block()
298 }
299}
300
301impl OwnedIntermediateShardBlock {
302 pub fn init<'a, OS, LSB>(
304 own_segments: OS,
305 leaf_shard_blocks: LSB,
306 ) -> Result<OwnedIntermediateShardBlockBuilder, OwnedIntermediateShardBodyError>
307 where
308 OS: TrustedLen<Item = (LocalSegmentIndex, SegmentRoot)>,
309 LSB: TrustedLen<Item = LeafShardBlockInfo<'a>> + Clone + 'a,
310 {
311 Ok(OwnedIntermediateShardBlockBuilder {
312 body: OwnedIntermediateShardBody::new(own_segments, leaf_shard_blocks)?,
313 })
314 }
315
316 #[inline]
318 pub fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
319 let block = Self {
320 header: OwnedIntermediateShardHeader::from_buffer(header).ok()?,
321 body: OwnedIntermediateShardBody::from_buffer(body).ok()?,
322 };
323
324 if !block.block().is_internally_consistent() {
325 return None;
326 }
327
328 Some(block)
329 }
330
331 #[inline(always)]
334 pub(super) fn from_block(block: IntermediateShardBlock<'_>) -> Self {
335 Self {
336 header: block.header.to_owned(),
337 body: block.body.to_owned(),
338 }
339 }
340
341 pub fn block(&self) -> IntermediateShardBlock<'_> {
343 IntermediateShardBlock {
344 header: self.header.header().clone(),
345 body: *self.body.body(),
346 }
347 }
348}
349
350#[derive(Debug, Copy, Clone, Eq, PartialEq, thiserror::Error)]
352pub enum OwnedIntermediateShardBlockBuilderError {
353 #[error("Invalid header parts: {error}")]
355 InvalidHeaderParts {
356 #[from]
358 error: BlockHeaderConsistencyError,
359 },
360 #[error("Leaf shard block of shard {leaf_shard_index} is not a child of shard {shard_index}")]
362 LeafShardBlockOfAnotherShard {
363 shard_index: ShardIndex,
365 leaf_shard_index: ShardIndex,
367 },
368}
369
370#[derive(Debug, Clone)]
372pub struct OwnedIntermediateShardBlockBuilder {
373 body: OwnedIntermediateShardBody,
374}
375
376impl OwnedIntermediateShardBlockBuilder {
377 pub fn with_header(
382 self,
383 prefix: &BlockHeaderPrefix,
384 state_root: Blake3Hash,
385 consensus_info: &BlockHeaderConsensusInfo,
386 beacon_chain_info: &BlockHeaderBeaconChainInfo,
387 ) -> Result<OwnedIntermediateShardBlockUnsealed, OwnedIntermediateShardBlockBuilderError> {
388 let body = self.body;
389 let header = OwnedIntermediateShardHeader::from_parts(
390 prefix,
391 &BlockHeaderResult {
392 body_root: body.body().root(),
393 state_root,
394 },
395 consensus_info,
396 beacon_chain_info,
397 &body.body().leaf_shard_blocks().headers_root(),
398 )?;
399
400 if let Some(leaf_shard_index) =
401 IntermediateShardBlock::find_leaf_shard_block_of_another_shard(
402 body.body().leaf_shard_blocks(),
403 prefix.shard_index,
404 )
405 {
406 return Err(
407 OwnedIntermediateShardBlockBuilderError::LeafShardBlockOfAnotherShard {
408 shard_index: prefix.shard_index,
409 leaf_shard_index,
410 },
411 );
412 }
413
414 Ok(OwnedIntermediateShardBlockUnsealed { body, header })
415 }
416}
417
418#[derive(Debug, Clone)]
420pub struct OwnedIntermediateShardBlockUnsealed {
421 body: OwnedIntermediateShardBody,
422 header: OwnedIntermediateShardHeaderUnsealed,
423}
424
425impl OwnedIntermediateShardBlockUnsealed {
426 #[inline(always)]
428 pub fn pre_seal_hash(&self) -> Blake3Hash {
429 self.header.pre_seal_hash()
430 }
431
432 pub fn with_seal(
436 self,
437 seal: BlockHeaderSeal<'_>,
438 ) -> Result<OwnedIntermediateShardBlock, BlockHeaderConsistencyError> {
439 let header = self.header.with_seal(seal)?;
440
441 Ok(OwnedIntermediateShardBlock {
442 header,
443 body: self.body,
444 })
445 }
446}
447
448#[derive(Debug, Clone)]
456pub struct OwnedLeafShardBlock {
457 pub mut(self) header: OwnedLeafShardHeader,
459 pub mut(self) body: OwnedLeafShardBody,
461}
462
463impl GenericOwnedBlock for OwnedLeafShardBlock {
464 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
465
466 type Header = OwnedLeafShardHeader;
467 type Body = OwnedLeafShardBody;
468 type Block<'a> = LeafShardBlock<'a>;
469
470 #[inline(always)]
471 fn split(self) -> (Self::Header, Self::Body) {
472 (self.header, self.body)
473 }
474
475 #[inline(always)]
476 fn header(&self) -> &Self::Header {
477 &self.header
478 }
479
480 #[inline(always)]
481 fn body(&self) -> &Self::Body {
482 &self.body
483 }
484
485 #[inline(always)]
486 fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
487 Self::from_buffers(header, body)
488 }
489
490 #[inline(always)]
491 fn block(&self) -> Self::Block<'_> {
492 self.block()
493 }
494}
495
496impl OwnedLeafShardBlock {
497 pub fn init<OS>(own_segments: OS) -> Result<OwnedLeafShardBlockBuilder, OwnedLeafShardBodyError>
499 where
500 OS: TrustedLen<Item = (LocalSegmentIndex, SegmentRoot)>,
501 {
502 Ok(OwnedLeafShardBlockBuilder {
503 body_builder: OwnedLeafShardBody::init(own_segments)?,
504 })
505 }
506
507 #[inline]
509 pub fn from_buffers(header: SharedAlignedBuffer, body: SharedAlignedBuffer) -> Option<Self> {
510 let block = Self {
511 header: OwnedLeafShardHeader::from_buffer(header).ok()?,
512 body: OwnedLeafShardBody::from_buffer(body).ok()?,
513 };
514
515 if !block.block().is_internally_consistent() {
516 return None;
517 }
518
519 Some(block)
520 }
521
522 #[inline(always)]
525 pub(super) fn from_block(block: LeafShardBlock<'_>) -> Self {
526 Self {
527 header: block.header.to_owned(),
528 body: block.body.to_owned(),
529 }
530 }
531
532 pub fn block(&self) -> LeafShardBlock<'_> {
534 LeafShardBlock {
535 header: self.header.header().clone(),
536 body: *self.body.body(),
537 }
538 }
539}
540
541#[derive(Debug, Clone)]
543pub struct OwnedLeafShardBlockBuilder {
544 body_builder: OwnedLeafShardBlockBodyBuilder,
545}
546
547impl OwnedLeafShardBlockBuilder {
548 #[inline(always)]
550 pub fn add_transaction<T>(&mut self, transaction: T) -> Result<(), OwnedLeafShardBodyError>
551 where
552 T: WritableBodyTransaction,
553 {
554 self.body_builder.add_transaction(transaction)?;
555
556 Ok(())
557 }
558
559 pub fn with_header(
564 self,
565 prefix: &BlockHeaderPrefix,
566 state_root: Blake3Hash,
567 consensus_info: &BlockHeaderConsensusInfo,
568 beacon_chain_info: &BlockHeaderBeaconChainInfo,
569 ) -> Result<OwnedLeafShardBlockUnsealed, BlockHeaderConsistencyError> {
570 let body = self.body_builder.finish();
571 let header = OwnedLeafShardHeader::from_parts(
572 prefix,
573 &BlockHeaderResult {
574 body_root: body.body().root(),
575 state_root,
576 },
577 consensus_info,
578 beacon_chain_info,
579 )?;
580 Ok(OwnedLeafShardBlockUnsealed { body, header })
581 }
582}
583
584#[derive(Debug, Clone)]
586pub struct OwnedLeafShardBlockUnsealed {
587 body: OwnedLeafShardBody,
588 header: OwnedLeafShardHeaderUnsealed,
589}
590
591impl OwnedLeafShardBlockUnsealed {
592 #[inline(always)]
594 pub fn pre_seal_hash(&self) -> Blake3Hash {
595 self.header.pre_seal_hash()
596 }
597
598 pub fn with_seal(
602 self,
603 seal: BlockHeaderSeal<'_>,
604 ) -> Result<OwnedLeafShardBlock, BlockHeaderConsistencyError> {
605 let header = self.header.with_seal(seal)?;
606
607 Ok(OwnedLeafShardBlock {
608 header,
609 body: self.body,
610 })
611 }
612}
613
614#[derive(Debug, Clone, From)]
620pub enum OwnedBlock {
621 BeaconChain(OwnedBeaconChainBlock),
623 IntermediateShard(OwnedIntermediateShardBlock),
625 LeafShard(OwnedLeafShardBlock),
627}
628
629impl OwnedBlock {
630 #[inline]
632 pub fn split(self) -> (OwnedBlockHeader, OwnedBlockBody) {
633 match self {
634 Self::BeaconChain(block) => {
635 let (header, body) = block.split();
636 (header.into(), body.into())
637 }
638 Self::IntermediateShard(block) => {
639 let (header, body) = block.split();
640 (header.into(), body.into())
641 }
642 Self::LeafShard(block) => {
643 let (header, body) = block.split();
644 (header.into(), body.into())
645 }
646 }
647 }
648
649 #[inline(always)]
651 pub fn header(&self) -> BlockHeader<'_> {
652 match self {
653 Self::BeaconChain(block) => BlockHeader::BeaconChain(block.header.header().clone()),
654 Self::IntermediateShard(block) => {
655 BlockHeader::IntermediateShard(block.header.header().clone())
656 }
657 Self::LeafShard(block) => BlockHeader::LeafShard(block.header.header().clone()),
658 }
659 }
660
661 #[inline(always)]
663 pub fn body(&self) -> BlockBody<'_> {
664 match self {
665 Self::BeaconChain(block) => BlockBody::BeaconChain(*block.body.body()),
666 Self::IntermediateShard(block) => BlockBody::IntermediateShard(*block.body.body()),
667 Self::LeafShard(block) => BlockBody::LeafShard(*block.body.body()),
668 }
669 }
670
671 #[inline]
673 pub fn from_buffers(
674 header: SharedAlignedBuffer,
675 body: SharedAlignedBuffer,
676 shard_kind: RealShardKind,
677 ) -> Option<Self> {
678 Some(match shard_kind {
679 RealShardKind::BeaconChain => {
680 Self::BeaconChain(OwnedBeaconChainBlock::from_buffers(header, body)?)
681 }
682 RealShardKind::IntermediateShard => {
683 Self::IntermediateShard(OwnedIntermediateShardBlock::from_buffers(header, body)?)
684 }
685 RealShardKind::LeafShard => {
686 Self::LeafShard(OwnedLeafShardBlock::from_buffers(header, body)?)
687 }
688 })
689 }
690
691 #[inline(always)]
693 pub fn block(&self) -> Block<'_> {
694 match self {
695 Self::BeaconChain(block) => Block::BeaconChain(block.block()),
696 Self::IntermediateShard(block) => Block::IntermediateShard(block.block()),
697 Self::LeafShard(block) => Block::LeafShard(block.block()),
698 }
699 }
700}