1#[cfg(all(
6 test,
7 any(
8 not(miri),
9 not(any(
10 feature = "ed25519",
11 feature = "parallel",
12 feature = "scale-codec",
13 feature = "serde"
14 )),
15 all(
16 feature = "ed25519",
17 feature = "parallel",
18 feature = "scale-codec",
19 feature = "serde"
20 ),
21 ),
22))]
23mod tests;
24
25use crate::block::header::{
26 BeaconChainHeader, BlockHeader, BlockHeaderBeaconChainInfo, BlockHeaderConsensusInfo,
27 BlockHeaderConsensusParameters, BlockHeaderConsistencyError,
28 BlockHeaderFixedConsensusParameters, BlockHeaderPrefix, BlockHeaderResult, BlockHeaderSeal,
29 BlockHeaderSealType, GenericBlockHeader, IntermediateShardHeader, LeafShardHeader,
30};
31use crate::hashes::Blake3Hash;
32use crate::shard::{NumShardsUnchecked, RealShardKind};
33use ab_aligned_buffer::alignment::Align16;
34use ab_aligned_buffer::{OwnedAlignedBuffer, SharedAlignedBuffer};
35use ab_io_type::trivial_type::TrivialType;
36use core::fmt;
37use derive_more::From;
38use triomphe::Arc;
39use yoke::Yoke;
40
41pub trait GenericOwnedBlockHeader:
43 Clone + fmt::Debug + Send + Sync + Into<OwnedBlockHeader> + 'static
44{
45 const SHARD_KIND: RealShardKind;
47
48 type Header<'a>: GenericBlockHeader<'a>
50 where
51 Self: 'a;
52
53 fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer>;
55
56 fn buffer(&self) -> &SharedAlignedBuffer;
58
59 fn ref_count(&self) -> usize;
61
62 fn header(&self) -> &Self::Header<'_>;
64}
65
66fn append_seal(buffer: &mut OwnedAlignedBuffer, seal: BlockHeaderSeal<'_>) {
67 match seal {
68 BlockHeaderSeal::Ed25519(seal) => {
69 let true = buffer.append(&[BlockHeaderSealType::Ed25519 as u8]) else {
70 unreachable!("Unsealed headers are only created when the largest seal fits; qed");
71 };
72 let true = buffer.append(seal.as_bytes()) else {
73 unreachable!("Unsealed headers are only created when the largest seal fits; qed");
74 };
75 }
76 }
77}
78
79#[derive(Debug, thiserror::Error)]
81pub enum OwnedBeaconChainHeaderError {
82 #[error("The header is too large")]
85 HeaderTooLarge,
86 #[error("Invalid header parts: {error}")]
88 InvalidParts {
89 #[from]
91 error: BlockHeaderConsistencyError,
92 },
93}
94
95#[derive(Debug, Clone)]
100pub struct OwnedBeaconChainHeader {
101 inner: Arc<Yoke<BeaconChainHeader<'static>, SharedAlignedBuffer>>,
102}
103
104impl GenericOwnedBlockHeader for OwnedBeaconChainHeader {
105 const SHARD_KIND: RealShardKind = RealShardKind::BeaconChain;
106
107 type Header<'a> = BeaconChainHeader<'a>;
108
109 #[inline(always)]
110 fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
111 Self::from_buffer(buffer)
112 }
113
114 #[inline(always)]
115 fn buffer(&self) -> &SharedAlignedBuffer {
116 self.buffer()
117 }
118
119 #[inline(always)]
120 fn ref_count(&self) -> usize {
121 self.ref_count()
122 }
123
124 #[inline(always)]
125 fn header(&self) -> &Self::Header<'_> {
126 self.header()
127 }
128}
129
130impl OwnedBeaconChainHeader {
131 pub const MAX_ALLOCATION: u32 = BlockHeaderPrefix::SIZE
133 + BlockHeaderResult::SIZE
134 + BlockHeaderConsensusInfo::SIZE
135 + <Blake3Hash as TrivialType>::SIZE
136 + BlockHeaderConsensusParameters::MAX_SIZE
137 + BlockHeaderSeal::MAX_SIZE;
138
139 pub fn from_parts(
143 prefix: &BlockHeaderPrefix,
144 result: &BlockHeaderResult,
145 consensus_info: &BlockHeaderConsensusInfo,
146 intermediate_shard_blocks_root: &Blake3Hash,
147 consensus_parameters: &BlockHeaderConsensusParameters<'_>,
148 ) -> Result<OwnedBeaconChainHeaderUnsealed, BlockHeaderConsistencyError> {
149 BlockHeader::check_shared_parts(prefix, consensus_info, RealShardKind::BeaconChain)?;
150
151 let mut buffer = OwnedAlignedBuffer::with_capacity(Self::MAX_ALLOCATION);
152
153 Self::append_unsealed(
154 prefix,
155 result,
156 consensus_info,
157 intermediate_shard_blocks_root,
158 consensus_parameters,
159 &mut buffer,
160 )
161 .expect("The header with the largest seal fits into an empty buffer; qed");
162
163 Ok(OwnedBeaconChainHeaderUnsealed {
164 buffer,
165 public_key_hash: consensus_info.solution.public_key_hash,
166 })
167 }
168
169 pub fn from_parts_into<'a>(
177 prefix: &BlockHeaderPrefix,
178 result: &BlockHeaderResult,
179 consensus_info: &BlockHeaderConsensusInfo,
180 intermediate_shard_blocks_root: &Blake3Hash,
181 consensus_parameters: &BlockHeaderConsensusParameters<'_>,
182 buffer: &'a mut OwnedAlignedBuffer,
183 ) -> Result<OwnedBeaconChainHeaderUnsealedRef<'a>, OwnedBeaconChainHeaderError> {
184 BlockHeader::check_shared_parts(prefix, consensus_info, RealShardKind::BeaconChain)?;
185
186 let header_offset = buffer.len();
187
188 Self::append_unsealed(
189 prefix,
190 result,
191 consensus_info,
192 intermediate_shard_blocks_root,
193 consensus_parameters,
194 buffer,
195 )?;
196
197 Ok(OwnedBeaconChainHeaderUnsealedRef {
198 buffer,
199 header_offset,
200 public_key_hash: consensus_info.solution.public_key_hash,
201 })
202 }
203
204 fn append_unsealed(
206 prefix: &BlockHeaderPrefix,
207 result: &BlockHeaderResult,
208 consensus_info: &BlockHeaderConsensusInfo,
209 intermediate_shard_blocks_root: &Blake3Hash,
210 consensus_parameters: &BlockHeaderConsensusParameters<'_>,
211 buffer: &mut OwnedAlignedBuffer,
212 ) -> Result<(), OwnedBeaconChainHeaderError> {
213 let BlockHeaderConsensusParameters {
214 fixed_parameters,
215 super_segment_root,
216 next_solution_range,
217 pot_parameters_change,
218 } = consensus_parameters;
219 let BlockHeaderFixedConsensusParameters {
220 solution_range,
221 slot_iterations,
222 num_shards,
223 } = fixed_parameters;
224
225 if OwnedAlignedBuffer::<Align16>::MAX_CAPACITY - buffer.len() < Self::MAX_ALLOCATION {
229 return Err(OwnedBeaconChainHeaderError::HeaderTooLarge);
230 }
231 let true = buffer.append(prefix.as_bytes()) else {
232 unreachable!("Checked size above; qed");
233 };
234 let true = buffer.append(result.as_bytes()) else {
235 unreachable!("Checked size above; qed");
236 };
237 let true = buffer.append(consensus_info.as_bytes()) else {
238 unreachable!("Checked size above; qed");
239 };
240 let true = buffer.append(intermediate_shard_blocks_root.as_bytes()) else {
241 unreachable!("Checked size above; qed");
242 };
243 {
246 let true = buffer.append(&solution_range.to_bytes()) else {
247 unreachable!("Checked size above; qed");
248 };
249 let true = buffer.append(&slot_iterations.get().to_le_bytes()) else {
250 unreachable!("Checked size above; qed");
251 };
252 let true = buffer.append(NumShardsUnchecked::from(*num_shards).as_bytes()) else {
253 unreachable!("Checked size above; qed");
254 };
255
256 let bitflags = {
257 let mut bitflags = 0u8;
258
259 if super_segment_root.is_some() {
260 bitflags |= BlockHeaderConsensusParameters::SUPER_SEGMENT_ROOT_MASK;
261 }
262 if next_solution_range.is_some() {
263 bitflags |= BlockHeaderConsensusParameters::NEXT_SOLUTION_RANGE_MASK;
264 }
265 if pot_parameters_change.is_some() {
266 bitflags |= BlockHeaderConsensusParameters::POT_PARAMETERS_CHANGE_MASK;
267 }
268
269 bitflags
270 };
271
272 let true = buffer.append(&[bitflags]) else {
273 unreachable!("Checked size above; qed");
274 };
275
276 if let Some(super_segment_root) = super_segment_root {
277 let true = buffer.append(super_segment_root.as_ref()) else {
278 unreachable!("Checked size above; qed");
279 };
280 }
281
282 if let Some(next_solution_range) = next_solution_range {
283 let true = buffer.append(&next_solution_range.to_bytes()) else {
284 unreachable!("Checked size above; qed");
285 };
286 }
287
288 if let Some(pot_parameters_change) = pot_parameters_change {
289 let true = buffer.append(&pot_parameters_change.slot.to_bytes()) else {
290 unreachable!("Checked size above; qed");
291 };
292 let true =
293 buffer.append(&pot_parameters_change.slot_iterations.get().to_le_bytes())
294 else {
295 unreachable!("Checked size above; qed");
296 };
297 let true = buffer.append(pot_parameters_change.entropy.as_ref()) else {
298 unreachable!("Checked size above; qed");
299 };
300 }
301 }
302
303 Ok(())
304 }
305
306 #[inline]
308 pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
309 let inner = Yoke::try_attach_to_cart(buffer.clone(), |buffer| {
312 let Some((header, extra_bytes)) = BeaconChainHeader::try_from_bytes(buffer) else {
313 return Err(());
314 };
315 if !extra_bytes.is_empty() {
316 return Err(());
317 }
318
319 Ok(header)
320 })
321 .map_err(move |()| buffer)?;
322
323 Ok(Self {
324 inner: Arc::new(inner),
325 })
326 }
327
328 #[inline(always)]
330 pub fn buffer(&self) -> &SharedAlignedBuffer {
331 self.inner.backing_cart()
332 }
333
334 #[inline(always)]
336 pub fn ref_count(&self) -> usize {
337 Arc::count(&self.inner)
338 }
339
340 #[inline(always)]
342 pub fn header(&self) -> &BeaconChainHeader<'_> {
343 self.inner.get()
344 }
345}
346
347#[derive(Debug, Clone)]
349pub struct OwnedBeaconChainHeaderUnsealed {
350 buffer: OwnedAlignedBuffer,
351 public_key_hash: Blake3Hash,
353}
354
355impl OwnedBeaconChainHeaderUnsealed {
356 #[inline(always)]
358 pub fn pre_seal_hash(&self) -> Blake3Hash {
359 Blake3Hash::from(blake3::hash(self.buffer.as_slice()))
361 }
362
363 pub fn with_seal(
367 self,
368 seal: BlockHeaderSeal<'_>,
369 ) -> Result<OwnedBeaconChainHeader, BlockHeaderConsistencyError> {
370 let Self {
371 mut buffer,
372 public_key_hash,
373 } = self;
374 BlockHeader::check_seal(&public_key_hash, seal)?;
375 append_seal(&mut buffer, seal);
376
377 let header = OwnedBeaconChainHeader::from_buffer(buffer.into_shared())
378 .expect("`from_parts()` checked the parts it wrote, the seal is checked above; qed");
379
380 Ok(header)
381 }
382}
383
384#[derive(Debug)]
389#[must_use = "The header in the buffer is not complete until `with_seal()` attaches the seal"]
390pub struct OwnedBeaconChainHeaderUnsealedRef<'a> {
391 buffer: &'a mut OwnedAlignedBuffer,
392 header_offset: u32,
393 public_key_hash: Blake3Hash,
395}
396
397impl OwnedBeaconChainHeaderUnsealedRef<'_> {
398 #[inline(always)]
400 pub fn pre_seal_hash(&self) -> Blake3Hash {
401 let header_bytes = self
402 .buffer
403 .as_slice()
404 .get(self.header_offset as usize..)
405 .expect("The buffer only grew since `header_offset` was its length; qed");
406 Blake3Hash::from(blake3::hash(header_bytes))
408 }
409
410 #[inline(always)]
416 pub fn with_seal(self, seal: BlockHeaderSeal<'_>) -> Result<(), BlockHeaderConsistencyError> {
417 let Self {
418 buffer,
419 header_offset: _,
420 public_key_hash,
421 } = self;
422 BlockHeader::check_seal(&public_key_hash, seal)?;
423 append_seal(buffer, seal);
424
425 Ok(())
426 }
427}
428
429#[derive(Debug, thiserror::Error)]
431pub enum OwnedIntermediateShardHeaderError {
432 #[error("The header is too large")]
434 HeaderTooLarge,
435 #[error("Invalid header parts: {error}")]
437 InvalidParts {
438 #[from]
440 error: BlockHeaderConsistencyError,
441 },
442}
443
444#[derive(Debug, Clone)]
449pub struct OwnedIntermediateShardHeader {
450 inner: Arc<Yoke<IntermediateShardHeader<'static>, SharedAlignedBuffer>>,
451}
452
453impl GenericOwnedBlockHeader for OwnedIntermediateShardHeader {
454 const SHARD_KIND: RealShardKind = RealShardKind::IntermediateShard;
455
456 type Header<'a> = IntermediateShardHeader<'a>;
457
458 #[inline(always)]
459 fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
460 Self::from_buffer(buffer)
461 }
462
463 #[inline(always)]
464 fn buffer(&self) -> &SharedAlignedBuffer {
465 self.buffer()
466 }
467
468 #[inline(always)]
469 fn ref_count(&self) -> usize {
470 self.ref_count()
471 }
472
473 #[inline(always)]
474 fn header(&self) -> &Self::Header<'_> {
475 self.header()
476 }
477}
478
479impl OwnedIntermediateShardHeader {
480 pub const MAX_ALLOCATION: u32 = BlockHeaderPrefix::SIZE
482 + BlockHeaderResult::SIZE
483 + BlockHeaderConsensusInfo::SIZE
484 + BlockHeaderBeaconChainInfo::SIZE
485 + <Blake3Hash as TrivialType>::SIZE
486 + BlockHeaderSeal::MAX_SIZE;
487
488 pub fn from_parts(
492 prefix: &BlockHeaderPrefix,
493 result: &BlockHeaderResult,
494 consensus_info: &BlockHeaderConsensusInfo,
495 beacon_chain_info: &BlockHeaderBeaconChainInfo,
496 leaf_shard_blocks_root: &Blake3Hash,
497 ) -> Result<OwnedIntermediateShardHeaderUnsealed, BlockHeaderConsistencyError> {
498 BlockHeader::check_shared_parts(prefix, consensus_info, RealShardKind::IntermediateShard)?;
499
500 let mut buffer = OwnedAlignedBuffer::with_capacity(Self::MAX_ALLOCATION);
501
502 Self::append_unsealed(
503 prefix,
504 result,
505 consensus_info,
506 beacon_chain_info,
507 leaf_shard_blocks_root,
508 &mut buffer,
509 )
510 .expect("The header with the largest seal fits into an empty buffer; qed");
511
512 Ok(OwnedIntermediateShardHeaderUnsealed {
513 buffer,
514 public_key_hash: consensus_info.solution.public_key_hash,
515 })
516 }
517
518 pub fn from_parts_into<'a>(
526 prefix: &BlockHeaderPrefix,
527 result: &BlockHeaderResult,
528 consensus_info: &BlockHeaderConsensusInfo,
529 beacon_chain_info: &BlockHeaderBeaconChainInfo,
530 leaf_shard_blocks_root: &Blake3Hash,
531 buffer: &'a mut OwnedAlignedBuffer,
532 ) -> Result<OwnedIntermediateShardHeaderUnsealedRef<'a>, OwnedIntermediateShardHeaderError>
533 {
534 BlockHeader::check_shared_parts(prefix, consensus_info, RealShardKind::IntermediateShard)?;
535
536 let header_offset = buffer.len();
537
538 Self::append_unsealed(
539 prefix,
540 result,
541 consensus_info,
542 beacon_chain_info,
543 leaf_shard_blocks_root,
544 buffer,
545 )?;
546
547 Ok(OwnedIntermediateShardHeaderUnsealedRef {
548 buffer,
549 header_offset,
550 public_key_hash: consensus_info.solution.public_key_hash,
551 })
552 }
553
554 fn append_unsealed(
556 prefix: &BlockHeaderPrefix,
557 result: &BlockHeaderResult,
558 consensus_info: &BlockHeaderConsensusInfo,
559 beacon_chain_info: &BlockHeaderBeaconChainInfo,
560 leaf_shard_blocks_root: &Blake3Hash,
561 buffer: &mut OwnedAlignedBuffer,
562 ) -> Result<(), OwnedIntermediateShardHeaderError> {
563 if OwnedAlignedBuffer::<Align16>::MAX_CAPACITY - buffer.len() < Self::MAX_ALLOCATION {
567 return Err(OwnedIntermediateShardHeaderError::HeaderTooLarge);
568 }
569 let true = buffer.append(prefix.as_bytes()) else {
570 unreachable!("Checked size above; qed");
571 };
572 let true = buffer.append(result.as_bytes()) else {
573 unreachable!("Checked size above; qed");
574 };
575 let true = buffer.append(consensus_info.as_bytes()) else {
576 unreachable!("Checked size above; qed");
577 };
578 let true = buffer.append(beacon_chain_info.as_bytes()) else {
579 unreachable!("Checked size above; qed");
580 };
581 let true = buffer.append(leaf_shard_blocks_root.as_bytes()) else {
582 unreachable!("Checked size above; qed");
583 };
584
585 Ok(())
586 }
587
588 #[inline]
590 pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
591 let inner = Yoke::try_attach_to_cart(buffer.clone(), |buffer| {
594 let Some((header, extra_bytes)) = IntermediateShardHeader::try_from_bytes(buffer)
595 else {
596 return Err(());
597 };
598 if !extra_bytes.is_empty() {
599 return Err(());
600 }
601
602 Ok(header)
603 })
604 .map_err(move |()| buffer)?;
605
606 Ok(Self {
607 inner: Arc::new(inner),
608 })
609 }
610
611 #[inline(always)]
613 pub fn buffer(&self) -> &SharedAlignedBuffer {
614 self.inner.backing_cart()
615 }
616
617 #[inline(always)]
619 pub fn ref_count(&self) -> usize {
620 Arc::count(&self.inner)
621 }
622
623 #[inline(always)]
625 pub fn header(&self) -> &IntermediateShardHeader<'_> {
626 self.inner.get()
627 }
628}
629
630#[derive(Debug, Clone)]
632pub struct OwnedIntermediateShardHeaderUnsealed {
633 buffer: OwnedAlignedBuffer,
634 public_key_hash: Blake3Hash,
636}
637
638impl OwnedIntermediateShardHeaderUnsealed {
639 #[inline(always)]
641 pub fn pre_seal_hash(&self) -> Blake3Hash {
642 Blake3Hash::from(blake3::hash(self.buffer.as_slice()))
644 }
645
646 pub fn with_seal(
650 self,
651 seal: BlockHeaderSeal<'_>,
652 ) -> Result<OwnedIntermediateShardHeader, BlockHeaderConsistencyError> {
653 let Self {
654 mut buffer,
655 public_key_hash,
656 } = self;
657 BlockHeader::check_seal(&public_key_hash, seal)?;
658 append_seal(&mut buffer, seal);
659
660 let header = OwnedIntermediateShardHeader::from_buffer(buffer.into_shared())
661 .expect("`from_parts()` checked the parts it wrote, the seal is checked above; qed");
662
663 Ok(header)
664 }
665}
666
667#[derive(Debug)]
672#[must_use = "The header in the buffer is not complete until `with_seal()` attaches the seal"]
673pub struct OwnedIntermediateShardHeaderUnsealedRef<'a> {
674 buffer: &'a mut OwnedAlignedBuffer,
675 header_offset: u32,
676 public_key_hash: Blake3Hash,
678}
679
680impl OwnedIntermediateShardHeaderUnsealedRef<'_> {
681 #[inline(always)]
683 pub fn pre_seal_hash(&self) -> Blake3Hash {
684 let header_bytes = self
685 .buffer
686 .as_slice()
687 .get(self.header_offset as usize..)
688 .expect("The buffer only grew since `header_offset` was its length; qed");
689 Blake3Hash::from(blake3::hash(header_bytes))
691 }
692
693 #[inline(always)]
699 pub fn with_seal(self, seal: BlockHeaderSeal<'_>) -> Result<(), BlockHeaderConsistencyError> {
700 let Self {
701 buffer,
702 header_offset: _,
703 public_key_hash,
704 } = self;
705 BlockHeader::check_seal(&public_key_hash, seal)?;
706 append_seal(buffer, seal);
707
708 Ok(())
709 }
710}
711
712#[derive(Debug, thiserror::Error)]
714pub enum OwnedLeafShardHeaderError {
715 #[error("The header is too large")]
717 HeaderTooLarge,
718 #[error("Invalid header parts: {error}")]
720 InvalidParts {
721 #[from]
723 error: BlockHeaderConsistencyError,
724 },
725}
726
727#[derive(Debug, Clone)]
732pub struct OwnedLeafShardHeader {
733 inner: Arc<Yoke<LeafShardHeader<'static>, SharedAlignedBuffer>>,
734}
735
736impl GenericOwnedBlockHeader for OwnedLeafShardHeader {
737 const SHARD_KIND: RealShardKind = RealShardKind::LeafShard;
738
739 type Header<'a> = LeafShardHeader<'a>;
740
741 #[inline(always)]
742 fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
743 Self::from_buffer(buffer)
744 }
745
746 #[inline(always)]
747 fn buffer(&self) -> &SharedAlignedBuffer {
748 self.buffer()
749 }
750
751 #[inline(always)]
752 fn ref_count(&self) -> usize {
753 self.ref_count()
754 }
755
756 #[inline(always)]
757 fn header(&self) -> &Self::Header<'_> {
758 self.header()
759 }
760}
761
762impl OwnedLeafShardHeader {
763 pub const MAX_ALLOCATION: u32 = BlockHeaderPrefix::SIZE
765 + BlockHeaderResult::SIZE
766 + BlockHeaderConsensusInfo::SIZE
767 + BlockHeaderBeaconChainInfo::SIZE
768 + BlockHeaderSeal::MAX_SIZE;
769
770 pub fn from_parts(
774 prefix: &BlockHeaderPrefix,
775 result: &BlockHeaderResult,
776 consensus_info: &BlockHeaderConsensusInfo,
777 beacon_chain_info: &BlockHeaderBeaconChainInfo,
778 ) -> Result<OwnedLeafShardHeaderUnsealed, BlockHeaderConsistencyError> {
779 BlockHeader::check_shared_parts(prefix, consensus_info, RealShardKind::LeafShard)?;
780
781 let mut buffer = OwnedAlignedBuffer::with_capacity(Self::MAX_ALLOCATION);
782
783 Self::append_unsealed(
784 prefix,
785 result,
786 consensus_info,
787 beacon_chain_info,
788 &mut buffer,
789 )
790 .expect("The header with the largest seal fits into an empty buffer; qed");
791
792 Ok(OwnedLeafShardHeaderUnsealed {
793 buffer,
794 public_key_hash: consensus_info.solution.public_key_hash,
795 })
796 }
797
798 pub fn from_parts_into<'a>(
806 prefix: &BlockHeaderPrefix,
807 result: &BlockHeaderResult,
808 consensus_info: &BlockHeaderConsensusInfo,
809 beacon_chain_info: &BlockHeaderBeaconChainInfo,
810 buffer: &'a mut OwnedAlignedBuffer,
811 ) -> Result<OwnedLeafShardHeaderUnsealedRef<'a>, OwnedLeafShardHeaderError> {
812 BlockHeader::check_shared_parts(prefix, consensus_info, RealShardKind::LeafShard)?;
813
814 let header_offset = buffer.len();
815
816 Self::append_unsealed(prefix, result, consensus_info, beacon_chain_info, buffer)?;
817
818 Ok(OwnedLeafShardHeaderUnsealedRef {
819 buffer,
820 header_offset,
821 public_key_hash: consensus_info.solution.public_key_hash,
822 })
823 }
824
825 fn append_unsealed(
827 prefix: &BlockHeaderPrefix,
828 result: &BlockHeaderResult,
829 consensus_info: &BlockHeaderConsensusInfo,
830 beacon_chain_info: &BlockHeaderBeaconChainInfo,
831 buffer: &mut OwnedAlignedBuffer,
832 ) -> Result<(), OwnedLeafShardHeaderError> {
833 if OwnedAlignedBuffer::<Align16>::MAX_CAPACITY - buffer.len() < Self::MAX_ALLOCATION {
837 return Err(OwnedLeafShardHeaderError::HeaderTooLarge);
838 }
839 let true = buffer.append(prefix.as_bytes()) else {
840 unreachable!("Checked size above; qed");
841 };
842 let true = buffer.append(result.as_bytes()) else {
843 unreachable!("Checked size above; qed");
844 };
845 let true = buffer.append(consensus_info.as_bytes()) else {
846 unreachable!("Checked size above; qed");
847 };
848 let true = buffer.append(beacon_chain_info.as_bytes()) else {
849 unreachable!("Checked size above; qed");
850 };
851
852 Ok(())
853 }
854
855 #[inline]
857 pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, SharedAlignedBuffer> {
858 let inner = Yoke::try_attach_to_cart(buffer.clone(), |buffer| {
861 let Some((header, extra_bytes)) = LeafShardHeader::try_from_bytes(buffer) else {
862 return Err(());
863 };
864 if !extra_bytes.is_empty() {
865 return Err(());
866 }
867
868 Ok(header)
869 })
870 .map_err(move |()| buffer)?;
871
872 Ok(Self {
873 inner: Arc::new(inner),
874 })
875 }
876
877 #[inline(always)]
879 pub fn buffer(&self) -> &SharedAlignedBuffer {
880 self.inner.backing_cart()
881 }
882
883 #[inline(always)]
885 pub fn ref_count(&self) -> usize {
886 Arc::count(&self.inner)
887 }
888
889 #[inline(always)]
891 pub fn header(&self) -> &LeafShardHeader<'_> {
892 self.inner.get()
893 }
894}
895
896#[derive(Debug, Clone)]
898pub struct OwnedLeafShardHeaderUnsealed {
899 buffer: OwnedAlignedBuffer,
900 public_key_hash: Blake3Hash,
902}
903
904impl OwnedLeafShardHeaderUnsealed {
905 #[inline(always)]
907 pub fn pre_seal_hash(&self) -> Blake3Hash {
908 Blake3Hash::from(blake3::hash(self.buffer.as_slice()))
910 }
911
912 pub fn with_seal(
916 self,
917 seal: BlockHeaderSeal<'_>,
918 ) -> Result<OwnedLeafShardHeader, BlockHeaderConsistencyError> {
919 let Self {
920 mut buffer,
921 public_key_hash,
922 } = self;
923 BlockHeader::check_seal(&public_key_hash, seal)?;
924 append_seal(&mut buffer, seal);
925
926 let header = OwnedLeafShardHeader::from_buffer(buffer.into_shared())
927 .expect("`from_parts()` checked the parts it wrote, the seal is checked above; qed");
928
929 Ok(header)
930 }
931}
932
933#[derive(Debug)]
938#[must_use = "The header in the buffer is not complete until `with_seal()` attaches the seal"]
939pub struct OwnedLeafShardHeaderUnsealedRef<'a> {
940 buffer: &'a mut OwnedAlignedBuffer,
941 header_offset: u32,
942 public_key_hash: Blake3Hash,
944}
945
946impl OwnedLeafShardHeaderUnsealedRef<'_> {
947 #[inline(always)]
949 pub fn pre_seal_hash(&self) -> Blake3Hash {
950 let header_bytes = self
951 .buffer
952 .as_slice()
953 .get(self.header_offset as usize..)
954 .expect("The buffer only grew since `header_offset` was its length; qed");
955 Blake3Hash::from(blake3::hash(header_bytes))
957 }
958
959 #[inline(always)]
965 pub fn with_seal(self, seal: BlockHeaderSeal<'_>) -> Result<(), BlockHeaderConsistencyError> {
966 let Self {
967 buffer,
968 header_offset: _,
969 public_key_hash,
970 } = self;
971 BlockHeader::check_seal(&public_key_hash, seal)?;
972 append_seal(buffer, seal);
973
974 Ok(())
975 }
976}
977
978#[derive(Debug, Clone, From)]
983pub enum OwnedBlockHeader {
984 BeaconChain(OwnedBeaconChainHeader),
986 IntermediateShard(OwnedIntermediateShardHeader),
988 LeafShard(OwnedLeafShardHeader),
990}
991
992impl OwnedBlockHeader {
993 #[inline]
995 pub fn from_buffer(
996 buffer: SharedAlignedBuffer,
997 shard_kind: RealShardKind,
998 ) -> Result<Self, SharedAlignedBuffer> {
999 Ok(match shard_kind {
1000 RealShardKind::BeaconChain => {
1001 Self::BeaconChain(OwnedBeaconChainHeader::from_buffer(buffer)?)
1002 }
1003 RealShardKind::IntermediateShard => {
1004 Self::IntermediateShard(OwnedIntermediateShardHeader::from_buffer(buffer)?)
1005 }
1006 RealShardKind::LeafShard => Self::LeafShard(OwnedLeafShardHeader::from_buffer(buffer)?),
1007 })
1008 }
1009
1010 #[inline]
1012 pub fn buffer(&self) -> &SharedAlignedBuffer {
1013 match self {
1014 Self::BeaconChain(owned_header) => owned_header.buffer(),
1015 Self::IntermediateShard(owned_header) => owned_header.buffer(),
1016 Self::LeafShard(owned_header) => owned_header.buffer(),
1017 }
1018 }
1019
1020 #[inline]
1022 pub fn ref_count(&self) -> usize {
1023 match self {
1024 Self::BeaconChain(owned_header) => owned_header.ref_count(),
1025 Self::IntermediateShard(owned_header) => owned_header.ref_count(),
1026 Self::LeafShard(owned_header) => owned_header.ref_count(),
1027 }
1028 }
1029
1030 #[inline]
1032 pub fn header(&self) -> BlockHeader<'_> {
1033 match self {
1034 Self::BeaconChain(owned_header) => {
1035 BlockHeader::BeaconChain(owned_header.header().clone())
1036 }
1037 Self::IntermediateShard(owned_header) => {
1038 BlockHeader::IntermediateShard(owned_header.header().clone())
1039 }
1040 Self::LeafShard(owned_header) => BlockHeader::LeafShard(owned_header.header().clone()),
1041 }
1042 }
1043}