1#[cfg(feature = "alloc")]
4pub mod owned;
5
6#[cfg(feature = "alloc")]
7use crate::block::body::owned::{
8 GenericOwnedBlockBody, OwnedBeaconChainBody, OwnedBlockBody, OwnedIntermediateShardBody,
9 OwnedLeafShardBody,
10};
11use crate::block::header::{IntermediateShardHeader, LeafShardHeader};
12use crate::block::{BlockNumber, align_to_and_ensure_zero_padding};
13use crate::hashes::Blake3Hash;
14use crate::pot::PotCheckpoints;
15use crate::segments::{LocalSegmentIndex, SegmentRoot};
16use crate::shard::{RealShardKind, ShardIndex};
17use crate::transaction::Transaction;
18use ab_blake3::{BLOCK_LEN, OUT_LEN, single_block_hash};
19use ab_io_type::trivial_type::TrivialType;
20use ab_io_type::unaligned::Unaligned;
21use ab_merkle_tree::balanced::BalancedMerkleTree;
22use ab_merkle_tree::unbalanced::UnbalancedMerkleTree;
23use core::iter::TrustedLen;
24use core::{array, cmp, fmt, iter, slice};
25use derive_more::From;
26use yoke::Yokeable;
27
28pub trait GenericBlockBody<'a>
30where
31 Self: Copy + fmt::Debug + Into<BlockBody<'a>> + Send + Sync,
32{
33 const SHARD_KIND: RealShardKind;
35
36 #[cfg(feature = "alloc")]
38 type Owned: GenericOwnedBlockBody<Body<'a> = Self>
39 where
40 Self: 'a;
41
42 #[cfg(feature = "alloc")]
44 fn to_owned(self) -> Self::Owned;
45
46 fn root(&self) -> Blake3Hash;
48}
49
50#[inline]
52pub fn compute_segments_root<'a, const MAX_SEGMENTS: u64, Iter>(segment_roots: Iter) -> Blake3Hash
53where
54 Iter: IntoIterator<Item = &'a SegmentRoot>,
55{
56 let root = UnbalancedMerkleTree::compute_root_only::<MAX_SEGMENTS, _, _>(
58 segment_roots.into_iter().map(|segment_root| {
59 single_block_hash(segment_root.as_ref())
62 .expect("Less than a single block worth of bytes; qed")
63 }),
64 );
65
66 Blake3Hash::new(root.unwrap_or_default())
67}
68
69#[derive(Debug, Copy, Clone)]
71pub struct OwnSegments<'a> {
72 pub first_local_segment_index: LocalSegmentIndex,
74 pub segment_roots: &'a [SegmentRoot],
76}
77
78impl OwnSegments<'_> {
79 #[inline]
81 pub fn root(&self) -> Blake3Hash {
82 let root = BalancedMerkleTree::compute_root_only(&[
84 single_block_hash(self.first_local_segment_index.as_bytes())
85 .expect("Less than a single block worth of bytes; qed"),
86 *compute_segments_root::<const { u64::from(u8::MAX) }, _>(self.segment_roots),
87 ]);
88
89 Blake3Hash::new(root)
90 }
91
92 #[inline]
98 pub fn root_with_shard_index(&self, shard_index: ShardIndex) -> Blake3Hash {
99 let root = BalancedMerkleTree::compute_root_only(&[
101 {
102 const {
103 assert!((ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize <= BLOCK_LEN);
104 }
105 let mut pair = [0u8; (ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize];
106 pair[..ShardIndex::SIZE as usize].copy_from_slice(shard_index.as_bytes());
107 pair[ShardIndex::SIZE as usize..]
108 .copy_from_slice(self.first_local_segment_index.as_bytes());
109
110 single_block_hash(&pair).expect("Less than a single block worth of bytes; qed")
111 },
112 *compute_segments_root::<const { u64::from(u8::MAX) }, _>(self.segment_roots),
113 ]);
114
115 Blake3Hash::new(root)
116 }
117}
118
119#[derive(Debug, Clone)]
121#[expect(
122 clippy::partial_pub_fields,
123 reason = "Intentionally exposing immediately decoded fields above and hiding the rest of the implementation"
124)]
125pub struct IntermediateShardBlockInfo<'a> {
126 pub header: IntermediateShardHeader<'a>,
128 pub segments_proof: Option<&'a [u8; OUT_LEN]>,
130 pub own_segments: Option<OwnSegments<'a>>,
132 num_leaf_shard_blocks_with_segments: u8,
133 leaf_shards_segments_bytes: &'a [u8],
134}
135
136impl<'a> IntermediateShardBlockInfo<'a> {
137 #[inline]
139 pub fn leaf_shards_segments(
140 &self,
141 ) -> impl ExactSizeIterator<Item = (ShardIndex, OwnSegments<'a>)> + TrustedLen + use<'a> {
142 let (counts, mut remainder) = unsafe {
144 self.leaf_shards_segments_bytes.split_at_unchecked(
145 usize::from(self.num_leaf_shard_blocks_with_segments) * size_of::<u8>(),
146 )
147 };
148 counts.iter().map(move |&num_own_segment_roots| {
149 let num_own_segment_roots = usize::from(num_own_segment_roots);
150
151 let shard_index;
152 (shard_index, remainder) =
154 unsafe { remainder.split_at_unchecked(ShardIndex::SIZE as usize) };
155 let shard_index =
157 unsafe { Unaligned::<ShardIndex>::from_bytes_unchecked(shard_index) }.as_inner();
158
159 let first_local_segment_index;
160 (first_local_segment_index, remainder) =
162 unsafe { remainder.split_at_unchecked(LocalSegmentIndex::SIZE as usize) };
163 let first_local_segment_index = unsafe {
165 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
166 }
167 .as_inner();
168
169 let own_segment_roots;
170 (own_segment_roots, remainder) =
172 unsafe { remainder.split_at_unchecked(num_own_segment_roots * SegmentRoot::SIZE) };
173 let own_segment_roots = unsafe {
175 slice::from_raw_parts(
176 own_segment_roots
177 .as_ptr()
178 .cast::<[u8; const { SegmentRoot::SIZE }]>(),
179 num_own_segment_roots,
180 )
181 };
182 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
183
184 (
185 shard_index,
186 OwnSegments {
187 first_local_segment_index,
188 segment_roots: own_segment_roots,
189 },
190 )
191 })
192 }
193}
194
195#[derive(Debug, Copy, Clone)]
197pub struct IntermediateShardBlocksInfo<'a> {
198 num_blocks: usize,
199 bytes: &'a [u8],
200}
201
202impl<'a> IntermediateShardBlocksInfo<'a> {
203 #[inline]
209 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
210 let num_blocks = bytes.split_off(..size_of::<u16>())?;
230 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
231
232 let bytes_start = bytes;
233
234 let mut counts = bytes.split_off(..num_blocks * (size_of::<u8>() * 2))?;
235
236 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
237
238 for _ in 0..num_blocks {
239 let num_own_segment_roots = usize::from(counts[0]);
240 let num_leaf_shard_blocks_with_segments = usize::from(counts[1]);
241 counts = &counts[2..];
242
243 (_, remainder) = IntermediateShardHeader::try_from_bytes(remainder)?;
244
245 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
246 let _segments_proof = remainder.split_off(..SegmentRoot::SIZE)?;
247 }
248
249 if num_own_segment_roots > 0 {
250 let _first_local_segment_index =
251 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
252 let _own_segment_roots =
253 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
254 }
255
256 let leaf_shard_segment_roots_counts =
257 remainder.split_off(..num_leaf_shard_blocks_with_segments * size_of::<u8>())?;
258
259 for &num_own_segment_roots in leaf_shard_segment_roots_counts {
260 let _shard_index = remainder.split_off(..ShardIndex::SIZE as usize)?;
261 let _first_local_segment_index =
262 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
263 let _own_segment_roots = remainder
264 .split_off(..usize::from(num_own_segment_roots) * SegmentRoot::SIZE)?;
265 }
266
267 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
268 }
269
270 let info = Self {
271 num_blocks,
272 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
273 };
274
275 if !info.is_internally_consistent() {
276 return None;
277 }
278
279 Some((info, remainder))
280 }
281
282 #[inline]
285 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
286 let num_blocks = bytes.split_off(..size_of::<u16>())?;
306 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
307
308 let bytes_start = bytes;
309
310 let mut counts = bytes.split_off(..num_blocks * (size_of::<u8>() * 2))?;
311
312 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
313
314 for _ in 0..num_blocks {
315 let num_own_segment_roots = usize::from(counts[0]);
316 let num_leaf_shard_blocks_with_segments = usize::from(counts[1]);
317 counts = &counts[2..];
318
319 (_, remainder) = IntermediateShardHeader::try_from_bytes(remainder)?;
320
321 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
322 let _segments_proof = remainder.split_off(..OUT_LEN)?;
323 }
324
325 if num_own_segment_roots > 0 {
326 let _first_local_segment_index =
327 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
328 let _own_segment_roots =
329 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
330 }
331
332 let leaf_shard_segment_roots_counts =
333 remainder.split_off(..num_leaf_shard_blocks_with_segments * size_of::<u8>())?;
334
335 for &num_own_segment_roots in leaf_shard_segment_roots_counts {
336 let _shard_index = remainder.split_off(..ShardIndex::SIZE as usize)?;
337 let _first_local_segment_index =
338 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
339 let _own_segment_roots = remainder
340 .split_off(..usize::from(num_own_segment_roots) * SegmentRoot::SIZE)?;
341 }
342
343 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
344 }
345
346 Some((
347 Self {
348 num_blocks,
349 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
350 },
351 remainder,
352 ))
353 }
354
355 #[inline]
360 pub fn is_internally_consistent(&self) -> bool {
361 let mut last_intermediate_shard_info =
362 None::<(ShardIndex, BlockNumber, Option<LocalSegmentIndex>)>;
363
364 self.iter().all(|intermediate_shard_block| {
365 let shard_index = intermediate_shard_block.header.prefix.shard_index;
366
367 if let Some((
369 last_intermediate_shard_index,
370 last_intermediate_shard_block_number,
371 last_intermediate_shard_first_local_segment_index,
372 )) = last_intermediate_shard_info
373 {
374 match last_intermediate_shard_index.cmp(&shard_index) {
375 cmp::Ordering::Less => {
376 last_intermediate_shard_info.replace((
377 shard_index,
378 intermediate_shard_block.header.prefix.number,
379 intermediate_shard_block
380 .own_segments
381 .as_ref()
382 .map(|own_segments| own_segments.first_local_segment_index),
383 ));
384 }
385 cmp::Ordering::Equal => {
386 if last_intermediate_shard_block_number
387 >= intermediate_shard_block.header.prefix.number
388 {
389 return false;
390 }
391 if let Some(own_segments) = &intermediate_shard_block.own_segments {
392 if let Some(last_intermediate_shard_first_local_segment_index) =
393 last_intermediate_shard_first_local_segment_index
394 && last_intermediate_shard_first_local_segment_index
395 >= own_segments.first_local_segment_index
396 {
397 return false;
398 }
399
400 last_intermediate_shard_info.replace((
401 shard_index,
402 intermediate_shard_block.header.prefix.number,
403 Some(own_segments.first_local_segment_index),
404 ));
405 } else {
406 last_intermediate_shard_info.replace((
407 shard_index,
408 intermediate_shard_block.header.prefix.number,
409 last_intermediate_shard_first_local_segment_index,
410 ));
411 }
412 }
413 cmp::Ordering::Greater => {
414 return false;
415 }
416 }
417 } else {
418 last_intermediate_shard_info.replace((
419 shard_index,
420 intermediate_shard_block.header.prefix.number,
421 intermediate_shard_block
422 .own_segments
423 .as_ref()
424 .map(|own_segments| own_segments.first_local_segment_index),
425 ));
426 }
427
428 let mut last_leaf_shard_info = None::<(ShardIndex, LocalSegmentIndex)>;
429
430 if !intermediate_shard_block.leaf_shards_segments().all(
432 |(leaf_shard_index, own_segments)| {
433 if !leaf_shard_index.is_child_of(shard_index) {
434 return false;
435 }
436
437 if let Some((
438 last_leaf_shard_index,
439 last_leaf_shard_first_local_segment_index,
440 )) = last_leaf_shard_info
441 {
442 match last_leaf_shard_index.cmp(&leaf_shard_index) {
443 cmp::Ordering::Less => {
444 }
446 cmp::Ordering::Equal => {
447 if last_leaf_shard_first_local_segment_index
448 >= own_segments.first_local_segment_index
449 {
450 return false;
451 }
452 }
453 cmp::Ordering::Greater => {
454 return false;
455 }
456 }
457 }
458 last_leaf_shard_info
459 .replace((leaf_shard_index, own_segments.first_local_segment_index));
460
461 true
462 },
463 ) {
464 return false;
465 }
466
467 if intermediate_shard_block.own_segments.is_none()
468 && intermediate_shard_block
469 .leaf_shards_segments()
470 .size_hint()
471 .0
472 == 0
473 {
474 return intermediate_shard_block.segments_proof.is_none();
475 }
476
477 let segments_proof = intermediate_shard_block.segments_proof.unwrap_or(&[0; _]);
478
479 let leaf_shards_root =
480 UnbalancedMerkleTree::compute_root_only::<const { u64::from(u16::MAX) }, _, _>(
481 intermediate_shard_block.leaf_shards_segments().map(
482 |(shard_index, own_segments)| {
483 own_segments.root_with_shard_index(shard_index)
484 },
485 ),
486 )
487 .unwrap_or_default();
488
489 BalancedMerkleTree::<2>::verify(
490 &intermediate_shard_block.header.result.body_root,
491 array::from_ref(segments_proof),
492 0,
493 BalancedMerkleTree::compute_root_only(&[
494 *intermediate_shard_block
495 .own_segments
496 .as_ref()
497 .map(OwnSegments::root)
498 .unwrap_or_default(),
499 leaf_shards_root,
500 ]),
501 )
502 })
503 }
504
505 #[inline]
507 pub fn iter(
508 &self,
509 ) -> impl ExactSizeIterator<Item = IntermediateShardBlockInfo<'a>> + TrustedLen + use<'a> {
510 let (mut counts, mut remainder) = unsafe {
512 self.bytes
513 .split_at_unchecked(self.num_blocks * (size_of::<u8>() + size_of::<u16>()))
514 };
515
516 iter::repeat_with(move || {
517 let num_own_segment_roots = usize::from(counts[0]);
518 let num_leaf_shard_blocks_with_segments = counts[1];
519 counts = &counts[2..];
520
521 let header;
523 (header, remainder) = IntermediateShardHeader::try_from_bytes(remainder)
524 .expect("Already checked in constructor; qed");
525
526 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)
527 .expect("Already checked in constructor; qed");
528
529 let segments_proof =
530 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
531 let segments_proof;
532 (segments_proof, remainder) = unsafe { remainder.split_at_unchecked(OUT_LEN) };
534 Some(unsafe {
536 segments_proof
537 .as_ptr()
538 .cast::<[u8; OUT_LEN]>()
539 .as_ref_unchecked()
540 })
541 } else {
542 None
543 };
544
545 let own_segments = if num_own_segment_roots > 0 {
546 let first_local_segment_index;
547 (first_local_segment_index, remainder) =
549 unsafe { remainder.split_at_unchecked(size_of::<LocalSegmentIndex>()) };
550 let first_local_segment_index =
552 *unsafe { LocalSegmentIndex::from_bytes_unchecked(first_local_segment_index) };
553
554 let own_segment_roots;
555 (own_segment_roots, remainder) = unsafe {
557 remainder.split_at_unchecked(num_own_segment_roots * SegmentRoot::SIZE)
558 };
559 let own_segment_roots = unsafe {
561 slice::from_raw_parts(
562 own_segment_roots
563 .as_ptr()
564 .cast::<[u8; const { SegmentRoot::SIZE }]>(),
565 num_own_segment_roots,
566 )
567 };
568 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
569
570 Some(OwnSegments {
571 first_local_segment_index,
572 segment_roots: own_segment_roots,
573 })
574 } else {
575 None
576 };
577
578 let leaf_shard_segment_roots_counts = unsafe {
580 remainder.get_unchecked(
581 ..usize::from(num_leaf_shard_blocks_with_segments) * size_of::<u8>(),
582 )
583 };
584
585 let leaf_shards_segments_bytes;
586 (leaf_shards_segments_bytes, remainder) = unsafe {
588 remainder.split_at_unchecked(
589 usize::from(num_leaf_shard_blocks_with_segments) * size_of::<u8>()
590 + usize::from(num_leaf_shard_blocks_with_segments)
591 * (ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize
592 + leaf_shard_segment_roots_counts.iter().fold(
593 0usize,
594 |acc, &num_own_segment_roots| {
595 acc + usize::from(num_own_segment_roots) * SegmentRoot::SIZE
596 },
597 ),
598 )
599 };
600
601 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)
602 .expect("Already checked in constructor; qed");
603
604 IntermediateShardBlockInfo {
605 header,
606 segments_proof,
607 own_segments,
608 num_leaf_shard_blocks_with_segments,
609 leaf_shards_segments_bytes,
610 }
611 })
612 .take(self.num_blocks)
613 }
614
615 #[inline(always)]
617 pub const fn len(&self) -> usize {
618 self.num_blocks
619 }
620
621 #[inline(always)]
623 pub const fn is_empty(&self) -> bool {
624 self.num_blocks == 0
625 }
626
627 #[inline]
631 pub fn segments_root(&self) -> Blake3Hash {
632 let root = UnbalancedMerkleTree::compute_root_only::<const { u64::from(u16::MAX) }, _, _>(
633 self.iter().map(|shard_block_info| {
634 UnbalancedMerkleTree::compute_root_only::<const { u64::from(u32::MAX) }, _, _>(
635 shard_block_info
636 .own_segments
637 .as_ref()
638 .map(OwnSegments::root)
639 .into_iter()
640 .chain(shard_block_info.leaf_shards_segments().map(
641 |(shard_index, own_segments)| {
642 own_segments.root_with_shard_index(shard_index)
643 },
644 )),
645 )
646 .unwrap_or_default()
647 }),
648 )
649 .unwrap_or_default();
650
651 Blake3Hash::new(root)
652 }
653
654 #[inline]
658 pub fn headers_root(&self) -> Blake3Hash {
659 let root = UnbalancedMerkleTree::compute_root_only::<const { u64::from(u16::MAX) }, _, _>(
660 self.iter().map(|shard_block_info| {
662 single_block_hash(shard_block_info.header.root().as_ref())
666 .expect("Less than a single block worth of bytes; qed")
667 }),
668 )
669 .unwrap_or_default();
670
671 Blake3Hash::new(root)
672 }
673}
674
675#[derive(Debug, Copy, Clone, Yokeable)]
677#[non_exhaustive]
679pub struct BeaconChainBody<'a> {
680 own_segments: Option<OwnSegments<'a>>,
682 intermediate_shard_blocks: IntermediateShardBlocksInfo<'a>,
684 pot_checkpoints: &'a [PotCheckpoints],
687}
688
689impl<'a> GenericBlockBody<'a> for BeaconChainBody<'a> {
690 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
691
692 #[cfg(feature = "alloc")]
693 type Owned = OwnedBeaconChainBody;
694
695 #[cfg(feature = "alloc")]
696 #[inline(always)]
697 fn to_owned(self) -> Self::Owned {
698 self.to_owned()
699 }
700
701 #[inline(always)]
702 fn root(&self) -> Blake3Hash {
703 self.root()
704 }
705}
706
707impl<'a> BeaconChainBody<'a> {
708 #[inline]
714 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
715 let num_pot_checkpoints = bytes.split_off(..size_of::<u32>())?;
724 let num_pot_checkpoints =
726 *unsafe { <u32 as TrivialType>::from_bytes(num_pot_checkpoints) }? as usize;
727
728 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
729 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
730
731 let own_segments = if num_own_segment_roots > 0 {
732 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
733 let first_local_segment_index = unsafe {
735 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
736 }
737 .as_inner();
738
739 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
740 let own_segment_roots = unsafe {
742 slice::from_raw_parts(
743 own_segment_roots
744 .as_ptr()
745 .cast::<[u8; const { SegmentRoot::SIZE }]>(),
746 num_own_segment_roots,
747 )
748 };
749 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
750
751 Some(OwnSegments {
752 first_local_segment_index,
753 segment_roots: own_segment_roots,
754 })
755 } else {
756 None
757 };
758
759 let (intermediate_shard_blocks, mut remainder) =
760 IntermediateShardBlocksInfo::try_from_bytes(bytes)?;
761
762 let pot_checkpoints = remainder.split_off(..num_pot_checkpoints * PotCheckpoints::SIZE)?;
763 let pot_checkpoints = unsafe {
765 slice::from_raw_parts(
766 pot_checkpoints
767 .as_ptr()
768 .cast::<[u8; const { PotCheckpoints::SIZE }]>(),
769 num_pot_checkpoints,
770 )
771 };
772 let pot_checkpoints = PotCheckpoints::slice_from_bytes(pot_checkpoints);
773
774 let body = Self {
775 own_segments,
776 intermediate_shard_blocks,
777 pot_checkpoints,
778 };
779
780 if !body.is_internally_consistent() {
781 return None;
782 }
783
784 Some((body, remainder))
785 }
786
787 #[inline]
792 pub fn is_internally_consistent(&self) -> bool {
793 true
795 }
796
797 #[inline]
800 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
801 let num_pot_checkpoints = bytes.split_off(..size_of::<u32>())?;
810 let num_pot_checkpoints =
812 *unsafe { <u32 as TrivialType>::from_bytes(num_pot_checkpoints) }? as usize;
813
814 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
815 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
816
817 let own_segments = if num_own_segment_roots > 0 {
818 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
819 let first_local_segment_index = unsafe {
821 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
822 }
823 .as_inner();
824
825 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
826 let own_segment_roots = unsafe {
828 slice::from_raw_parts(
829 own_segment_roots
830 .as_ptr()
831 .cast::<[u8; const { SegmentRoot::SIZE }]>(),
832 num_own_segment_roots,
833 )
834 };
835 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
836
837 Some(OwnSegments {
838 first_local_segment_index,
839 segment_roots: own_segment_roots,
840 })
841 } else {
842 None
843 };
844
845 let (intermediate_shard_blocks, mut remainder) =
846 IntermediateShardBlocksInfo::try_from_bytes_unchecked(bytes)?;
847
848 let pot_checkpoints = remainder.split_off(..num_pot_checkpoints * PotCheckpoints::SIZE)?;
849 let pot_checkpoints = unsafe {
851 slice::from_raw_parts(
852 pot_checkpoints
853 .as_ptr()
854 .cast::<[u8; const { PotCheckpoints::SIZE }]>(),
855 num_pot_checkpoints,
856 )
857 };
858 let pot_checkpoints = PotCheckpoints::slice_from_bytes(pot_checkpoints);
859
860 Some((
861 Self {
862 own_segments,
863 intermediate_shard_blocks,
864 pot_checkpoints,
865 },
866 remainder,
867 ))
868 }
869
870 #[cfg(feature = "alloc")]
872 #[inline(always)]
873 pub fn to_owned(self) -> OwnedBeaconChainBody {
874 if let Some(own_segments) = self.own_segments {
875 let first_local_segment_index = own_segments.first_local_segment_index;
876
877 OwnedBeaconChainBody::new(
878 own_segments.segment_roots.iter().copied().enumerate().map(
879 |(index, segment_root)| {
880 (
881 first_local_segment_index + LocalSegmentIndex::from(index as u64),
882 segment_root,
883 )
884 },
885 ),
886 self.intermediate_shard_blocks.iter(),
887 self.pot_checkpoints,
888 )
889 .expect("`self` is always a valid invariant; qed")
890 } else {
891 OwnedBeaconChainBody::new(
892 iter::empty(),
893 self.intermediate_shard_blocks.iter(),
894 self.pot_checkpoints,
895 )
896 .expect("`self` is always a valid invariant; qed")
897 }
898 }
899
900 #[inline(always)]
902 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
903 self.own_segments
904 }
905
906 #[inline(always)]
908 pub fn intermediate_shard_blocks(&self) -> &IntermediateShardBlocksInfo<'a> {
909 &self.intermediate_shard_blocks
910 }
911
912 #[inline(always)]
915 pub fn pot_checkpoints(&self) -> &'a [PotCheckpoints] {
916 self.pot_checkpoints
917 }
918
919 #[inline]
921 pub fn root(&self) -> Blake3Hash {
922 let root = BalancedMerkleTree::compute_root_only(&[
924 *self
925 .own_segments
926 .as_ref()
927 .map(OwnSegments::root)
928 .unwrap_or_default(),
929 *self.intermediate_shard_blocks.segments_root(),
930 *self.intermediate_shard_blocks.headers_root(),
931 blake3::hash(PotCheckpoints::bytes_from_slice(self.pot_checkpoints).as_flattened())
932 .into(),
933 ]);
934
935 Blake3Hash::new(root)
936 }
937}
938
939#[derive(Debug, Copy, Clone)]
941pub struct LeafShardOwnSegments<'a> {
942 pub segment_roots_proof: &'a [u8; OUT_LEN],
944 pub own_segments: OwnSegments<'a>,
946}
947
948#[derive(Debug, Clone)]
950pub struct LeafShardBlockInfo<'a> {
951 pub header: LeafShardHeader<'a>,
953 pub segments: Option<LeafShardOwnSegments<'a>>,
955}
956
957#[derive(Debug, Copy, Clone)]
959pub struct LeafShardBlocksInfo<'a> {
960 num_blocks: usize,
961 bytes: &'a [u8],
962}
963
964impl<'a> LeafShardBlocksInfo<'a> {
965 #[inline]
971 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
972 let num_blocks = bytes.split_off(..size_of::<u16>())?;
985 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
986
987 let bytes_start = bytes;
988
989 let mut counts = bytes.split_off(..num_blocks * size_of::<u8>())?;
990
991 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
992
993 for _ in 0..num_blocks {
994 let num_own_segment_roots = usize::from(counts[0]);
995 counts = &counts[1..];
996
997 (_, remainder) = LeafShardHeader::try_from_bytes(remainder)?;
998
999 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
1000
1001 if num_own_segment_roots > 0 {
1002 let _first_local_segment_index =
1003 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
1004 let _segment_roots_proof = remainder.split_off(..OUT_LEN)?;
1005 let _own_segment_roots =
1006 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1007 }
1008 }
1009
1010 let info = Self {
1011 num_blocks,
1012 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1013 };
1014
1015 if !info.is_internally_consistent() {
1016 return None;
1017 }
1018
1019 Some((info, remainder))
1020 }
1021
1022 #[inline]
1025 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1026 let num_blocks = bytes.split_off(..size_of::<u16>())?;
1039 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
1040
1041 let bytes_start = bytes;
1042
1043 let mut counts = bytes.split_off(..num_blocks * size_of::<u8>())?;
1044
1045 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
1046
1047 for _ in 0..num_blocks {
1048 let num_own_segment_roots = usize::from(counts[0]);
1049 counts = &counts[1..];
1050
1051 (_, remainder) = LeafShardHeader::try_from_bytes(remainder)?;
1052
1053 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
1054
1055 if num_own_segment_roots > 0 {
1056 let _first_local_segment_index =
1057 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
1058 let _segment_roots_proof = remainder.split_off(..OUT_LEN)?;
1059 let _own_segment_roots =
1060 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1061 }
1062 }
1063
1064 Some((
1065 Self {
1066 num_blocks,
1067 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1068 },
1069 remainder,
1070 ))
1071 }
1072
1073 #[inline]
1078 pub fn is_internally_consistent(&self) -> bool {
1079 let mut last_leaf_shard_info = None::<(ShardIndex, BlockNumber, Option<LocalSegmentIndex>)>;
1080
1081 self.iter().all(|leaf_shard_block| {
1082 let shard_index = leaf_shard_block.header.prefix.shard_index;
1083
1084 if let Some((
1086 last_leaf_shard_index,
1087 last_leaf_shard_block_number,
1088 last_leaf_shard_first_local_segment_index,
1089 )) = last_leaf_shard_info
1090 {
1091 match last_leaf_shard_index.cmp(&shard_index) {
1092 cmp::Ordering::Less => {
1093 last_leaf_shard_info.replace((
1094 shard_index,
1095 leaf_shard_block.header.prefix.number,
1096 leaf_shard_block
1097 .segments
1098 .as_ref()
1099 .map(|segments| segments.own_segments.first_local_segment_index),
1100 ));
1101 }
1102 cmp::Ordering::Equal => {
1103 if last_leaf_shard_block_number >= leaf_shard_block.header.prefix.number {
1104 return false;
1105 }
1106 if let Some(leaf_shard_segments) = &leaf_shard_block.segments {
1107 if let Some(last_leaf_shard_first_local_segment_index) =
1108 last_leaf_shard_first_local_segment_index
1109 && last_leaf_shard_first_local_segment_index
1110 >= leaf_shard_segments.own_segments.first_local_segment_index
1111 {
1112 return false;
1113 }
1114
1115 last_leaf_shard_info.replace((
1116 shard_index,
1117 leaf_shard_block.header.prefix.number,
1118 Some(leaf_shard_segments.own_segments.first_local_segment_index),
1119 ));
1120 } else {
1121 last_leaf_shard_info.replace((
1122 shard_index,
1123 leaf_shard_block.header.prefix.number,
1124 last_leaf_shard_first_local_segment_index,
1125 ));
1126 }
1127 }
1128 cmp::Ordering::Greater => {
1129 return false;
1130 }
1131 }
1132 } else {
1133 last_leaf_shard_info.replace((
1134 shard_index,
1135 leaf_shard_block.header.prefix.number,
1136 leaf_shard_block
1137 .segments
1138 .as_ref()
1139 .map(|segments| segments.own_segments.first_local_segment_index),
1140 ));
1141 }
1142
1143 let Some(segments) = leaf_shard_block.segments else {
1144 return true;
1145 };
1146
1147 BalancedMerkleTree::<2>::verify(
1148 &leaf_shard_block.header.result.body_root,
1149 array::from_ref(segments.segment_roots_proof),
1150 0,
1151 *segments.own_segments.root(),
1152 )
1153 })
1154 }
1155
1156 #[inline]
1158 pub fn iter(
1159 &self,
1160 ) -> impl ExactSizeIterator<Item = LeafShardBlockInfo<'a>> + TrustedLen + use<'a> {
1161 let (mut counts, mut remainder) = unsafe {
1163 self.bytes
1164 .split_at_unchecked(self.num_blocks * size_of::<u8>())
1165 };
1166
1167 iter::repeat_with(move || {
1168 let num_own_segment_roots = usize::from(counts[0]);
1169 counts = &counts[1..];
1170
1171 let header;
1173 (header, remainder) = LeafShardHeader::try_from_bytes(remainder)
1174 .expect("Already checked in constructor; qed");
1175
1176 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)
1177 .expect("Already checked in constructor; qed");
1178
1179 let segments = if num_own_segment_roots > 0 {
1180 let first_local_segment_index;
1181 (first_local_segment_index, remainder) =
1183 unsafe { remainder.split_at_unchecked(LocalSegmentIndex::SIZE as usize) };
1184 let first_local_segment_index =
1186 *unsafe { LocalSegmentIndex::from_bytes_unchecked(first_local_segment_index) };
1187
1188 let segment_roots_proof;
1189 (segment_roots_proof, remainder) = unsafe { remainder.split_at_unchecked(OUT_LEN) };
1191 let segment_roots_proof = unsafe {
1193 segment_roots_proof
1194 .as_ptr()
1195 .cast::<[u8; OUT_LEN]>()
1196 .as_ref_unchecked()
1197 };
1198
1199 let own_segment_roots;
1200 (own_segment_roots, remainder) = unsafe {
1202 remainder.split_at_unchecked(num_own_segment_roots * SegmentRoot::SIZE)
1203 };
1204 let own_segment_roots = unsafe {
1206 slice::from_raw_parts(
1207 own_segment_roots
1208 .as_ptr()
1209 .cast::<[u8; const { SegmentRoot::SIZE }]>(),
1210 num_own_segment_roots,
1211 )
1212 };
1213 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1214
1215 Some(LeafShardOwnSegments {
1216 segment_roots_proof,
1217 own_segments: OwnSegments {
1218 first_local_segment_index,
1219 segment_roots: own_segment_roots,
1220 },
1221 })
1222 } else {
1223 None
1224 };
1225
1226 LeafShardBlockInfo { header, segments }
1227 })
1228 .take(self.num_blocks)
1229 }
1230
1231 #[inline(always)]
1233 pub const fn len(&self) -> usize {
1234 self.num_blocks
1235 }
1236
1237 #[inline(always)]
1239 pub const fn is_empty(&self) -> bool {
1240 self.num_blocks == 0
1241 }
1242
1243 #[inline]
1247 pub fn segments_root(&self) -> Blake3Hash {
1248 let root = UnbalancedMerkleTree::compute_root_only::<const { u64::from(u16::MAX) }, _, _>(
1249 self.iter().map(|shard_block_info| {
1250 shard_block_info
1251 .segments
1252 .map(|own_segments| {
1253 own_segments
1254 .own_segments
1255 .root_with_shard_index(shard_block_info.header.prefix.shard_index)
1256 })
1257 .unwrap_or_default()
1258 }),
1259 )
1260 .unwrap_or_default();
1261
1262 Blake3Hash::new(root)
1263 }
1264
1265 #[inline]
1269 pub fn headers_root(&self) -> Blake3Hash {
1270 let root = UnbalancedMerkleTree::compute_root_only::<const { u64::from(u16::MAX) }, _, _>(
1271 self.iter().map(|shard_block_info| {
1272 single_block_hash(shard_block_info.header.root().as_ref())
1276 .expect("Less than a single block worth of bytes; qed")
1277 }),
1278 )
1279 .unwrap_or_default();
1280
1281 Blake3Hash::new(root)
1282 }
1283}
1284
1285#[derive(Debug, Copy, Clone, Yokeable)]
1287#[non_exhaustive]
1289pub struct IntermediateShardBody<'a> {
1290 own_segments: Option<OwnSegments<'a>>,
1292 leaf_shard_blocks: LeafShardBlocksInfo<'a>,
1294}
1295
1296impl<'a> GenericBlockBody<'a> for IntermediateShardBody<'a> {
1297 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
1298
1299 #[cfg(feature = "alloc")]
1300 type Owned = OwnedIntermediateShardBody;
1301
1302 #[cfg(feature = "alloc")]
1303 #[inline(always)]
1304 fn to_owned(self) -> Self::Owned {
1305 self.to_owned()
1306 }
1307
1308 #[inline(always)]
1309 fn root(&self) -> Blake3Hash {
1310 self.root()
1311 }
1312}
1313
1314impl<'a> IntermediateShardBody<'a> {
1315 #[inline]
1321 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1322 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1329 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1330
1331 let own_segments = if num_own_segment_roots > 0 {
1332 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1333 let first_local_segment_index = unsafe {
1335 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1336 }
1337 .as_inner();
1338
1339 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1340 let own_segment_roots = unsafe {
1342 slice::from_raw_parts(
1343 own_segment_roots
1344 .as_ptr()
1345 .cast::<[u8; const { SegmentRoot::SIZE }]>(),
1346 num_own_segment_roots,
1347 )
1348 };
1349 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1350
1351 Some(OwnSegments {
1352 first_local_segment_index,
1353 segment_roots: own_segment_roots,
1354 })
1355 } else {
1356 None
1357 };
1358
1359 let (leaf_shard_blocks, remainder) = LeafShardBlocksInfo::try_from_bytes(bytes)?;
1360
1361 let body = Self {
1362 own_segments,
1363 leaf_shard_blocks,
1364 };
1365
1366 if !body.is_internally_consistent() {
1367 return None;
1368 }
1369
1370 Some((body, remainder))
1371 }
1372
1373 #[inline]
1378 pub fn is_internally_consistent(&self) -> bool {
1379 true
1381 }
1382
1383 #[inline]
1386 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1387 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1394 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1395
1396 let own_segments = if num_own_segment_roots > 0 {
1397 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1398 let first_local_segment_index = unsafe {
1400 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1401 }
1402 .as_inner();
1403
1404 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1405 let own_segment_roots = unsafe {
1407 slice::from_raw_parts(
1408 own_segment_roots
1409 .as_ptr()
1410 .cast::<[u8; const { SegmentRoot::SIZE }]>(),
1411 num_own_segment_roots,
1412 )
1413 };
1414 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1415
1416 Some(OwnSegments {
1417 first_local_segment_index,
1418 segment_roots: own_segment_roots,
1419 })
1420 } else {
1421 None
1422 };
1423
1424 let (leaf_shard_blocks, remainder) = LeafShardBlocksInfo::try_from_bytes_unchecked(bytes)?;
1425
1426 Some((
1427 Self {
1428 own_segments,
1429 leaf_shard_blocks,
1430 },
1431 remainder,
1432 ))
1433 }
1434
1435 #[inline(always)]
1437 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
1438 self.own_segments
1439 }
1440
1441 #[inline(always)]
1443 pub fn leaf_shard_blocks(&self) -> &LeafShardBlocksInfo<'a> {
1444 &self.leaf_shard_blocks
1445 }
1446
1447 #[cfg(feature = "alloc")]
1449 #[inline(always)]
1450 pub fn to_owned(self) -> OwnedIntermediateShardBody {
1451 if let Some(own_segments) = self.own_segments {
1452 let first_local_segment_index = own_segments.first_local_segment_index;
1453
1454 OwnedIntermediateShardBody::new(
1455 own_segments.segment_roots.iter().copied().enumerate().map(
1456 |(index, segment_root)| {
1457 (
1458 first_local_segment_index + LocalSegmentIndex::from(index as u64),
1459 segment_root,
1460 )
1461 },
1462 ),
1463 self.leaf_shard_blocks.iter(),
1464 )
1465 .expect("`self` is always a valid invariant; qed")
1466 } else {
1467 OwnedIntermediateShardBody::new(iter::empty(), self.leaf_shard_blocks.iter())
1468 .expect("`self` is always a valid invariant; qed")
1469 }
1470 }
1471
1472 #[inline]
1474 pub fn root(&self) -> Blake3Hash {
1475 let root = BalancedMerkleTree::compute_root_only(&[
1477 BalancedMerkleTree::compute_root_only(&[
1478 *self
1479 .own_segments
1480 .as_ref()
1481 .map(OwnSegments::root)
1482 .unwrap_or_default(),
1483 *self.leaf_shard_blocks.segments_root(),
1484 ]),
1485 *self.leaf_shard_blocks.headers_root(),
1486 ]);
1487
1488 Blake3Hash::new(root)
1489 }
1490}
1491
1492#[derive(Debug, Copy, Clone)]
1494pub struct Transactions<'a> {
1495 num_transactions: usize,
1496 bytes: &'a [u8],
1497}
1498
1499impl<'a> Transactions<'a> {
1500 #[inline]
1506 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1507 let num_transactions = bytes.split_off(..size_of::<u32>())?;
1515 let num_transactions = u32::from_le_bytes([
1516 num_transactions[0],
1517 num_transactions[1],
1518 num_transactions[2],
1519 num_transactions[3],
1520 ]) as usize;
1521
1522 let mut remainder = align_to_and_ensure_zero_padding::<u128>(bytes)?;
1523 let bytes_start = remainder;
1524
1525 for _ in 0..num_transactions {
1526 (_, remainder) = Transaction::try_from_bytes(bytes)?;
1527 remainder = align_to_and_ensure_zero_padding::<u128>(remainder)?;
1528 }
1529
1530 Some((
1531 Self {
1532 num_transactions,
1533 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1534 },
1535 remainder,
1536 ))
1537 }
1538
1539 #[inline]
1541 pub fn iter(&self) -> impl ExactSizeIterator<Item = Transaction<'a>> + TrustedLen + use<'a> {
1542 let mut remainder = self.bytes;
1543
1544 iter::repeat_with(move || {
1545 let transaction = unsafe { Transaction::from_bytes_unchecked(remainder) };
1547
1548 remainder = &remainder[transaction.encoded_size()..];
1549 remainder = align_to_and_ensure_zero_padding::<u128>(remainder)
1550 .expect("Already checked in constructor; qed");
1551
1552 transaction
1553 })
1554 .take(self.num_transactions)
1555 }
1556
1557 #[inline(always)]
1559 pub const fn len(&self) -> usize {
1560 self.num_transactions
1561 }
1562
1563 #[inline(always)]
1565 pub const fn is_empty(&self) -> bool {
1566 self.num_transactions == 0
1567 }
1568
1569 #[inline]
1573 pub fn root(&self) -> Blake3Hash {
1574 let root = UnbalancedMerkleTree::compute_root_only::<const { u64::from(u32::MAX) }, _, _>(
1575 self.iter().map(|transaction| {
1576 single_block_hash(transaction.hash().as_ref())
1580 .expect("Less than a single block worth of bytes; qed")
1581 }),
1582 )
1583 .unwrap_or_default();
1584
1585 Blake3Hash::new(root)
1586 }
1587}
1588
1589#[derive(Debug, Copy, Clone, Yokeable)]
1591#[non_exhaustive]
1593pub struct LeafShardBody<'a> {
1594 own_segments: Option<OwnSegments<'a>>,
1596 transactions: Transactions<'a>,
1598}
1599
1600impl<'a> GenericBlockBody<'a> for LeafShardBody<'a> {
1601 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1602
1603 #[cfg(feature = "alloc")]
1604 type Owned = OwnedLeafShardBody;
1605
1606 #[cfg(feature = "alloc")]
1607 #[inline(always)]
1608 fn to_owned(self) -> Self::Owned {
1609 self.to_owned()
1610 }
1611
1612 #[inline(always)]
1613 fn root(&self) -> Blake3Hash {
1614 self.root()
1615 }
1616}
1617
1618impl<'a> LeafShardBody<'a> {
1619 #[inline]
1625 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1626 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1633 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1634
1635 let own_segments = if num_own_segment_roots > 0 {
1636 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1637 let first_local_segment_index = unsafe {
1639 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1640 }
1641 .as_inner();
1642
1643 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1644 let own_segment_roots = unsafe {
1646 slice::from_raw_parts(
1647 own_segment_roots
1648 .as_ptr()
1649 .cast::<[u8; const { SegmentRoot::SIZE }]>(),
1650 num_own_segment_roots,
1651 )
1652 };
1653 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1654
1655 Some(OwnSegments {
1656 first_local_segment_index,
1657 segment_roots: own_segment_roots,
1658 })
1659 } else {
1660 None
1661 };
1662
1663 let (transactions, remainder) = Transactions::try_from_bytes(bytes)?;
1664
1665 let body = Self {
1666 own_segments,
1667 transactions,
1668 };
1669
1670 if !body.is_internally_consistent() {
1671 return None;
1672 }
1673
1674 Some((body, remainder))
1675 }
1676
1677 #[inline]
1682 pub fn is_internally_consistent(&self) -> bool {
1683 true
1685 }
1686
1687 #[inline]
1690 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1691 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1698 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1699
1700 let own_segments = if num_own_segment_roots > 0 {
1701 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1702 let first_local_segment_index = unsafe {
1704 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1705 }
1706 .as_inner();
1707
1708 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1709 let own_segment_roots = unsafe {
1711 slice::from_raw_parts(
1712 own_segment_roots
1713 .as_ptr()
1714 .cast::<[u8; const { SegmentRoot::SIZE }]>(),
1715 num_own_segment_roots,
1716 )
1717 };
1718 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1719
1720 Some(OwnSegments {
1721 first_local_segment_index,
1722 segment_roots: own_segment_roots,
1723 })
1724 } else {
1725 None
1726 };
1727
1728 let (transactions, remainder) = Transactions::try_from_bytes(bytes)?;
1729
1730 Some((
1731 Self {
1732 own_segments,
1733 transactions,
1734 },
1735 remainder,
1736 ))
1737 }
1738
1739 #[inline(always)]
1741 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
1742 self.own_segments
1743 }
1744
1745 #[inline(always)]
1747 pub fn transactions(&self) -> &Transactions<'a> {
1748 &self.transactions
1749 }
1750
1751 #[cfg(feature = "alloc")]
1753 #[inline(always)]
1754 pub fn to_owned(self) -> OwnedLeafShardBody {
1755 let mut builder = if let Some(own_segments) = self.own_segments {
1756 let first_local_segment_index = own_segments.first_local_segment_index;
1757
1758 OwnedLeafShardBody::init(own_segments.segment_roots.iter().copied().enumerate().map(
1759 |(index, segment_root)| {
1760 (
1761 first_local_segment_index + LocalSegmentIndex::from(index as u64),
1762 segment_root,
1763 )
1764 },
1765 ))
1766 .expect("`self` is always a valid invariant; qed")
1767 } else {
1768 OwnedLeafShardBody::init(iter::empty())
1769 .expect("`self` is always a valid invariant; qed")
1770 };
1771 for transaction in self.transactions.iter() {
1772 builder
1773 .add_transaction(transaction)
1774 .expect("`self` is always a valid invariant; qed");
1775 }
1776
1777 builder.finish()
1778 }
1779
1780 #[inline]
1782 pub fn root(&self) -> Blake3Hash {
1783 let root = BalancedMerkleTree::compute_root_only(&[
1784 *self
1785 .own_segments
1786 .as_ref()
1787 .map(OwnSegments::root)
1788 .unwrap_or_default(),
1789 *self.transactions.root(),
1790 ]);
1791
1792 Blake3Hash::new(root)
1793 }
1794}
1795
1796#[derive(Debug, Copy, Clone, From)]
1801pub enum BlockBody<'a> {
1802 BeaconChain(BeaconChainBody<'a>),
1804 IntermediateShard(IntermediateShardBody<'a>),
1806 LeafShard(LeafShardBody<'a>),
1808}
1809
1810impl<'a> BlockBody<'a> {
1811 #[inline]
1818 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1819 match shard_kind {
1820 RealShardKind::BeaconChain => {
1821 let (body, remainder) = BeaconChainBody::try_from_bytes(bytes)?;
1822 Some((Self::BeaconChain(body), remainder))
1823 }
1824 RealShardKind::IntermediateShard => {
1825 let (body, remainder) = IntermediateShardBody::try_from_bytes(bytes)?;
1826 Some((Self::IntermediateShard(body), remainder))
1827 }
1828 RealShardKind::LeafShard => {
1829 let (body, remainder) = LeafShardBody::try_from_bytes(bytes)?;
1830 Some((Self::LeafShard(body), remainder))
1831 }
1832 }
1833 }
1834
1835 #[inline]
1840 pub fn is_internally_consistent(&self) -> bool {
1841 match self {
1842 Self::BeaconChain(body) => body.is_internally_consistent(),
1843 Self::IntermediateShard(body) => body.is_internally_consistent(),
1844 Self::LeafShard(body) => body.is_internally_consistent(),
1845 }
1846 }
1847
1848 #[inline]
1851 pub fn try_from_bytes_unchecked(
1852 bytes: &'a [u8],
1853 shard_kind: RealShardKind,
1854 ) -> Option<(Self, &'a [u8])> {
1855 match shard_kind {
1856 RealShardKind::BeaconChain => {
1857 let (body, remainder) = BeaconChainBody::try_from_bytes_unchecked(bytes)?;
1858 Some((Self::BeaconChain(body), remainder))
1859 }
1860 RealShardKind::IntermediateShard => {
1861 let (body, remainder) = IntermediateShardBody::try_from_bytes_unchecked(bytes)?;
1862 Some((Self::IntermediateShard(body), remainder))
1863 }
1864 RealShardKind::LeafShard => {
1865 let (body, remainder) = LeafShardBody::try_from_bytes_unchecked(bytes)?;
1866 Some((Self::LeafShard(body), remainder))
1867 }
1868 }
1869 }
1870
1871 #[cfg(feature = "alloc")]
1873 #[inline(always)]
1874 pub fn to_owned(self) -> OwnedBlockBody {
1875 match self {
1876 Self::BeaconChain(body) => body.to_owned().into(),
1877 Self::IntermediateShard(body) => body.to_owned().into(),
1878 Self::LeafShard(body) => body.to_owned().into(),
1879 }
1880 }
1881
1882 #[inline]
1887 pub fn root(&self) -> Blake3Hash {
1888 match self {
1889 Self::BeaconChain(body) => body.root(),
1890 Self::IntermediateShard(body) => body.root(),
1891 Self::LeafShard(body) => body.root(),
1892 }
1893 }
1894}