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::alignment::Alignment;
20use ab_io_type::trivial_type::TrivialType;
21use ab_io_type::unaligned::Unaligned;
22use ab_merkle_tree::balanced::BalancedMerkleTree;
23use ab_merkle_tree::unbalanced::UnbalancedMerkleTree;
24use core::iter::TrustedLen;
25use core::{array, cmp, fmt, iter, slice};
26use derive_more::From;
27use yoke::Yokeable;
28
29pub trait GenericBlockBody<'a>
31where
32 Self: Copy + fmt::Debug + Into<BlockBody<'a>> + Send + Sync,
33{
34 const SHARD_KIND: RealShardKind;
36
37 #[cfg(feature = "alloc")]
39 type Owned: GenericOwnedBlockBody<Body<'a> = Self>
40 where
41 Self: 'a;
42
43 #[cfg(feature = "alloc")]
45 fn to_owned(self) -> Self::Owned;
46
47 fn root(&self) -> Blake3Hash;
49}
50
51#[inline]
53pub fn compute_segments_root<'a, const MAX_SEGMENTS: u64, Iter>(segment_roots: Iter) -> Blake3Hash
54where
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::<{ u64::from(u8::MAX) }, _>(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::<{ u64::from(u8::MAX) }, _>(self.segment_roots),
114 ]);
115
116 Blake3Hash::new(root)
117 }
118}
119
120#[derive(Debug, Clone)]
122#[expect(
123 clippy::partial_pub_fields,
124 reason = "Intentionally exposing immediately decoded fields above and hiding the rest of the implementation"
125)]
126pub struct IntermediateShardBlockInfo<'a> {
127 pub header: IntermediateShardHeader<'a>,
129 pub segments_proof: Option<&'a [u8; OUT_LEN]>,
131 pub own_segments: Option<OwnSegments<'a>>,
133 num_leaf_shard_blocks_with_segments: u8,
134 leaf_shards_segments_bytes: &'a [u8],
135}
136
137impl<'a> IntermediateShardBlockInfo<'a> {
138 #[inline]
140 pub fn leaf_shards_segments(
141 &self,
142 ) -> impl ExactSizeIterator<Item = (ShardIndex, OwnSegments<'a>)> + TrustedLen + use<'a> {
143 let (counts, mut remainder) = unsafe {
145 self.leaf_shards_segments_bytes.split_at_unchecked(
146 usize::from(self.num_leaf_shard_blocks_with_segments) * size_of::<u8>(),
147 )
148 };
149 counts.iter().map(move |&num_own_segment_roots| {
150 let num_own_segment_roots = usize::from(num_own_segment_roots);
151
152 let shard_index;
153 (shard_index, remainder) =
155 unsafe { remainder.split_at_unchecked(ShardIndex::SIZE as usize) };
156 let shard_index =
158 unsafe { Unaligned::<ShardIndex>::from_bytes_unchecked(shard_index) }.as_inner();
159
160 let first_local_segment_index;
161 (first_local_segment_index, remainder) =
163 unsafe { remainder.split_at_unchecked(LocalSegmentIndex::SIZE as usize) };
164 let first_local_segment_index = unsafe {
166 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
167 }
168 .as_inner();
169
170 let own_segment_roots;
171 (own_segment_roots, remainder) =
173 unsafe { remainder.split_at_unchecked(num_own_segment_roots * SegmentRoot::SIZE) };
174 let own_segment_roots = unsafe {
176 slice::from_raw_parts(
177 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
178 num_own_segment_roots,
179 )
180 };
181 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
182
183 (
184 shard_index,
185 OwnSegments {
186 first_local_segment_index,
187 segment_roots: own_segment_roots,
188 },
189 )
190 })
191 }
192}
193
194#[derive(Debug, Copy, Clone)]
196pub struct IntermediateShardBlocksInfo<'a> {
197 num_blocks: usize,
198 bytes: &'a [u8],
199}
200
201impl<'a> IntermediateShardBlocksInfo<'a> {
202 #[inline]
208 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
209 let num_blocks = bytes.split_off(..size_of::<u16>())?;
229 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
230
231 let bytes_start = bytes;
232
233 let mut counts = bytes.split_off(..num_blocks * (size_of::<u8>() * 2))?;
234
235 let mut remainder = align_to_and_ensure_zero_padding(bytes, Alignment::of::<u64>())?;
236
237 for _ in 0..num_blocks {
238 let num_own_segment_roots = usize::from(counts[0]);
239 let num_leaf_shard_blocks_with_segments = usize::from(counts[1]);
240 counts = &counts[2..];
241
242 (_, remainder) = IntermediateShardHeader::try_from_bytes(remainder)?;
243
244 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
245 let _segments_proof = remainder.split_off(..SegmentRoot::SIZE)?;
246 }
247
248 if num_own_segment_roots > 0 {
249 let _first_local_segment_index =
250 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
251 let _own_segment_roots =
252 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
253 }
254
255 let leaf_shard_segment_roots_counts =
256 remainder.split_off(..num_leaf_shard_blocks_with_segments * size_of::<u8>())?;
257
258 for &num_own_segment_roots in leaf_shard_segment_roots_counts {
259 let _shard_index = remainder.split_off(..ShardIndex::SIZE as usize)?;
260 let _first_local_segment_index =
261 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
262 let _own_segment_roots = remainder
263 .split_off(..usize::from(num_own_segment_roots) * SegmentRoot::SIZE)?;
264 }
265
266 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())?;
267 }
268
269 let info = Self {
270 num_blocks,
271 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
272 };
273
274 if !info.is_internally_consistent() {
275 return None;
276 }
277
278 Some((info, remainder))
279 }
280
281 #[inline]
284 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
285 let num_blocks = bytes.split_off(..size_of::<u16>())?;
305 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
306
307 let bytes_start = bytes;
308
309 let mut counts = bytes.split_off(..num_blocks * (size_of::<u8>() * 2))?;
310
311 let mut remainder = align_to_and_ensure_zero_padding(bytes, Alignment::of::<u64>())?;
312
313 for _ in 0..num_blocks {
314 let num_own_segment_roots = usize::from(counts[0]);
315 let num_leaf_shard_blocks_with_segments = usize::from(counts[1]);
316 counts = &counts[2..];
317
318 (_, remainder) = IntermediateShardHeader::try_from_bytes(remainder)?;
319
320 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
321 let _segments_proof = remainder.split_off(..OUT_LEN)?;
322 }
323
324 if num_own_segment_roots > 0 {
325 let _first_local_segment_index =
326 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
327 let _own_segment_roots =
328 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
329 }
330
331 let leaf_shard_segment_roots_counts =
332 remainder.split_off(..num_leaf_shard_blocks_with_segments * size_of::<u8>())?;
333
334 for &num_own_segment_roots in leaf_shard_segment_roots_counts {
335 let _shard_index = remainder.split_off(..ShardIndex::SIZE as usize)?;
336 let _first_local_segment_index =
337 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
338 let _own_segment_roots = remainder
339 .split_off(..usize::from(num_own_segment_roots) * SegmentRoot::SIZE)?;
340 }
341
342 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())?;
343 }
344
345 Some((
346 Self {
347 num_blocks,
348 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
349 },
350 remainder,
351 ))
352 }
353
354 #[inline]
359 pub fn is_internally_consistent(&self) -> bool {
360 let mut last_intermediate_shard_info =
361 None::<(ShardIndex, BlockNumber, Option<LocalSegmentIndex>)>;
362
363 self.iter().all(|intermediate_shard_block| {
364 let shard_index = intermediate_shard_block.header.prefix.shard_index;
365
366 if let Some((
368 last_intermediate_shard_index,
369 last_intermediate_shard_block_number,
370 last_intermediate_shard_first_local_segment_index,
371 )) = last_intermediate_shard_info
372 {
373 match last_intermediate_shard_index.cmp(&shard_index) {
374 cmp::Ordering::Less => {
375 last_intermediate_shard_info.replace((
376 shard_index,
377 intermediate_shard_block.header.prefix.number,
378 intermediate_shard_block
379 .own_segments
380 .as_ref()
381 .map(|own_segments| own_segments.first_local_segment_index),
382 ));
383 }
384 cmp::Ordering::Equal => {
385 if last_intermediate_shard_block_number
386 >= intermediate_shard_block.header.prefix.number
387 {
388 return false;
389 }
390 if let Some(own_segments) = &intermediate_shard_block.own_segments {
391 if let Some(last_intermediate_shard_first_local_segment_index) =
392 last_intermediate_shard_first_local_segment_index
393 && last_intermediate_shard_first_local_segment_index
394 >= own_segments.first_local_segment_index
395 {
396 return false;
397 }
398
399 last_intermediate_shard_info.replace((
400 shard_index,
401 intermediate_shard_block.header.prefix.number,
402 Some(own_segments.first_local_segment_index),
403 ));
404 } else {
405 last_intermediate_shard_info.replace((
406 shard_index,
407 intermediate_shard_block.header.prefix.number,
408 last_intermediate_shard_first_local_segment_index,
409 ));
410 }
411 }
412 cmp::Ordering::Greater => {
413 return false;
414 }
415 }
416 } else {
417 last_intermediate_shard_info.replace((
418 shard_index,
419 intermediate_shard_block.header.prefix.number,
420 intermediate_shard_block
421 .own_segments
422 .as_ref()
423 .map(|own_segments| own_segments.first_local_segment_index),
424 ));
425 }
426
427 let mut last_leaf_shard_info = None::<(ShardIndex, LocalSegmentIndex)>;
428
429 if !intermediate_shard_block.leaf_shards_segments().all(
431 |(leaf_shard_index, own_segments)| {
432 if !leaf_shard_index.is_child_of(shard_index) {
433 return false;
434 }
435
436 if let Some((
437 last_leaf_shard_index,
438 last_leaf_shard_first_local_segment_index,
439 )) = last_leaf_shard_info
440 {
441 match last_leaf_shard_index.cmp(&leaf_shard_index) {
442 cmp::Ordering::Less => {
443 }
445 cmp::Ordering::Equal => {
446 if last_leaf_shard_first_local_segment_index
447 >= own_segments.first_local_segment_index
448 {
449 return false;
450 }
451 }
452 cmp::Ordering::Greater => {
453 return false;
454 }
455 }
456 }
457 last_leaf_shard_info
458 .replace((leaf_shard_index, own_segments.first_local_segment_index));
459
460 true
461 },
462 ) {
463 return false;
464 }
465
466 if intermediate_shard_block.own_segments.is_none()
467 && intermediate_shard_block
468 .leaf_shards_segments()
469 .size_hint()
470 .0
471 == 0
472 {
473 return intermediate_shard_block.segments_proof.is_none();
474 }
475
476 let segments_proof = intermediate_shard_block.segments_proof.unwrap_or(&[0; _]);
477
478 let leaf_shards_root =
479 UnbalancedMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
480 intermediate_shard_block.leaf_shards_segments().map(
481 |(shard_index, own_segments)| {
482 own_segments.root_with_shard_index(shard_index)
483 },
484 ),
485 )
486 .unwrap_or_default();
487
488 BalancedMerkleTree::<2>::verify(
489 &intermediate_shard_block.header.result.body_root,
490 array::from_ref(segments_proof),
491 0,
492 BalancedMerkleTree::compute_root_only(&[
493 *intermediate_shard_block
494 .own_segments
495 .as_ref()
496 .map(OwnSegments::root)
497 .unwrap_or_default(),
498 leaf_shards_root,
499 ]),
500 )
501 })
502 }
503
504 #[inline]
506 pub fn iter(
507 &self,
508 ) -> impl ExactSizeIterator<Item = IntermediateShardBlockInfo<'a>> + TrustedLen + use<'a> {
509 let (mut counts, mut remainder) = unsafe {
511 self.bytes
512 .split_at_unchecked(self.num_blocks * (size_of::<u8>() + size_of::<u16>()))
513 };
514
515 iter::repeat_with(move || {
516 let num_own_segment_roots = usize::from(counts[0]);
517 let num_leaf_shard_blocks_with_segments = counts[1];
518 counts = &counts[2..];
519
520 let header;
522 (header, remainder) = IntermediateShardHeader::try_from_bytes(remainder)
523 .expect("Already checked in constructor; qed");
524
525 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())
526 .expect("Already checked in constructor; qed");
527
528 let segments_proof =
529 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
530 let segments_proof;
531 (segments_proof, remainder) = unsafe { remainder.split_at_unchecked(OUT_LEN) };
533 Some(unsafe {
535 segments_proof
536 .as_ptr()
537 .cast::<[u8; OUT_LEN]>()
538 .as_ref_unchecked()
539 })
540 } else {
541 None
542 };
543
544 let own_segments = if num_own_segment_roots > 0 {
545 let first_local_segment_index;
546 (first_local_segment_index, remainder) =
548 unsafe { remainder.split_at_unchecked(size_of::<LocalSegmentIndex>()) };
549 let first_local_segment_index =
551 *unsafe { LocalSegmentIndex::from_bytes_unchecked(first_local_segment_index) };
552
553 let own_segment_roots;
554 (own_segment_roots, remainder) = unsafe {
556 remainder.split_at_unchecked(num_own_segment_roots * SegmentRoot::SIZE)
557 };
558 let own_segment_roots = unsafe {
560 slice::from_raw_parts(
561 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
562 num_own_segment_roots,
563 )
564 };
565 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
566
567 Some(OwnSegments {
568 first_local_segment_index,
569 segment_roots: own_segment_roots,
570 })
571 } else {
572 None
573 };
574
575 let leaf_shard_segment_roots_counts = unsafe {
577 remainder.get_unchecked(
578 ..usize::from(num_leaf_shard_blocks_with_segments) * size_of::<u8>(),
579 )
580 };
581
582 let leaf_shards_segments_bytes;
583 (leaf_shards_segments_bytes, remainder) = unsafe {
585 remainder.split_at_unchecked(
586 usize::from(num_leaf_shard_blocks_with_segments) * size_of::<u8>()
587 + usize::from(num_leaf_shard_blocks_with_segments)
588 * (ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize
589 + leaf_shard_segment_roots_counts.iter().fold(
590 0usize,
591 |acc, &num_own_segment_roots| {
592 acc + usize::from(num_own_segment_roots) * SegmentRoot::SIZE
593 },
594 ),
595 )
596 };
597
598 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())
599 .expect("Already checked in constructor; qed");
600
601 IntermediateShardBlockInfo {
602 header,
603 segments_proof,
604 own_segments,
605 num_leaf_shard_blocks_with_segments,
606 leaf_shards_segments_bytes,
607 }
608 })
609 .take(self.num_blocks)
610 }
611
612 #[inline(always)]
614 pub const fn len(&self) -> usize {
615 self.num_blocks
616 }
617
618 #[inline(always)]
620 pub const fn is_empty(&self) -> bool {
621 self.num_blocks == 0
622 }
623
624 #[inline]
628 pub fn segments_root(&self) -> Blake3Hash {
629 let root = UnbalancedMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
630 self.iter().map(|shard_block_info| {
631 UnbalancedMerkleTree::compute_root_only::<{ u64::from(u32::MAX) }, _, _>(
632 shard_block_info
633 .own_segments
634 .as_ref()
635 .map(OwnSegments::root)
636 .into_iter()
637 .chain(shard_block_info.leaf_shards_segments().map(
638 |(shard_index, own_segments)| {
639 own_segments.root_with_shard_index(shard_index)
640 },
641 )),
642 )
643 .unwrap_or_default()
644 }),
645 )
646 .unwrap_or_default();
647
648 Blake3Hash::new(root)
649 }
650
651 #[inline]
655 pub fn headers_root(&self) -> Blake3Hash {
656 let root = UnbalancedMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
657 self.iter().map(|shard_block_info| {
659 single_block_hash(shard_block_info.header.root().as_ref())
663 .expect("Less than a single block worth of bytes; qed")
664 }),
665 )
666 .unwrap_or_default();
667
668 Blake3Hash::new(root)
669 }
670}
671
672#[derive(Debug, Copy, Clone, Yokeable)]
674#[non_exhaustive]
676pub struct BeaconChainBody<'a> {
677 own_segments: Option<OwnSegments<'a>>,
679 intermediate_shard_blocks: IntermediateShardBlocksInfo<'a>,
681 pot_checkpoints: &'a [PotCheckpoints],
684}
685
686impl<'a> GenericBlockBody<'a> for BeaconChainBody<'a> {
687 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
688
689 #[cfg(feature = "alloc")]
690 type Owned = OwnedBeaconChainBody;
691
692 #[cfg(feature = "alloc")]
693 #[inline(always)]
694 fn to_owned(self) -> Self::Owned {
695 self.to_owned()
696 }
697
698 #[inline(always)]
699 fn root(&self) -> Blake3Hash {
700 self.root()
701 }
702}
703
704impl<'a> BeaconChainBody<'a> {
705 #[inline]
711 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
712 let num_pot_checkpoints = bytes.split_off(..size_of::<u32>())?;
721 let num_pot_checkpoints =
723 *unsafe { <u32 as TrivialType>::from_bytes(num_pot_checkpoints) }? as usize;
724
725 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
726 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
727
728 let own_segments = if num_own_segment_roots > 0 {
729 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
730 let first_local_segment_index = unsafe {
732 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
733 }
734 .as_inner();
735
736 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
737 let own_segment_roots = unsafe {
739 slice::from_raw_parts(
740 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
741 num_own_segment_roots,
742 )
743 };
744 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
745
746 Some(OwnSegments {
747 first_local_segment_index,
748 segment_roots: own_segment_roots,
749 })
750 } else {
751 None
752 };
753
754 let (intermediate_shard_blocks, mut remainder) =
755 IntermediateShardBlocksInfo::try_from_bytes(bytes)?;
756
757 let pot_checkpoints = remainder.split_off(..num_pot_checkpoints * PotCheckpoints::SIZE)?;
758 let pot_checkpoints = unsafe {
760 slice::from_raw_parts(
761 pot_checkpoints
762 .as_ptr()
763 .cast::<[u8; PotCheckpoints::SIZE]>(),
764 num_pot_checkpoints,
765 )
766 };
767 let pot_checkpoints = PotCheckpoints::slice_from_bytes(pot_checkpoints);
768
769 let body = Self {
770 own_segments,
771 intermediate_shard_blocks,
772 pot_checkpoints,
773 };
774
775 if !body.is_internally_consistent() {
776 return None;
777 }
778
779 Some((body, remainder))
780 }
781
782 #[inline]
787 pub fn is_internally_consistent(&self) -> bool {
788 true
790 }
791
792 #[inline]
795 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
796 let num_pot_checkpoints = bytes.split_off(..size_of::<u32>())?;
805 let num_pot_checkpoints =
807 *unsafe { <u32 as TrivialType>::from_bytes(num_pot_checkpoints) }? as usize;
808
809 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
810 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
811
812 let own_segments = if num_own_segment_roots > 0 {
813 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
814 let first_local_segment_index = unsafe {
816 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
817 }
818 .as_inner();
819
820 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
821 let own_segment_roots = unsafe {
823 slice::from_raw_parts(
824 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
825 num_own_segment_roots,
826 )
827 };
828 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
829
830 Some(OwnSegments {
831 first_local_segment_index,
832 segment_roots: own_segment_roots,
833 })
834 } else {
835 None
836 };
837
838 let (intermediate_shard_blocks, mut remainder) =
839 IntermediateShardBlocksInfo::try_from_bytes_unchecked(bytes)?;
840
841 let pot_checkpoints = remainder.split_off(..num_pot_checkpoints * PotCheckpoints::SIZE)?;
842 let pot_checkpoints = unsafe {
844 slice::from_raw_parts(
845 pot_checkpoints
846 .as_ptr()
847 .cast::<[u8; PotCheckpoints::SIZE]>(),
848 num_pot_checkpoints,
849 )
850 };
851 let pot_checkpoints = PotCheckpoints::slice_from_bytes(pot_checkpoints);
852
853 Some((
854 Self {
855 own_segments,
856 intermediate_shard_blocks,
857 pot_checkpoints,
858 },
859 remainder,
860 ))
861 }
862
863 #[cfg(feature = "alloc")]
865 #[inline(always)]
866 pub fn to_owned(self) -> OwnedBeaconChainBody {
867 if let Some(own_segments) = self.own_segments {
868 let first_local_segment_index = own_segments.first_local_segment_index;
869
870 OwnedBeaconChainBody::new(
871 own_segments.segment_roots.iter().copied().enumerate().map(
872 |(index, segment_root)| {
873 (
874 first_local_segment_index + LocalSegmentIndex::from(index as u64),
875 segment_root,
876 )
877 },
878 ),
879 self.intermediate_shard_blocks.iter(),
880 self.pot_checkpoints,
881 )
882 .expect("`self` is always a valid invariant; qed")
883 } else {
884 OwnedBeaconChainBody::new(
885 iter::empty(),
886 self.intermediate_shard_blocks.iter(),
887 self.pot_checkpoints,
888 )
889 .expect("`self` is always a valid invariant; qed")
890 }
891 }
892
893 #[inline(always)]
895 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
896 self.own_segments
897 }
898
899 #[inline(always)]
901 pub fn intermediate_shard_blocks(&self) -> &IntermediateShardBlocksInfo<'a> {
902 &self.intermediate_shard_blocks
903 }
904
905 #[inline(always)]
908 pub fn pot_checkpoints(&self) -> &'a [PotCheckpoints] {
909 self.pot_checkpoints
910 }
911
912 #[inline]
914 pub fn root(&self) -> Blake3Hash {
915 let root = BalancedMerkleTree::compute_root_only(&[
917 *self
918 .own_segments
919 .as_ref()
920 .map(OwnSegments::root)
921 .unwrap_or_default(),
922 *self.intermediate_shard_blocks.segments_root(),
923 *self.intermediate_shard_blocks.headers_root(),
924 blake3::hash(PotCheckpoints::bytes_from_slice(self.pot_checkpoints).as_flattened())
925 .into(),
926 ]);
927
928 Blake3Hash::new(root)
929 }
930}
931
932#[derive(Debug, Copy, Clone)]
934pub struct LeafShardOwnSegments<'a> {
935 pub segment_roots_proof: &'a [u8; OUT_LEN],
937 pub own_segments: OwnSegments<'a>,
939}
940
941#[derive(Debug, Clone)]
943pub struct LeafShardBlockInfo<'a> {
944 pub header: LeafShardHeader<'a>,
946 pub segments: Option<LeafShardOwnSegments<'a>>,
948}
949
950#[derive(Debug, Copy, Clone)]
952pub struct LeafShardBlocksInfo<'a> {
953 num_blocks: usize,
954 bytes: &'a [u8],
955}
956
957impl<'a> LeafShardBlocksInfo<'a> {
958 #[inline]
964 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
965 let num_blocks = bytes.split_off(..size_of::<u16>())?;
978 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
979
980 let bytes_start = bytes;
981
982 let mut counts = bytes.split_off(..num_blocks * size_of::<u8>())?;
983
984 let mut remainder = align_to_and_ensure_zero_padding(bytes, Alignment::of::<u64>())?;
985
986 for _ in 0..num_blocks {
987 let num_own_segment_roots = usize::from(counts[0]);
988 counts = &counts[1..];
989
990 (_, remainder) = LeafShardHeader::try_from_bytes(remainder)?;
991
992 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())?;
993
994 if num_own_segment_roots > 0 {
995 let _first_local_segment_index =
996 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
997 let _segment_roots_proof = remainder.split_off(..OUT_LEN)?;
998 let _own_segment_roots =
999 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1000 }
1001 }
1002
1003 let info = Self {
1004 num_blocks,
1005 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1006 };
1007
1008 if !info.is_internally_consistent() {
1009 return None;
1010 }
1011
1012 Some((info, remainder))
1013 }
1014
1015 #[inline]
1018 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1019 let num_blocks = bytes.split_off(..size_of::<u16>())?;
1032 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
1033
1034 let bytes_start = bytes;
1035
1036 let mut counts = bytes.split_off(..num_blocks * size_of::<u8>())?;
1037
1038 let mut remainder = align_to_and_ensure_zero_padding(bytes, Alignment::of::<u64>())?;
1039
1040 for _ in 0..num_blocks {
1041 let num_own_segment_roots = usize::from(counts[0]);
1042 counts = &counts[1..];
1043
1044 (_, remainder) = LeafShardHeader::try_from_bytes(remainder)?;
1045
1046 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())?;
1047
1048 if num_own_segment_roots > 0 {
1049 let _first_local_segment_index =
1050 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
1051 let _segment_roots_proof = remainder.split_off(..OUT_LEN)?;
1052 let _own_segment_roots =
1053 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1054 }
1055 }
1056
1057 Some((
1058 Self {
1059 num_blocks,
1060 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1061 },
1062 remainder,
1063 ))
1064 }
1065
1066 #[inline]
1071 pub fn is_internally_consistent(&self) -> bool {
1072 let mut last_leaf_shard_info = None::<(ShardIndex, BlockNumber, Option<LocalSegmentIndex>)>;
1073
1074 self.iter().all(|leaf_shard_block| {
1075 let shard_index = leaf_shard_block.header.prefix.shard_index;
1076
1077 if let Some((
1079 last_leaf_shard_index,
1080 last_leaf_shard_block_number,
1081 last_leaf_shard_first_local_segment_index,
1082 )) = last_leaf_shard_info
1083 {
1084 match last_leaf_shard_index.cmp(&shard_index) {
1085 cmp::Ordering::Less => {
1086 last_leaf_shard_info.replace((
1087 shard_index,
1088 leaf_shard_block.header.prefix.number,
1089 leaf_shard_block
1090 .segments
1091 .as_ref()
1092 .map(|segments| segments.own_segments.first_local_segment_index),
1093 ));
1094 }
1095 cmp::Ordering::Equal => {
1096 if last_leaf_shard_block_number >= leaf_shard_block.header.prefix.number {
1097 return false;
1098 }
1099 if let Some(leaf_shard_segments) = &leaf_shard_block.segments {
1100 if let Some(last_leaf_shard_first_local_segment_index) =
1101 last_leaf_shard_first_local_segment_index
1102 && last_leaf_shard_first_local_segment_index
1103 >= leaf_shard_segments.own_segments.first_local_segment_index
1104 {
1105 return false;
1106 }
1107
1108 last_leaf_shard_info.replace((
1109 shard_index,
1110 leaf_shard_block.header.prefix.number,
1111 Some(leaf_shard_segments.own_segments.first_local_segment_index),
1112 ));
1113 } else {
1114 last_leaf_shard_info.replace((
1115 shard_index,
1116 leaf_shard_block.header.prefix.number,
1117 last_leaf_shard_first_local_segment_index,
1118 ));
1119 }
1120 }
1121 cmp::Ordering::Greater => {
1122 return false;
1123 }
1124 }
1125 } else {
1126 last_leaf_shard_info.replace((
1127 shard_index,
1128 leaf_shard_block.header.prefix.number,
1129 leaf_shard_block
1130 .segments
1131 .as_ref()
1132 .map(|segments| segments.own_segments.first_local_segment_index),
1133 ));
1134 }
1135
1136 let Some(segments) = leaf_shard_block.segments else {
1137 return true;
1138 };
1139
1140 BalancedMerkleTree::<2>::verify(
1141 &leaf_shard_block.header.result.body_root,
1142 array::from_ref(segments.segment_roots_proof),
1143 0,
1144 *segments.own_segments.root(),
1145 )
1146 })
1147 }
1148
1149 #[inline]
1151 pub fn iter(
1152 &self,
1153 ) -> impl ExactSizeIterator<Item = LeafShardBlockInfo<'a>> + TrustedLen + use<'a> {
1154 let (mut counts, mut remainder) = unsafe {
1156 self.bytes
1157 .split_at_unchecked(self.num_blocks * size_of::<u8>())
1158 };
1159
1160 iter::repeat_with(move || {
1161 let num_own_segment_roots = usize::from(counts[0]);
1162 counts = &counts[1..];
1163
1164 let header;
1166 (header, remainder) = LeafShardHeader::try_from_bytes(remainder)
1167 .expect("Already checked in constructor; qed");
1168
1169 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())
1170 .expect("Already checked in constructor; qed");
1171
1172 let segments = if num_own_segment_roots > 0 {
1173 let first_local_segment_index;
1174 (first_local_segment_index, remainder) =
1176 unsafe { remainder.split_at_unchecked(LocalSegmentIndex::SIZE as usize) };
1177 let first_local_segment_index =
1179 *unsafe { LocalSegmentIndex::from_bytes_unchecked(first_local_segment_index) };
1180
1181 let segment_roots_proof;
1182 (segment_roots_proof, remainder) = unsafe { remainder.split_at_unchecked(OUT_LEN) };
1184 let segment_roots_proof = unsafe {
1186 segment_roots_proof
1187 .as_ptr()
1188 .cast::<[u8; OUT_LEN]>()
1189 .as_ref_unchecked()
1190 };
1191
1192 let own_segment_roots;
1193 (own_segment_roots, remainder) = unsafe {
1195 remainder.split_at_unchecked(num_own_segment_roots * SegmentRoot::SIZE)
1196 };
1197 let own_segment_roots = unsafe {
1199 slice::from_raw_parts(
1200 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1201 num_own_segment_roots,
1202 )
1203 };
1204 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1205
1206 Some(LeafShardOwnSegments {
1207 segment_roots_proof,
1208 own_segments: OwnSegments {
1209 first_local_segment_index,
1210 segment_roots: own_segment_roots,
1211 },
1212 })
1213 } else {
1214 None
1215 };
1216
1217 LeafShardBlockInfo { header, segments }
1218 })
1219 .take(self.num_blocks)
1220 }
1221
1222 #[inline(always)]
1224 pub const fn len(&self) -> usize {
1225 self.num_blocks
1226 }
1227
1228 #[inline(always)]
1230 pub const fn is_empty(&self) -> bool {
1231 self.num_blocks == 0
1232 }
1233
1234 #[inline]
1238 pub fn segments_root(&self) -> Blake3Hash {
1239 let root = UnbalancedMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
1240 self.iter().map(|shard_block_info| {
1241 shard_block_info
1242 .segments
1243 .map(|own_segments| {
1244 own_segments
1245 .own_segments
1246 .root_with_shard_index(shard_block_info.header.prefix.shard_index)
1247 })
1248 .unwrap_or_default()
1249 }),
1250 )
1251 .unwrap_or_default();
1252
1253 Blake3Hash::new(root)
1254 }
1255
1256 #[inline]
1260 pub fn headers_root(&self) -> Blake3Hash {
1261 let root = UnbalancedMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
1262 self.iter().map(|shard_block_info| {
1263 single_block_hash(shard_block_info.header.root().as_ref())
1267 .expect("Less than a single block worth of bytes; qed")
1268 }),
1269 )
1270 .unwrap_or_default();
1271
1272 Blake3Hash::new(root)
1273 }
1274}
1275
1276#[derive(Debug, Copy, Clone, Yokeable)]
1278#[non_exhaustive]
1280pub struct IntermediateShardBody<'a> {
1281 own_segments: Option<OwnSegments<'a>>,
1283 leaf_shard_blocks: LeafShardBlocksInfo<'a>,
1285}
1286
1287impl<'a> GenericBlockBody<'a> for IntermediateShardBody<'a> {
1288 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
1289
1290 #[cfg(feature = "alloc")]
1291 type Owned = OwnedIntermediateShardBody;
1292
1293 #[cfg(feature = "alloc")]
1294 #[inline(always)]
1295 fn to_owned(self) -> Self::Owned {
1296 self.to_owned()
1297 }
1298
1299 #[inline(always)]
1300 fn root(&self) -> Blake3Hash {
1301 self.root()
1302 }
1303}
1304
1305impl<'a> IntermediateShardBody<'a> {
1306 #[inline]
1312 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1313 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1320 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1321
1322 let own_segments = if num_own_segment_roots > 0 {
1323 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1324 let first_local_segment_index = unsafe {
1326 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1327 }
1328 .as_inner();
1329
1330 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1331 let own_segment_roots = unsafe {
1333 slice::from_raw_parts(
1334 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1335 num_own_segment_roots,
1336 )
1337 };
1338 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1339
1340 Some(OwnSegments {
1341 first_local_segment_index,
1342 segment_roots: own_segment_roots,
1343 })
1344 } else {
1345 None
1346 };
1347
1348 let (leaf_shard_blocks, remainder) = LeafShardBlocksInfo::try_from_bytes(bytes)?;
1349
1350 let body = Self {
1351 own_segments,
1352 leaf_shard_blocks,
1353 };
1354
1355 if !body.is_internally_consistent() {
1356 return None;
1357 }
1358
1359 Some((body, remainder))
1360 }
1361
1362 #[inline]
1367 pub fn is_internally_consistent(&self) -> bool {
1368 true
1370 }
1371
1372 #[inline]
1375 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1376 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1383 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1384
1385 let own_segments = if num_own_segment_roots > 0 {
1386 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1387 let first_local_segment_index = unsafe {
1389 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1390 }
1391 .as_inner();
1392
1393 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1394 let own_segment_roots = unsafe {
1396 slice::from_raw_parts(
1397 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1398 num_own_segment_roots,
1399 )
1400 };
1401 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1402
1403 Some(OwnSegments {
1404 first_local_segment_index,
1405 segment_roots: own_segment_roots,
1406 })
1407 } else {
1408 None
1409 };
1410
1411 let (leaf_shard_blocks, remainder) = LeafShardBlocksInfo::try_from_bytes_unchecked(bytes)?;
1412
1413 Some((
1414 Self {
1415 own_segments,
1416 leaf_shard_blocks,
1417 },
1418 remainder,
1419 ))
1420 }
1421
1422 #[inline(always)]
1424 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
1425 self.own_segments
1426 }
1427
1428 #[inline(always)]
1430 pub fn leaf_shard_blocks(&self) -> &LeafShardBlocksInfo<'a> {
1431 &self.leaf_shard_blocks
1432 }
1433
1434 #[cfg(feature = "alloc")]
1436 #[inline(always)]
1437 pub fn to_owned(self) -> OwnedIntermediateShardBody {
1438 if let Some(own_segments) = self.own_segments {
1439 let first_local_segment_index = own_segments.first_local_segment_index;
1440
1441 OwnedIntermediateShardBody::new(
1442 own_segments.segment_roots.iter().copied().enumerate().map(
1443 |(index, segment_root)| {
1444 (
1445 first_local_segment_index + LocalSegmentIndex::from(index as u64),
1446 segment_root,
1447 )
1448 },
1449 ),
1450 self.leaf_shard_blocks.iter(),
1451 )
1452 .expect("`self` is always a valid invariant; qed")
1453 } else {
1454 OwnedIntermediateShardBody::new(iter::empty(), self.leaf_shard_blocks.iter())
1455 .expect("`self` is always a valid invariant; qed")
1456 }
1457 }
1458
1459 #[inline]
1461 pub fn root(&self) -> Blake3Hash {
1462 let root = BalancedMerkleTree::compute_root_only(&[
1464 BalancedMerkleTree::compute_root_only(&[
1465 *self
1466 .own_segments
1467 .as_ref()
1468 .map(OwnSegments::root)
1469 .unwrap_or_default(),
1470 *self.leaf_shard_blocks.segments_root(),
1471 ]),
1472 *self.leaf_shard_blocks.headers_root(),
1473 ]);
1474
1475 Blake3Hash::new(root)
1476 }
1477}
1478
1479#[derive(Debug, Copy, Clone)]
1481pub struct Transactions<'a> {
1482 num_transactions: usize,
1483 bytes: &'a [u8],
1484}
1485
1486impl<'a> Transactions<'a> {
1487 #[inline]
1493 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1494 let num_transactions = bytes.split_off(..size_of::<u32>())?;
1502 let num_transactions = u32::from_le_bytes([
1503 num_transactions[0],
1504 num_transactions[1],
1505 num_transactions[2],
1506 num_transactions[3],
1507 ]) as usize;
1508
1509 let mut remainder = align_to_and_ensure_zero_padding(bytes, Alignment::MAX)?;
1510 let bytes_start = remainder;
1511
1512 for _ in 0..num_transactions {
1513 (_, remainder) = Transaction::try_from_bytes(remainder)?;
1514 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::MAX)?;
1515 }
1516
1517 Some((
1518 Self {
1519 num_transactions,
1520 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1521 },
1522 remainder,
1523 ))
1524 }
1525
1526 #[inline]
1528 pub fn iter(&self) -> impl ExactSizeIterator<Item = Transaction<'a>> + TrustedLen + use<'a> {
1529 let mut remainder = self.bytes;
1530
1531 iter::repeat_with(move || {
1532 let transaction = unsafe { Transaction::from_bytes_unchecked(remainder) };
1534
1535 remainder = &remainder[transaction.encoded_size()..];
1536 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::MAX)
1537 .expect("Already checked in constructor; qed");
1538
1539 transaction
1540 })
1541 .take(self.num_transactions)
1542 }
1543
1544 #[inline(always)]
1546 pub const fn len(&self) -> usize {
1547 self.num_transactions
1548 }
1549
1550 #[inline(always)]
1552 pub const fn is_empty(&self) -> bool {
1553 self.num_transactions == 0
1554 }
1555
1556 #[inline]
1560 pub fn root(&self) -> Blake3Hash {
1561 let root = UnbalancedMerkleTree::compute_root_only::<{ u64::from(u32::MAX) }, _, _>(
1562 self.iter().map(|transaction| {
1563 single_block_hash(transaction.hash().as_ref())
1567 .expect("Less than a single block worth of bytes; qed")
1568 }),
1569 )
1570 .unwrap_or_default();
1571
1572 Blake3Hash::new(root)
1573 }
1574}
1575
1576#[derive(Debug, Copy, Clone, Yokeable)]
1578#[non_exhaustive]
1580pub struct LeafShardBody<'a> {
1581 own_segments: Option<OwnSegments<'a>>,
1583 transactions: Transactions<'a>,
1585}
1586
1587impl<'a> GenericBlockBody<'a> for LeafShardBody<'a> {
1588 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1589
1590 #[cfg(feature = "alloc")]
1591 type Owned = OwnedLeafShardBody;
1592
1593 #[cfg(feature = "alloc")]
1594 #[inline(always)]
1595 fn to_owned(self) -> Self::Owned {
1596 self.to_owned()
1597 }
1598
1599 #[inline(always)]
1600 fn root(&self) -> Blake3Hash {
1601 self.root()
1602 }
1603}
1604
1605impl<'a> LeafShardBody<'a> {
1606 #[inline]
1612 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1613 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1620 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1621
1622 let own_segments = if num_own_segment_roots > 0 {
1623 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1624 let first_local_segment_index = unsafe {
1626 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1627 }
1628 .as_inner();
1629
1630 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1631 let own_segment_roots = unsafe {
1633 slice::from_raw_parts(
1634 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1635 num_own_segment_roots,
1636 )
1637 };
1638 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1639
1640 Some(OwnSegments {
1641 first_local_segment_index,
1642 segment_roots: own_segment_roots,
1643 })
1644 } else {
1645 None
1646 };
1647
1648 let (transactions, remainder) = Transactions::try_from_bytes(bytes)?;
1649
1650 let body = Self {
1651 own_segments,
1652 transactions,
1653 };
1654
1655 if !body.is_internally_consistent() {
1656 return None;
1657 }
1658
1659 Some((body, remainder))
1660 }
1661
1662 #[inline]
1667 pub fn is_internally_consistent(&self) -> bool {
1668 true
1670 }
1671
1672 #[inline]
1675 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1676 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1683 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1684
1685 let own_segments = if num_own_segment_roots > 0 {
1686 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1687 let first_local_segment_index = unsafe {
1689 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1690 }
1691 .as_inner();
1692
1693 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1694 let own_segment_roots = unsafe {
1696 slice::from_raw_parts(
1697 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1698 num_own_segment_roots,
1699 )
1700 };
1701 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1702
1703 Some(OwnSegments {
1704 first_local_segment_index,
1705 segment_roots: own_segment_roots,
1706 })
1707 } else {
1708 None
1709 };
1710
1711 let (transactions, remainder) = Transactions::try_from_bytes(bytes)?;
1712
1713 Some((
1714 Self {
1715 own_segments,
1716 transactions,
1717 },
1718 remainder,
1719 ))
1720 }
1721
1722 #[inline(always)]
1724 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
1725 self.own_segments
1726 }
1727
1728 #[inline(always)]
1730 pub fn transactions(&self) -> &Transactions<'a> {
1731 &self.transactions
1732 }
1733
1734 #[cfg(feature = "alloc")]
1736 #[inline(always)]
1737 pub fn to_owned(self) -> OwnedLeafShardBody {
1738 let mut builder = if let Some(own_segments) = self.own_segments {
1739 let first_local_segment_index = own_segments.first_local_segment_index;
1740
1741 OwnedLeafShardBody::init(own_segments.segment_roots.iter().copied().enumerate().map(
1742 |(index, segment_root)| {
1743 (
1744 first_local_segment_index + LocalSegmentIndex::from(index as u64),
1745 segment_root,
1746 )
1747 },
1748 ))
1749 .expect("`self` is always a valid invariant; qed")
1750 } else {
1751 OwnedLeafShardBody::init(iter::empty())
1752 .expect("`self` is always a valid invariant; qed")
1753 };
1754 for transaction in self.transactions.iter() {
1755 builder
1756 .add_transaction(transaction)
1757 .expect("`self` is always a valid invariant; qed");
1758 }
1759
1760 builder.finish()
1761 }
1762
1763 #[inline]
1765 pub fn root(&self) -> Blake3Hash {
1766 let root = BalancedMerkleTree::compute_root_only(&[
1767 *self
1768 .own_segments
1769 .as_ref()
1770 .map(OwnSegments::root)
1771 .unwrap_or_default(),
1772 *self.transactions.root(),
1773 ]);
1774
1775 Blake3Hash::new(root)
1776 }
1777}
1778
1779#[derive(Debug, Copy, Clone, From)]
1784pub enum BlockBody<'a> {
1785 BeaconChain(BeaconChainBody<'a>),
1787 IntermediateShard(IntermediateShardBody<'a>),
1789 LeafShard(LeafShardBody<'a>),
1791}
1792
1793impl<'a> BlockBody<'a> {
1794 #[inline]
1801 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1802 match shard_kind {
1803 RealShardKind::BeaconChain => {
1804 let (body, remainder) = BeaconChainBody::try_from_bytes(bytes)?;
1805 Some((Self::BeaconChain(body), remainder))
1806 }
1807 RealShardKind::IntermediateShard => {
1808 let (body, remainder) = IntermediateShardBody::try_from_bytes(bytes)?;
1809 Some((Self::IntermediateShard(body), remainder))
1810 }
1811 RealShardKind::LeafShard => {
1812 let (body, remainder) = LeafShardBody::try_from_bytes(bytes)?;
1813 Some((Self::LeafShard(body), remainder))
1814 }
1815 }
1816 }
1817
1818 #[inline]
1823 pub fn is_internally_consistent(&self) -> bool {
1824 match self {
1825 Self::BeaconChain(body) => body.is_internally_consistent(),
1826 Self::IntermediateShard(body) => body.is_internally_consistent(),
1827 Self::LeafShard(body) => body.is_internally_consistent(),
1828 }
1829 }
1830
1831 #[inline]
1834 pub fn try_from_bytes_unchecked(
1835 bytes: &'a [u8],
1836 shard_kind: RealShardKind,
1837 ) -> Option<(Self, &'a [u8])> {
1838 match shard_kind {
1839 RealShardKind::BeaconChain => {
1840 let (body, remainder) = BeaconChainBody::try_from_bytes_unchecked(bytes)?;
1841 Some((Self::BeaconChain(body), remainder))
1842 }
1843 RealShardKind::IntermediateShard => {
1844 let (body, remainder) = IntermediateShardBody::try_from_bytes_unchecked(bytes)?;
1845 Some((Self::IntermediateShard(body), remainder))
1846 }
1847 RealShardKind::LeafShard => {
1848 let (body, remainder) = LeafShardBody::try_from_bytes_unchecked(bytes)?;
1849 Some((Self::LeafShard(body), remainder))
1850 }
1851 }
1852 }
1853
1854 #[cfg(feature = "alloc")]
1856 #[inline(always)]
1857 pub fn to_owned(self) -> OwnedBlockBody {
1858 match self {
1859 Self::BeaconChain(body) => body.to_owned().into(),
1860 Self::IntermediateShard(body) => body.to_owned().into(),
1861 Self::LeafShard(body) => body.to_owned().into(),
1862 }
1863 }
1864
1865 #[inline]
1870 pub fn root(&self) -> Blake3Hash {
1871 match self {
1872 Self::BeaconChain(body) => body.root(),
1873 Self::IntermediateShard(body) => body.root(),
1874 Self::LeafShard(body) => body.root(),
1875 }
1876 }
1877}