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 [(); MAX_SEGMENTS.next_power_of_two().ilog2() as usize + 1]:,
55 Iter: IntoIterator<Item = &'a SegmentRoot>,
56{
57 let root = UnbalancedMerkleTree::compute_root_only::<MAX_SEGMENTS, _, _>(
59 segment_roots.into_iter().map(|segment_root| {
60 single_block_hash(segment_root.as_ref())
63 .expect("Less than a single block worth of bytes; qed")
64 }),
65 );
66
67 Blake3Hash::new(root.unwrap_or_default())
68}
69
70#[derive(Debug, Copy, Clone)]
72pub struct OwnSegments<'a> {
73 pub first_local_segment_index: LocalSegmentIndex,
75 pub segment_roots: &'a [SegmentRoot],
77}
78
79impl OwnSegments<'_> {
80 #[inline]
82 pub fn root(&self) -> Blake3Hash {
83 let root = BalancedMerkleTree::compute_root_only(&[
85 single_block_hash(self.first_local_segment_index.as_bytes())
86 .expect("Less than a single block worth of bytes; qed"),
87 *compute_segments_root::<{ u8::MAX as u64 }, _>(self.segment_roots),
88 ]);
89
90 Blake3Hash::new(root)
91 }
92
93 #[inline]
99 pub fn root_with_shard_index(&self, shard_index: ShardIndex) -> Blake3Hash {
100 let root = BalancedMerkleTree::compute_root_only(&[
102 {
103 const {
104 assert!((ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize <= BLOCK_LEN);
105 }
106 let mut pair = [0u8; (ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize];
107 pair[..ShardIndex::SIZE as usize].copy_from_slice(shard_index.as_bytes());
108 pair[ShardIndex::SIZE as usize..]
109 .copy_from_slice(self.first_local_segment_index.as_bytes());
110
111 single_block_hash(&pair).expect("Less than a single block worth of bytes; qed")
112 },
113 *compute_segments_root::<{ u8::MAX as u64 }, _>(self.segment_roots),
114 ]);
115
116 Blake3Hash::new(root)
117 }
118}
119
120#[derive(Debug, Clone)]
122pub struct IntermediateShardBlockInfo<'a> {
123 pub header: IntermediateShardHeader<'a>,
125 pub segments_proof: Option<&'a [u8; OUT_LEN]>,
127 pub own_segments: Option<OwnSegments<'a>>,
129 num_leaf_shard_blocks_with_segments: u8,
130 leaf_shards_segments_bytes: &'a [u8],
131}
132
133impl<'a> IntermediateShardBlockInfo<'a> {
134 #[inline]
136 pub fn leaf_shards_segments(
137 &self,
138 ) -> impl ExactSizeIterator<Item = (ShardIndex, OwnSegments<'a>)> + TrustedLen + use<'a> {
139 let (counts, mut remainder) = unsafe {
141 self.leaf_shards_segments_bytes.split_at_unchecked(
142 usize::from(self.num_leaf_shard_blocks_with_segments) * size_of::<u8>(),
143 )
144 };
145 counts.iter().map(move |&num_own_segment_roots| {
146 let num_own_segment_roots = usize::from(num_own_segment_roots);
147
148 let shard_index;
149 (shard_index, remainder) =
151 unsafe { remainder.split_at_unchecked(ShardIndex::SIZE as usize) };
152 let shard_index =
154 unsafe { Unaligned::<ShardIndex>::from_bytes_unchecked(shard_index) }.as_inner();
155
156 let first_local_segment_index;
157 (first_local_segment_index, remainder) =
159 unsafe { remainder.split_at_unchecked(LocalSegmentIndex::SIZE as usize) };
160 let first_local_segment_index = unsafe {
162 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
163 }
164 .as_inner();
165
166 let own_segment_roots;
167 (own_segment_roots, remainder) =
169 unsafe { remainder.split_at_unchecked(num_own_segment_roots * SegmentRoot::SIZE) };
170 let own_segment_roots = unsafe {
172 slice::from_raw_parts(
173 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
174 num_own_segment_roots,
175 )
176 };
177 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
178
179 (
180 shard_index,
181 OwnSegments {
182 first_local_segment_index,
183 segment_roots: own_segment_roots,
184 },
185 )
186 })
187 }
188}
189
190#[derive(Debug, Copy, Clone)]
192pub struct IntermediateShardBlocksInfo<'a> {
193 num_blocks: usize,
194 bytes: &'a [u8],
195}
196
197impl<'a> IntermediateShardBlocksInfo<'a> {
198 #[inline]
204 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
205 let num_blocks = bytes.split_off(..size_of::<u16>())?;
225 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
226
227 let bytes_start = bytes;
228
229 let mut counts = bytes.split_off(..num_blocks * (size_of::<u8>() * 2))?;
230
231 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
232
233 for _ in 0..num_blocks {
234 let num_own_segment_roots = usize::from(counts[0]);
235 let num_leaf_shard_blocks_with_segments = usize::from(counts[1]);
236 counts = &counts[2..];
237
238 (_, remainder) = IntermediateShardHeader::try_from_bytes(remainder)?;
239
240 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
241 let _segments_proof = remainder.split_off(..SegmentRoot::SIZE)?;
242 }
243
244 if num_own_segment_roots > 0 {
245 let _first_local_segment_index =
246 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
247 let _own_segment_roots =
248 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
249 }
250
251 let leaf_shard_segment_roots_counts =
252 remainder.split_off(..num_leaf_shard_blocks_with_segments * size_of::<u8>())?;
253
254 for &num_own_segment_roots in leaf_shard_segment_roots_counts {
255 let _shard_index = remainder.split_off(..ShardIndex::SIZE as usize)?;
256 let _first_local_segment_index =
257 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
258 let _own_segment_roots = remainder
259 .split_off(..usize::from(num_own_segment_roots) * SegmentRoot::SIZE)?;
260 }
261
262 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
263 }
264
265 let info = Self {
266 num_blocks,
267 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
268 };
269
270 if !info.is_internally_consistent() {
271 return None;
272 }
273
274 Some((info, remainder))
275 }
276
277 #[inline]
280 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
281 let num_blocks = bytes.split_off(..size_of::<u16>())?;
301 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
302
303 let bytes_start = bytes;
304
305 let mut counts = bytes.split_off(..num_blocks * (size_of::<u8>() * 2))?;
306
307 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
308
309 for _ in 0..num_blocks {
310 let num_own_segment_roots = usize::from(counts[0]);
311 let num_leaf_shard_blocks_with_segments = usize::from(counts[1]);
312 counts = &counts[2..];
313
314 (_, remainder) = IntermediateShardHeader::try_from_bytes(remainder)?;
315
316 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
317 let _segments_proof = remainder.split_off(..OUT_LEN)?;
318 }
319
320 if num_own_segment_roots > 0 {
321 let _first_local_segment_index =
322 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
323 let _own_segment_roots =
324 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
325 }
326
327 let leaf_shard_segment_roots_counts =
328 remainder.split_off(..num_leaf_shard_blocks_with_segments * size_of::<u8>())?;
329
330 for &num_own_segment_roots in leaf_shard_segment_roots_counts {
331 let _shard_index = remainder.split_off(..ShardIndex::SIZE as usize)?;
332 let _first_local_segment_index =
333 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
334 let _own_segment_roots = remainder
335 .split_off(..usize::from(num_own_segment_roots) * SegmentRoot::SIZE)?;
336 }
337
338 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
339 }
340
341 Some((
342 Self {
343 num_blocks,
344 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
345 },
346 remainder,
347 ))
348 }
349
350 #[inline]
355 pub fn is_internally_consistent(&self) -> bool {
356 let mut last_intermediate_shard_info =
357 None::<(ShardIndex, BlockNumber, Option<LocalSegmentIndex>)>;
358
359 self.iter().all(|intermediate_shard_block| {
360 let shard_index = intermediate_shard_block.header.prefix.shard_index;
361
362 if let Some((
364 last_intermediate_shard_index,
365 last_intermediate_shard_block_number,
366 last_intermediate_shard_first_local_segment_index,
367 )) = last_intermediate_shard_info
368 {
369 match last_intermediate_shard_index.cmp(&shard_index) {
370 cmp::Ordering::Less => {
371 last_intermediate_shard_info.replace((
372 shard_index,
373 intermediate_shard_block.header.prefix.number,
374 intermediate_shard_block
375 .own_segments
376 .as_ref()
377 .map(|own_segments| own_segments.first_local_segment_index),
378 ));
379 }
380 cmp::Ordering::Equal => {
381 if last_intermediate_shard_block_number
382 >= intermediate_shard_block.header.prefix.number
383 {
384 return false;
385 }
386 if let Some(own_segments) = &intermediate_shard_block.own_segments {
387 if let Some(last_intermediate_shard_first_local_segment_index) =
388 last_intermediate_shard_first_local_segment_index
389 && last_intermediate_shard_first_local_segment_index
390 >= own_segments.first_local_segment_index
391 {
392 return false;
393 }
394
395 last_intermediate_shard_info.replace((
396 shard_index,
397 intermediate_shard_block.header.prefix.number,
398 Some(own_segments.first_local_segment_index),
399 ));
400 } else {
401 last_intermediate_shard_info.replace((
402 shard_index,
403 intermediate_shard_block.header.prefix.number,
404 last_intermediate_shard_first_local_segment_index,
405 ));
406 }
407 }
408 cmp::Ordering::Greater => {
409 return false;
410 }
411 }
412 } else {
413 last_intermediate_shard_info.replace((
414 shard_index,
415 intermediate_shard_block.header.prefix.number,
416 intermediate_shard_block
417 .own_segments
418 .as_ref()
419 .map(|own_segments| own_segments.first_local_segment_index),
420 ));
421 }
422
423 let mut last_leaf_shard_info = None::<(ShardIndex, LocalSegmentIndex)>;
424
425 if !intermediate_shard_block.leaf_shards_segments().all(
427 |(leaf_shard_index, own_segments)| {
428 if !leaf_shard_index.is_child_of(shard_index) {
429 return false;
430 }
431
432 if let Some((
433 last_leaf_shard_index,
434 last_leaf_shard_first_local_segment_index,
435 )) = last_leaf_shard_info
436 {
437 match last_leaf_shard_index.cmp(&leaf_shard_index) {
438 cmp::Ordering::Less => {
439 }
441 cmp::Ordering::Equal => {
442 if last_leaf_shard_first_local_segment_index
443 >= own_segments.first_local_segment_index
444 {
445 return false;
446 }
447 }
448 cmp::Ordering::Greater => {
449 return false;
450 }
451 }
452 }
453 last_leaf_shard_info
454 .replace((leaf_shard_index, own_segments.first_local_segment_index));
455
456 true
457 },
458 ) {
459 return false;
460 }
461
462 if intermediate_shard_block.own_segments.is_none()
463 && intermediate_shard_block
464 .leaf_shards_segments()
465 .size_hint()
466 .0
467 == 0
468 {
469 return intermediate_shard_block.segments_proof.is_none();
470 }
471
472 let segments_proof = intermediate_shard_block.segments_proof.unwrap_or(&[0; _]);
473
474 #[expect(clippy::assertions_on_constants, reason = "Intentional documentation")]
478 #[expect(clippy::eq_op, reason = "Intentional documentation")]
479 const {
480 assert!(u16::MAX == 65535);
481 }
482 let leaf_shards_root = UnbalancedMerkleTree::compute_root_only::<65535, _, _>(
483 intermediate_shard_block.leaf_shards_segments().map(
484 |(shard_index, own_segments)| own_segments.root_with_shard_index(shard_index),
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.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
563 num_own_segment_roots,
564 )
565 };
566 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
567
568 Some(OwnSegments {
569 first_local_segment_index,
570 segment_roots: own_segment_roots,
571 })
572 } else {
573 None
574 };
575
576 let leaf_shard_segment_roots_counts = unsafe {
578 remainder.get_unchecked(
579 ..usize::from(num_leaf_shard_blocks_with_segments) * size_of::<u8>(),
580 )
581 };
582
583 let leaf_shards_segments_bytes;
584 (leaf_shards_segments_bytes, remainder) = unsafe {
586 remainder.split_at_unchecked(
587 usize::from(num_leaf_shard_blocks_with_segments) * size_of::<u8>()
588 + usize::from(num_leaf_shard_blocks_with_segments)
589 * (ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize
590 + leaf_shard_segment_roots_counts.iter().fold(
591 0usize,
592 |acc, &num_own_segment_roots| {
593 acc + usize::from(num_own_segment_roots) * SegmentRoot::SIZE
594 },
595 ),
596 )
597 };
598
599 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)
600 .expect("Already checked in constructor; qed");
601
602 IntermediateShardBlockInfo {
603 header,
604 segments_proof,
605 own_segments,
606 num_leaf_shard_blocks_with_segments,
607 leaf_shards_segments_bytes,
608 }
609 })
610 .take(self.num_blocks)
611 }
612
613 #[inline(always)]
615 pub const fn len(&self) -> usize {
616 self.num_blocks
617 }
618
619 #[inline(always)]
621 pub const fn is_empty(&self) -> bool {
622 self.num_blocks == 0
623 }
624
625 #[inline]
629 pub fn segments_root(&self) -> Blake3Hash {
630 let root = UnbalancedMerkleTree::compute_root_only::<{ u16::MAX as u64 }, _, _>(
631 self.iter().map(|shard_block_info| {
632 #[expect(clippy::assertions_on_constants, reason = "Intentional documentation")]
636 #[expect(clippy::eq_op, reason = "Intentional documentation")]
637 const {
638 assert!(u32::MAX == 4_294_967_295);
639 }
640 UnbalancedMerkleTree::compute_root_only::<4_294_967_295, _, _>(
641 shard_block_info
642 .own_segments
643 .as_ref()
644 .map(OwnSegments::root)
645 .into_iter()
646 .chain(shard_block_info.leaf_shards_segments().map(
647 |(shard_index, own_segments)| {
648 own_segments.root_with_shard_index(shard_index)
649 },
650 )),
651 )
652 .unwrap_or_default()
653 }),
654 )
655 .unwrap_or_default();
656
657 Blake3Hash::new(root)
658 }
659
660 #[inline]
664 pub fn headers_root(&self) -> Blake3Hash {
665 let root = UnbalancedMerkleTree::compute_root_only::<{ u16::MAX as u64 }, _, _>(
666 self.iter().map(|shard_block_info| {
668 single_block_hash(shard_block_info.header.root().as_ref())
672 .expect("Less than a single block worth of bytes; qed")
673 }),
674 )
675 .unwrap_or_default();
676
677 Blake3Hash::new(root)
678 }
679}
680
681#[derive(Debug, Copy, Clone, Yokeable)]
683#[non_exhaustive]
685pub struct BeaconChainBody<'a> {
686 own_segments: Option<OwnSegments<'a>>,
688 intermediate_shard_blocks: IntermediateShardBlocksInfo<'a>,
690 pot_checkpoints: &'a [PotCheckpoints],
693}
694
695impl<'a> GenericBlockBody<'a> for BeaconChainBody<'a> {
696 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
697
698 #[cfg(feature = "alloc")]
699 type Owned = OwnedBeaconChainBody;
700
701 #[cfg(feature = "alloc")]
702 #[inline(always)]
703 fn to_owned(self) -> Self::Owned {
704 self.to_owned()
705 }
706
707 #[inline(always)]
708 fn root(&self) -> Blake3Hash {
709 self.root()
710 }
711}
712
713impl<'a> BeaconChainBody<'a> {
714 #[inline]
720 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
721 let num_pot_checkpoints = bytes.split_off(..size_of::<u32>())?;
730 let num_pot_checkpoints =
732 *unsafe { <u32 as TrivialType>::from_bytes(num_pot_checkpoints) }? as usize;
733
734 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
735 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
736
737 let own_segments = if num_own_segment_roots > 0 {
738 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
739 let first_local_segment_index = unsafe {
741 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
742 }
743 .as_inner();
744
745 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
746 let own_segment_roots = unsafe {
748 slice::from_raw_parts(
749 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
750 num_own_segment_roots,
751 )
752 };
753 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
754
755 Some(OwnSegments {
756 first_local_segment_index,
757 segment_roots: own_segment_roots,
758 })
759 } else {
760 None
761 };
762
763 let (intermediate_shard_blocks, mut remainder) =
764 IntermediateShardBlocksInfo::try_from_bytes(bytes)?;
765
766 let pot_checkpoints = remainder.split_off(..num_pot_checkpoints * PotCheckpoints::SIZE)?;
767 let pot_checkpoints = unsafe {
769 slice::from_raw_parts(
770 pot_checkpoints
771 .as_ptr()
772 .cast::<[u8; PotCheckpoints::SIZE]>(),
773 num_pot_checkpoints,
774 )
775 };
776 let pot_checkpoints = PotCheckpoints::slice_from_bytes(pot_checkpoints);
777
778 let body = Self {
779 own_segments,
780 intermediate_shard_blocks,
781 pot_checkpoints,
782 };
783
784 if !body.is_internally_consistent() {
785 return None;
786 }
787
788 Some((body, remainder))
789 }
790
791 #[inline]
796 pub fn is_internally_consistent(&self) -> bool {
797 true
799 }
800
801 #[inline]
804 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
805 let num_pot_checkpoints = bytes.split_off(..size_of::<u32>())?;
814 let num_pot_checkpoints =
816 *unsafe { <u32 as TrivialType>::from_bytes(num_pot_checkpoints) }? as usize;
817
818 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
819 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
820
821 let own_segments = if num_own_segment_roots > 0 {
822 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
823 let first_local_segment_index = unsafe {
825 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
826 }
827 .as_inner();
828
829 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
830 let own_segment_roots = unsafe {
832 slice::from_raw_parts(
833 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
834 num_own_segment_roots,
835 )
836 };
837 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
838
839 Some(OwnSegments {
840 first_local_segment_index,
841 segment_roots: own_segment_roots,
842 })
843 } else {
844 None
845 };
846
847 let (intermediate_shard_blocks, mut remainder) =
848 IntermediateShardBlocksInfo::try_from_bytes_unchecked(bytes)?;
849
850 let pot_checkpoints = remainder.split_off(..num_pot_checkpoints * PotCheckpoints::SIZE)?;
851 let pot_checkpoints = unsafe {
853 slice::from_raw_parts(
854 pot_checkpoints
855 .as_ptr()
856 .cast::<[u8; PotCheckpoints::SIZE]>(),
857 num_pot_checkpoints,
858 )
859 };
860 let pot_checkpoints = PotCheckpoints::slice_from_bytes(pot_checkpoints);
861
862 Some((
863 Self {
864 own_segments,
865 intermediate_shard_blocks,
866 pot_checkpoints,
867 },
868 remainder,
869 ))
870 }
871
872 #[cfg(feature = "alloc")]
874 #[inline(always)]
875 pub fn to_owned(self) -> OwnedBeaconChainBody {
876 if let Some(own_segments) = self.own_segments {
877 let first_local_segment_index = own_segments.first_local_segment_index;
878
879 OwnedBeaconChainBody::new(
880 own_segments.segment_roots.iter().copied().enumerate().map(
881 |(index, segment_root)| {
882 (
883 first_local_segment_index + LocalSegmentIndex::from(index as u64),
884 segment_root,
885 )
886 },
887 ),
888 self.intermediate_shard_blocks.iter(),
889 self.pot_checkpoints,
890 )
891 .expect("`self` is always a valid invariant; qed")
892 } else {
893 OwnedBeaconChainBody::new(
894 iter::empty(),
895 self.intermediate_shard_blocks.iter(),
896 self.pot_checkpoints,
897 )
898 .expect("`self` is always a valid invariant; qed")
899 }
900 }
901
902 #[inline(always)]
904 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
905 self.own_segments
906 }
907
908 #[inline(always)]
910 pub fn intermediate_shard_blocks(&self) -> &IntermediateShardBlocksInfo<'a> {
911 &self.intermediate_shard_blocks
912 }
913
914 #[inline(always)]
917 pub fn pot_checkpoints(&self) -> &'a [PotCheckpoints] {
918 self.pot_checkpoints
919 }
920
921 #[inline]
923 pub fn root(&self) -> Blake3Hash {
924 let root = BalancedMerkleTree::compute_root_only(&[
926 *self
927 .own_segments
928 .as_ref()
929 .map(OwnSegments::root)
930 .unwrap_or_default(),
931 *self.intermediate_shard_blocks.segments_root(),
932 *self.intermediate_shard_blocks.headers_root(),
933 blake3::hash(PotCheckpoints::bytes_from_slice(self.pot_checkpoints).as_flattened())
934 .into(),
935 ]);
936
937 Blake3Hash::new(root)
938 }
939}
940
941#[derive(Debug, Copy, Clone)]
943pub struct LeafShardOwnSegments<'a> {
944 pub segment_roots_proof: &'a [u8; OUT_LEN],
946 pub own_segments: OwnSegments<'a>,
948}
949
950#[derive(Debug, Clone)]
952pub struct LeafShardBlockInfo<'a> {
953 pub header: LeafShardHeader<'a>,
955 pub segments: Option<LeafShardOwnSegments<'a>>,
957}
958
959#[derive(Debug, Copy, Clone)]
961pub struct LeafShardBlocksInfo<'a> {
962 num_blocks: usize,
963 bytes: &'a [u8],
964}
965
966impl<'a> LeafShardBlocksInfo<'a> {
967 #[inline]
973 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
974 let num_blocks = bytes.split_off(..size_of::<u16>())?;
987 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
988
989 let bytes_start = bytes;
990
991 let mut counts = bytes.split_off(..num_blocks * size_of::<u8>())?;
992
993 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
994
995 for _ in 0..num_blocks {
996 let num_own_segment_roots = usize::from(counts[0]);
997 counts = &counts[1..];
998
999 (_, remainder) = LeafShardHeader::try_from_bytes(remainder)?;
1000
1001 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
1002
1003 if num_own_segment_roots > 0 {
1004 let _first_local_segment_index =
1005 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
1006 let _segment_roots_proof = remainder.split_off(..OUT_LEN)?;
1007 let _own_segment_roots =
1008 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1009 }
1010 }
1011
1012 let info = Self {
1013 num_blocks,
1014 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1015 };
1016
1017 if !info.is_internally_consistent() {
1018 return None;
1019 }
1020
1021 Some((info, remainder))
1022 }
1023
1024 #[inline]
1027 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1028 let num_blocks = bytes.split_off(..size_of::<u16>())?;
1041 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
1042
1043 let bytes_start = bytes;
1044
1045 let mut counts = bytes.split_off(..num_blocks * size_of::<u8>())?;
1046
1047 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
1048
1049 for _ in 0..num_blocks {
1050 let num_own_segment_roots = usize::from(counts[0]);
1051 counts = &counts[1..];
1052
1053 (_, remainder) = LeafShardHeader::try_from_bytes(remainder)?;
1054
1055 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
1056
1057 if num_own_segment_roots > 0 {
1058 let _first_local_segment_index =
1059 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
1060 let _segment_roots_proof = remainder.split_off(..OUT_LEN)?;
1061 let _own_segment_roots =
1062 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1063 }
1064 }
1065
1066 Some((
1067 Self {
1068 num_blocks,
1069 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1070 },
1071 remainder,
1072 ))
1073 }
1074
1075 #[inline]
1080 pub fn is_internally_consistent(&self) -> bool {
1081 let mut last_leaf_shard_info = None::<(ShardIndex, BlockNumber, Option<LocalSegmentIndex>)>;
1082
1083 self.iter().all(|leaf_shard_block| {
1084 let shard_index = leaf_shard_block.header.prefix.shard_index;
1085
1086 if let Some((
1088 last_leaf_shard_index,
1089 last_leaf_shard_block_number,
1090 last_leaf_shard_first_local_segment_index,
1091 )) = last_leaf_shard_info
1092 {
1093 match last_leaf_shard_index.cmp(&shard_index) {
1094 cmp::Ordering::Less => {
1095 last_leaf_shard_info.replace((
1096 shard_index,
1097 leaf_shard_block.header.prefix.number,
1098 leaf_shard_block
1099 .segments
1100 .as_ref()
1101 .map(|segments| segments.own_segments.first_local_segment_index),
1102 ));
1103 }
1104 cmp::Ordering::Equal => {
1105 if last_leaf_shard_block_number >= leaf_shard_block.header.prefix.number {
1106 return false;
1107 }
1108 if let Some(leaf_shard_segments) = &leaf_shard_block.segments {
1109 if let Some(last_leaf_shard_first_local_segment_index) =
1110 last_leaf_shard_first_local_segment_index
1111 && last_leaf_shard_first_local_segment_index
1112 >= leaf_shard_segments.own_segments.first_local_segment_index
1113 {
1114 return false;
1115 }
1116
1117 last_leaf_shard_info.replace((
1118 shard_index,
1119 leaf_shard_block.header.prefix.number,
1120 Some(leaf_shard_segments.own_segments.first_local_segment_index),
1121 ));
1122 } else {
1123 last_leaf_shard_info.replace((
1124 shard_index,
1125 leaf_shard_block.header.prefix.number,
1126 last_leaf_shard_first_local_segment_index,
1127 ));
1128 }
1129 }
1130 cmp::Ordering::Greater => {
1131 return false;
1132 }
1133 }
1134 } else {
1135 last_leaf_shard_info.replace((
1136 shard_index,
1137 leaf_shard_block.header.prefix.number,
1138 leaf_shard_block
1139 .segments
1140 .as_ref()
1141 .map(|segments| segments.own_segments.first_local_segment_index),
1142 ));
1143 }
1144
1145 let Some(segments) = leaf_shard_block.segments else {
1146 return true;
1147 };
1148
1149 BalancedMerkleTree::<2>::verify(
1150 &leaf_shard_block.header.result.body_root,
1151 array::from_ref(segments.segment_roots_proof),
1152 0,
1153 *segments.own_segments.root(),
1154 )
1155 })
1156 }
1157
1158 #[inline]
1160 pub fn iter(
1161 &self,
1162 ) -> impl ExactSizeIterator<Item = LeafShardBlockInfo<'a>> + TrustedLen + use<'a> {
1163 let (mut counts, mut remainder) = unsafe {
1165 self.bytes
1166 .split_at_unchecked(self.num_blocks * size_of::<u8>())
1167 };
1168
1169 iter::repeat_with(move || {
1170 let num_own_segment_roots = usize::from(counts[0]);
1171 counts = &counts[1..];
1172
1173 let header;
1175 (header, remainder) = LeafShardHeader::try_from_bytes(remainder)
1176 .expect("Already checked in constructor; qed");
1177
1178 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)
1179 .expect("Already checked in constructor; qed");
1180
1181 let segments = if num_own_segment_roots > 0 {
1182 let first_local_segment_index;
1183 (first_local_segment_index, remainder) =
1185 unsafe { remainder.split_at_unchecked(LocalSegmentIndex::SIZE as usize) };
1186 let first_local_segment_index =
1188 *unsafe { LocalSegmentIndex::from_bytes_unchecked(first_local_segment_index) };
1189
1190 let segment_roots_proof;
1191 (segment_roots_proof, remainder) = unsafe { remainder.split_at_unchecked(OUT_LEN) };
1193 let segment_roots_proof = unsafe {
1195 segment_roots_proof
1196 .as_ptr()
1197 .cast::<[u8; OUT_LEN]>()
1198 .as_ref_unchecked()
1199 };
1200
1201 let own_segment_roots;
1202 (own_segment_roots, remainder) = unsafe {
1204 remainder.split_at_unchecked(num_own_segment_roots * SegmentRoot::SIZE)
1205 };
1206 let own_segment_roots = unsafe {
1208 slice::from_raw_parts(
1209 own_segment_roots.as_ptr().cast::<[u8; 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::<{ u16::MAX as u64 }, _, _>(
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::<{ u16::MAX as u64 }, _, _>(
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.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1344 num_own_segment_roots,
1345 )
1346 };
1347 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1348
1349 Some(OwnSegments {
1350 first_local_segment_index,
1351 segment_roots: own_segment_roots,
1352 })
1353 } else {
1354 None
1355 };
1356
1357 let (leaf_shard_blocks, remainder) = LeafShardBlocksInfo::try_from_bytes(bytes)?;
1358
1359 let body = Self {
1360 own_segments,
1361 leaf_shard_blocks,
1362 };
1363
1364 if !body.is_internally_consistent() {
1365 return None;
1366 }
1367
1368 Some((body, remainder))
1369 }
1370
1371 #[inline]
1376 pub fn is_internally_consistent(&self) -> bool {
1377 true
1379 }
1380
1381 #[inline]
1384 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1385 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1392 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1393
1394 let own_segments = if num_own_segment_roots > 0 {
1395 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1396 let first_local_segment_index = unsafe {
1398 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1399 }
1400 .as_inner();
1401
1402 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1403 let own_segment_roots = unsafe {
1405 slice::from_raw_parts(
1406 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1407 num_own_segment_roots,
1408 )
1409 };
1410 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1411
1412 Some(OwnSegments {
1413 first_local_segment_index,
1414 segment_roots: own_segment_roots,
1415 })
1416 } else {
1417 None
1418 };
1419
1420 let (leaf_shard_blocks, remainder) = LeafShardBlocksInfo::try_from_bytes_unchecked(bytes)?;
1421
1422 Some((
1423 Self {
1424 own_segments,
1425 leaf_shard_blocks,
1426 },
1427 remainder,
1428 ))
1429 }
1430
1431 #[inline(always)]
1433 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
1434 self.own_segments
1435 }
1436
1437 #[inline(always)]
1439 pub fn leaf_shard_blocks(&self) -> &LeafShardBlocksInfo<'a> {
1440 &self.leaf_shard_blocks
1441 }
1442
1443 #[cfg(feature = "alloc")]
1445 #[inline(always)]
1446 pub fn to_owned(self) -> OwnedIntermediateShardBody {
1447 if let Some(own_segments) = self.own_segments {
1448 let first_local_segment_index = own_segments.first_local_segment_index;
1449
1450 OwnedIntermediateShardBody::new(
1451 own_segments.segment_roots.iter().copied().enumerate().map(
1452 |(index, segment_root)| {
1453 (
1454 first_local_segment_index + LocalSegmentIndex::from(index as u64),
1455 segment_root,
1456 )
1457 },
1458 ),
1459 self.leaf_shard_blocks.iter(),
1460 )
1461 .expect("`self` is always a valid invariant; qed")
1462 } else {
1463 OwnedIntermediateShardBody::new(iter::empty(), self.leaf_shard_blocks.iter())
1464 .expect("`self` is always a valid invariant; qed")
1465 }
1466 }
1467
1468 #[inline]
1470 pub fn root(&self) -> Blake3Hash {
1471 let root = BalancedMerkleTree::compute_root_only(&[
1473 BalancedMerkleTree::compute_root_only(&[
1474 *self
1475 .own_segments
1476 .as_ref()
1477 .map(OwnSegments::root)
1478 .unwrap_or_default(),
1479 *self.leaf_shard_blocks.segments_root(),
1480 ]),
1481 *self.leaf_shard_blocks.headers_root(),
1482 ]);
1483
1484 Blake3Hash::new(root)
1485 }
1486}
1487
1488#[derive(Debug, Copy, Clone)]
1490pub struct Transactions<'a> {
1491 num_transactions: usize,
1492 bytes: &'a [u8],
1493}
1494
1495impl<'a> Transactions<'a> {
1496 #[inline]
1502 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1503 let num_transactions = bytes.split_off(..size_of::<u32>())?;
1511 let num_transactions = u32::from_le_bytes([
1512 num_transactions[0],
1513 num_transactions[1],
1514 num_transactions[2],
1515 num_transactions[3],
1516 ]) as usize;
1517
1518 let mut remainder = align_to_and_ensure_zero_padding::<u128>(bytes)?;
1519 let bytes_start = remainder;
1520
1521 for _ in 0..num_transactions {
1522 (_, remainder) = Transaction::try_from_bytes(bytes)?;
1523 remainder = align_to_and_ensure_zero_padding::<u128>(remainder)?;
1524 }
1525
1526 Some((
1527 Self {
1528 num_transactions,
1529 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1530 },
1531 remainder,
1532 ))
1533 }
1534
1535 #[inline]
1537 pub fn iter(&self) -> impl ExactSizeIterator<Item = Transaction<'a>> + TrustedLen + use<'a> {
1538 let mut remainder = self.bytes;
1539
1540 iter::repeat_with(move || {
1541 let transaction = unsafe { Transaction::from_bytes_unchecked(remainder) };
1543
1544 remainder = &remainder[transaction.encoded_size()..];
1545 remainder = align_to_and_ensure_zero_padding::<u128>(remainder)
1546 .expect("Already checked in constructor; qed");
1547
1548 transaction
1549 })
1550 .take(self.num_transactions)
1551 }
1552
1553 #[inline(always)]
1555 pub const fn len(&self) -> usize {
1556 self.num_transactions
1557 }
1558
1559 #[inline(always)]
1561 pub const fn is_empty(&self) -> bool {
1562 self.num_transactions == 0
1563 }
1564
1565 #[inline]
1569 pub fn root(&self) -> Blake3Hash {
1570 let root = UnbalancedMerkleTree::compute_root_only::<{ u32::MAX as u64 }, _, _>(
1571 self.iter().map(|transaction| {
1572 single_block_hash(transaction.hash().as_ref())
1576 .expect("Less than a single block worth of bytes; qed")
1577 }),
1578 )
1579 .unwrap_or_default();
1580
1581 Blake3Hash::new(root)
1582 }
1583}
1584
1585#[derive(Debug, Copy, Clone, Yokeable)]
1587#[non_exhaustive]
1589pub struct LeafShardBody<'a> {
1590 own_segments: Option<OwnSegments<'a>>,
1592 transactions: Transactions<'a>,
1594}
1595
1596impl<'a> GenericBlockBody<'a> for LeafShardBody<'a> {
1597 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1598
1599 #[cfg(feature = "alloc")]
1600 type Owned = OwnedLeafShardBody;
1601
1602 #[cfg(feature = "alloc")]
1603 #[inline(always)]
1604 fn to_owned(self) -> Self::Owned {
1605 self.to_owned()
1606 }
1607
1608 #[inline(always)]
1609 fn root(&self) -> Blake3Hash {
1610 self.root()
1611 }
1612}
1613
1614impl<'a> LeafShardBody<'a> {
1615 #[inline]
1621 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1622 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1629 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1630
1631 let own_segments = if num_own_segment_roots > 0 {
1632 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1633 let first_local_segment_index = unsafe {
1635 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1636 }
1637 .as_inner();
1638
1639 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1640 let own_segment_roots = unsafe {
1642 slice::from_raw_parts(
1643 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1644 num_own_segment_roots,
1645 )
1646 };
1647 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1648
1649 Some(OwnSegments {
1650 first_local_segment_index,
1651 segment_roots: own_segment_roots,
1652 })
1653 } else {
1654 None
1655 };
1656
1657 let (transactions, remainder) = Transactions::try_from_bytes(bytes)?;
1658
1659 let body = Self {
1660 own_segments,
1661 transactions,
1662 };
1663
1664 if !body.is_internally_consistent() {
1665 return None;
1666 }
1667
1668 Some((body, remainder))
1669 }
1670
1671 #[inline]
1676 pub fn is_internally_consistent(&self) -> bool {
1677 true
1679 }
1680
1681 #[inline]
1684 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1685 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1692 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1693
1694 let own_segments = if num_own_segment_roots > 0 {
1695 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1696 let first_local_segment_index = unsafe {
1698 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1699 }
1700 .as_inner();
1701
1702 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1703 let own_segment_roots = unsafe {
1705 slice::from_raw_parts(
1706 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1707 num_own_segment_roots,
1708 )
1709 };
1710 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1711
1712 Some(OwnSegments {
1713 first_local_segment_index,
1714 segment_roots: own_segment_roots,
1715 })
1716 } else {
1717 None
1718 };
1719
1720 let (transactions, remainder) = Transactions::try_from_bytes(bytes)?;
1721
1722 Some((
1723 Self {
1724 own_segments,
1725 transactions,
1726 },
1727 remainder,
1728 ))
1729 }
1730
1731 #[inline(always)]
1733 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
1734 self.own_segments
1735 }
1736
1737 #[inline(always)]
1739 pub fn transactions(&self) -> &Transactions<'a> {
1740 &self.transactions
1741 }
1742
1743 #[cfg(feature = "alloc")]
1745 #[inline(always)]
1746 pub fn to_owned(self) -> OwnedLeafShardBody {
1747 let mut builder = if let Some(own_segments) = self.own_segments {
1748 let first_local_segment_index = own_segments.first_local_segment_index;
1749
1750 OwnedLeafShardBody::init(own_segments.segment_roots.iter().copied().enumerate().map(
1751 |(index, segment_root)| {
1752 (
1753 first_local_segment_index + LocalSegmentIndex::from(index as u64),
1754 segment_root,
1755 )
1756 },
1757 ))
1758 .expect("`self` is always a valid invariant; qed")
1759 } else {
1760 OwnedLeafShardBody::init(iter::empty())
1761 .expect("`self` is always a valid invariant; qed")
1762 };
1763 for transaction in self.transactions.iter() {
1764 builder
1765 .add_transaction(transaction)
1766 .expect("`self` is always a valid invariant; qed");
1767 }
1768
1769 builder.finish()
1770 }
1771
1772 #[inline]
1774 pub fn root(&self) -> Blake3Hash {
1775 let root = BalancedMerkleTree::compute_root_only(&[
1776 *self
1777 .own_segments
1778 .as_ref()
1779 .map(OwnSegments::root)
1780 .unwrap_or_default(),
1781 *self.transactions.root(),
1782 ]);
1783
1784 Blake3Hash::new(root)
1785 }
1786}
1787
1788#[derive(Debug, Copy, Clone, From)]
1793pub enum BlockBody<'a> {
1794 BeaconChain(BeaconChainBody<'a>),
1796 IntermediateShard(IntermediateShardBody<'a>),
1798 LeafShard(LeafShardBody<'a>),
1800}
1801
1802impl<'a> BlockBody<'a> {
1803 #[inline]
1810 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1811 match shard_kind {
1812 RealShardKind::BeaconChain => {
1813 let (body, remainder) = BeaconChainBody::try_from_bytes(bytes)?;
1814 Some((Self::BeaconChain(body), remainder))
1815 }
1816 RealShardKind::IntermediateShard => {
1817 let (body, remainder) = IntermediateShardBody::try_from_bytes(bytes)?;
1818 Some((Self::IntermediateShard(body), remainder))
1819 }
1820 RealShardKind::LeafShard => {
1821 let (body, remainder) = LeafShardBody::try_from_bytes(bytes)?;
1822 Some((Self::LeafShard(body), remainder))
1823 }
1824 }
1825 }
1826
1827 #[inline]
1832 pub fn is_internally_consistent(&self) -> bool {
1833 match self {
1834 Self::BeaconChain(body) => body.is_internally_consistent(),
1835 Self::IntermediateShard(body) => body.is_internally_consistent(),
1836 Self::LeafShard(body) => body.is_internally_consistent(),
1837 }
1838 }
1839
1840 #[inline]
1843 pub fn try_from_bytes_unchecked(
1844 bytes: &'a [u8],
1845 shard_kind: RealShardKind,
1846 ) -> Option<(Self, &'a [u8])> {
1847 match shard_kind {
1848 RealShardKind::BeaconChain => {
1849 let (body, remainder) = BeaconChainBody::try_from_bytes_unchecked(bytes)?;
1850 Some((Self::BeaconChain(body), remainder))
1851 }
1852 RealShardKind::IntermediateShard => {
1853 let (body, remainder) = IntermediateShardBody::try_from_bytes_unchecked(bytes)?;
1854 Some((Self::IntermediateShard(body), remainder))
1855 }
1856 RealShardKind::LeafShard => {
1857 let (body, remainder) = LeafShardBody::try_from_bytes_unchecked(bytes)?;
1858 Some((Self::LeafShard(body), remainder))
1859 }
1860 }
1861 }
1862
1863 #[cfg(feature = "alloc")]
1865 #[inline(always)]
1866 pub fn to_owned(self) -> OwnedBlockBody {
1867 match self {
1868 Self::BeaconChain(body) => body.to_owned().into(),
1869 Self::IntermediateShard(body) => body.to_owned().into(),
1870 Self::LeafShard(body) => body.to_owned().into(),
1871 }
1872 }
1873
1874 #[inline]
1879 pub fn root(&self) -> Blake3Hash {
1880 match self {
1881 Self::BeaconChain(body) => body.root(),
1882 Self::IntermediateShard(body) => body.root(),
1883 Self::LeafShard(body) => body.root(),
1884 }
1885 }
1886}