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 crate::trees::{
19 BeaconChainBodyMerkleTree, ChildIntermediateShardBlocksMerkleTree,
20 ChildLeafShardBlocksMerkleTree, IntermediateShardBodyMerkleTree,
21 IntermediateShardsSegmentsMerkleTree, LeafShardBodyMerkleTree, LeafShardsSegmentsMerkleTree,
22 OwnSegmentsMerkleTree, SegmentRootsMerkleTree, ShardOwnSegmentsMerkleTree,
23 TransactionsMerkleTree,
24};
25#[cfg(feature = "alloc")]
26use ab_aligned_buffer::SharedAlignedBuffer;
27use ab_blake3::{BLOCK_LEN, single_block_hash};
28use ab_io_type::alignment::Alignment;
29use ab_io_type::trivial_type::TrivialType;
30use ab_io_type::unaligned::Unaligned;
31use core::iter::{Step, TrustedLen};
32use core::num::NonZeroU8;
33use core::{cmp, fmt, iter};
34use derive_more::From;
35use yoke::Yokeable;
36
37pub trait GenericBlockBody<'a>
39where
40 Self: Copy + fmt::Debug + Into<BlockBody<'a>> + Send + Sync,
41{
42 const SHARD_KIND: RealShardKind;
44
45 #[cfg(feature = "alloc")]
47 type Owned: GenericOwnedBlockBody<Body<'a> = Self>
48 where
49 Self: 'a;
50
51 #[cfg(feature = "alloc")]
53 fn to_owned(self) -> Self::Owned;
54
55 fn root(&self) -> Blake3Hash;
57}
58
59#[inline]
61pub fn compute_segments_root<'a, const MAX_SEGMENTS: u64, Iter>(segment_roots: Iter) -> Blake3Hash
62where
63 Iter: IntoIterator<Item = &'a SegmentRoot, IntoIter: TrustedLen>,
64{
65 let root = SegmentRootsMerkleTree::compute_root_only::<MAX_SEGMENTS, _, _>(
66 segment_roots.into_iter().copied(),
67 );
68
69 Blake3Hash::new(root.unwrap_or_default())
70}
71
72#[derive(Debug, Copy, Clone)]
78pub struct OwnSegments<'a> {
79 pub mut(self) first_local_segment_index: LocalSegmentIndex,
81 pub mut(self) segment_roots: &'a [SegmentRoot],
83}
84
85impl<'a> OwnSegments<'a> {
86 #[inline]
91 pub fn new(
92 first_local_segment_index: LocalSegmentIndex,
93 segment_roots: &'a [SegmentRoot],
94 ) -> Option<Self> {
95 if segment_roots.is_empty()
96 || segment_roots.len() > usize::from(u8::MAX)
97 || LocalSegmentIndex::forward_checked(first_local_segment_index, segment_roots.len())
98 .is_none()
99 {
100 return None;
101 }
102
103 Some(Self::new_unchecked(
104 first_local_segment_index,
105 segment_roots,
106 ))
107 }
108
109 #[inline(always)]
115 const fn new_unchecked(
116 first_local_segment_index: LocalSegmentIndex,
117 segment_roots: &'a [SegmentRoot],
118 ) -> Self {
119 Self {
120 first_local_segment_index,
121 segment_roots,
122 }
123 }
124
125 #[inline(always)]
127 pub fn num_segment_roots(&self) -> NonZeroU8 {
128 u8::try_from(self.segment_roots.len())
129 .ok()
130 .and_then(NonZeroU8::new)
131 .expect("Constructors ensure between 1 and `u8::MAX` segment roots; qed")
132 }
133
134 #[inline]
136 pub fn iter(
137 &self,
138 ) -> impl ExactSizeIterator<Item = (LocalSegmentIndex, &'a SegmentRoot)> + TrustedLen + use<'a>
139 {
140 let first_local_segment_index = self.first_local_segment_index;
141
142 self.segment_roots
143 .iter()
144 .enumerate()
145 .map(move |(offset, segment_root)| {
146 let local_segment_index =
147 LocalSegmentIndex::forward_checked(first_local_segment_index, offset).expect(
148 "`Self::new()` and parsers check that the index after the last root fits \
149 into `u64`; qed",
150 );
151
152 (local_segment_index, segment_root)
153 })
154 }
155
156 #[inline]
158 pub fn root(&self) -> Blake3Hash {
159 let root = OwnSegmentsMerkleTree::compute_root_only(&[
160 single_block_hash(self.first_local_segment_index.as_bytes())
161 .expect("Less than a single block worth of bytes; qed"),
162 *compute_segments_root::<{ u64::from(u8::MAX) }, _>(self.segment_roots),
163 ]);
164
165 Blake3Hash::new(root)
166 }
167
168 #[inline]
174 pub fn root_with_shard_index(&self, shard_index: ShardIndex) -> Blake3Hash {
175 let root = ShardOwnSegmentsMerkleTree::compute_root_only(&[
176 {
177 const {
178 assert!((ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize <= BLOCK_LEN);
179 }
180 let mut pair = [0u8; (ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize];
181 pair[..ShardIndex::SIZE as usize].copy_from_slice(shard_index.as_bytes());
182 pair[ShardIndex::SIZE as usize..]
183 .copy_from_slice(self.first_local_segment_index.as_bytes());
184
185 single_block_hash(&pair).expect("Less than a single block worth of bytes; qed")
186 },
187 *compute_segments_root::<{ u64::from(u8::MAX) }, _>(self.segment_roots),
188 ]);
189
190 Blake3Hash::new(root)
191 }
192}
193
194fn compute_leaf_shards_segments_root<'a, Iter>(
200 num_leaf_shard_blocks: u16,
201 leaf_shard_blocks_segments: Iter,
202) -> Option<Blake3Hash>
203where
204 Iter: IntoIterator<Item = (u16, ShardIndex, OwnSegments<'a>)>,
205{
206 let mut leaves =
207 leaf_shard_blocks_segments
208 .into_iter()
209 .map(|(position, shard_index, own_segments)| {
210 (
211 u64::from(position),
212 *own_segments.root_with_shard_index(shard_index),
213 )
214 });
215
216 if num_leaf_shard_blocks == 0 {
217 return leaves.next().is_none().then_some(Blake3Hash::default());
218 }
219
220 LeafShardsSegmentsMerkleTree::compute_root_only_sparse::<{ u64::from(u16::MAX) }, _, _>(
221 u64::from(num_leaf_shard_blocks),
222 leaves,
223 )
224 .map(Blake3Hash::new)
225}
226
227fn intermediate_shard_body_root(
229 own_segments: Option<&OwnSegments<'_>>,
230 leaf_shards_segments_root: &Blake3Hash,
231 leaf_shard_blocks_root: &Blake3Hash,
232) -> Blake3Hash {
233 Blake3Hash::new(IntermediateShardBodyMerkleTree::compute_root_only_array(&[
234 *own_segments.map_or_default(OwnSegments::root),
235 **leaf_shards_segments_root,
236 **leaf_shard_blocks_root,
237 ]))
238}
239
240#[derive(Debug, Clone)]
242#[expect(
243 clippy::partial_pub_fields,
244 reason = "Intentionally exposing immediately decoded fields above and hiding the rest of the implementation"
245)]
246pub struct IntermediateShardBlockInfo<'a> {
247 pub header: IntermediateShardHeader<'a>,
249 pub own_segments: Option<OwnSegments<'a>>,
251 num_leaf_shard_blocks: u16,
252 num_leaf_shard_blocks_with_segments: u16,
253 leaf_shards_segments_bytes: &'a [u8],
254}
255
256impl<'a> IntermediateShardBlockInfo<'a> {
257 #[inline(always)]
259 pub const fn num_leaf_shard_blocks(&self) -> u16 {
260 self.num_leaf_shard_blocks
261 }
262
263 #[inline(always)]
265 pub const fn num_leaf_shard_blocks_with_segments(&self) -> u16 {
266 self.num_leaf_shard_blocks_with_segments
267 }
268
269 #[inline]
272 pub fn leaf_shards_segments(
273 &self,
274 ) -> impl ExactSizeIterator<Item = (u16, ShardIndex, OwnSegments<'a>)> + TrustedLen + use<'a>
275 {
276 let (counts, mut remainder) = unsafe {
278 self.leaf_shards_segments_bytes.split_at_unchecked(
279 usize::from(self.num_leaf_shard_blocks_with_segments) * size_of::<u8>(),
280 )
281 };
282 counts.iter().map(move |&num_own_segment_roots| {
283 let num_own_segment_roots = usize::from(num_own_segment_roots);
284
285 let position;
286 (position, remainder) = unsafe { remainder.split_at_unchecked(size_of::<u16>()) };
288 let position = u16::from_le_bytes([position[0], position[1]]);
289
290 let shard_index;
291 (shard_index, remainder) =
293 unsafe { remainder.split_at_unchecked(ShardIndex::SIZE as usize) };
294 let shard_index = Unaligned::<ShardIndex>::from_bytes_exact(shard_index)
295 .expect("Correct size; qed")
296 .as_inner();
297
298 let first_local_segment_index;
299 (first_local_segment_index, remainder) =
301 unsafe { remainder.split_at_unchecked(LocalSegmentIndex::SIZE as usize) };
302 let first_local_segment_index =
303 Unaligned::<LocalSegmentIndex>::from_bytes_exact(first_local_segment_index)
304 .expect("Correct size; qed")
305 .as_inner();
306
307 let own_segment_roots;
308 (own_segment_roots, remainder) =
309 SegmentRoot::slice_from_bytes(remainder, num_own_segment_roots)
310 .expect("Already checked in constructor; qed");
311
312 (
313 position,
314 shard_index,
315 OwnSegments::new_unchecked(first_local_segment_index, own_segment_roots),
316 )
317 })
318 }
319
320 #[inline]
322 fn leaf_shards_segments_root(&self) -> Blake3Hash {
323 compute_leaf_shards_segments_root(self.num_leaf_shard_blocks, self.leaf_shards_segments())
324 .expect("Positions are checked in constructor; qed")
325 }
326
327 #[inline]
332 pub fn body_root(&self) -> Blake3Hash {
333 intermediate_shard_body_root(
334 self.own_segments.as_ref(),
335 &self.leaf_shards_segments_root(),
336 self.header.leaf_shard_blocks_root(),
337 )
338 }
339}
340
341#[derive(Debug, Copy, Clone)]
343pub struct IntermediateShardBlocksInfo<'a> {
344 num_blocks: usize,
345 bytes: &'a [u8],
346}
347
348impl<'a> IntermediateShardBlocksInfo<'a> {
349 #[inline]
361 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
362 let num_blocks = bytes.split_off(..size_of::<u16>())?;
384 let num_blocks = usize::from(u16::from_le_bytes([num_blocks[0], num_blocks[1]]));
385
386 let bytes_start = bytes;
387
388 let mut counts =
389 bytes.split_off(..num_blocks * (size_of::<u8>() + 2 * size_of::<u16>()))?;
390
391 let mut remainder = align_to_and_ensure_zero_padding(bytes, Alignment::of::<u64>())?;
392
393 for _ in 0..num_blocks {
394 let num_own_segment_roots = usize::from(counts[0]);
395 let num_leaf_shard_blocks = u16::from_le_bytes([counts[1], counts[2]]);
396 let num_leaf_shard_blocks_with_segments =
397 usize::from(u16::from_le_bytes([counts[3], counts[4]]));
398 counts = &counts[5..];
399
400 (_, remainder) = IntermediateShardHeader::try_from_bytes(remainder)?;
401
402 if num_own_segment_roots > 0 {
403 let first_local_segment_index;
404 (first_local_segment_index, remainder) =
405 Unaligned::<LocalSegmentIndex>::from_bytes(remainder)?;
406 let _next_local_segment_index = LocalSegmentIndex::forward_checked(
408 first_local_segment_index.as_inner(),
409 num_own_segment_roots,
410 )?;
411 (_, remainder) = SegmentRoot::slice_from_bytes(remainder, num_own_segment_roots)?;
412 }
413
414 let leaf_shard_segment_roots_counts =
415 remainder.split_off(..num_leaf_shard_blocks_with_segments * size_of::<u8>())?;
416
417 let mut next_position = 0;
420 for &num_own_segment_roots in leaf_shard_segment_roots_counts {
421 let num_own_segment_roots = NonZeroU8::new(num_own_segment_roots)?;
422 let position = remainder.split_off(..size_of::<u16>())?;
423 let position = u16::from_le_bytes([position[0], position[1]]);
424 if position < next_position || position >= num_leaf_shard_blocks {
425 return None;
426 }
427 next_position = position + 1;
428 let _shard_index = remainder.split_off(..ShardIndex::SIZE as usize)?;
429 let first_local_segment_index;
430 (first_local_segment_index, remainder) =
431 Unaligned::<LocalSegmentIndex>::from_bytes(remainder)?;
432 let _next_local_segment_index = LocalSegmentIndex::forward_checked(
434 first_local_segment_index.as_inner(),
435 usize::from(num_own_segment_roots.get()),
436 )?;
437 (_, remainder) = SegmentRoot::slice_from_bytes(
438 remainder,
439 usize::from(num_own_segment_roots.get()),
440 )?;
441 }
442
443 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())?;
444 }
445
446 let info = Self {
447 num_blocks,
448 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
449 };
450
451 if !info.is_internally_consistent() {
452 return None;
453 }
454
455 Some((info, remainder))
456 }
457
458 #[inline]
460 fn is_internally_consistent(&self) -> bool {
461 let mut last_intermediate_shard_info =
462 None::<(ShardIndex, BlockNumber, Option<LocalSegmentIndex>)>;
463
464 self.iter().all(|intermediate_shard_block| {
465 let shard_index = intermediate_shard_block.header.prefix.shard_index;
466
467 if let Some((
469 last_intermediate_shard_index,
470 last_intermediate_shard_block_number,
471 last_intermediate_shard_first_local_segment_index,
472 )) = last_intermediate_shard_info
473 {
474 match last_intermediate_shard_index.cmp(&shard_index) {
475 cmp::Ordering::Less => {
476 last_intermediate_shard_info.replace((
477 shard_index,
478 intermediate_shard_block.header.prefix.number,
479 intermediate_shard_block
480 .own_segments
481 .as_ref()
482 .map(|own_segments| own_segments.first_local_segment_index),
483 ));
484 }
485 cmp::Ordering::Equal => {
486 if last_intermediate_shard_block_number
487 >= intermediate_shard_block.header.prefix.number
488 {
489 return false;
490 }
491 if let Some(own_segments) = &intermediate_shard_block.own_segments {
492 if let Some(last_intermediate_shard_first_local_segment_index) =
493 last_intermediate_shard_first_local_segment_index
494 && last_intermediate_shard_first_local_segment_index
495 >= own_segments.first_local_segment_index
496 {
497 return false;
498 }
499
500 last_intermediate_shard_info.replace((
501 shard_index,
502 intermediate_shard_block.header.prefix.number,
503 Some(own_segments.first_local_segment_index),
504 ));
505 } else {
506 last_intermediate_shard_info.replace((
507 shard_index,
508 intermediate_shard_block.header.prefix.number,
509 last_intermediate_shard_first_local_segment_index,
510 ));
511 }
512 }
513 cmp::Ordering::Greater => {
514 return false;
515 }
516 }
517 } else {
518 last_intermediate_shard_info.replace((
519 shard_index,
520 intermediate_shard_block.header.prefix.number,
521 intermediate_shard_block
522 .own_segments
523 .as_ref()
524 .map(|own_segments| own_segments.first_local_segment_index),
525 ));
526 }
527
528 let mut last_leaf_shard_info = None::<(ShardIndex, LocalSegmentIndex)>;
529
530 if !intermediate_shard_block.leaf_shards_segments().all(
532 |(_position, leaf_shard_index, own_segments)| {
533 if !leaf_shard_index.is_child_of(shard_index) {
534 return false;
535 }
536
537 if let Some((
538 last_leaf_shard_index,
539 last_leaf_shard_first_local_segment_index,
540 )) = last_leaf_shard_info
541 {
542 match last_leaf_shard_index.cmp(&leaf_shard_index) {
543 cmp::Ordering::Less => {
544 }
546 cmp::Ordering::Equal => {
547 if last_leaf_shard_first_local_segment_index
548 >= own_segments.first_local_segment_index
549 {
550 return false;
551 }
552 }
553 cmp::Ordering::Greater => {
554 return false;
555 }
556 }
557 }
558 last_leaf_shard_info
559 .replace((leaf_shard_index, own_segments.first_local_segment_index));
560
561 true
562 },
563 ) {
564 return false;
565 }
566
567 intermediate_shard_block.body_root() == intermediate_shard_block.header.result.body_root
570 })
571 }
572
573 #[inline]
575 pub fn iter(
576 &self,
577 ) -> impl ExactSizeIterator<Item = IntermediateShardBlockInfo<'a>> + TrustedLen + use<'a> {
578 let (mut counts, remainder) = unsafe {
580 self.bytes
581 .split_at_unchecked(self.num_blocks * (size_of::<u8>() + 2 * size_of::<u16>()))
582 };
583 let mut remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())
584 .expect("Already checked in constructor; qed");
585
586 iter::repeat_with(move || {
587 let num_own_segment_roots = usize::from(counts[0]);
588 let num_leaf_shard_blocks = u16::from_le_bytes([counts[1], counts[2]]);
589 let num_leaf_shard_blocks_with_segments = u16::from_le_bytes([counts[3], counts[4]]);
590 counts = &counts[5..];
591
592 let header;
594 (header, remainder) = IntermediateShardHeader::try_from_bytes(remainder)
595 .expect("Already checked in constructor; qed");
596
597 let own_segments = if num_own_segment_roots > 0 {
598 let first_local_segment_index;
599 (first_local_segment_index, remainder) =
601 unsafe { remainder.split_at_unchecked(size_of::<LocalSegmentIndex>()) };
602 let first_local_segment_index =
603 Unaligned::<LocalSegmentIndex>::from_bytes_exact(first_local_segment_index)
604 .expect("Correct size; qed")
605 .as_inner();
606
607 let own_segment_roots;
608 (own_segment_roots, remainder) =
609 SegmentRoot::slice_from_bytes(remainder, num_own_segment_roots)
610 .expect("Already checked in constructor; qed");
611
612 Some(OwnSegments::new_unchecked(
613 first_local_segment_index,
614 own_segment_roots,
615 ))
616 } else {
617 None
618 };
619
620 let leaf_shard_segment_roots_counts = unsafe {
622 remainder.get_unchecked(
623 ..usize::from(num_leaf_shard_blocks_with_segments) * size_of::<u8>(),
624 )
625 };
626
627 let leaf_shards_segments_bytes;
628 (leaf_shards_segments_bytes, remainder) = unsafe {
630 remainder.split_at_unchecked(
631 usize::from(num_leaf_shard_blocks_with_segments) * size_of::<u8>()
632 + usize::from(num_leaf_shard_blocks_with_segments)
633 * (size_of::<u16>()
634 + (ShardIndex::SIZE + LocalSegmentIndex::SIZE) as usize)
635 + leaf_shard_segment_roots_counts.iter().fold(
636 0usize,
637 |acc, &num_own_segment_roots| {
638 acc + usize::from(num_own_segment_roots) * SegmentRoot::SIZE
639 },
640 ),
641 )
642 };
643
644 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())
645 .expect("Already checked in constructor; qed");
646
647 IntermediateShardBlockInfo {
648 header,
649 own_segments,
650 num_leaf_shard_blocks,
651 num_leaf_shard_blocks_with_segments,
652 leaf_shards_segments_bytes,
653 }
654 })
655 .take(self.num_blocks)
656 }
657
658 #[inline(always)]
660 pub const fn len(&self) -> usize {
661 self.num_blocks
662 }
663
664 #[inline(always)]
666 pub const fn is_empty(&self) -> bool {
667 self.num_blocks == 0
668 }
669
670 #[inline]
674 pub fn segments_root(&self) -> Blake3Hash {
675 let root = IntermediateShardsSegmentsMerkleTree::compute_root_only::<
676 { u64::from(u16::MAX) },
677 _,
678 _,
679 >(self.iter().map(|shard_block_info| {
680 IntermediateShardBodyMerkleTree::compute_root_only_array(&[
684 *shard_block_info
685 .own_segments
686 .as_ref()
687 .map_or_default(OwnSegments::root),
688 *shard_block_info.leaf_shards_segments_root(),
689 ])
690 }))
691 .unwrap_or_default();
692
693 Blake3Hash::new(root)
694 }
695
696 #[inline]
700 pub fn headers_root(&self) -> Blake3Hash {
701 let root = ChildIntermediateShardBlocksMerkleTree::compute_root_only::<
702 { u64::from(u16::MAX) },
703 _,
704 _,
705 >(
706 self.iter()
707 .map(|shard_block_info| **shard_block_info.header.root()),
708 )
709 .unwrap_or_default();
710
711 Blake3Hash::new(root)
712 }
713}
714
715#[derive(Debug, Copy, Clone, Yokeable)]
717#[non_exhaustive]
719pub struct BeaconChainBody<'a> {
720 own_segments: Option<OwnSegments<'a>>,
722 intermediate_shard_blocks: IntermediateShardBlocksInfo<'a>,
724 pot_checkpoints: &'a [PotCheckpoints],
727 #[cfg(feature = "alloc")]
729 bytes: &'a [u8],
730}
731
732impl<'a> GenericBlockBody<'a> for BeaconChainBody<'a> {
733 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
734
735 #[cfg(feature = "alloc")]
736 type Owned = OwnedBeaconChainBody;
737
738 #[cfg(feature = "alloc")]
739 #[inline(always)]
740 fn to_owned(self) -> Self::Owned {
741 self.to_owned()
742 }
743
744 #[inline(always)]
745 fn root(&self) -> Blake3Hash {
746 self.root()
747 }
748}
749
750impl<'a> BeaconChainBody<'a> {
751 #[inline]
759 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
760 if !Alignment::MAX.is_slice_aligned(bytes) {
769 return None;
770 }
771
772 let bytes_start = bytes;
773
774 let num_pot_checkpoints;
775 (num_pot_checkpoints, bytes) = u32::from_bytes(bytes)?;
776 let num_pot_checkpoints = *num_pot_checkpoints as usize;
777
778 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
779 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
780
781 let own_segments = if num_own_segment_roots > 0 {
782 let first_local_segment_index;
783 (first_local_segment_index, bytes) = Unaligned::<LocalSegmentIndex>::from_bytes(bytes)?;
784
785 let own_segment_roots;
786 (own_segment_roots, bytes) =
787 SegmentRoot::slice_from_bytes(bytes, num_own_segment_roots)?;
788
789 Some(OwnSegments::new(
790 first_local_segment_index.as_inner(),
791 own_segment_roots,
792 )?)
793 } else {
794 None
795 };
796
797 let (intermediate_shard_blocks, remainder) =
798 IntermediateShardBlocksInfo::try_from_bytes(bytes)?;
799
800 let (pot_checkpoints, remainder) =
801 PotCheckpoints::slice_from_bytes(remainder, num_pot_checkpoints)?;
802
803 let bytes = &bytes_start[..bytes_start.len() - remainder.len()];
804 if u32::try_from(bytes.len()).is_err() {
807 return None;
808 }
809
810 let body = Self {
811 own_segments,
812 intermediate_shard_blocks,
813 pot_checkpoints,
814 #[cfg(feature = "alloc")]
815 bytes,
816 };
817
818 Some((body, remainder))
819 }
820
821 #[cfg(feature = "alloc")]
823 #[inline(always)]
824 pub fn to_owned(self) -> OwnedBeaconChainBody {
825 OwnedBeaconChainBody::from_buffer(SharedAlignedBuffer::from_bytes(self.bytes)).expect(
826 "The parser accepted the same bytes at a 16-byte aligned address, as in the buffer, \
827 and checked that they fit into it; qed",
828 )
829 }
830
831 #[inline(always)]
833 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
834 self.own_segments
835 }
836
837 #[inline(always)]
839 pub fn intermediate_shard_blocks(&self) -> &IntermediateShardBlocksInfo<'a> {
840 &self.intermediate_shard_blocks
841 }
842
843 #[inline(always)]
846 pub fn pot_checkpoints(&self) -> &'a [PotCheckpoints] {
847 self.pot_checkpoints
848 }
849
850 #[inline]
852 pub fn root(&self) -> Blake3Hash {
853 self.root_with_intermediate_shard_blocks_root(
854 &self.intermediate_shard_blocks.headers_root(),
855 )
856 }
857
858 #[inline]
861 pub(crate) fn root_with_intermediate_shard_blocks_root(
862 &self,
863 intermediate_shard_blocks_root: &Blake3Hash,
864 ) -> Blake3Hash {
865 let root = BeaconChainBodyMerkleTree::compute_root_only(&[
866 *self.own_segments.as_ref().map_or_default(OwnSegments::root),
867 *self.intermediate_shard_blocks.segments_root(),
868 **intermediate_shard_blocks_root,
869 blake3::hash(PotCheckpoints::slice_as_bytes(self.pot_checkpoints)).into(),
870 ]);
871
872 Blake3Hash::new(root)
873 }
874}
875
876fn leaf_shard_body_root(
878 own_segments: Option<&OwnSegments<'_>>,
879 transactions_root: &Blake3Hash,
880) -> Blake3Hash {
881 Blake3Hash::new(LeafShardBodyMerkleTree::compute_root_only(&[
882 *own_segments.map_or_default(OwnSegments::root),
883 **transactions_root,
884 ]))
885}
886
887#[derive(Debug, Clone)]
889pub struct LeafShardBlockInfo<'a> {
890 pub header: LeafShardHeader<'a>,
892 pub transactions_root: &'a Blake3Hash,
894 pub own_segments: Option<OwnSegments<'a>>,
896}
897
898#[derive(Debug, Copy, Clone)]
900pub struct LeafShardBlocksInfo<'a> {
901 num_blocks: u16,
902 bytes: &'a [u8],
903}
904
905impl<'a> LeafShardBlocksInfo<'a> {
906 #[inline]
916 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
917 let num_blocks = bytes.split_off(..size_of::<u16>())?;
930 let num_blocks = u16::from_le_bytes([num_blocks[0], num_blocks[1]]);
931
932 let bytes_start = bytes;
933
934 let mut counts = bytes.split_off(..usize::from(num_blocks) * size_of::<u8>())?;
935
936 let mut remainder = align_to_and_ensure_zero_padding(bytes, Alignment::of::<u64>())?;
937
938 for _ in 0..num_blocks {
939 let num_own_segment_roots = usize::from(counts[0]);
940 counts = &counts[1..];
941
942 (_, remainder) = LeafShardHeader::try_from_bytes(remainder)?;
943
944 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())?;
945
946 (_, remainder) = Blake3Hash::from_bytes(remainder)?;
947
948 if num_own_segment_roots > 0 {
949 let first_local_segment_index;
950 (first_local_segment_index, remainder) = LocalSegmentIndex::from_bytes(remainder)?;
951 let _next_local_segment_index = LocalSegmentIndex::forward_checked(
953 *first_local_segment_index,
954 num_own_segment_roots,
955 )?;
956 (_, remainder) = SegmentRoot::slice_from_bytes(remainder, num_own_segment_roots)?;
957 }
958 }
959
960 let info = Self {
961 num_blocks,
962 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
963 };
964
965 if !info.is_internally_consistent() {
966 return None;
967 }
968
969 Some((info, remainder))
970 }
971
972 #[inline]
974 fn is_internally_consistent(&self) -> bool {
975 let mut last_leaf_shard_info = None::<(ShardIndex, BlockNumber, Option<LocalSegmentIndex>)>;
976
977 self.iter().all(|leaf_shard_block| {
978 let shard_index = leaf_shard_block.header.prefix.shard_index;
979
980 if let Some((
982 last_leaf_shard_index,
983 last_leaf_shard_block_number,
984 last_leaf_shard_first_local_segment_index,
985 )) = last_leaf_shard_info
986 {
987 match last_leaf_shard_index.cmp(&shard_index) {
988 cmp::Ordering::Less => {
989 last_leaf_shard_info.replace((
990 shard_index,
991 leaf_shard_block.header.prefix.number,
992 leaf_shard_block
993 .own_segments
994 .as_ref()
995 .map(|own_segments| own_segments.first_local_segment_index),
996 ));
997 }
998 cmp::Ordering::Equal => {
999 if last_leaf_shard_block_number >= leaf_shard_block.header.prefix.number {
1000 return false;
1001 }
1002 if let Some(own_segments) = &leaf_shard_block.own_segments {
1003 if let Some(last_leaf_shard_first_local_segment_index) =
1004 last_leaf_shard_first_local_segment_index
1005 && last_leaf_shard_first_local_segment_index
1006 >= own_segments.first_local_segment_index
1007 {
1008 return false;
1009 }
1010
1011 last_leaf_shard_info.replace((
1012 shard_index,
1013 leaf_shard_block.header.prefix.number,
1014 Some(own_segments.first_local_segment_index),
1015 ));
1016 } else {
1017 last_leaf_shard_info.replace((
1018 shard_index,
1019 leaf_shard_block.header.prefix.number,
1020 last_leaf_shard_first_local_segment_index,
1021 ));
1022 }
1023 }
1024 cmp::Ordering::Greater => {
1025 return false;
1026 }
1027 }
1028 } else {
1029 last_leaf_shard_info.replace((
1030 shard_index,
1031 leaf_shard_block.header.prefix.number,
1032 leaf_shard_block
1033 .own_segments
1034 .as_ref()
1035 .map(|own_segments| own_segments.first_local_segment_index),
1036 ));
1037 }
1038
1039 leaf_shard_body_root(
1041 leaf_shard_block.own_segments.as_ref(),
1042 leaf_shard_block.transactions_root,
1043 ) == leaf_shard_block.header.result.body_root
1044 })
1045 }
1046
1047 #[inline]
1049 pub fn iter(
1050 &self,
1051 ) -> impl ExactSizeIterator<Item = LeafShardBlockInfo<'a>> + TrustedLen + use<'a> {
1052 let (mut counts, remainder) = unsafe {
1054 self.bytes
1055 .split_at_unchecked(usize::from(self.num_blocks) * size_of::<u8>())
1056 };
1057 let mut remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())
1058 .expect("Already checked in constructor; qed");
1059
1060 iter::repeat_with(move || {
1061 let num_own_segment_roots = usize::from(counts[0]);
1062 counts = &counts[1..];
1063
1064 let header;
1066 (header, remainder) = LeafShardHeader::try_from_bytes(remainder)
1067 .expect("Already checked in constructor; qed");
1068
1069 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::of::<u64>())
1070 .expect("Already checked in constructor; qed");
1071
1072 let transactions_root;
1073 (transactions_root, remainder) =
1075 unsafe { remainder.split_at_unchecked(Blake3Hash::SIZE) };
1076 let transactions_root = Blake3Hash::from_bytes_exact(transactions_root)
1077 .expect("Already checked in constructor; qed");
1078
1079 let own_segments = if num_own_segment_roots > 0 {
1080 let first_local_segment_index;
1081 (first_local_segment_index, remainder) =
1083 unsafe { remainder.split_at_unchecked(LocalSegmentIndex::SIZE as usize) };
1084 let first_local_segment_index =
1085 *LocalSegmentIndex::from_bytes_exact(first_local_segment_index)
1086 .expect("Already checked in constructor; qed");
1087
1088 let own_segment_roots;
1089 (own_segment_roots, remainder) =
1090 SegmentRoot::slice_from_bytes(remainder, num_own_segment_roots)
1091 .expect("Already checked in constructor; qed");
1092
1093 Some(OwnSegments::new_unchecked(
1094 first_local_segment_index,
1095 own_segment_roots,
1096 ))
1097 } else {
1098 None
1099 };
1100
1101 LeafShardBlockInfo {
1102 header,
1103 transactions_root,
1104 own_segments,
1105 }
1106 })
1107 .take(usize::from(self.num_blocks))
1108 }
1109
1110 #[inline(always)]
1112 pub const fn len(&self) -> usize {
1113 self.num_blocks as usize
1114 }
1115
1116 #[inline(always)]
1118 pub const fn is_empty(&self) -> bool {
1119 self.num_blocks == 0
1120 }
1121
1122 #[inline]
1126 pub fn segments_root(&self) -> Blake3Hash {
1127 compute_leaf_shards_segments_root(
1129 self.num_blocks,
1130 self.iter()
1131 .zip(0..)
1132 .filter_map(|(shard_block_info, position)| {
1133 shard_block_info.own_segments.map(|own_segments| {
1134 (
1135 position,
1136 shard_block_info.header.prefix.shard_index,
1137 own_segments,
1138 )
1139 })
1140 }),
1141 )
1142 .expect("Positions are strictly increasing and smaller than the number of blocks; qed")
1143 }
1144
1145 #[inline]
1149 pub fn headers_root(&self) -> Blake3Hash {
1150 let root =
1151 ChildLeafShardBlocksMerkleTree::compute_root_only::<{ u64::from(u16::MAX) }, _, _>(
1152 self.iter()
1153 .map(|shard_block_info| **shard_block_info.header.root()),
1154 )
1155 .unwrap_or_default();
1156
1157 Blake3Hash::new(root)
1158 }
1159}
1160
1161#[derive(Debug, Copy, Clone, Yokeable)]
1163#[non_exhaustive]
1165pub struct IntermediateShardBody<'a> {
1166 own_segments: Option<OwnSegments<'a>>,
1168 leaf_shard_blocks: LeafShardBlocksInfo<'a>,
1170 #[cfg(feature = "alloc")]
1172 bytes: &'a [u8],
1173}
1174
1175impl<'a> GenericBlockBody<'a> for IntermediateShardBody<'a> {
1176 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
1177
1178 #[cfg(feature = "alloc")]
1179 type Owned = OwnedIntermediateShardBody;
1180
1181 #[cfg(feature = "alloc")]
1182 #[inline(always)]
1183 fn to_owned(self) -> Self::Owned {
1184 self.to_owned()
1185 }
1186
1187 #[inline(always)]
1188 fn root(&self) -> Blake3Hash {
1189 self.root()
1190 }
1191}
1192
1193impl<'a> IntermediateShardBody<'a> {
1194 #[inline]
1202 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1203 if !Alignment::MAX.is_slice_aligned(bytes) {
1210 return None;
1211 }
1212
1213 let bytes_start = bytes;
1214
1215 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1216 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1217
1218 let own_segments = if num_own_segment_roots > 0 {
1219 let first_local_segment_index;
1220 (first_local_segment_index, bytes) = Unaligned::<LocalSegmentIndex>::from_bytes(bytes)?;
1221
1222 let own_segment_roots;
1223 (own_segment_roots, bytes) =
1224 SegmentRoot::slice_from_bytes(bytes, num_own_segment_roots)?;
1225
1226 Some(OwnSegments::new(
1227 first_local_segment_index.as_inner(),
1228 own_segment_roots,
1229 )?)
1230 } else {
1231 None
1232 };
1233
1234 let (leaf_shard_blocks, remainder) = LeafShardBlocksInfo::try_from_bytes(bytes)?;
1235
1236 let bytes = &bytes_start[..bytes_start.len() - remainder.len()];
1237 if u32::try_from(bytes.len()).is_err() {
1240 return None;
1241 }
1242
1243 let body = Self {
1244 own_segments,
1245 leaf_shard_blocks,
1246 #[cfg(feature = "alloc")]
1247 bytes,
1248 };
1249
1250 Some((body, remainder))
1251 }
1252
1253 #[inline(always)]
1255 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
1256 self.own_segments
1257 }
1258
1259 #[inline(always)]
1261 pub fn leaf_shard_blocks(&self) -> &LeafShardBlocksInfo<'a> {
1262 &self.leaf_shard_blocks
1263 }
1264
1265 #[cfg(feature = "alloc")]
1267 #[inline(always)]
1268 pub fn to_owned(self) -> OwnedIntermediateShardBody {
1269 OwnedIntermediateShardBody::from_buffer(SharedAlignedBuffer::from_bytes(self.bytes)).expect(
1270 "The parser accepted the same bytes at a 16-byte aligned address, as in the buffer, \
1271 and checked that they fit into it; qed",
1272 )
1273 }
1274
1275 #[inline]
1277 pub fn root(&self) -> Blake3Hash {
1278 self.root_with_leaf_shard_blocks_root(&self.leaf_shard_blocks.headers_root())
1279 }
1280
1281 #[inline]
1284 pub(crate) fn root_with_leaf_shard_blocks_root(
1285 &self,
1286 leaf_shard_blocks_root: &Blake3Hash,
1287 ) -> Blake3Hash {
1288 intermediate_shard_body_root(
1289 self.own_segments.as_ref(),
1290 &self.leaf_shard_blocks.segments_root(),
1291 leaf_shard_blocks_root,
1292 )
1293 }
1294}
1295
1296#[derive(Debug, Copy, Clone)]
1298pub struct Transactions<'a> {
1299 num_transactions: usize,
1300 bytes: &'a [u8],
1301}
1302
1303impl<'a> Transactions<'a> {
1304 #[inline]
1311 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1312 let num_transactions = bytes.split_off(..size_of::<u32>())?;
1320 let num_transactions = u32::from_le_bytes([
1321 num_transactions[0],
1322 num_transactions[1],
1323 num_transactions[2],
1324 num_transactions[3],
1325 ]) as usize;
1326
1327 let mut remainder = align_to_and_ensure_zero_padding(bytes, Alignment::MAX)?;
1328 let bytes_start = remainder;
1329
1330 for _ in 0..num_transactions {
1331 (_, remainder) = Transaction::try_from_bytes(remainder)?;
1332 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::MAX)?;
1333 }
1334
1335 Some((
1336 Self {
1337 num_transactions,
1338 bytes: &bytes_start[..bytes_start.len() - remainder.len()],
1339 },
1340 remainder,
1341 ))
1342 }
1343
1344 #[inline]
1346 pub fn iter(&self) -> impl ExactSizeIterator<Item = Transaction<'a>> + TrustedLen + use<'a> {
1347 let mut remainder = self.bytes;
1348
1349 iter::repeat_with(move || {
1350 let transaction;
1351 (transaction, remainder) = Transaction::try_from_bytes(remainder)
1352 .expect("Already checked in constructor; qed");
1353 remainder = align_to_and_ensure_zero_padding(remainder, Alignment::MAX)
1354 .expect("Already checked in constructor; qed");
1355
1356 transaction
1357 })
1358 .take(self.num_transactions)
1359 }
1360
1361 #[inline(always)]
1363 pub const fn len(&self) -> usize {
1364 self.num_transactions
1365 }
1366
1367 #[inline(always)]
1369 pub const fn is_empty(&self) -> bool {
1370 self.num_transactions == 0
1371 }
1372
1373 #[inline]
1377 pub fn root(&self) -> Blake3Hash {
1378 let root = TransactionsMerkleTree::compute_root_only::<{ u64::from(u32::MAX) }, _, _>(
1379 self.iter().map(|transaction| ***transaction.hash()),
1380 )
1381 .unwrap_or_default();
1382
1383 Blake3Hash::new(root)
1384 }
1385}
1386
1387#[derive(Debug, Copy, Clone, Yokeable)]
1389#[non_exhaustive]
1391pub struct LeafShardBody<'a> {
1392 own_segments: Option<OwnSegments<'a>>,
1394 transactions: Transactions<'a>,
1396 #[cfg(feature = "alloc")]
1398 bytes: &'a [u8],
1399}
1400
1401impl<'a> GenericBlockBody<'a> for LeafShardBody<'a> {
1402 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
1403
1404 #[cfg(feature = "alloc")]
1405 type Owned = OwnedLeafShardBody;
1406
1407 #[cfg(feature = "alloc")]
1408 #[inline(always)]
1409 fn to_owned(self) -> Self::Owned {
1410 self.to_owned()
1411 }
1412
1413 #[inline(always)]
1414 fn root(&self) -> Blake3Hash {
1415 self.root()
1416 }
1417}
1418
1419impl<'a> LeafShardBody<'a> {
1420 #[inline]
1428 pub fn try_from_bytes(mut bytes: &'a [u8]) -> Option<(Self, &'a [u8])> {
1429 if !Alignment::MAX.is_slice_aligned(bytes) {
1436 return None;
1437 }
1438
1439 let bytes_start = bytes;
1440
1441 let num_own_segment_roots = bytes.split_off(..size_of::<u8>())?;
1442 let num_own_segment_roots = usize::from(num_own_segment_roots[0]);
1443
1444 let own_segments = if num_own_segment_roots > 0 {
1445 let first_local_segment_index;
1446 (first_local_segment_index, bytes) = Unaligned::<LocalSegmentIndex>::from_bytes(bytes)?;
1447
1448 let own_segment_roots;
1449 (own_segment_roots, bytes) =
1450 SegmentRoot::slice_from_bytes(bytes, num_own_segment_roots)?;
1451
1452 Some(OwnSegments::new(
1453 first_local_segment_index.as_inner(),
1454 own_segment_roots,
1455 )?)
1456 } else {
1457 None
1458 };
1459
1460 let (transactions, remainder) = Transactions::try_from_bytes(bytes)?;
1461
1462 let bytes = &bytes_start[..bytes_start.len() - remainder.len()];
1463 if u32::try_from(bytes.len()).is_err() {
1466 return None;
1467 }
1468
1469 let body = Self {
1470 own_segments,
1471 transactions,
1472 #[cfg(feature = "alloc")]
1473 bytes,
1474 };
1475
1476 Some((body, remainder))
1477 }
1478
1479 #[inline(always)]
1481 pub fn own_segments(&self) -> Option<OwnSegments<'a>> {
1482 self.own_segments
1483 }
1484
1485 #[inline(always)]
1487 pub fn transactions(&self) -> &Transactions<'a> {
1488 &self.transactions
1489 }
1490
1491 #[cfg(feature = "alloc")]
1493 #[inline(always)]
1494 pub fn to_owned(self) -> OwnedLeafShardBody {
1495 OwnedLeafShardBody::from_buffer(SharedAlignedBuffer::from_bytes(self.bytes)).expect(
1496 "The parser accepted the same bytes at a 16-byte aligned address, as in the buffer, \
1497 and checked that they fit into it; qed",
1498 )
1499 }
1500
1501 #[inline]
1503 pub fn root(&self) -> Blake3Hash {
1504 leaf_shard_body_root(self.own_segments.as_ref(), &self.transactions.root())
1505 }
1506}
1507
1508#[derive(Debug, Copy, Clone, From)]
1513pub enum BlockBody<'a> {
1514 BeaconChain(BeaconChainBody<'a>),
1516 IntermediateShard(IntermediateShardBody<'a>),
1518 LeafShard(LeafShardBody<'a>),
1520}
1521
1522impl<'a> BlockBody<'a> {
1523 #[inline]
1530 pub fn try_from_bytes(bytes: &'a [u8], shard_kind: RealShardKind) -> Option<(Self, &'a [u8])> {
1531 match shard_kind {
1532 RealShardKind::BeaconChain => {
1533 let (body, remainder) = BeaconChainBody::try_from_bytes(bytes)?;
1534 Some((Self::BeaconChain(body), remainder))
1535 }
1536 RealShardKind::IntermediateShard => {
1537 let (body, remainder) = IntermediateShardBody::try_from_bytes(bytes)?;
1538 Some((Self::IntermediateShard(body), remainder))
1539 }
1540 RealShardKind::LeafShard => {
1541 let (body, remainder) = LeafShardBody::try_from_bytes(bytes)?;
1542 Some((Self::LeafShard(body), remainder))
1543 }
1544 }
1545 }
1546
1547 #[cfg(feature = "alloc")]
1549 #[inline(always)]
1550 pub fn to_owned(self) -> OwnedBlockBody {
1551 match self {
1552 Self::BeaconChain(body) => body.to_owned().into(),
1553 Self::IntermediateShard(body) => body.to_owned().into(),
1554 Self::LeafShard(body) => body.to_owned().into(),
1555 }
1556 }
1557
1558 #[inline]
1563 pub fn root(&self) -> Blake3Hash {
1564 match self {
1565 Self::BeaconChain(body) => body.root(),
1566 Self::IntermediateShard(body) => body.root(),
1567 Self::LeafShard(body) => body.root(),
1568 }
1569 }
1570}