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::<{ 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::<{ 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.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
177 num_own_segment_roots,
178 )
179 };
180 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
181
182 (
183 shard_index,
184 OwnSegments {
185 first_local_segment_index,
186 segment_roots: own_segment_roots,
187 },
188 )
189 })
190 }
191}
192
193#[derive(Debug, Copy, Clone)]
195pub struct IntermediateShardBlocksInfo<'a> {
196 num_blocks: usize,
197 bytes: &'a [u8],
198}
199
200impl<'a> IntermediateShardBlocksInfo<'a> {
201 #[inline]
207 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
208 let num_blocks = bytes.split_off(..size_of::<u16>())?;
228 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
229
230 let bytes_start = bytes;
231
232 let mut counts = bytes.split_off(..num_blocks * (size_of::<u8>() * 2))?;
233
234 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
235
236 for _ in 0..num_blocks {
237 let num_own_segment_roots = usize::from(counts[0]);
238 let num_leaf_shard_blocks_with_segments = usize::from(counts[1]);
239 counts = &counts[2..];
240
241 (_, remainder) = IntermediateShardHeader::try_from_bytes(remainder)?;
242
243 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
244 let _segments_proof = remainder.split_off(..SegmentRoot::SIZE)?;
245 }
246
247 if num_own_segment_roots > 0 {
248 let _first_local_segment_index =
249 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
250 let _own_segment_roots =
251 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
252 }
253
254 let leaf_shard_segment_roots_counts =
255 remainder.split_off(..num_leaf_shard_blocks_with_segments * size_of::<u8>())?;
256
257 for &num_own_segment_roots in leaf_shard_segment_roots_counts {
258 let _shard_index = remainder.split_off(..ShardIndex::SIZE as usize)?;
259 let _first_local_segment_index =
260 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
261 let _own_segment_roots = remainder
262 .split_off(..usize::from(num_own_segment_roots) * SegmentRoot::SIZE)?;
263 }
264
265 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
266 }
267
268 let info = Self {
269 num_blocks,
270 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
271 };
272
273 if !info.is_internally_consistent() {
274 return None;
275 }
276
277 Some((info, remainder))
278 }
279
280 #[inline]
283 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
284 let num_blocks = bytes.split_off(..size_of::<u16>())?;
304 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
305
306 let bytes_start = bytes;
307
308 let mut counts = bytes.split_off(..num_blocks * (size_of::<u8>() * 2))?;
309
310 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
311
312 for _ in 0..num_blocks {
313 let num_own_segment_roots = usize::from(counts[0]);
314 let num_leaf_shard_blocks_with_segments = usize::from(counts[1]);
315 counts = &counts[2..];
316
317 (_, remainder) = IntermediateShardHeader::try_from_bytes(remainder)?;
318
319 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
320 let _segments_proof = remainder.split_off(..OUT_LEN)?;
321 }
322
323 if num_own_segment_roots > 0 {
324 let _first_local_segment_index =
325 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
326 let _own_segment_roots =
327 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
328 }
329
330 let leaf_shard_segment_roots_counts =
331 remainder.split_off(..num_leaf_shard_blocks_with_segments * size_of::<u8>())?;
332
333 for &num_own_segment_roots in leaf_shard_segment_roots_counts {
334 let _shard_index = remainder.split_off(..ShardIndex::SIZE as usize)?;
335 let _first_local_segment_index =
336 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
337 let _own_segment_roots = remainder
338 .split_off(..usize::from(num_own_segment_roots) * SegmentRoot::SIZE)?;
339 }
340
341 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
342 }
343
344 Some((
345 Self {
346 num_blocks,
347 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
348 },
349 remainder,
350 ))
351 }
352
353 #[inline]
358 pub fn is_internally_consistent(&self) -> bool {
359 let mut last_intermediate_shard_info =
360 None::<(ShardIndex, BlockNumber, Option<LocalSegmentIndex>)>;
361
362 self.iter().all(|intermediate_shard_block| {
363 let shard_index = intermediate_shard_block.header.prefix.shard_index;
364
365 if let Some((
367 last_intermediate_shard_index,
368 last_intermediate_shard_block_number,
369 last_intermediate_shard_first_local_segment_index,
370 )) = last_intermediate_shard_info
371 {
372 match last_intermediate_shard_index.cmp(&shard_index) {
373 cmp::Ordering::Less => {
374 last_intermediate_shard_info.replace((
375 shard_index,
376 intermediate_shard_block.header.prefix.number,
377 intermediate_shard_block
378 .own_segments
379 .as_ref()
380 .map(|own_segments| own_segments.first_local_segment_index),
381 ));
382 }
383 cmp::Ordering::Equal => {
384 if last_intermediate_shard_block_number
385 >= intermediate_shard_block.header.prefix.number
386 {
387 return false;
388 }
389 if let Some(own_segments) = &intermediate_shard_block.own_segments {
390 if let Some(last_intermediate_shard_first_local_segment_index) =
391 last_intermediate_shard_first_local_segment_index
392 && last_intermediate_shard_first_local_segment_index
393 >= own_segments.first_local_segment_index
394 {
395 return false;
396 }
397
398 last_intermediate_shard_info.replace((
399 shard_index,
400 intermediate_shard_block.header.prefix.number,
401 Some(own_segments.first_local_segment_index),
402 ));
403 } else {
404 last_intermediate_shard_info.replace((
405 shard_index,
406 intermediate_shard_block.header.prefix.number,
407 last_intermediate_shard_first_local_segment_index,
408 ));
409 }
410 }
411 cmp::Ordering::Greater => {
412 return false;
413 }
414 }
415 } else {
416 last_intermediate_shard_info.replace((
417 shard_index,
418 intermediate_shard_block.header.prefix.number,
419 intermediate_shard_block
420 .own_segments
421 .as_ref()
422 .map(|own_segments| own_segments.first_local_segment_index),
423 ));
424 }
425
426 let mut last_leaf_shard_info = None::<(ShardIndex, LocalSegmentIndex)>;
427
428 if !intermediate_shard_block.leaf_shards_segments().all(
430 |(leaf_shard_index, own_segments)| {
431 if !leaf_shard_index.is_child_of(shard_index) {
432 return false;
433 }
434
435 if let Some((
436 last_leaf_shard_index,
437 last_leaf_shard_first_local_segment_index,
438 )) = last_leaf_shard_info
439 {
440 match last_leaf_shard_index.cmp(&leaf_shard_index) {
441 cmp::Ordering::Less => {
442 }
444 cmp::Ordering::Equal => {
445 if last_leaf_shard_first_local_segment_index
446 >= own_segments.first_local_segment_index
447 {
448 return false;
449 }
450 }
451 cmp::Ordering::Greater => {
452 return false;
453 }
454 }
455 }
456 last_leaf_shard_info
457 .replace((leaf_shard_index, own_segments.first_local_segment_index));
458
459 true
460 },
461 ) {
462 return false;
463 }
464
465 if intermediate_shard_block.own_segments.is_none()
466 && intermediate_shard_block
467 .leaf_shards_segments()
468 .size_hint()
469 .0
470 == 0
471 {
472 return intermediate_shard_block.segments_proof.is_none();
473 }
474
475 let segments_proof = intermediate_shard_block.segments_proof.unwrap_or(&[0; _]);
476
477 let leaf_shards_root =
478 UnbalancedMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
479 intermediate_shard_block.leaf_shards_segments().map(
480 |(shard_index, own_segments)| {
481 own_segments.root_with_shard_index(shard_index)
482 },
483 ),
484 )
485 .unwrap_or_default();
486
487 BalancedMerkleTree::<2>::verify(
488 &intermediate_shard_block.header.result.body_root,
489 array::from_ref(segments_proof),
490 0,
491 BalancedMerkleTree::compute_root_only(&[
492 *intermediate_shard_block
493 .own_segments
494 .as_ref()
495 .map(OwnSegments::root)
496 .unwrap_or_default(),
497 leaf_shards_root,
498 ]),
499 )
500 })
501 }
502
503 #[inline]
505 pub fn iter(
506 &self,
507 ) -> impl ExactSizeIterator<Item = IntermediateShardBlockInfo<'a>> + TrustedLen + use<'a> {
508 let (mut counts, mut remainder) = unsafe {
510 self.bytes
511 .split_at_unchecked(self.num_blocks * (size_of::<u8>() + size_of::<u16>()))
512 };
513
514 iter::repeat_with(move || {
515 let num_own_segment_roots = usize::from(counts[0]);
516 let num_leaf_shard_blocks_with_segments = counts[1];
517 counts = &counts[2..];
518
519 let header;
521 (header, remainder) = IntermediateShardHeader::try_from_bytes(remainder)
522 .expect("Already checked in constructor; qed");
523
524 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)
525 .expect("Already checked in constructor; qed");
526
527 let segments_proof =
528 if num_own_segment_roots > 0 || num_leaf_shard_blocks_with_segments > 0 {
529 let segments_proof;
530 (segments_proof, remainder) = unsafe { remainder.split_at_unchecked(OUT_LEN) };
532 Some(unsafe {
534 segments_proof
535 .as_ptr()
536 .cast::<[u8; OUT_LEN]>()
537 .as_ref_unchecked()
538 })
539 } else {
540 None
541 };
542
543 let own_segments = if num_own_segment_roots > 0 {
544 let first_local_segment_index;
545 (first_local_segment_index, remainder) =
547 unsafe { remainder.split_at_unchecked(size_of::<LocalSegmentIndex>()) };
548 let first_local_segment_index =
550 *unsafe { LocalSegmentIndex::from_bytes_unchecked(first_local_segment_index) };
551
552 let own_segment_roots;
553 (own_segment_roots, remainder) = unsafe {
555 remainder.split_at_unchecked(num_own_segment_roots * SegmentRoot::SIZE)
556 };
557 let own_segment_roots = unsafe {
559 slice::from_raw_parts(
560 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
561 num_own_segment_roots,
562 )
563 };
564 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
565
566 Some(OwnSegments {
567 first_local_segment_index,
568 segment_roots: own_segment_roots,
569 })
570 } else {
571 None
572 };
573
574 let leaf_shard_segment_roots_counts = unsafe {
576 remainder.get_unchecked(
577 ..usize::from(num_leaf_shard_blocks_with_segments) * size_of::<u8>(),
578 )
579 };
580
581 let leaf_shards_segments_bytes;
582 (leaf_shards_segments_bytes, remainder) = unsafe {
584 remainder.split_at_unchecked(
585 usize::from(num_leaf_shard_blocks_with_segments) * size_of::<u8>()
586 + usize::from(num_leaf_shard_blocks_with_segments)
587 * (ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize
588 + leaf_shard_segment_roots_counts.iter().fold(
589 0usize,
590 |acc, &num_own_segment_roots| {
591 acc + usize::from(num_own_segment_roots) * SegmentRoot::SIZE
592 },
593 ),
594 )
595 };
596
597 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)
598 .expect("Already checked in constructor; qed");
599
600 IntermediateShardBlockInfo {
601 header,
602 segments_proof,
603 own_segments,
604 num_leaf_shard_blocks_with_segments,
605 leaf_shards_segments_bytes,
606 }
607 })
608 .take(self.num_blocks)
609 }
610
611 #[inline(always)]
613 pub const fn len(&self) -> usize {
614 self.num_blocks
615 }
616
617 #[inline(always)]
619 pub const fn is_empty(&self) -> bool {
620 self.num_blocks == 0
621 }
622
623 #[inline]
627 pub fn segments_root(&self) -> Blake3Hash {
628 let root = UnbalancedMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
629 self.iter().map(|shard_block_info| {
630 UnbalancedMerkleTree::compute_root_only::<{ u64::from(u32::MAX) }, _, _>(
631 shard_block_info
632 .own_segments
633 .as_ref()
634 .map(OwnSegments::root)
635 .into_iter()
636 .chain(shard_block_info.leaf_shards_segments().map(
637 |(shard_index, own_segments)| {
638 own_segments.root_with_shard_index(shard_index)
639 },
640 )),
641 )
642 .unwrap_or_default()
643 }),
644 )
645 .unwrap_or_default();
646
647 Blake3Hash::new(root)
648 }
649
650 #[inline]
654 pub fn headers_root(&self) -> Blake3Hash {
655 let root = UnbalancedMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
656 self.iter().map(|shard_block_info| {
658 single_block_hash(shard_block_info.header.root().as_ref())
662 .expect("Less than a single block worth of bytes; qed")
663 }),
664 )
665 .unwrap_or_default();
666
667 Blake3Hash::new(root)
668 }
669}
670
671#[derive(Debug, Copy, Clone, Yokeable)]
673#[non_exhaustive]
675pub struct BeaconChainBody<'a> {
676 own_segments: Option<OwnSegments<'a>>,
678 intermediate_shard_blocks: IntermediateShardBlocksInfo<'a>,
680 pot_checkpoints: &'a [PotCheckpoints],
683}
684
685impl<'a> GenericBlockBody<'a> for BeaconChainBody<'a> {
686 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
687
688 #[cfg(feature = "alloc")]
689 type Owned = OwnedBeaconChainBody;
690
691 #[cfg(feature = "alloc")]
692 #[inline(always)]
693 fn to_owned(self) -> Self::Owned {
694 self.to_owned()
695 }
696
697 #[inline(always)]
698 fn root(&self) -> Blake3Hash {
699 self.root()
700 }
701}
702
703impl<'a> BeaconChainBody<'a> {
704 #[inline]
710 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
711 let num_pot_checkpoints = bytes.split_off(..size_of::<u32>())?;
720 let num_pot_checkpoints =
722 *unsafe { <u32 as TrivialType>::from_bytes(num_pot_checkpoints) }? as usize;
723
724 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
725 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
726
727 let own_segments = if num_own_segment_roots > 0 {
728 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
729 let first_local_segment_index = unsafe {
731 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
732 }
733 .as_inner();
734
735 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
736 let own_segment_roots = unsafe {
738 slice::from_raw_parts(
739 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
740 num_own_segment_roots,
741 )
742 };
743 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
744
745 Some(OwnSegments {
746 first_local_segment_index,
747 segment_roots: own_segment_roots,
748 })
749 } else {
750 None
751 };
752
753 let (intermediate_shard_blocks, mut remainder) =
754 IntermediateShardBlocksInfo::try_from_bytes(bytes)?;
755
756 let pot_checkpoints = remainder.split_off(..num_pot_checkpoints * PotCheckpoints::SIZE)?;
757 let pot_checkpoints = unsafe {
759 slice::from_raw_parts(
760 pot_checkpoints
761 .as_ptr()
762 .cast::<[u8; PotCheckpoints::SIZE]>(),
763 num_pot_checkpoints,
764 )
765 };
766 let pot_checkpoints = PotCheckpoints::slice_from_bytes(pot_checkpoints);
767
768 let body = Self {
769 own_segments,
770 intermediate_shard_blocks,
771 pot_checkpoints,
772 };
773
774 if !body.is_internally_consistent() {
775 return None;
776 }
777
778 Some((body, remainder))
779 }
780
781 #[inline]
786 pub fn is_internally_consistent(&self) -> bool {
787 true
789 }
790
791 #[inline]
794 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
795 let num_pot_checkpoints = bytes.split_off(..size_of::<u32>())?;
804 let num_pot_checkpoints =
806 *unsafe { <u32 as TrivialType>::from_bytes(num_pot_checkpoints) }? as usize;
807
808 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
809 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
810
811 let own_segments = if num_own_segment_roots > 0 {
812 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
813 let first_local_segment_index = unsafe {
815 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
816 }
817 .as_inner();
818
819 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
820 let own_segment_roots = unsafe {
822 slice::from_raw_parts(
823 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
824 num_own_segment_roots,
825 )
826 };
827 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
828
829 Some(OwnSegments {
830 first_local_segment_index,
831 segment_roots: own_segment_roots,
832 })
833 } else {
834 None
835 };
836
837 let (intermediate_shard_blocks, mut remainder) =
838 IntermediateShardBlocksInfo::try_from_bytes_unchecked(bytes)?;
839
840 let pot_checkpoints = remainder.split_off(..num_pot_checkpoints * PotCheckpoints::SIZE)?;
841 let pot_checkpoints = unsafe {
843 slice::from_raw_parts(
844 pot_checkpoints
845 .as_ptr()
846 .cast::<[u8; PotCheckpoints::SIZE]>(),
847 num_pot_checkpoints,
848 )
849 };
850 let pot_checkpoints = PotCheckpoints::slice_from_bytes(pot_checkpoints);
851
852 Some((
853 Self {
854 own_segments,
855 intermediate_shard_blocks,
856 pot_checkpoints,
857 },
858 remainder,
859 ))
860 }
861
862 #[cfg(feature = "alloc")]
864 #[inline(always)]
865 pub fn to_owned(self) -> OwnedBeaconChainBody {
866 if let Some(own_segments) = self.own_segments {
867 let first_local_segment_index = own_segments.first_local_segment_index;
868
869 OwnedBeaconChainBody::new(
870 own_segments.segment_roots.iter().copied().enumerate().map(
871 |(index, segment_root)| {
872 (
873 first_local_segment_index + LocalSegmentIndex::from(index as u64),
874 segment_root,
875 )
876 },
877 ),
878 self.intermediate_shard_blocks.iter(),
879 self.pot_checkpoints,
880 )
881 .expect("`self` is always a valid invariant; qed")
882 } else {
883 OwnedBeaconChainBody::new(
884 iter::empty(),
885 self.intermediate_shard_blocks.iter(),
886 self.pot_checkpoints,
887 )
888 .expect("`self` is always a valid invariant; qed")
889 }
890 }
891
892 #[inline(always)]
894 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
895 self.own_segments
896 }
897
898 #[inline(always)]
900 pub fn intermediate_shard_blocks(&self) -> &IntermediateShardBlocksInfo<'a> {
901 &self.intermediate_shard_blocks
902 }
903
904 #[inline(always)]
907 pub fn pot_checkpoints(&self) -> &'a [PotCheckpoints] {
908 self.pot_checkpoints
909 }
910
911 #[inline]
913 pub fn root(&self) -> Blake3Hash {
914 let root = BalancedMerkleTree::compute_root_only(&[
916 *self
917 .own_segments
918 .as_ref()
919 .map(OwnSegments::root)
920 .unwrap_or_default(),
921 *self.intermediate_shard_blocks.segments_root(),
922 *self.intermediate_shard_blocks.headers_root(),
923 blake3::hash(PotCheckpoints::bytes_from_slice(self.pot_checkpoints).as_flattened())
924 .into(),
925 ]);
926
927 Blake3Hash::new(root)
928 }
929}
930
931#[derive(Debug, Copy, Clone)]
933pub struct LeafShardOwnSegments<'a> {
934 pub segment_roots_proof: &'a [u8; OUT_LEN],
936 pub own_segments: OwnSegments<'a>,
938}
939
940#[derive(Debug, Clone)]
942pub struct LeafShardBlockInfo<'a> {
943 pub header: LeafShardHeader<'a>,
945 pub segments: Option<LeafShardOwnSegments<'a>>,
947}
948
949#[derive(Debug, Copy, Clone)]
951pub struct LeafShardBlocksInfo<'a> {
952 num_blocks: usize,
953 bytes: &'a [u8],
954}
955
956impl<'a> LeafShardBlocksInfo<'a> {
957 #[inline]
963 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
964 let num_blocks = bytes.split_off(..size_of::<u16>())?;
977 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
978
979 let bytes_start = bytes;
980
981 let mut counts = bytes.split_off(..num_blocks * size_of::<u8>())?;
982
983 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
984
985 for _ in 0..num_blocks {
986 let num_own_segment_roots = usize::from(counts[0]);
987 counts = &counts[1..];
988
989 (_, remainder) = LeafShardHeader::try_from_bytes(remainder)?;
990
991 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
992
993 if num_own_segment_roots > 0 {
994 let _first_local_segment_index =
995 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
996 let _segment_roots_proof = remainder.split_off(..OUT_LEN)?;
997 let _own_segment_roots =
998 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
999 }
1000 }
1001
1002 let info = Self {
1003 num_blocks,
1004 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1005 };
1006
1007 if !info.is_internally_consistent() {
1008 return None;
1009 }
1010
1011 Some((info, remainder))
1012 }
1013
1014 #[inline]
1017 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1018 let num_blocks = bytes.split_off(..size_of::<u16>())?;
1031 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
1032
1033 let bytes_start = bytes;
1034
1035 let mut counts = bytes.split_off(..num_blocks * size_of::<u8>())?;
1036
1037 let mut remainder = align_to_and_ensure_zero_padding::<u64>(bytes)?;
1038
1039 for _ in 0..num_blocks {
1040 let num_own_segment_roots = usize::from(counts[0]);
1041 counts = &counts[1..];
1042
1043 (_, remainder) = LeafShardHeader::try_from_bytes(remainder)?;
1044
1045 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)?;
1046
1047 if num_own_segment_roots > 0 {
1048 let _first_local_segment_index =
1049 remainder.split_off(..LocalSegmentIndex::SIZE as usize)?;
1050 let _segment_roots_proof = remainder.split_off(..OUT_LEN)?;
1051 let _own_segment_roots =
1052 remainder.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1053 }
1054 }
1055
1056 Some((
1057 Self {
1058 num_blocks,
1059 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1060 },
1061 remainder,
1062 ))
1063 }
1064
1065 #[inline]
1070 pub fn is_internally_consistent(&self) -> bool {
1071 let mut last_leaf_shard_info = None::<(ShardIndex, BlockNumber, Option<LocalSegmentIndex>)>;
1072
1073 self.iter().all(|leaf_shard_block| {
1074 let shard_index = leaf_shard_block.header.prefix.shard_index;
1075
1076 if let Some((
1078 last_leaf_shard_index,
1079 last_leaf_shard_block_number,
1080 last_leaf_shard_first_local_segment_index,
1081 )) = last_leaf_shard_info
1082 {
1083 match last_leaf_shard_index.cmp(&shard_index) {
1084 cmp::Ordering::Less => {
1085 last_leaf_shard_info.replace((
1086 shard_index,
1087 leaf_shard_block.header.prefix.number,
1088 leaf_shard_block
1089 .segments
1090 .as_ref()
1091 .map(|segments| segments.own_segments.first_local_segment_index),
1092 ));
1093 }
1094 cmp::Ordering::Equal => {
1095 if last_leaf_shard_block_number >= leaf_shard_block.header.prefix.number {
1096 return false;
1097 }
1098 if let Some(leaf_shard_segments) = &leaf_shard_block.segments {
1099 if let Some(last_leaf_shard_first_local_segment_index) =
1100 last_leaf_shard_first_local_segment_index
1101 && last_leaf_shard_first_local_segment_index
1102 >= leaf_shard_segments.own_segments.first_local_segment_index
1103 {
1104 return false;
1105 }
1106
1107 last_leaf_shard_info.replace((
1108 shard_index,
1109 leaf_shard_block.header.prefix.number,
1110 Some(leaf_shard_segments.own_segments.first_local_segment_index),
1111 ));
1112 } else {
1113 last_leaf_shard_info.replace((
1114 shard_index,
1115 leaf_shard_block.header.prefix.number,
1116 last_leaf_shard_first_local_segment_index,
1117 ));
1118 }
1119 }
1120 cmp::Ordering::Greater => {
1121 return false;
1122 }
1123 }
1124 } else {
1125 last_leaf_shard_info.replace((
1126 shard_index,
1127 leaf_shard_block.header.prefix.number,
1128 leaf_shard_block
1129 .segments
1130 .as_ref()
1131 .map(|segments| segments.own_segments.first_local_segment_index),
1132 ));
1133 }
1134
1135 let Some(segments) = leaf_shard_block.segments else {
1136 return true;
1137 };
1138
1139 BalancedMerkleTree::<2>::verify(
1140 &leaf_shard_block.header.result.body_root,
1141 array::from_ref(segments.segment_roots_proof),
1142 0,
1143 *segments.own_segments.root(),
1144 )
1145 })
1146 }
1147
1148 #[inline]
1150 pub fn iter(
1151 &self,
1152 ) -> impl ExactSizeIterator<Item = LeafShardBlockInfo<'a>> + TrustedLen + use<'a> {
1153 let (mut counts, mut remainder) = unsafe {
1155 self.bytes
1156 .split_at_unchecked(self.num_blocks * size_of::<u8>())
1157 };
1158
1159 iter::repeat_with(move || {
1160 let num_own_segment_roots = usize::from(counts[0]);
1161 counts = &counts[1..];
1162
1163 let header;
1165 (header, remainder) = LeafShardHeader::try_from_bytes(remainder)
1166 .expect("Already checked in constructor; qed");
1167
1168 remainder = align_to_and_ensure_zero_padding::<u64>(remainder)
1169 .expect("Already checked in constructor; qed");
1170
1171 let segments = if num_own_segment_roots > 0 {
1172 let first_local_segment_index;
1173 (first_local_segment_index, remainder) =
1175 unsafe { remainder.split_at_unchecked(LocalSegmentIndex::SIZE as usize) };
1176 let first_local_segment_index =
1178 *unsafe { LocalSegmentIndex::from_bytes_unchecked(first_local_segment_index) };
1179
1180 let segment_roots_proof;
1181 (segment_roots_proof, remainder) = unsafe { remainder.split_at_unchecked(OUT_LEN) };
1183 let segment_roots_proof = unsafe {
1185 segment_roots_proof
1186 .as_ptr()
1187 .cast::<[u8; OUT_LEN]>()
1188 .as_ref_unchecked()
1189 };
1190
1191 let own_segment_roots;
1192 (own_segment_roots, remainder) = unsafe {
1194 remainder.split_at_unchecked(num_own_segment_roots * SegmentRoot::SIZE)
1195 };
1196 let own_segment_roots = unsafe {
1198 slice::from_raw_parts(
1199 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1200 num_own_segment_roots,
1201 )
1202 };
1203 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1204
1205 Some(LeafShardOwnSegments {
1206 segment_roots_proof,
1207 own_segments: OwnSegments {
1208 first_local_segment_index,
1209 segment_roots: own_segment_roots,
1210 },
1211 })
1212 } else {
1213 None
1214 };
1215
1216 LeafShardBlockInfo { header, segments }
1217 })
1218 .take(self.num_blocks)
1219 }
1220
1221 #[inline(always)]
1223 pub const fn len(&self) -> usize {
1224 self.num_blocks
1225 }
1226
1227 #[inline(always)]
1229 pub const fn is_empty(&self) -> bool {
1230 self.num_blocks == 0
1231 }
1232
1233 #[inline]
1237 pub fn segments_root(&self) -> Blake3Hash {
1238 let root = UnbalancedMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
1239 self.iter().map(|shard_block_info| {
1240 shard_block_info
1241 .segments
1242 .map(|own_segments| {
1243 own_segments
1244 .own_segments
1245 .root_with_shard_index(shard_block_info.header.prefix.shard_index)
1246 })
1247 .unwrap_or_default()
1248 }),
1249 )
1250 .unwrap_or_default();
1251
1252 Blake3Hash::new(root)
1253 }
1254
1255 #[inline]
1259 pub fn headers_root(&self) -> Blake3Hash {
1260 let root = UnbalancedMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
1261 self.iter().map(|shard_block_info| {
1262 single_block_hash(shard_block_info.header.root().as_ref())
1266 .expect("Less than a single block worth of bytes; qed")
1267 }),
1268 )
1269 .unwrap_or_default();
1270
1271 Blake3Hash::new(root)
1272 }
1273}
1274
1275#[derive(Debug, Copy, Clone, Yokeable)]
1277#[non_exhaustive]
1279pub struct IntermediateShardBody<'a> {
1280 own_segments: Option<OwnSegments<'a>>,
1282 leaf_shard_blocks: LeafShardBlocksInfo<'a>,
1284}
1285
1286impl<'a> GenericBlockBody<'a> for IntermediateShardBody<'a> {
1287 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
1288
1289 #[cfg(feature = "alloc")]
1290 type Owned = OwnedIntermediateShardBody;
1291
1292 #[cfg(feature = "alloc")]
1293 #[inline(always)]
1294 fn to_owned(self) -> Self::Owned {
1295 self.to_owned()
1296 }
1297
1298 #[inline(always)]
1299 fn root(&self) -> Blake3Hash {
1300 self.root()
1301 }
1302}
1303
1304impl<'a> IntermediateShardBody<'a> {
1305 #[inline]
1311 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1312 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1319 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1320
1321 let own_segments = if num_own_segment_roots > 0 {
1322 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1323 let first_local_segment_index = unsafe {
1325 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1326 }
1327 .as_inner();
1328
1329 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1330 let own_segment_roots = unsafe {
1332 slice::from_raw_parts(
1333 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1334 num_own_segment_roots,
1335 )
1336 };
1337 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1338
1339 Some(OwnSegments {
1340 first_local_segment_index,
1341 segment_roots: own_segment_roots,
1342 })
1343 } else {
1344 None
1345 };
1346
1347 let (leaf_shard_blocks, remainder) = LeafShardBlocksInfo::try_from_bytes(bytes)?;
1348
1349 let body = Self {
1350 own_segments,
1351 leaf_shard_blocks,
1352 };
1353
1354 if !body.is_internally_consistent() {
1355 return None;
1356 }
1357
1358 Some((body, remainder))
1359 }
1360
1361 #[inline]
1366 pub fn is_internally_consistent(&self) -> bool {
1367 true
1369 }
1370
1371 #[inline]
1374 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1375 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1382 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1383
1384 let own_segments = if num_own_segment_roots > 0 {
1385 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1386 let first_local_segment_index = unsafe {
1388 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1389 }
1390 .as_inner();
1391
1392 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1393 let own_segment_roots = unsafe {
1395 slice::from_raw_parts(
1396 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1397 num_own_segment_roots,
1398 )
1399 };
1400 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1401
1402 Some(OwnSegments {
1403 first_local_segment_index,
1404 segment_roots: own_segment_roots,
1405 })
1406 } else {
1407 None
1408 };
1409
1410 let (leaf_shard_blocks, remainder) = LeafShardBlocksInfo::try_from_bytes_unchecked(bytes)?;
1411
1412 Some((
1413 Self {
1414 own_segments,
1415 leaf_shard_blocks,
1416 },
1417 remainder,
1418 ))
1419 }
1420
1421 #[inline(always)]
1423 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
1424 self.own_segments
1425 }
1426
1427 #[inline(always)]
1429 pub fn leaf_shard_blocks(&self) -> &LeafShardBlocksInfo<'a> {
1430 &self.leaf_shard_blocks
1431 }
1432
1433 #[cfg(feature = "alloc")]
1435 #[inline(always)]
1436 pub fn to_owned(self) -> OwnedIntermediateShardBody {
1437 if let Some(own_segments) = self.own_segments {
1438 let first_local_segment_index = own_segments.first_local_segment_index;
1439
1440 OwnedIntermediateShardBody::new(
1441 own_segments.segment_roots.iter().copied().enumerate().map(
1442 |(index, segment_root)| {
1443 (
1444 first_local_segment_index + LocalSegmentIndex::from(index as u64),
1445 segment_root,
1446 )
1447 },
1448 ),
1449 self.leaf_shard_blocks.iter(),
1450 )
1451 .expect("`self` is always a valid invariant; qed")
1452 } else {
1453 OwnedIntermediateShardBody::new(iter::empty(), self.leaf_shard_blocks.iter())
1454 .expect("`self` is always a valid invariant; qed")
1455 }
1456 }
1457
1458 #[inline]
1460 pub fn root(&self) -> Blake3Hash {
1461 let root = BalancedMerkleTree::compute_root_only(&[
1463 BalancedMerkleTree::compute_root_only(&[
1464 *self
1465 .own_segments
1466 .as_ref()
1467 .map(OwnSegments::root)
1468 .unwrap_or_default(),
1469 *self.leaf_shard_blocks.segments_root(),
1470 ]),
1471 *self.leaf_shard_blocks.headers_root(),
1472 ]);
1473
1474 Blake3Hash::new(root)
1475 }
1476}
1477
1478#[derive(Debug, Copy, Clone)]
1480pub struct Transactions<'a> {
1481 num_transactions: usize,
1482 bytes: &'a [u8],
1483}
1484
1485impl<'a> Transactions<'a> {
1486 #[inline]
1492 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1493 let num_transactions = bytes.split_off(..size_of::<u32>())?;
1501 let num_transactions = u32::from_le_bytes([
1502 num_transactions[0],
1503 num_transactions[1],
1504 num_transactions[2],
1505 num_transactions[3],
1506 ]) as usize;
1507
1508 let mut remainder = align_to_and_ensure_zero_padding::<u128>(bytes)?;
1509 let bytes_start = remainder;
1510
1511 for _ in 0..num_transactions {
1512 (_, remainder) = Transaction::try_from_bytes(bytes)?;
1513 remainder = align_to_and_ensure_zero_padding::<u128>(remainder)?;
1514 }
1515
1516 Some((
1517 Self {
1518 num_transactions,
1519 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1520 },
1521 remainder,
1522 ))
1523 }
1524
1525 #[inline]
1527 pub fn iter(&self) -> impl ExactSizeIterator<Item = Transaction<'a>> + TrustedLen + use<'a> {
1528 let mut remainder = self.bytes;
1529
1530 iter::repeat_with(move || {
1531 let transaction = unsafe { Transaction::from_bytes_unchecked(remainder) };
1533
1534 remainder = &remainder[transaction.encoded_size()..];
1535 remainder = align_to_and_ensure_zero_padding::<u128>(remainder)
1536 .expect("Already checked in constructor; qed");
1537
1538 transaction
1539 })
1540 .take(self.num_transactions)
1541 }
1542
1543 #[inline(always)]
1545 pub const fn len(&self) -> usize {
1546 self.num_transactions
1547 }
1548
1549 #[inline(always)]
1551 pub const fn is_empty(&self) -> bool {
1552 self.num_transactions == 0
1553 }
1554
1555 #[inline]
1559 pub fn root(&self) -> Blake3Hash {
1560 let root = UnbalancedMerkleTree::compute_root_only::<{ u64::from(u32::MAX) }, _, _>(
1561 self.iter().map(|transaction| {
1562 single_block_hash(transaction.hash().as_ref())
1566 .expect("Less than a single block worth of bytes; qed")
1567 }),
1568 )
1569 .unwrap_or_default();
1570
1571 Blake3Hash::new(root)
1572 }
1573}
1574
1575#[derive(Debug, Copy, Clone, Yokeable)]
1577#[non_exhaustive]
1579pub struct LeafShardBody<'a> {
1580 own_segments: Option<OwnSegments<'a>>,
1582 transactions: Transactions<'a>,
1584}
1585
1586impl<'a> GenericBlockBody<'a> for LeafShardBody<'a> {
1587 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1588
1589 #[cfg(feature = "alloc")]
1590 type Owned = OwnedLeafShardBody;
1591
1592 #[cfg(feature = "alloc")]
1593 #[inline(always)]
1594 fn to_owned(self) -> Self::Owned {
1595 self.to_owned()
1596 }
1597
1598 #[inline(always)]
1599 fn root(&self) -> Blake3Hash {
1600 self.root()
1601 }
1602}
1603
1604impl<'a> LeafShardBody<'a> {
1605 #[inline]
1611 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1612 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1619 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1620
1621 let own_segments = if num_own_segment_roots > 0 {
1622 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1623 let first_local_segment_index = unsafe {
1625 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1626 }
1627 .as_inner();
1628
1629 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1630 let own_segment_roots = unsafe {
1632 slice::from_raw_parts(
1633 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1634 num_own_segment_roots,
1635 )
1636 };
1637 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1638
1639 Some(OwnSegments {
1640 first_local_segment_index,
1641 segment_roots: own_segment_roots,
1642 })
1643 } else {
1644 None
1645 };
1646
1647 let (transactions, remainder) = Transactions::try_from_bytes(bytes)?;
1648
1649 let body = Self {
1650 own_segments,
1651 transactions,
1652 };
1653
1654 if !body.is_internally_consistent() {
1655 return None;
1656 }
1657
1658 Some((body, remainder))
1659 }
1660
1661 #[inline]
1666 pub fn is_internally_consistent(&self) -> bool {
1667 true
1669 }
1670
1671 #[inline]
1674 pub fn try_from_bytes_unchecked(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1675 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1682 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1683
1684 let own_segments = if num_own_segment_roots > 0 {
1685 let first_local_segment_index = bytes.split_off(..LocalSegmentIndex::SIZE as usize)?;
1686 let first_local_segment_index = unsafe {
1688 Unaligned::<LocalSegmentIndex>::from_bytes_unchecked(first_local_segment_index)
1689 }
1690 .as_inner();
1691
1692 let own_segment_roots = bytes.split_off(..num_own_segment_roots * SegmentRoot::SIZE)?;
1693 let own_segment_roots = unsafe {
1695 slice::from_raw_parts(
1696 own_segment_roots.as_ptr().cast::<[u8; SegmentRoot::SIZE]>(),
1697 num_own_segment_roots,
1698 )
1699 };
1700 let own_segment_roots = SegmentRoot::slice_from_repr(own_segment_roots);
1701
1702 Some(OwnSegments {
1703 first_local_segment_index,
1704 segment_roots: own_segment_roots,
1705 })
1706 } else {
1707 None
1708 };
1709
1710 let (transactions, remainder) = Transactions::try_from_bytes(bytes)?;
1711
1712 Some((
1713 Self {
1714 own_segments,
1715 transactions,
1716 },
1717 remainder,
1718 ))
1719 }
1720
1721 #[inline(always)]
1723 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
1724 self.own_segments
1725 }
1726
1727 #[inline(always)]
1729 pub fn transactions(&self) -> &Transactions<'a> {
1730 &self.transactions
1731 }
1732
1733 #[cfg(feature = "alloc")]
1735 #[inline(always)]
1736 pub fn to_owned(self) -> OwnedLeafShardBody {
1737 let mut builder = if let Some(own_segments) = self.own_segments {
1738 let first_local_segment_index = own_segments.first_local_segment_index;
1739
1740 OwnedLeafShardBody::init(own_segments.segment_roots.iter().copied().enumerate().map(
1741 |(index, segment_root)| {
1742 (
1743 first_local_segment_index + LocalSegmentIndex::from(index as u64),
1744 segment_root,
1745 )
1746 },
1747 ))
1748 .expect("`self` is always a valid invariant; qed")
1749 } else {
1750 OwnedLeafShardBody::init(iter::empty())
1751 .expect("`self` is always a valid invariant; qed")
1752 };
1753 for transaction in self.transactions.iter() {
1754 builder
1755 .add_transaction(transaction)
1756 .expect("`self` is always a valid invariant; qed");
1757 }
1758
1759 builder.finish()
1760 }
1761
1762 #[inline]
1764 pub fn root(&self) -> Blake3Hash {
1765 let root = BalancedMerkleTree::compute_root_only(&[
1766 *self
1767 .own_segments
1768 .as_ref()
1769 .map(OwnSegments::root)
1770 .unwrap_or_default(),
1771 *self.transactions.root(),
1772 ]);
1773
1774 Blake3Hash::new(root)
1775 }
1776}
1777
1778#[derive(Debug, Copy, Clone, From)]
1783pub enum BlockBody<'a> {
1784 BeaconChain(BeaconChainBody<'a>),
1786 IntermediateShard(IntermediateShardBody<'a>),
1788 LeafShard(LeafShardBody<'a>),
1790}
1791
1792impl<'a> BlockBody<'a> {
1793 #[inline]
1800 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1801 match shard_kind {
1802 RealShardKind::BeaconChain => {
1803 let (body, remainder) = BeaconChainBody::try_from_bytes(bytes)?;
1804 Some((Self::BeaconChain(body), remainder))
1805 }
1806 RealShardKind::IntermediateShard => {
1807 let (body, remainder) = IntermediateShardBody::try_from_bytes(bytes)?;
1808 Some((Self::IntermediateShard(body), remainder))
1809 }
1810 RealShardKind::LeafShard => {
1811 let (body, remainder) = LeafShardBody::try_from_bytes(bytes)?;
1812 Some((Self::LeafShard(body), remainder))
1813 }
1814 }
1815 }
1816
1817 #[inline]
1822 pub fn is_internally_consistent(&self) -> bool {
1823 match self {
1824 Self::BeaconChain(body) => body.is_internally_consistent(),
1825 Self::IntermediateShard(body) => body.is_internally_consistent(),
1826 Self::LeafShard(body) => body.is_internally_consistent(),
1827 }
1828 }
1829
1830 #[inline]
1833 pub fn try_from_bytes_unchecked(
1834 bytes: &'a [u8],
1835 shard_kind: RealShardKind,
1836 ) -> Option<(Self, &'a [u8])> {
1837 match shard_kind {
1838 RealShardKind::BeaconChain => {
1839 let (body, remainder) = BeaconChainBody::try_from_bytes_unchecked(bytes)?;
1840 Some((Self::BeaconChain(body), remainder))
1841 }
1842 RealShardKind::IntermediateShard => {
1843 let (body, remainder) = IntermediateShardBody::try_from_bytes_unchecked(bytes)?;
1844 Some((Self::IntermediateShard(body), remainder))
1845 }
1846 RealShardKind::LeafShard => {
1847 let (body, remainder) = LeafShardBody::try_from_bytes_unchecked(bytes)?;
1848 Some((Self::LeafShard(body), remainder))
1849 }
1850 }
1851 }
1852
1853 #[cfg(feature = "alloc")]
1855 #[inline(always)]
1856 pub fn to_owned(self) -> OwnedBlockBody {
1857 match self {
1858 Self::BeaconChain(body) => body.to_owned().into(),
1859 Self::IntermediateShard(body) => body.to_owned().into(),
1860 Self::LeafShard(body) => body.to_owned().into(),
1861 }
1862 }
1863
1864 #[inline]
1869 pub fn root(&self) -> Blake3Hash {
1870 match self {
1871 Self::BeaconChain(body) => body.root(),
1872 Self::IntermediateShard(body) => body.root(),
1873 Self::LeafShard(body) => body.root(),
1874 }
1875 }
1876}