1use crate::block::body::{
4 BeaconChainBody, BlockBody, GenericBlockBody, IntermediateShardBlockInfo,
5 IntermediateShardBody, LeafShardBlockInfo, LeafShardBody,
6};
7use crate::block::header::owned::{
8 OwnedIntermediateShardHeader, OwnedIntermediateShardHeaderError, OwnedLeafShardHeader,
9};
10use crate::pot::PotCheckpoints;
11use crate::segments::SegmentRoot;
12use crate::shard::ShardKind;
13use crate::transaction::Transaction;
14use crate::transaction::owned::{OwnedTransaction, OwnedTransactionError};
15use ab_aligned_buffer::{OwnedAlignedBuffer, SharedAlignedBuffer};
16use ab_io_type::trivial_type::TrivialType;
17use core::iter::TrustedLen;
18use derive_more::From;
19
20pub trait GenericOwnedBlockBody {
22 type Body<'a>: GenericBlockBody<'a>
24 where
25 Self: 'a;
26
27 fn body(&self) -> Self::Body<'_>;
29}
30
31#[derive(Debug, thiserror::Error)]
33enum AddTransactionError {
34 #[error("Block body is too large")]
36 BlockBodyIsTooLarge,
37 #[error("Too many transactions")]
39 TooManyTransactions,
40 #[error("Failed to add transaction: {error}")]
42 FailedToAddTransaction {
43 #[from]
45 error: OwnedTransactionError,
46 },
47}
48
49pub trait WritableBodyTransaction {
51 fn write_into(&self, buffer: &mut OwnedAlignedBuffer) -> Result<(), OwnedTransactionError>;
53}
54
55impl WritableBodyTransaction for Transaction<'_> {
56 fn write_into(&self, buffer: &mut OwnedAlignedBuffer) -> Result<(), OwnedTransactionError> {
57 OwnedTransaction::from_parts_into(
58 self.header,
59 self.read_slots,
60 self.write_slots,
61 self.payload,
62 self.seal,
63 buffer,
64 )
65 }
66}
67
68impl WritableBodyTransaction for &OwnedTransaction {
69 fn write_into(&self, buffer: &mut OwnedAlignedBuffer) -> Result<(), OwnedTransactionError> {
70 if buffer.append(self.buffer().as_slice()) {
71 Ok(())
72 } else {
73 Err(OwnedTransactionError::TransactionTooLarge)
74 }
75 }
76}
77
78#[derive(Debug, Clone)]
79struct TransactionBuilder {
80 num_transactions_offset: usize,
81 buffer: OwnedAlignedBuffer,
82}
83
84impl TransactionBuilder {
85 fn new(num_transactions_offset: usize, buffer: OwnedAlignedBuffer) -> Self {
86 Self {
87 num_transactions_offset,
88 buffer,
89 }
90 }
91
92 fn add_transaction<T>(&mut self, transaction: T) -> Result<(), AddTransactionError>
94 where
95 T: WritableBodyTransaction,
96 {
97 if self.inc_transaction_count()? == 1 && !align_to_16_bytes_with_padding(&mut self.buffer) {
100 self.dec_transaction_count();
101 return Err(AddTransactionError::BlockBodyIsTooLarge);
102 }
103
104 let old_buffer_len = self.buffer.len();
105
106 transaction
107 .write_into(&mut self.buffer)
108 .inspect_err(|_error| {
109 self.dec_transaction_count();
110 })?;
111
112 if !align_to_16_bytes_with_padding(&mut self.buffer) {
113 self.dec_transaction_count();
114 unsafe {
116 self.buffer.set_len(old_buffer_len);
117 }
118 return Err(AddTransactionError::BlockBodyIsTooLarge);
119 }
120
121 Ok(())
122 }
123
124 #[inline(always)]
126 fn finish(self) -> OwnedAlignedBuffer {
127 self.buffer
128 }
129
130 #[inline(always)]
132 fn inc_transaction_count(&mut self) -> Result<u32, AddTransactionError> {
133 unsafe {
136 let num_transactions_ptr = self
137 .buffer
138 .as_mut_ptr()
139 .add(self.num_transactions_offset)
140 .cast::<u32>();
141 let num_transactions = num_transactions_ptr.read_unaligned();
142 let num_transactions = num_transactions
143 .checked_add(1)
144 .ok_or(AddTransactionError::TooManyTransactions)?;
145 num_transactions_ptr.write_unaligned(num_transactions);
146 Ok(num_transactions)
147 }
148 }
149
150 #[inline(always)]
152 fn dec_transaction_count(&mut self) {
153 unsafe {
156 let num_transactions_ptr = self
157 .buffer
158 .as_mut_ptr()
159 .add(self.num_transactions_offset)
160 .cast::<u32>();
161 let num_transactions = num_transactions_ptr.read_unaligned();
162 let num_transactions = num_transactions.saturating_sub(1);
163 num_transactions_ptr.write_unaligned(num_transactions);
164 }
165 }
166}
167
168#[derive(Debug, thiserror::Error)]
170pub enum OwnedBeaconChainBodyError {
171 #[error("Too many PoT checkpoints: {actual}")]
173 TooManyPotCheckpoints {
174 actual: usize,
176 },
177 #[error("Too many own segment roots: {actual}")]
179 TooManyOwnSegmentRoots {
180 actual: usize,
182 },
183 #[error("Too many intermediate shard blocks: {actual}")]
185 TooManyIntermediateShardBlocks {
186 actual: usize,
188 },
189 #[error("Too many intermediate shard own segment roots: {actual}")]
191 TooManyIntermediateShardOwnSegmentRoots {
192 actual: usize,
194 },
195 #[error("Too many intermediate shard child segment roots: {actual}")]
197 TooManyIntermediateShardChildSegmentRoots {
198 actual: usize,
200 },
201 #[error("Failed to intermediate shard header: {error}")]
203 FailedToAddTransaction {
204 #[from]
206 error: OwnedIntermediateShardHeaderError,
207 },
208 #[error("Block body is too large")]
210 BlockBodyIsTooLarge,
211}
212
213#[derive(Debug, Clone)]
218pub struct OwnedBeaconChainBody {
219 buffer: SharedAlignedBuffer,
220}
221
222impl GenericOwnedBlockBody for OwnedBeaconChainBody {
223 type Body<'a> = BeaconChainBody<'a>;
224
225 #[inline(always)]
226 fn body(&self) -> Self::Body<'_> {
227 self.body()
228 }
229}
230
231impl OwnedBeaconChainBody {
232 pub fn init<'a, ISB>(
234 own_segment_roots: &[SegmentRoot],
235 intermediate_shard_blocks: ISB,
236 pot_checkpoints: &[PotCheckpoints],
237 ) -> Result<Self, OwnedBeaconChainBodyError>
238 where
239 ISB: TrustedLen<Item = IntermediateShardBlockInfo<'a>> + Clone + 'a,
240 {
241 let num_pot_checkpoints = pot_checkpoints.len();
242 let num_pot_checkpoints = u32::try_from(num_pot_checkpoints).map_err(|_error| {
243 OwnedBeaconChainBodyError::TooManyPotCheckpoints {
244 actual: num_pot_checkpoints,
245 }
246 })?;
247 let num_own_segment_roots = own_segment_roots.len();
248 let num_own_segment_roots = u8::try_from(num_own_segment_roots).map_err(|_error| {
249 OwnedBeaconChainBodyError::TooManyOwnSegmentRoots {
250 actual: num_own_segment_roots,
251 }
252 })?;
253 let num_blocks = intermediate_shard_blocks.size_hint().0;
254 let num_blocks = u8::try_from(num_blocks).map_err(|_error| {
255 OwnedBeaconChainBodyError::TooManyIntermediateShardBlocks { actual: num_blocks }
256 })?;
257
258 let mut buffer = OwnedAlignedBuffer::with_capacity(
259 u8::SIZE
260 + size_of_val(own_segment_roots) as u32
261 + u32::from(num_blocks) * OwnedIntermediateShardHeader::max_allocation_for(&[]) * 2,
264 );
265
266 let true = buffer.append(&num_pot_checkpoints.to_le_bytes()) else {
267 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
268 };
269
270 let true = buffer.append(&[num_own_segment_roots]) else {
271 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
272 };
273 let true = buffer.append(SegmentRoot::repr_from_slice(own_segment_roots).as_flattened())
274 else {
275 unreachable!("Checked size above; qed");
276 };
277 {
279 let true = buffer.append(&num_blocks.to_le_bytes()) else {
280 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
281 };
282 let mut segments_roots_num_cursor = buffer.len() as usize;
283 for _ in 0..num_blocks {
284 let true = buffer.append(&[0, 0, 0]) else {
285 unreachable!("Checked size above; qed");
286 };
287 }
288 let true = align_to_8_with_padding(&mut buffer) else {
289 unreachable!("Checked size above; qed");
290 };
291 for intermediate_shard_block in intermediate_shard_blocks.clone() {
292 if !intermediate_shard_block.own_segment_roots.is_empty()
293 || !intermediate_shard_block.child_segment_roots.is_empty()
294 {
295 let num_own_segment_roots = intermediate_shard_block.own_segment_roots.len();
296 let num_own_segment_roots =
297 u8::try_from(num_own_segment_roots).map_err(|_error| {
298 OwnedBeaconChainBodyError::TooManyIntermediateShardOwnSegmentRoots {
299 actual: num_own_segment_roots,
300 }
301 })?;
302 let num_child_segment_roots =
303 intermediate_shard_block.child_segment_roots.len();
304 let num_child_segment_roots =
305 u16::try_from(num_child_segment_roots).map_err(|_error| {
306 OwnedBeaconChainBodyError::TooManyIntermediateShardChildSegmentRoots {
307 actual: num_child_segment_roots,
308 }
309 })?;
310 let num_child_segment_roots = num_child_segment_roots.to_le_bytes();
311 buffer.as_mut_slice()[segments_roots_num_cursor..][..3].copy_from_slice(&[
312 num_own_segment_roots,
313 num_child_segment_roots[0],
314 num_child_segment_roots[1],
315 ]);
316 }
317 segments_roots_num_cursor += 3;
318
319 OwnedIntermediateShardHeader::from_parts_into(
320 intermediate_shard_block.header.prefix,
321 intermediate_shard_block.header.result,
322 intermediate_shard_block.header.consensus_info,
323 intermediate_shard_block.header.beacon_chain_info,
324 &intermediate_shard_block.header.child_shard_blocks,
325 &mut buffer,
326 )?;
327 if !align_to_8_with_padding(&mut buffer) {
328 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
329 }
330 if let Some(segment_roots_proof) = intermediate_shard_block.segment_roots_proof
331 && !buffer.append(segment_roots_proof)
332 {
333 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
334 }
335 if !intermediate_shard_block.own_segment_roots.is_empty()
336 && !buffer.append(
337 SegmentRoot::repr_from_slice(intermediate_shard_block.own_segment_roots)
338 .as_flattened(),
339 )
340 {
341 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
342 }
343 if !intermediate_shard_block.child_segment_roots.is_empty()
344 && !buffer.append(
345 SegmentRoot::repr_from_slice(intermediate_shard_block.child_segment_roots)
346 .as_flattened(),
347 )
348 {
349 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
350 }
351 }
352 }
353
354 let true = buffer.append(PotCheckpoints::bytes_from_slice(pot_checkpoints).as_flattened())
355 else {
356 return Err(OwnedBeaconChainBodyError::BlockBodyIsTooLarge);
357 };
358
359 Ok(Self {
360 buffer: buffer.into_shared(),
361 })
362 }
363
364 #[inline]
366 pub fn from_body(body: BeaconChainBody<'_>) -> Result<Self, OwnedBeaconChainBodyError> {
367 Self::init(
368 body.own_segment_roots,
369 body.intermediate_shard_blocks.iter(),
370 body.pot_checkpoints,
371 )
372 }
373
374 #[inline]
376 pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
377 let Some((_body, extra_bytes)) = BeaconChainBody::try_from_bytes(buffer.as_slice()) else {
378 return Err(buffer);
379 };
380 if !extra_bytes.is_empty() {
381 return Err(buffer);
382 }
383
384 Ok(Self { buffer })
385 }
386
387 pub fn buffer(&self) -> &SharedAlignedBuffer {
389 &self.buffer
390 }
391
392 pub fn body(&self) -> BeaconChainBody<'_> {
394 BeaconChainBody::try_from_bytes_unchecked(self.buffer.as_slice())
395 .expect("Constructor ensures validity; qed")
396 .0
397 }
398}
399
400#[derive(Debug, thiserror::Error)]
402pub enum OwnedIntermediateShardBodyError {
403 #[error("Too many own segment roots: {actual}")]
405 TooManyOwnSegmentRoots {
406 actual: usize,
408 },
409 #[error("Too many leaf shard blocks: {actual}")]
411 TooManyLeafShardBlocks {
412 actual: usize,
414 },
415 #[error("Too many leaf shard own segment roots: {actual}")]
417 TooManyLeafShardOwnSegmentRoots {
418 actual: usize,
420 },
421 #[error("Block body is too large")]
423 BlockBodyIsTooLarge,
424 #[error("Too many transactions")]
426 TooManyTransactions,
427 #[error("Failed to add transaction: {error}")]
429 FailedToAddTransaction {
430 error: OwnedTransactionError,
432 },
433}
434
435impl From<AddTransactionError> for OwnedIntermediateShardBodyError {
436 fn from(value: AddTransactionError) -> Self {
437 match value {
438 AddTransactionError::BlockBodyIsTooLarge => {
439 OwnedIntermediateShardBodyError::BlockBodyIsTooLarge
440 }
441 AddTransactionError::TooManyTransactions => {
442 OwnedIntermediateShardBodyError::TooManyTransactions
443 }
444 AddTransactionError::FailedToAddTransaction { error } => {
445 OwnedIntermediateShardBodyError::FailedToAddTransaction { error }
446 }
447 }
448 }
449}
450
451#[derive(Debug, Clone)]
456pub struct OwnedIntermediateShardBody {
457 buffer: SharedAlignedBuffer,
458}
459
460impl GenericOwnedBlockBody for OwnedIntermediateShardBody {
461 type Body<'a> = IntermediateShardBody<'a>;
462
463 #[inline(always)]
464 fn body(&self) -> Self::Body<'_> {
465 self.body()
466 }
467}
468
469impl OwnedIntermediateShardBody {
470 pub fn init<'a, LSB>(
472 own_segment_roots: &[SegmentRoot],
473 leaf_shard_blocks: LSB,
474 ) -> Result<OwnedIntermediateShardBlockBodyBuilder, OwnedIntermediateShardBodyError>
475 where
476 LSB: TrustedLen<Item = LeafShardBlockInfo<'a>> + Clone + 'a,
477 {
478 let num_own_segment_roots = own_segment_roots.len();
479 let num_own_segment_roots = u8::try_from(num_own_segment_roots).map_err(|_error| {
480 OwnedIntermediateShardBodyError::TooManyOwnSegmentRoots {
481 actual: num_own_segment_roots,
482 }
483 })?;
484 let num_blocks = leaf_shard_blocks.size_hint().0;
485 let num_blocks = u8::try_from(num_blocks).map_err(|_error| {
486 OwnedIntermediateShardBodyError::TooManyLeafShardBlocks { actual: num_blocks }
487 })?;
488
489 let mut buffer = OwnedAlignedBuffer::with_capacity(
490 u8::SIZE
491 + size_of_val(own_segment_roots) as u32
492 + u32::from(num_blocks) * OwnedLeafShardHeader::MAX_ALLOCATION * 2,
495 );
496
497 let true = buffer.append(&[num_own_segment_roots]) else {
498 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
499 };
500 let true = buffer.append(SegmentRoot::repr_from_slice(own_segment_roots).as_flattened())
501 else {
502 unreachable!("Checked size above; qed");
503 };
504 {
506 let true = buffer.append(&num_blocks.to_le_bytes()) else {
507 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
508 };
509 let mut own_segments_roots_num_cursor = buffer.len() as usize;
510 for _ in 0..num_blocks {
511 let true = buffer.append(&[0]) else {
512 unreachable!("Checked size above; qed");
513 };
514 }
515 let true = align_to_8_with_padding(&mut buffer) else {
516 unreachable!("Checked size above; qed");
517 };
518 for leaf_shard_block in leaf_shard_blocks.clone() {
519 if !leaf_shard_block.own_segment_roots.is_empty() {
520 let num_own_segment_roots = leaf_shard_block.own_segment_roots.len();
521 let num_own_segment_roots =
522 u8::try_from(num_own_segment_roots).map_err(|_error| {
523 OwnedIntermediateShardBodyError::TooManyLeafShardOwnSegmentRoots {
524 actual: num_own_segment_roots,
525 }
526 })?;
527 buffer.as_mut_slice()[own_segments_roots_num_cursor] = num_own_segment_roots;
528 }
529 own_segments_roots_num_cursor += 1;
530
531 OwnedLeafShardHeader::from_parts_into(
532 leaf_shard_block.header.prefix,
533 leaf_shard_block.header.result,
534 leaf_shard_block.header.consensus_info,
535 leaf_shard_block.header.beacon_chain_info,
536 &mut buffer,
537 );
538 let true = align_to_8_with_padding(&mut buffer) else {
539 unreachable!("Checked size above; qed");
540 };
541 if let Some(segment_roots_proof) = leaf_shard_block.segment_roots_proof {
542 let true = buffer.append(segment_roots_proof) else {
543 unreachable!("Checked size above; qed");
544 };
545 }
546 if !leaf_shard_block.own_segment_roots.is_empty() {
547 let true = buffer.append(
548 SegmentRoot::repr_from_slice(leaf_shard_block.own_segment_roots)
549 .as_flattened(),
550 ) else {
551 unreachable!("Checked size above; qed");
552 };
553 }
554 }
555 }
556 let num_transactions_offset = buffer.len() as usize;
557 let true = buffer.append(&0u32.to_le_bytes()) else {
558 unreachable!("Checked size above; qed");
559 };
560
561 Ok(OwnedIntermediateShardBlockBodyBuilder {
562 transaction_builder: TransactionBuilder::new(num_transactions_offset, buffer),
563 })
564 }
565
566 #[inline]
568 pub fn from_body(
569 body: IntermediateShardBody<'_>,
570 ) -> Result<Self, OwnedIntermediateShardBodyError> {
571 let mut builder = Self::init(body.own_segment_roots, body.leaf_shard_blocks.iter())?;
572 for transaction in body.transactions.iter() {
573 builder.add_transaction(transaction)?;
574 }
575
576 Ok(builder.finish())
577 }
578
579 #[inline]
581 pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
582 let Some((_body, extra_bytes)) = IntermediateShardBody::try_from_bytes(buffer.as_slice())
583 else {
584 return Err(buffer);
585 };
586 if !extra_bytes.is_empty() {
587 return Err(buffer);
588 }
589
590 Ok(Self { buffer })
591 }
592
593 pub fn buffer(&self) -> &SharedAlignedBuffer {
595 &self.buffer
596 }
597
598 pub fn body(&self) -> IntermediateShardBody<'_> {
600 IntermediateShardBody::try_from_bytes_unchecked(self.buffer.as_slice())
601 .expect("Constructor ensures validity; qed")
602 .0
603 }
604}
605
606#[derive(Debug, Clone)]
608pub struct OwnedIntermediateShardBlockBodyBuilder {
609 transaction_builder: TransactionBuilder,
610}
611
612impl OwnedIntermediateShardBlockBodyBuilder {
613 #[inline(always)]
615 pub fn add_transaction<T>(
616 &mut self,
617 transaction: T,
618 ) -> Result<(), OwnedIntermediateShardBodyError>
619 where
620 T: WritableBodyTransaction,
621 {
622 self.transaction_builder.add_transaction(transaction)?;
623
624 Ok(())
625 }
626
627 pub fn finish(self) -> OwnedIntermediateShardBody {
629 OwnedIntermediateShardBody {
630 buffer: self.transaction_builder.finish().into_shared(),
631 }
632 }
633}
634
635#[derive(Debug, thiserror::Error)]
637pub enum OwnedLeafShardBodyError {
638 #[error("Too many own segment roots: {actual}")]
640 TooManyOwnSegmentRoots {
641 actual: usize,
643 },
644 #[error("Block body is too large")]
646 BlockBodyIsTooLarge,
647 #[error("Too many transactions")]
649 TooManyTransactions,
650 #[error("Failed to add transaction: {error}")]
652 FailedToAddTransaction {
653 error: OwnedTransactionError,
655 },
656}
657
658impl From<AddTransactionError> for OwnedLeafShardBodyError {
659 fn from(value: AddTransactionError) -> Self {
660 match value {
661 AddTransactionError::BlockBodyIsTooLarge => {
662 OwnedLeafShardBodyError::BlockBodyIsTooLarge
663 }
664 AddTransactionError::TooManyTransactions => {
665 OwnedLeafShardBodyError::TooManyTransactions
666 }
667 AddTransactionError::FailedToAddTransaction { error } => {
668 OwnedLeafShardBodyError::FailedToAddTransaction { error }
669 }
670 }
671 }
672}
673
674#[derive(Debug, Clone)]
679pub struct OwnedLeafShardBody {
680 buffer: SharedAlignedBuffer,
681}
682
683impl GenericOwnedBlockBody for OwnedLeafShardBody {
684 type Body<'a> = LeafShardBody<'a>;
685
686 #[inline(always)]
687 fn body(&self) -> Self::Body<'_> {
688 self.body()
689 }
690}
691
692impl OwnedLeafShardBody {
693 pub fn init(
695 own_segment_roots: &[SegmentRoot],
696 ) -> Result<OwnedLeafShardBlockBodyBuilder, OwnedLeafShardBodyError> {
697 let num_own_segment_roots = own_segment_roots.len();
698 let num_own_segment_roots = u8::try_from(num_own_segment_roots).map_err(|_error| {
699 OwnedLeafShardBodyError::TooManyOwnSegmentRoots {
700 actual: num_own_segment_roots,
701 }
702 })?;
703
704 let mut buffer =
705 OwnedAlignedBuffer::with_capacity(u8::SIZE + size_of_val(own_segment_roots) as u32);
706
707 let true = buffer.append(&[num_own_segment_roots]) else {
708 unreachable!("Fixed size data structures that are guaranteed to fit; qed");
709 };
710 let true = buffer.append(SegmentRoot::repr_from_slice(own_segment_roots).as_flattened())
711 else {
712 unreachable!("Checked size above; qed");
713 };
714
715 let num_transactions_offset = buffer.len() as usize;
716 let true = buffer.append(&0u32.to_le_bytes()) else {
717 unreachable!("Checked size above; qed");
718 };
719
720 Ok(OwnedLeafShardBlockBodyBuilder {
721 transaction_builder: TransactionBuilder::new(num_transactions_offset, buffer),
722 })
723 }
724
725 #[inline]
727 pub fn from_body(body: LeafShardBody<'_>) -> Result<Self, OwnedLeafShardBodyError> {
728 let mut builder = Self::init(body.own_segment_roots)?;
729 for transaction in body.transactions.iter() {
730 builder.add_transaction(transaction)?;
731 }
732
733 Ok(builder.finish())
734 }
735
736 #[inline]
738 pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
739 let Some((_body, extra_bytes)) = LeafShardBody::try_from_bytes(buffer.as_slice()) else {
740 return Err(buffer);
741 };
742 if !extra_bytes.is_empty() {
743 return Err(buffer);
744 }
745
746 Ok(Self { buffer })
747 }
748
749 pub fn buffer(&self) -> &SharedAlignedBuffer {
751 &self.buffer
752 }
753
754 pub fn body(&self) -> LeafShardBody<'_> {
756 LeafShardBody::try_from_bytes_unchecked(self.buffer.as_slice())
757 .expect("Constructor ensures validity; qed")
758 .0
759 }
760}
761
762#[derive(Debug, Clone)]
764pub struct OwnedLeafShardBlockBodyBuilder {
765 transaction_builder: TransactionBuilder,
766}
767
768impl OwnedLeafShardBlockBodyBuilder {
769 #[inline(always)]
771 pub fn add_transaction<T>(&mut self, transaction: T) -> Result<(), OwnedLeafShardBodyError>
772 where
773 T: WritableBodyTransaction,
774 {
775 self.transaction_builder.add_transaction(transaction)?;
776
777 Ok(())
778 }
779
780 pub fn finish(self) -> OwnedLeafShardBody {
782 OwnedLeafShardBody {
783 buffer: self.transaction_builder.finish().into_shared(),
784 }
785 }
786}
787
788#[derive(Debug, thiserror::Error)]
790pub enum OwnedBlockBodyError {
791 #[error("Beacon chain block body error: {0}")]
793 BeaconChain(#[from] OwnedBeaconChainBodyError),
794 #[error("Intermediate shard block body error: {0}")]
796 IntermediateShard(#[from] OwnedIntermediateShardBodyError),
797 #[error("Leaf shard block body error: {0}")]
799 LeafShard(#[from] OwnedLeafShardBodyError),
800}
801
802#[derive(Debug, Clone, From)]
807pub enum OwnedBlockBody {
808 BeaconChain(OwnedBeaconChainBody),
810 IntermediateShard(OwnedIntermediateShardBody),
812 LeafShard(OwnedLeafShardBody),
814}
815
816impl GenericOwnedBlockBody for OwnedBlockBody {
817 type Body<'a> = BlockBody<'a>;
818
819 #[inline(always)]
820 fn body(&self) -> Self::Body<'_> {
821 self.body()
822 }
823}
824
825impl OwnedBlockBody {
826 #[inline]
828 pub fn from_body(body: BlockBody<'_>) -> Result<Self, OwnedBlockBodyError> {
829 Ok(match body {
830 BlockBody::BeaconChain(body) => {
831 Self::BeaconChain(OwnedBeaconChainBody::from_body(body)?)
832 }
833 BlockBody::IntermediateShard(body) => {
834 Self::IntermediateShard(OwnedIntermediateShardBody::from_body(body)?)
835 }
836 BlockBody::LeafShard(body) => Self::LeafShard(OwnedLeafShardBody::from_body(body)?),
837 })
838 }
839
840 #[inline]
842 pub fn from_buffer(
843 buffer: SharedAlignedBuffer,
844 shard_kind: ShardKind,
845 ) -> Result<Self, SharedAlignedBuffer> {
846 let Some((_body, extra_bytes)) = BlockBody::try_from_bytes(buffer.as_slice(), shard_kind)
847 else {
848 return Err(buffer);
849 };
850 if !extra_bytes.is_empty() {
851 return Err(buffer);
852 }
853
854 Ok(match shard_kind {
855 ShardKind::BeaconChain => Self::BeaconChain(OwnedBeaconChainBody { buffer }),
856 ShardKind::IntermediateShard => {
857 Self::IntermediateShard(OwnedIntermediateShardBody { buffer })
858 }
859 ShardKind::LeafShard => Self::LeafShard(OwnedLeafShardBody { buffer }),
860 ShardKind::Phantom | ShardKind::Invalid => {
861 return Err(buffer);
863 }
864 })
865 }
866
867 pub fn buffer(&self) -> &SharedAlignedBuffer {
869 match self {
870 Self::BeaconChain(owned_body) => owned_body.buffer(),
871 Self::IntermediateShard(owned_body) => owned_body.buffer(),
872 Self::LeafShard(owned_body) => owned_body.buffer(),
873 }
874 }
875
876 pub fn body(&self) -> BlockBody<'_> {
878 match self {
879 Self::BeaconChain(owned_body) => BlockBody::BeaconChain(owned_body.body()),
880 Self::IntermediateShard(owned_body) => BlockBody::IntermediateShard(owned_body.body()),
881 Self::LeafShard(owned_body) => BlockBody::LeafShard(owned_body.body()),
882 }
883 }
884}
885
886#[inline(always)]
890#[must_use]
891fn align_to_8_with_padding(buffer: &mut OwnedAlignedBuffer) -> bool {
892 let alignment = align_of::<u64>();
893 let unaligned_by = buffer.as_ptr().addr() & (alignment - 1);
896 if unaligned_by > 0 {
897 let padding_bytes = unsafe { alignment.unchecked_sub(unaligned_by) };
899
900 if !buffer.append(&0u64.to_le_bytes()[..padding_bytes]) {
901 return false;
902 }
903 }
904
905 true
906}
907
908#[inline(always)]
912#[must_use]
913fn align_to_16_bytes_with_padding(buffer: &mut OwnedAlignedBuffer) -> bool {
914 let alignment = align_of::<u128>();
915 let unaligned_by = buffer.as_ptr().addr() & (alignment - 1);
918 if unaligned_by > 0 {
919 let padding_bytes = unsafe { alignment.unchecked_sub(unaligned_by) };
921
922 if !buffer.append(&0u128.to_le_bytes()[..padding_bytes]) {
923 return false;
924 }
925 }
926
927 true
928}