1#[cfg(feature = "alloc")]
4mod archival_history_segment;
5
6use crate::block::BlockNumber;
7use crate::hashes::Blake3Hash;
8use crate::pieces::{PieceIndex, Record, SegmentProof};
9#[cfg(feature = "alloc")]
10pub use crate::segments::archival_history_segment::ArchivedHistorySegment;
11use crate::shard::ShardIndex;
12use ab_blake3::{single_block_hash, single_chunk_hash};
13use ab_io_type::trivial_type::TrivialType;
14use ab_io_type::unaligned::Unaligned;
15use ab_merkle_tree::unbalanced::UnbalancedMerkleTree;
16#[cfg(feature = "alloc")]
17use alloc::boxed::Box;
18#[cfg(feature = "alloc")]
19use alloc::sync::Arc as StdArc;
20use blake3::{CHUNK_LEN, OUT_LEN};
21use core::iter::Step;
22use core::num::{NonZeroU32, NonZeroU64};
23use core::{fmt, mem};
24use derive_more::{
25 Add, AddAssign, Deref, DerefMut, Display, Div, DivAssign, From, Into, Mul, MulAssign, Sub,
26 SubAssign,
27};
28#[cfg(feature = "scale-codec")]
29use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
30#[cfg(feature = "serde")]
31use serde::{Deserialize, Deserializer, Serialize, Serializer};
32#[cfg(feature = "serde")]
33use serde_big_array::BigArray;
34
35#[derive(
37 Debug,
38 Display,
39 Default,
40 Copy,
41 Clone,
42 Ord,
43 PartialOrd,
44 Eq,
45 PartialEq,
46 Hash,
47 Add,
48 AddAssign,
49 Sub,
50 SubAssign,
51 Mul,
52 MulAssign,
53 Div,
54 DivAssign,
55 TrivialType,
56)]
57#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
58#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
59#[repr(C)]
60pub struct SuperSegmentIndex(u64);
61
62impl Step for SuperSegmentIndex {
63 #[inline]
64 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
65 u64::steps_between(&start.0, &end.0)
66 }
67
68 #[inline]
69 fn forward_checked(start: Self, count: usize) -> Option<Self> {
70 u64::forward_checked(start.0, count).map(Self)
71 }
72
73 #[inline]
74 fn backward_checked(start: Self, count: usize) -> Option<Self> {
75 u64::backward_checked(start.0, count).map(Self)
76 }
77}
78
79impl const From<u64> for SuperSegmentIndex {
80 #[inline(always)]
81 fn from(value: u64) -> Self {
82 Self(value)
83 }
84}
85
86impl const From<SuperSegmentIndex> for u64 {
87 #[inline(always)]
88 fn from(value: SuperSegmentIndex) -> Self {
89 value.0
90 }
91}
92
93impl SuperSegmentIndex {
94 pub const ZERO: Self = Self(0);
96 pub const ONE: Self = Self(1);
98
99 #[inline]
101 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
102 self.0.checked_sub(rhs.0).map(Self)
103 }
104
105 #[inline]
108 pub const fn saturating_sub(self, rhs: Self) -> Self {
109 Self(self.0.saturating_sub(rhs.0))
110 }
111}
112
113#[derive(Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, From, Into, TrivialType)]
115#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
116#[repr(C)]
117pub struct SuperSegmentRoot([u8; SuperSegmentRoot::SIZE]);
118
119impl fmt::Debug for SuperSegmentRoot {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 for byte in self.0 {
122 write!(f, "{byte:02x}")?;
123 }
124 Ok(())
125 }
126}
127
128impl const Default for SuperSegmentRoot {
129 #[inline]
130 fn default() -> Self {
131 Self([0; Self::SIZE])
132 }
133}
134
135#[cfg(feature = "serde")]
136#[derive(Serialize, Deserialize)]
137#[serde(transparent)]
138struct SuperSegmentRootBinary(#[serde(with = "BigArray")] [u8; SuperSegmentRoot::SIZE]);
139
140#[cfg(feature = "serde")]
141#[derive(Serialize, Deserialize)]
142#[serde(transparent)]
143struct SuperSegmentRootHex(#[serde(with = "hex")] [u8; SuperSegmentRoot::SIZE]);
144
145#[cfg(feature = "serde")]
146impl Serialize for SuperSegmentRoot {
147 #[inline]
148 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
149 where
150 S: Serializer,
151 {
152 if serializer.is_human_readable() {
153 SuperSegmentRootHex(self.0).serialize(serializer)
154 } else {
155 SuperSegmentRootBinary(self.0).serialize(serializer)
156 }
157 }
158}
159
160#[cfg(feature = "serde")]
161impl<'de> Deserialize<'de> for SuperSegmentRoot {
162 #[inline]
163 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
164 where
165 D: Deserializer<'de>,
166 {
167 Ok(Self(if deserializer.is_human_readable() {
168 SuperSegmentRootHex::deserialize(deserializer)?.0
169 } else {
170 SuperSegmentRootBinary::deserialize(deserializer)?.0
171 }))
172 }
173}
174
175impl AsRef<[u8]> for SuperSegmentRoot {
176 #[inline]
177 fn as_ref(&self) -> &[u8] {
178 &self.0
179 }
180}
181
182impl AsMut<[u8]> for SuperSegmentRoot {
183 #[inline]
184 fn as_mut(&mut self) -> &mut [u8] {
185 &mut self.0
186 }
187}
188
189impl SuperSegmentRoot {
190 pub const SIZE: usize = 32;
192 pub const MAX_SEGMENTS: u32 = 2u32.pow(20) - 1;
196}
197
198#[derive(
200 Debug,
201 Display,
202 Default,
203 Copy,
204 Clone,
205 Ord,
206 PartialOrd,
207 Eq,
208 PartialEq,
209 Hash,
210 From,
211 Into,
212 TrivialType,
213)]
214#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
215#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
216#[repr(C)]
217pub struct SegmentPosition(u32);
218
219impl From<SegmentPosition> for u64 {
220 #[inline]
221 fn from(original: SegmentPosition) -> Self {
222 Self::from(original.0)
223 }
224}
225
226impl SegmentPosition {
227 pub const ZERO: Self = Self(0);
229}
230
231#[derive(Debug, Clone, Copy, TrivialType)]
233#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
234#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
235#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
236#[repr(C)]
237pub struct ShardSegmentRootWithPosition {
238 pub shard_index: ShardIndex,
240 pub segment_position: SegmentPosition,
242 pub local_segment_index: LocalSegmentIndex,
244 pub segment_root: SegmentRoot,
246}
247
248impl ShardSegmentRootWithPosition {
249 #[inline(always)]
251 pub fn hash(&self) -> [u8; OUT_LEN] {
252 single_block_hash(self.as_bytes()).expect("Less than a single block worth of bytes; qed")
253 }
254}
255
256#[derive(Debug, Clone, Copy, Eq, PartialEq, TrivialType)]
258#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
259#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
260#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
261#[repr(C)]
262pub struct SuperSegmentHeader {
263 pub index: Unaligned<SuperSegmentIndex>,
265 pub root: SuperSegmentRoot,
267 pub prev_super_segment_header_hash: Blake3Hash,
269 pub max_segment_index: Unaligned<SegmentIndex>,
271 pub target_beacon_chain_block_number: Unaligned<BlockNumber>,
273 pub num_segments: u32,
276}
277
278#[cfg(feature = "alloc")]
280#[derive(Debug, Clone)]
281#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
284#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
285pub struct SuperSegment {
286 pub header: SuperSegmentHeader,
288 pub segment_roots: StdArc<[ShardSegmentRootWithPosition]>,
290}
291
292#[cfg(feature = "alloc")]
293impl SuperSegment {
294 pub fn new(
298 previous_header: &SuperSegmentHeader,
299 target_beacon_chain_block_number: BlockNumber,
300 segment_roots: StdArc<[ShardSegmentRootWithPosition]>,
301 ) -> Option<Self> {
302 let num_segments = u32::try_from(segment_roots.len()).ok()?;
303 let max_segment_index = SegmentIndex::from(
304 u64::from(previous_header.max_segment_index.as_inner()) + u64::from(num_segments),
305 );
306
307 const {
311 assert!(SuperSegmentRoot::MAX_SEGMENTS == 1_048_575);
312 }
313 let maybe_super_segment_root = UnbalancedMerkleTree::compute_root_only::<1_048_575, _, _>(
315 segment_roots.iter().map(ShardSegmentRootWithPosition::hash),
316 )?;
317
318 Some(Self {
319 header: SuperSegmentHeader {
320 index: (previous_header.index.as_inner() + SuperSegmentIndex::ONE).into(),
321 root: SuperSegmentRoot::from(maybe_super_segment_root),
322 prev_super_segment_header_hash: Blake3Hash::from(
323 single_chunk_hash(previous_header.as_bytes())
324 .expect("Less than a single chunk worth of bytes; qed"),
325 ),
326 max_segment_index: max_segment_index.into(),
327 target_beacon_chain_block_number: target_beacon_chain_block_number.into(),
328 num_segments,
329 },
330 segment_roots,
331 })
332 }
333
334 pub fn proof_for_segment(&self, segment_position: SegmentPosition) -> Option<SegmentProof> {
336 const {
340 assert!(SuperSegmentRoot::MAX_SEGMENTS == 1_048_575);
341 }
342 let mut segment_proof = SegmentProof::default();
344 UnbalancedMerkleTree::compute_root_and_proof_in::<1_048_575, _, _>(
345 self.segment_roots.iter().map(|shard_segment_root| {
346 single_block_hash(shard_segment_root.as_bytes())
347 .expect("Less than a single block worth of bytes; qed")
348 }),
349 u32::from(segment_position) as usize,
350 segment_proof.as_uninit_repr(),
351 )?;
352
353 Some(segment_proof)
354 }
355}
356
357#[derive(
359 Debug,
360 Display,
361 Default,
362 Copy,
363 Clone,
364 Ord,
365 PartialOrd,
366 Eq,
367 PartialEq,
368 Hash,
369 Add,
370 AddAssign,
371 Sub,
372 SubAssign,
373 Mul,
374 MulAssign,
375 Div,
376 DivAssign,
377 TrivialType,
378)]
379#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
380#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
381#[repr(C)]
382pub struct LocalSegmentIndex(u64);
383
384impl Step for LocalSegmentIndex {
385 #[inline]
386 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
387 u64::steps_between(&start.0, &end.0)
388 }
389
390 #[inline]
391 fn forward_checked(start: Self, count: usize) -> Option<Self> {
392 u64::forward_checked(start.0, count).map(Self)
393 }
394
395 #[inline]
396 fn backward_checked(start: Self, count: usize) -> Option<Self> {
397 u64::backward_checked(start.0, count).map(Self)
398 }
399}
400
401impl const From<u64> for LocalSegmentIndex {
402 #[inline(always)]
403 fn from(value: u64) -> Self {
404 Self(value)
405 }
406}
407
408impl const From<LocalSegmentIndex> for u64 {
409 #[inline(always)]
410 fn from(value: LocalSegmentIndex) -> Self {
411 value.0
412 }
413}
414
415impl LocalSegmentIndex {
416 pub const ZERO: Self = Self(0);
418 pub const ONE: Self = Self(1);
420
421 #[inline]
423 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
424 self.0.checked_sub(rhs.0).map(Self)
425 }
426
427 #[inline]
430 pub const fn saturating_sub(self, rhs: Self) -> Self {
431 Self(self.0.saturating_sub(rhs.0))
432 }
433}
434
435#[derive(
437 Debug,
438 Display,
439 Default,
440 Copy,
441 Clone,
442 Ord,
443 PartialOrd,
444 Eq,
445 PartialEq,
446 Hash,
447 Add,
448 AddAssign,
449 Sub,
450 SubAssign,
451 Mul,
452 MulAssign,
453 Div,
454 DivAssign,
455 TrivialType,
456)]
457#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
458#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
459#[repr(C)]
460pub struct SegmentIndex(u64);
461
462impl Step for SegmentIndex {
463 #[inline]
464 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
465 u64::steps_between(&start.0, &end.0)
466 }
467
468 #[inline]
469 fn forward_checked(start: Self, count: usize) -> Option<Self> {
470 u64::forward_checked(start.0, count).map(Self)
471 }
472
473 #[inline]
474 fn backward_checked(start: Self, count: usize) -> Option<Self> {
475 u64::backward_checked(start.0, count).map(Self)
476 }
477}
478
479impl const From<u64> for SegmentIndex {
480 #[inline(always)]
481 fn from(value: u64) -> Self {
482 Self(value)
483 }
484}
485
486impl const From<SegmentIndex> for u64 {
487 #[inline(always)]
488 fn from(value: SegmentIndex) -> Self {
489 value.0
490 }
491}
492
493impl SegmentIndex {
494 pub const ZERO: Self = Self(0);
496 pub const ONE: Self = Self(1);
498
499 #[inline]
501 pub const fn first_piece_index(&self) -> PieceIndex {
502 PieceIndex::from(self.0 * RecordedHistorySegment::NUM_PIECES as u64)
503 }
504
505 #[inline]
507 pub const fn last_piece_index(&self) -> PieceIndex {
508 PieceIndex::from((self.0 + 1) * RecordedHistorySegment::NUM_PIECES as u64 - 1)
509 }
510
511 #[inline]
513 pub fn segment_piece_indexes(&self) -> [PieceIndex; RecordedHistorySegment::NUM_PIECES] {
514 let mut piece_indices = [PieceIndex::ZERO; RecordedHistorySegment::NUM_PIECES];
515 (self.first_piece_index()..=self.last_piece_index())
516 .zip(&mut piece_indices)
517 .for_each(|(input, output)| {
518 *output = input;
519 });
520
521 piece_indices
522 }
523
524 #[inline]
526 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
527 self.0.checked_sub(rhs.0).map(Self)
528 }
529
530 #[inline]
533 pub const fn saturating_sub(self, rhs: Self) -> Self {
534 Self(self.0.saturating_sub(rhs.0))
535 }
536}
537
538#[derive(Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, From, Into, TrivialType)]
540#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
541#[repr(C)]
542pub struct SegmentRoot([u8; SegmentRoot::SIZE]);
543
544impl fmt::Debug for SegmentRoot {
545 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546 for byte in self.0 {
547 write!(f, "{byte:02x}")?;
548 }
549 Ok(())
550 }
551}
552
553#[cfg(feature = "serde")]
554#[derive(Serialize, Deserialize)]
555#[serde(transparent)]
556struct SegmentRootBinary(#[serde(with = "BigArray")] [u8; SegmentRoot::SIZE]);
557
558#[cfg(feature = "serde")]
559#[derive(Serialize, Deserialize)]
560#[serde(transparent)]
561struct SegmentRootHex(#[serde(with = "hex")] [u8; SegmentRoot::SIZE]);
562
563#[cfg(feature = "serde")]
564impl Serialize for SegmentRoot {
565 #[inline]
566 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
567 where
568 S: Serializer,
569 {
570 if serializer.is_human_readable() {
571 SegmentRootHex(self.0).serialize(serializer)
572 } else {
573 SegmentRootBinary(self.0).serialize(serializer)
574 }
575 }
576}
577
578#[cfg(feature = "serde")]
579impl<'de> Deserialize<'de> for SegmentRoot {
580 #[inline]
581 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
582 where
583 D: Deserializer<'de>,
584 {
585 Ok(Self(if deserializer.is_human_readable() {
586 SegmentRootHex::deserialize(deserializer)?.0
587 } else {
588 SegmentRootBinary::deserialize(deserializer)?.0
589 }))
590 }
591}
592
593impl Default for SegmentRoot {
594 #[inline(always)]
595 fn default() -> Self {
596 Self([0; Self::SIZE])
597 }
598}
599
600impl AsRef<[u8]> for SegmentRoot {
601 #[inline(always)]
602 fn as_ref(&self) -> &[u8] {
603 &self.0
604 }
605}
606
607impl AsMut<[u8]> for SegmentRoot {
608 #[inline(always)]
609 fn as_mut(&mut self) -> &mut [u8] {
610 &mut self.0
611 }
612}
613
614impl SegmentRoot {
615 pub const SIZE: usize = 32;
617
618 #[inline(always)]
620 pub const fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
621 unsafe { mem::transmute(value) }
623 }
624
625 #[inline(always)]
627 pub const fn repr_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
628 unsafe { mem::transmute(value) }
630 }
631
632 pub fn is_valid(
634 &self,
635 shard_index: ShardIndex,
636 local_segment_index: LocalSegmentIndex,
637 segment_position: SegmentPosition,
638 segment_proof: &SegmentProof,
639 num_segments: u32,
640 super_segment_root: &SuperSegmentRoot,
641 ) -> bool {
642 let shard_segment_root = ShardSegmentRootWithPosition {
643 shard_index,
644 segment_position,
645 local_segment_index,
646 segment_root: *self,
647 };
648 let segment_proof = segment_proof
651 .split_once(|hash| hash == &[0; _])
652 .map_or(segment_proof.as_slice(), |(before, _after)| before);
653 UnbalancedMerkleTree::verify(
654 super_segment_root,
655 segment_proof,
656 u64::from(segment_position),
657 shard_segment_root.hash(),
658 u64::from(num_segments),
659 )
660 }
661}
662
663#[derive(
665 Debug,
666 Display,
667 Copy,
668 Clone,
669 Ord,
670 PartialOrd,
671 Eq,
672 PartialEq,
673 Hash,
674 From,
675 Into,
676 Deref,
677 DerefMut,
678 TrivialType,
679)]
680#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
681#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
682#[repr(C)]
683pub struct HistorySize(SegmentIndex);
685
686impl HistorySize {
687 pub const ONE: Self = Self(SegmentIndex::ZERO);
689
690 #[inline(always)]
692 pub const fn new(value: NonZeroU64) -> Self {
693 Self(SegmentIndex::from(value.get() - 1))
694 }
695
696 pub const fn as_segment_index(&self) -> SegmentIndex {
698 self.0
699 }
700
701 pub const fn as_non_zero_u64(&self) -> NonZeroU64 {
703 NonZeroU64::new(u64::from(self.0).saturating_add(1)).expect("Not zero; qed")
704 }
705
706 #[inline(always)]
708 pub const fn in_pieces(&self) -> NonZeroU64 {
709 NonZeroU64::new(
710 u64::from(self.0)
711 .saturating_add(1)
712 .saturating_mul(RecordedHistorySegment::NUM_PIECES as u64),
713 )
714 .expect("Not zero; qed")
715 }
716
717 #[inline(always)]
719 pub fn segment_index(&self) -> SegmentIndex {
720 self.0
721 }
722
723 #[inline(always)]
727 pub fn sector_expiration_check(&self, min_sector_lifetime: Self) -> Option<Self> {
728 self.as_non_zero_u64()
729 .checked_add(min_sector_lifetime.as_non_zero_u64().get())
730 .map(Self::new)
731 }
732}
733
734#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, TrivialType)]
736#[cfg_attr(feature = "scale-codec", derive(Encode, Decode))]
737#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
738#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
739#[repr(C)]
740pub struct ArchivedBlockProgress {
741 bytes: u32,
743}
744
745impl Default for ArchivedBlockProgress {
746 #[inline(always)]
749 fn default() -> Self {
750 Self::new_complete()
751 }
752}
753
754impl ArchivedBlockProgress {
755 #[inline(always)]
757 pub const fn new_complete() -> Self {
758 Self { bytes: 0 }
759 }
760
761 #[inline(always)]
763 pub const fn new_partial(new_partial: NonZeroU32) -> Self {
764 Self {
765 bytes: new_partial.get(),
766 }
767 }
768
769 #[inline(always)]
771 pub const fn partial(&self) -> Option<NonZeroU32> {
772 NonZeroU32::new(self.bytes)
773 }
774}
775
776#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, TrivialType)]
778#[cfg_attr(feature = "scale-codec", derive(Encode, Decode))]
779#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
780#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
781#[repr(C)]
782pub struct LastArchivedBlock {
783 pub number: Unaligned<BlockNumber>,
785 pub archived_progress: ArchivedBlockProgress,
787}
788
789impl LastArchivedBlock {
790 #[inline(always)]
792 pub fn partial_archived(&self) -> Option<NonZeroU32> {
793 self.archived_progress.partial()
794 }
795
796 #[inline(always)]
798 pub fn set_partial_archived(&mut self, new_partial: NonZeroU32) {
799 self.archived_progress = ArchivedBlockProgress::new_partial(new_partial);
800 }
801
802 #[inline(always)]
804 pub fn set_complete(&mut self) {
805 self.archived_progress = ArchivedBlockProgress::new_complete();
806 }
807
808 pub const fn number(&self) -> BlockNumber {
810 self.number.as_inner()
811 }
812}
813
814#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, TrivialType)]
816#[cfg_attr(feature = "scale-codec", derive(Encode, Decode))]
817#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
818#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
819#[repr(C)]
820pub struct SegmentHeader {
821 pub index: Unaligned<LocalSegmentIndex>,
823 pub root: SegmentRoot,
825 pub prev_segment_header_hash: Blake3Hash,
827 pub last_archived_block: LastArchivedBlock,
829}
830
831impl SegmentHeader {
832 #[inline(always)]
834 pub fn hash(&self) -> Blake3Hash {
835 const {
836 assert!(size_of::<Self>() <= CHUNK_LEN);
837 }
838 Blake3Hash::new(
839 single_chunk_hash(self.as_bytes())
840 .expect("Less than a single chunk worth of bytes; qed"),
841 )
842 }
843}
844
845#[derive(Copy, Clone, Eq, PartialEq, Deref, DerefMut)]
849#[repr(C)]
850pub struct RecordedHistorySegment([Record; Self::NUM_RAW_RECORDS]);
851
852impl fmt::Debug for RecordedHistorySegment {
853 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
854 f.debug_struct("RecordedHistorySegment")
855 .finish_non_exhaustive()
856 }
857}
858
859impl AsRef<[u8]> for RecordedHistorySegment {
860 #[inline]
861 fn as_ref(&self) -> &[u8] {
862 Record::slice_to_repr(&self.0).as_flattened().as_flattened()
863 }
864}
865
866impl AsMut<[u8]> for RecordedHistorySegment {
867 #[inline]
868 fn as_mut(&mut self) -> &mut [u8] {
869 Record::slice_mut_to_repr(&mut self.0)
870 .as_flattened_mut()
871 .as_flattened_mut()
872 }
873}
874
875impl RecordedHistorySegment {
876 pub const NUM_RAW_RECORDS: usize = 128;
878 pub const ERASURE_CODING_RATE: (usize, usize) = (1, 2);
880 pub const NUM_PIECES: usize =
883 Self::NUM_RAW_RECORDS * Self::ERASURE_CODING_RATE.1 / Self::ERASURE_CODING_RATE.0;
884 pub const SIZE: usize = Record::SIZE * Self::NUM_RAW_RECORDS;
890
891 #[inline]
893 #[cfg(feature = "alloc")]
894 pub fn new_boxed() -> Box<Self> {
895 unsafe { Box::<Self>::new_zeroed().assume_init() }
898 }
899}