1#[cfg(test)]
4mod tests;
5
6use crate::block::body::{
7 BeaconChainBody, BlockBody, GenericBlockBody, IntermediateShardBlockInfo,
8 IntermediateShardBody, LeafShardBlockInfo, LeafShardBody,
9};
10use crate::block::header::owned::{
11 OwnedIntermediateShardHeader, OwnedIntermediateShardHeaderError, OwnedLeafShardHeader,
12};
13use crate::pot::PotCheckpoints;
14use crate::segments::{LocalSegmentIndex, SegmentRoot};
15use crate::shard::RealShardKind;
16use crate::transaction::Transaction;
17use crate::transaction::owned::{OwnedTransaction, OwnedTransactionError};
18use ab_aligned_buffer::{OwnedAlignedBuffer, SharedAlignedBuffer};
19use ab_io_type::alignment::Alignment;
20use ab_io_type::trivial_type::TrivialType;
21use core::fmt;
22use core::iter::TrustedLen;
23use derive_more::From;
24use triomphe::Arc;
25use yoke::Yoke;
26
27pub trait GenericOwnedBlockBody:
29 Clone + fmt::Debug + Send + Sync + Into<OwnedBlockBody> + 'static
30{
31 const SHARD_KIND: RealShardKind;
33
34 type Body<'a>: GenericBlockBody<'a>
36 where
37 Self: 'a;
38
39 fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer>;
41
42 fn buffer(&self) -> &SharedAlignedBuffer;
44
45 fn ref_count(&self) -> usize;
47
48 fn body(&self) -> &Self::Body<'_>;
50}
51
52#[derive(Debug, thiserror::Error)]
54enum AddTransactionError {
55 #[error("Block body is too large")]
57 BlockBodyIsTooLarge,
58 #[error("Too many transactions")]
60 TooManyTransactions,
61 #[error("Failed to add transaction: {error}")]
63 FailedToAddTransaction {
64 #[from]
66 error: OwnedTransactionError,
67 },
68}
69
70pub impl(self) trait WritableBodyTransaction {
75 fn write_into(&self, buffer: &mut OwnedAlignedBuffer) -> Result<(), OwnedTransactionError>;
77}
78
79impl WritableBodyTransaction for Transaction<'_> {
80 fn write_into(&self, buffer: &mut OwnedAlignedBuffer) -> Result<(), OwnedTransactionError> {
81 OwnedTransaction::from_parts_into(
82 self.header,
83 self.read_slots,
84 self.write_slots,
85 self.payload,
86 self.seal,
87 buffer,
88 )
89 }
90}
91
92impl WritableBodyTransaction for &OwnedTransaction {
93 fn write_into(&self, buffer: &mut OwnedAlignedBuffer) -> Result<(), OwnedTransactionError> {
94 if buffer.append(self.buffer().as_slice()) {
95 Ok(())
96 } else {
97 Err(OwnedTransactionError::TransactionTooLarge)
98 }
99 }
100}
101
102#[derive(Debug, Clone)]
103struct TransactionBuilder {
104 num_transactions_offset: usize,
105 buffer: OwnedAlignedBuffer,
106}
107
108impl TransactionBuilder {
109 fn new(num_transactions_offset: usize, buffer: OwnedAlignedBuffer) -> Self {
110 Self {
111 num_transactions_offset,
112 buffer,
113 }
114 }
115
116 fn add_transaction<T>(&mut self, transaction: T) -> Result<(), AddTransactionError>
118 where
119 T: WritableBodyTransaction,
120 {
121 if self.inc_transaction_count()? == 1 && !align_to_16_bytes_with_padding(&mut self.buffer) {
124 self.dec_transaction_count();
125 return Err(AddTransactionError::BlockBodyIsTooLarge);
126 }
127
128 let old_buffer_len = self.buffer.len();
129
130 if let Err(error) = transaction.write_into(&mut self.buffer) {
131 self.dec_transaction_count();
132 unsafe {
136 self.buffer.set_len(old_buffer_len);
137 }
138 return Err(error.into());
139 }
140
141 if !align_to_16_bytes_with_padding(&mut self.buffer) {
142 self.dec_transaction_count();
143 unsafe {
145 self.buffer.set_len(old_buffer_len);
146 }
147 return Err(AddTransactionError::BlockBodyIsTooLarge);
148 }
149
150 Ok(())
151 }
152
153 #[inline(always)]
155 fn finish(self) -> OwnedAlignedBuffer {
156 self.buffer
157 }
158
159 #[inline(always)]
161 fn inc_transaction_count(&mut self) -> Result<u32, AddTransactionError> {
162 unsafe {
165 let num_transactions_ptr = self
166 .buffer
167 .as_mut_ptr()
168 .byte_add(self.num_transactions_offset)
169 .cast::<u32>();
170 let num_transactions = num_transactions_ptr.read_unaligned();
171 let num_transactions = num_transactions
172 .checked_add(1)
173 .ok_or(AddTransactionError::TooManyTransactions)?;
174 num_transactions_ptr.write_unaligned(num_transactions);
175 Ok(num_transactions)
176 }
177 }
178
179 #[inline(always)]
181 fn dec_transaction_count(&mut self) {
182 unsafe {
185 let num_transactions_ptr = self
186 .buffer
187 .as_mut_ptr()
188 .byte_add(self.num_transactions_offset)
189 .cast::<u32>();
190 let num_transactions = num_transactions_ptr.read_unaligned();
191 let num_transactions = num_transactions.saturating_sub(1);
192 num_transactions_ptr.write_unaligned(num_transactions);
193 }
194 }
195}
196
197#[derive(Debug, thiserror::Error)]
199pub enum OwnedBeaconChainBodyError {
200 #[error("Too many PoT checkpoints: {actual}")]
202 TooManyPotCheckpoints {
203 actual: usize,
205 },
206 #[error("Too many own segment roots: {actual}")]
208 TooManyOwnSegmentRoots {
209 actual: usize,
211 },
212 #[error("Too many intermediate shard blocks: {actual}")]
214 TooManyIntermediateShardBlocks {
215 actual: usize,
217 },
218 #[error("Too many intermediate shard own segment roots: {actual}")]
220 TooManyIntermediateShardOwnSegmentRoots {
221 actual: usize,
223 },
224 #[error("Too many leaf shard blocks with segments: {actual}")]
226 TooManyLeafShardBlocksWithSegments {
227 actual: usize,
229 },
230 #[error("Too many leaf shard block segments: {actual}")]
232 TooManyLeafShardBlockSegments {
233 actual: usize,
235 },
236 #[error("Too many intermediate shard child segment roots: {actual}")]
238 TooManyIntermediateShardChildSegmentRoots {
239 actual: usize,
241 },
242 #[error("Failed to intermediate shard header: {error}")]
244 FailedToAddIntermediateShard {
245 #[from]
247 error: OwnedIntermediateShardHeaderError,
248 },
249 #[error("Block body is too large")]
251 BlockBodyIsTooLarge,
252}
253
254#[derive(Debug, Clone)]
259pub struct OwnedBeaconChainBody {
260 inner: Arc<Yoke<BeaconChainBody<'static>, SharedAlignedBuffer>>,
261}
262
263impl GenericOwnedBlockBody for OwnedBeaconChainBody {
264 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
265
266 type Body<'a> = BeaconChainBody<'a>;
267
268 #[inline(always)]
269 fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
270 Self::from_buffer(buffer)
271 }
272
273 #[inline(always)]
274 fn buffer(&self) -> &SharedAlignedBuffer {
275 self.buffer()
276 }
277
278 #[inline(always)]
279 fn ref_count(&self) -> usize {
280 self.ref_count()
281 }
282
283 #[inline(always)]
284 fn body(&self) -> &Self::Body<'_> {
285 self.body()
286 }
287}
288
289impl OwnedBeaconChainBody {
290 pub fn new<'a, OS, ISB>(
293 own_segments: OS,
294 intermediate_shard_blocks: ISB,
295 pot_checkpoints: &[PotCheckpoints],
296 ) -> Result<Self, OwnedBeaconChainBodyError>
297 where
298 OS: TrustedLen<Item = (LocalSegmentIndex, SegmentRoot)>,
299 ISB: TrustedLen<Item = IntermediateShardBlockInfo<'a>> + 'a,
302 {
303 let num_pot_checkpoints = pot_checkpoints.len();
304 let num_pot_checkpoints = u32::try_from(num_pot_checkpoints).map_err(|_error| {
305 OwnedBeaconChainBodyError::TooManyPotCheckpoints {
306 actual: num_pot_checkpoints,
307 }
308 })?;
309 let num_own_segment_roots = own_segments.size_hint().0;
310 let num_own_segment_roots = u8::try_from(num_own_segment_roots).map_err(|_error| {
311 OwnedBeaconChainBodyError::TooManyOwnSegmentRoots {
312 actual: num_own_segment_roots,
313 }
314 })?;
315 let num_blocks = intermediate_shard_blocks.size_hint().0;
316 let num_blocks = u16::try_from(num_blocks).map_err(|_error| {
317 OwnedBeaconChainBodyError::TooManyIntermediateShardBlocks { actual: num_blocks }
318 })?;
319
320 let mut buffer = OwnedAlignedBuffer::with_capacity(
321 u32::SIZE
322 + u8::SIZE
323 + if num_own_segment_roots > 0 { LocalSegmentIndex::SIZE } else { 0 }
324 + u32::from(num_own_segment_roots) * SegmentRoot::SIZE as u32
325 + u16::SIZE
326 + u32::from(num_blocks) * OwnedIntermediateShardHeader::max_allocation_for(&[]) * 2,
329 );
330
331 let true = buffer.append(&num_pot_checkpoints.to_le_bytes()) else {
332 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
333 };
334
335 let true = buffer.append(&[num_own_segment_roots]) else {
336 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
337 };
338 let mut own_segments = own_segments.peekable();
339 if let Some((first_local_segment_index, _own_segment_root)) = own_segments.peek() {
340 let true = buffer.append(first_local_segment_index.as_bytes()) else {
341 unreachable!("Checked size above; qed");
342 };
343 }
344 for (_segment_index, own_segment_root) in own_segments {
345 let true = buffer.append(own_segment_root.as_ref()) else {
346 unreachable!("Checked size above; qed");
347 };
348 }
349 {
351 let true = buffer.append(&num_blocks.to_le_bytes()) else {
352 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
353 };
354 let mut segments_roots_num_cursor = buffer.len() as usize;
355 for _ in 0..num_blocks {
356 let true = buffer.append(&[0, 0]) else {
359 unreachable!("Checked size above; qed");
360 };
361 }
362 let true = align_to_8_with_padding(&mut buffer) else {
363 unreachable!("Checked size above; qed");
364 };
365 for intermediate_shard_block in intermediate_shard_blocks {
366 let num_own_segment_roots = intermediate_shard_block
367 .own_segments
368 .as_ref()
369 .map(|own_segments| own_segments.segment_roots.len())
370 .unwrap_or_default();
371 let num_own_segment_roots =
372 u8::try_from(num_own_segment_roots).map_err(|_error| {
373 OwnedBeaconChainBodyError::TooManyIntermediateShardOwnSegmentRoots {
374 actual: num_own_segment_roots,
375 }
376 })?;
377 let num_leaf_shard_blocks_with_segments = intermediate_shard_block
378 .leaf_shards_segments()
379 .size_hint()
380 .0;
381 let num_leaf_shard_blocks_with_segments =
382 u8::try_from(num_leaf_shard_blocks_with_segments).map_err(|_error| {
383 OwnedBeaconChainBodyError::TooManyLeafShardBlocksWithSegments {
384 actual: num_leaf_shard_blocks_with_segments,
385 }
386 })?;
387
388 buffer.as_mut_slice()[segments_roots_num_cursor..][..2]
389 .copy_from_slice(&[num_own_segment_roots, num_leaf_shard_blocks_with_segments]);
390 segments_roots_num_cursor += 2;
391
392 OwnedIntermediateShardHeader::from_parts_into(
393 intermediate_shard_block.header.prefix,
394 intermediate_shard_block.header.result,
395 intermediate_shard_block.header.consensus_info,
396 intermediate_shard_block.header.beacon_chain_info(),
397 intermediate_shard_block.header.child_shard_blocks(),
398 &mut buffer,
399 )?;
400
401 if let Some(segments_proof) = &intermediate_shard_block.segments_proof
402 && !buffer.append(*segments_proof)
403 {
404 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
405 }
406
407 if let Some(own_segments) = &intermediate_shard_block.own_segments {
408 if !buffer.append(own_segments.first_local_segment_index.as_bytes()) {
409 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
410 }
411 if !buffer.append(
412 SegmentRoot::repr_from_slice(own_segments.segment_roots).as_flattened(),
413 ) {
414 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
415 }
416 }
417
418 for (_shard_index, own_segments) in intermediate_shard_block.leaf_shards_segments()
419 {
420 let num_own_segment_roots = own_segments.segment_roots.len();
421 let num_own_segment_roots =
422 u8::try_from(num_own_segment_roots).map_err(|_error| {
423 OwnedBeaconChainBodyError::TooManyLeafShardBlockSegments {
424 actual: num_own_segment_roots,
425 }
426 })?;
427 if !buffer.append(&[num_own_segment_roots]) {
428 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
429 }
430 }
431 for (shard_index, own_segments) in intermediate_shard_block.leaf_shards_segments() {
432 if !buffer.append(shard_index.as_bytes()) {
433 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
434 }
435 if !buffer.append(own_segments.first_local_segment_index.as_bytes()) {
436 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
437 }
438 if !buffer.append(
439 SegmentRoot::repr_from_slice(own_segments.segment_roots).as_flattened(),
440 ) {
441 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
442 }
443 }
444
445 if !align_to_8_with_padding(&mut buffer) {
446 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
447 }
448 }
449 }
450
451 let true = buffer.append(PotCheckpoints::bytes_from_slice(pot_checkpoints).as_flattened())
452 else {
453 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
454 };
455
456 Ok(Self::from_buffer(buffer.into_shared()).expect("Known to be created correctly; qed"))
458 }
459
460 #[inline]
462 pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
463 let inner = Yoke::try_attach_to_cart(buffer.clone(), |buffer| {
466 let Some((body, extra_bytes)) = BeaconChainBody::try_from_bytes(buffer) else {
467 return Err(());
468 };
469 if !extra_bytes.is_empty() {
470 return Err(());
471 }
472
473 Ok(body)
474 })
475 .map_err(move |()| buffer)?;
476
477 Ok(Self {
478 inner: Arc::new(inner),
479 })
480 }
481
482 #[inline(always)]
484 pub fn buffer(&self) -> &SharedAlignedBuffer {
485 self.inner.backing_cart()
486 }
487
488 #[inline(always)]
490 pub fn ref_count(&self) -> usize {
491 Arc::count(&self.inner)
492 }
493
494 #[inline(always)]
496 pub fn body(&self) -> &BeaconChainBody<'_> {
497 self.inner.get()
498 }
499}
500
501#[derive(Debug, thiserror::Error)]
503pub enum OwnedIntermediateShardBodyError {
504 #[error("Too many own segment roots: {actual}")]
506 TooManyOwnSegmentRoots {
507 actual: usize,
509 },
510 #[error("Too many leaf shard blocks: {actual}")]
512 TooManyLeafShardBlocks {
513 actual: usize,
515 },
516 #[error("Too many leaf shard own segment roots: {actual}")]
518 TooManyLeafShardOwnSegmentRoots {
519 actual: usize,
521 },
522}
523
524#[derive(Debug, Clone)]
529pub struct OwnedIntermediateShardBody {
530 inner: Arc<Yoke<IntermediateShardBody<'static>, SharedAlignedBuffer>>,
531}
532
533impl GenericOwnedBlockBody for OwnedIntermediateShardBody {
534 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
535
536 type Body<'a> = IntermediateShardBody<'a>;
537
538 #[inline(always)]
539 fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
540 Self::from_buffer(buffer)
541 }
542
543 #[inline(always)]
544 fn buffer(&self) -> &SharedAlignedBuffer {
545 self.buffer()
546 }
547
548 #[inline(always)]
549 fn ref_count(&self) -> usize {
550 self.ref_count()
551 }
552
553 #[inline(always)]
554 fn body(&self) -> &Self::Body<'_> {
555 self.body()
556 }
557}
558
559impl OwnedIntermediateShardBody {
560 pub fn new<'a, OS, LSB>(
563 own_segments: OS,
564 leaf_shard_blocks: LSB,
565 ) -> Result<Self, OwnedIntermediateShardBodyError>
566 where
567 OS: TrustedLen<Item = (LocalSegmentIndex, SegmentRoot)>,
568 LSB: TrustedLen<Item = LeafShardBlockInfo<'a>> + 'a,
569 {
570 let num_own_segment_roots = own_segments.size_hint().0;
571 let num_own_segment_roots = u8::try_from(num_own_segment_roots).map_err(|_error| {
572 OwnedIntermediateShardBodyError::TooManyOwnSegmentRoots {
573 actual: num_own_segment_roots,
574 }
575 })?;
576 let num_blocks = leaf_shard_blocks.size_hint().0;
577 let num_blocks = u8::try_from(num_blocks).map_err(|_error| {
578 OwnedIntermediateShardBodyError::TooManyLeafShardBlocks { actual: num_blocks }
579 })?;
580
581 let mut buffer = OwnedAlignedBuffer::with_capacity(
582 u8::SIZE
583 + if num_own_segment_roots > 0 { LocalSegmentIndex::SIZE } else { 0 }
584 + u32::from(num_own_segment_roots) * SegmentRoot::SIZE as u32
585 + u32::from(num_blocks) * OwnedLeafShardHeader::MAX_ALLOCATION * 2,
588 );
589
590 let true = buffer.append(&[num_own_segment_roots]) else {
591 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
592 };
593 let mut own_segments = own_segments.peekable();
594 if let Some((first_local_segment_index, _own_segment_root)) = own_segments.peek() {
595 let true = buffer.append(first_local_segment_index.as_bytes()) else {
596 unreachable!("Checked size above; qed");
597 };
598 }
599 for (_segment_index, own_segment_root) in own_segments {
600 let true = buffer.append(own_segment_root.as_ref()) else {
601 unreachable!("Checked size above; qed");
602 };
603 }
604 {
606 let true = buffer.append(&num_blocks.to_le_bytes()) else {
607 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
608 };
609 let mut own_segments_roots_num_cursor = buffer.len() as usize;
610 for _ in 0..num_blocks {
611 let true = buffer.append(&[0]) else {
612 unreachable!("Checked size above; qed");
613 };
614 }
615 let true = align_to_8_with_padding(&mut buffer) else {
616 unreachable!("Checked size above; qed");
617 };
618 for leaf_shard_block in leaf_shard_blocks {
619 if let Some(segments) = &leaf_shard_block.segments {
620 let num_own_segment_roots = segments.own_segments.segment_roots.len();
621 let num_own_segment_roots =
622 u8::try_from(num_own_segment_roots).map_err(|_error| {
623 OwnedIntermediateShardBodyError::TooManyLeafShardOwnSegmentRoots {
624 actual: num_own_segment_roots,
625 }
626 })?;
627 buffer.as_mut_slice()[own_segments_roots_num_cursor] = num_own_segment_roots;
628 }
629 own_segments_roots_num_cursor += 1;
630
631 OwnedLeafShardHeader::from_parts_into(
632 leaf_shard_block.header.prefix,
633 leaf_shard_block.header.result,
634 leaf_shard_block.header.consensus_info,
635 leaf_shard_block.header.beacon_chain_info(),
636 &mut buffer,
637 );
638 let true = align_to_8_with_padding(&mut buffer) else {
639 unreachable!("Checked size above; qed");
640 };
641
642 if let Some(segments) = &leaf_shard_block.segments {
643 let true =
644 buffer.append(segments.own_segments.first_local_segment_index.as_bytes())
645 else {
646 unreachable!("Checked size above; qed");
647 };
648 let true = buffer.append(segments.segment_roots_proof) else {
649 unreachable!("Checked size above; qed");
650 };
651 let true = buffer.append(
652 SegmentRoot::repr_from_slice(segments.own_segments.segment_roots)
653 .as_flattened(),
654 ) else {
655 unreachable!("Checked size above; qed");
656 };
657 }
658 }
659 }
660
661 Ok(Self::from_buffer(buffer.into_shared()).expect("Known to be created correctly; qed"))
663 }
664
665 #[inline]
667 pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
668 let inner = Yoke::try_attach_to_cart(buffer.clone(), |buffer| {
671 let Some((body, extra_bytes)) = IntermediateShardBody::try_from_bytes(buffer) else {
672 return Err(());
673 };
674 if !extra_bytes.is_empty() {
675 return Err(());
676 }
677
678 Ok(body)
679 })
680 .map_err(move |()| buffer)?;
681
682 Ok(Self {
683 inner: Arc::new(inner),
684 })
685 }
686
687 #[inline(always)]
689 pub fn buffer(&self) -> &SharedAlignedBuffer {
690 self.inner.backing_cart()
691 }
692
693 #[inline(always)]
695 pub fn ref_count(&self) -> usize {
696 Arc::count(&self.inner)
697 }
698
699 #[inline(always)]
701 pub fn body(&self) -> &IntermediateShardBody<'_> {
702 self.inner.get()
703 }
704}
705
706#[derive(Debug, thiserror::Error)]
708pub enum OwnedLeafShardBodyError {
709 #[error("Too many own segment roots: {actual}")]
711 TooManyOwnSegmentRoots {
712 actual: usize,
714 },
715 #[error("Block body is too large")]
717 BlockBodyIsTooLarge,
718 #[error("Too many transactions")]
720 TooManyTransactions,
721 #[error("Failed to add transaction: {error}")]
723 FailedToAddTransaction {
724 error: OwnedTransactionError,
726 },
727}
728
729impl From<AddTransactionError> for OwnedLeafShardBodyError {
730 fn from(value: AddTransactionError) -> Self {
731 match value {
732 AddTransactionError::BlockBodyIsTooLarge => {
733 OwnedLeafShardBodyError::BlockBodyIsTooLarge
734 }
735 AddTransactionError::TooManyTransactions => {
736 OwnedLeafShardBodyError::TooManyTransactions
737 }
738 AddTransactionError::FailedToAddTransaction { error } => {
739 OwnedLeafShardBodyError::FailedToAddTransaction { error }
740 }
741 }
742 }
743}
744
745#[derive(Debug, Clone)]
750pub struct OwnedLeafShardBody {
751 inner: Arc<Yoke<LeafShardBody<'static>, SharedAlignedBuffer>>,
752}
753
754impl GenericOwnedBlockBody for OwnedLeafShardBody {
755 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
756
757 type Body<'a> = LeafShardBody<'a>;
758
759 #[inline(always)]
760 fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
761 Self::from_buffer(buffer)
762 }
763
764 #[inline(always)]
765 fn buffer(&self) -> &SharedAlignedBuffer {
766 self.buffer()
767 }
768
769 #[inline(always)]
770 fn ref_count(&self) -> usize {
771 self.ref_count()
772 }
773
774 #[inline(always)]
775 fn body(&self) -> &Self::Body<'_> {
776 self.body()
777 }
778}
779
780impl OwnedLeafShardBody {
781 pub fn init<OS>(
784 own_segments: OS,
785 ) -> Result<OwnedLeafShardBlockBodyBuilder, OwnedLeafShardBodyError>
786 where
787 OS: TrustedLen<Item = (LocalSegmentIndex, SegmentRoot)>,
788 {
789 let num_own_segment_roots = own_segments.size_hint().0;
790 let num_own_segment_roots = u8::try_from(num_own_segment_roots).map_err(|_error| {
791 OwnedLeafShardBodyError::TooManyOwnSegmentRoots {
792 actual: num_own_segment_roots,
793 }
794 })?;
795
796 let mut buffer = OwnedAlignedBuffer::with_capacity(
797 u8::SIZE
798 + if num_own_segment_roots > 0 {
799 LocalSegmentIndex::SIZE
800 } else {
801 0
802 }
803 + u32::from(num_own_segment_roots) * SegmentRoot::SIZE as u32,
804 );
805
806 let true = buffer.append(&[num_own_segment_roots]) else {
807 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
808 };
809 let mut own_segments = own_segments.peekable();
810 if let Some((first_local_segment_index, _own_segment_root)) = own_segments.peek() {
811 let true = buffer.append(first_local_segment_index.as_bytes()) else {
812 unreachable!("Checked size above; qed");
813 };
814 }
815 for (_segment_index, own_segment_root) in own_segments {
816 let true = buffer.append(own_segment_root.as_ref()) else {
817 unreachable!("Checked size above; qed");
818 };
819 }
820
821 let num_transactions_offset = buffer.len() as usize;
822 let true = buffer.append(&0u32.to_le_bytes()) else {
823 unreachable!("Checked size above; qed");
824 };
825
826 Ok(OwnedLeafShardBlockBodyBuilder {
827 transaction_builder: TransactionBuilder::new(num_transactions_offset, buffer),
828 })
829 }
830
831 #[inline]
833 pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
834 let inner = Yoke::try_attach_to_cart(buffer.clone(), |buffer| {
837 let Some((body, extra_bytes)) = LeafShardBody::try_from_bytes(buffer) else {
838 return Err(());
839 };
840 if !extra_bytes.is_empty() {
841 return Err(());
842 }
843
844 Ok(body)
845 })
846 .map_err(move |()| buffer)?;
847
848 Ok(Self {
849 inner: Arc::new(inner),
850 })
851 }
852
853 #[inline(always)]
855 pub fn buffer(&self) -> &SharedAlignedBuffer {
856 self.inner.backing_cart()
857 }
858
859 #[inline(always)]
861 pub fn ref_count(&self) -> usize {
862 Arc::count(&self.inner)
863 }
864
865 #[inline(always)]
867 pub fn body(&self) -> &LeafShardBody<'_> {
868 self.inner.get()
869 }
870}
871
872#[derive(Debug, Clone)]
874pub struct OwnedLeafShardBlockBodyBuilder {
875 transaction_builder: TransactionBuilder,
876}
877
878impl OwnedLeafShardBlockBodyBuilder {
879 #[inline(always)]
881 pub fn add_transaction<T>(&mut self, transaction: T) -> Result<(), OwnedLeafShardBodyError>
882 where
883 T: WritableBodyTransaction,
884 {
885 self.transaction_builder.add_transaction(transaction)?;
886
887 Ok(())
888 }
889
890 pub fn finish(self) -> OwnedLeafShardBody {
892 OwnedLeafShardBody::from_buffer(self.transaction_builder.finish().into_shared())
894 .expect("Known to be created correctly; qed")
895 }
896}
897
898#[derive(Debug, Clone, From)]
903pub enum OwnedBlockBody {
904 BeaconChain(OwnedBeaconChainBody),
906 IntermediateShard(OwnedIntermediateShardBody),
908 LeafShard(OwnedLeafShardBody),
910}
911
912impl OwnedBlockBody {
913 #[inline]
915 pub fn from_buffer(
916 buffer: SharedAlignedBuffer,
917 shard_kind: RealShardKind,
918 ) -> Result<Self, SharedAlignedBuffer> {
919 Ok(match shard_kind {
920 RealShardKind::BeaconChain => {
921 Self::BeaconChain(OwnedBeaconChainBody::from_buffer(buffer)?)
922 }
923 RealShardKind::IntermediateShard => {
924 Self::IntermediateShard(OwnedIntermediateShardBody::from_buffer(buffer)?)
925 }
926 RealShardKind::LeafShard => Self::LeafShard(OwnedLeafShardBody::from_buffer(buffer)?),
927 })
928 }
929
930 #[inline]
932 pub fn buffer(&self) -> &SharedAlignedBuffer {
933 match self {
934 Self::BeaconChain(owned_body) => owned_body.buffer(),
935 Self::IntermediateShard(owned_body) => owned_body.buffer(),
936 Self::LeafShard(owned_body) => owned_body.buffer(),
937 }
938 }
939
940 #[inline(always)]
942 pub fn ref_count(&self) -> usize {
943 match self {
944 Self::BeaconChain(owned_body) => owned_body.ref_count(),
945 Self::IntermediateShard(owned_body) => owned_body.ref_count(),
946 Self::LeafShard(owned_body) => owned_body.ref_count(),
947 }
948 }
949
950 #[inline]
952 pub fn body(&self) -> BlockBody<'_> {
953 match self {
954 Self::BeaconChain(owned_body) => BlockBody::BeaconChain(*owned_body.body()),
955 Self::IntermediateShard(owned_body) => BlockBody::IntermediateShard(*owned_body.body()),
956 Self::LeafShard(owned_body) => BlockBody::LeafShard(*owned_body.body()),
957 }
958 }
959}
960
961#[inline(always)]
965#[must_use]
966fn align_to_8_with_padding(buffer: &mut OwnedAlignedBuffer) -> bool {
967 let alignment = align_of::<u64>();
968 let unaligned_by = buffer.len() as usize % alignment;
969 if unaligned_by > 0 {
970 let padding_bytes = unsafe { alignment.unchecked_sub(unaligned_by) };
972
973 if !buffer.append(&0u64.to_le_bytes()[..padding_bytes]) {
974 return false;
975 }
976 }
977
978 true
979}
980
981#[inline(always)]
985#[must_use]
986fn align_to_16_bytes_with_padding(buffer: &mut OwnedAlignedBuffer) -> bool {
987 let alignment = usize::from(Alignment::MAX.get());
988 let unaligned_by = buffer.len() as usize % alignment;
989 if unaligned_by > 0 {
990 let padding_bytes = unsafe { alignment.unchecked_sub(unaligned_by) };
992
993 if !buffer.append(&0u128.to_le_bytes()[..padding_bytes]) {
994 return false;
995 }
996 }
997
998 true
999}