Skip to main content

ab_core_primitives/
pieces.rs

1//! Pieces-related data structures.
2
3#[cfg(feature = "alloc")]
4mod cow_bytes;
5#[cfg(feature = "alloc")]
6mod flat_pieces;
7#[cfg(feature = "alloc")]
8mod piece;
9
10#[cfg(feature = "alloc")]
11pub use crate::pieces::flat_pieces::FlatPieces;
12#[cfg(feature = "alloc")]
13pub use crate::pieces::piece::Piece;
14use crate::segments::{
15    LocalSegmentIndex, RecordedHistorySegment, SegmentIndex, SegmentPosition, SegmentRoot,
16    SuperSegmentIndex, SuperSegmentRoot,
17};
18use crate::shard::ShardIndex;
19#[cfg(feature = "serde")]
20use ::serde::{Deserialize, Deserializer, Serialize, Serializer};
21use ab_io_type::trivial_type::TrivialType;
22use ab_io_type::unaligned::Unaligned;
23use ab_merkle_tree::balanced::BalancedMerkleTree;
24#[cfg(feature = "alloc")]
25use alloc::boxed::Box;
26#[cfg(feature = "alloc")]
27use alloc::vec::Vec;
28use blake3::OUT_LEN;
29use core::array::TryFromSliceError;
30use core::hash::Hash;
31use core::iter::Step;
32use core::mem::MaybeUninit;
33#[cfg(feature = "alloc")]
34use core::slice;
35use core::{fmt, mem};
36use derive_more::{
37    Add, AddAssign, AsMut, AsRef, Deref, DerefMut, Display, Div, DivAssign, From, Into, Mul,
38    MulAssign, Sub, SubAssign,
39};
40#[cfg(feature = "scale-codec")]
41use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
42#[cfg(feature = "serde")]
43use serde_big_array::BigArray;
44
45/// Piece index
46#[derive(
47    Debug,
48    Display,
49    Default,
50    Copy,
51    Clone,
52    Ord,
53    PartialOrd,
54    Eq,
55    PartialEq,
56    Hash,
57    Add,
58    AddAssign,
59    Sub,
60    SubAssign,
61    Mul,
62    MulAssign,
63    Div,
64    DivAssign,
65)]
66#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
67#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
68#[repr(C)]
69pub struct PieceIndex(u64);
70
71impl Step for PieceIndex {
72    #[inline]
73    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
74        u64::steps_between(&start.0, &end.0)
75    }
76
77    #[inline]
78    fn forward_checked(start: Self, count: usize) -> Option<Self> {
79        u64::forward_checked(start.0, count).map(Self)
80    }
81
82    #[inline(always)]
83    fn forward_overflowing(start: Self, count: usize) -> (Self, bool) {
84        let (n, overflowing) = u64::forward_overflowing(start.0, count);
85        (Self(n), overflowing)
86    }
87
88    #[inline]
89    fn backward_checked(start: Self, count: usize) -> Option<Self> {
90        u64::backward_checked(start.0, count).map(Self)
91    }
92
93    #[inline(always)]
94    fn backward_overflowing(start: Self, count: usize) -> (Self, bool) {
95        let (n, overflowing) = u64::backward_overflowing(start.0, count);
96        (Self(n), overflowing)
97    }
98}
99
100const impl From<u64> for PieceIndex {
101    #[inline(always)]
102    fn from(value: u64) -> Self {
103        Self(value)
104    }
105}
106
107const impl From<PieceIndex> for u64 {
108    #[inline(always)]
109    fn from(value: PieceIndex) -> Self {
110        value.0
111    }
112}
113
114impl PieceIndex {
115    /// Size in bytes.
116    pub const SIZE: usize = size_of::<u64>();
117    /// Piece index 0.
118    pub const ZERO: PieceIndex = PieceIndex(0);
119    /// Piece index 1.
120    pub const ONE: PieceIndex = PieceIndex(1);
121
122    /// Create a piece index from bytes.
123    #[inline]
124    pub const fn from_bytes(bytes: [u8; Self::SIZE]) -> Self {
125        Self(u64::from_le_bytes(bytes))
126    }
127
128    /// Convert a piece index to bytes.
129    #[inline]
130    pub const fn to_bytes(self) -> [u8; Self::SIZE] {
131        self.0.to_le_bytes()
132    }
133
134    /// Segment index piece index corresponds to
135    #[inline]
136    pub const fn segment_index(&self) -> SegmentIndex {
137        SegmentIndex::from(self.0 / RecordedHistorySegment::NUM_PIECES as u64)
138    }
139
140    /// Position of a piece in a segment
141    #[inline]
142    pub fn position(&self) -> PiecePosition {
143        PiecePosition::from((self.0 % RecordedHistorySegment::NUM_PIECES as u64) as u8)
144    }
145}
146
147const {
148    // Assert that `u8` represents `PiecePosition` perfectly
149    assert!(RecordedHistorySegment::NUM_PIECES == usize::from(u8::MAX) + 1);
150}
151
152/// Piece position in a segment
153#[derive(
154    Debug,
155    Display,
156    Default,
157    Copy,
158    Clone,
159    Ord,
160    PartialOrd,
161    Eq,
162    PartialEq,
163    Hash,
164    From,
165    Into,
166    TrivialType,
167)]
168#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
169#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
170#[repr(C)]
171pub struct PiecePosition(u8);
172
173impl Step for PiecePosition {
174    #[inline]
175    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
176        u8::steps_between(&start.0, &end.0)
177    }
178
179    #[inline]
180    fn forward_checked(start: Self, count: usize) -> Option<Self> {
181        u8::forward_checked(start.0, count).map(Self)
182    }
183
184    #[inline(always)]
185    fn forward_overflowing(start: Self, count: usize) -> (Self, bool) {
186        let (n, overflowing) = u8::forward_overflowing(start.0, count);
187        (Self(n), overflowing)
188    }
189
190    #[inline]
191    fn backward_checked(start: Self, count: usize) -> Option<Self> {
192        u8::backward_checked(start.0, count).map(Self)
193    }
194
195    #[inline(always)]
196    fn backward_overflowing(start: Self, count: usize) -> (Self, bool) {
197        let (n, overflowing) = u8::backward_overflowing(start.0, count);
198        (Self(n), overflowing)
199    }
200}
201
202impl From<PiecePosition> for u16 {
203    #[inline]
204    fn from(original: PiecePosition) -> Self {
205        Self::from(original.0)
206    }
207}
208
209impl From<PiecePosition> for u32 {
210    #[inline]
211    fn from(original: PiecePosition) -> Self {
212        Self::from(original.0)
213    }
214}
215
216impl From<PiecePosition> for u64 {
217    #[inline]
218    fn from(original: PiecePosition) -> Self {
219        Self::from(original.0)
220    }
221}
222
223impl From<PiecePosition> for usize {
224    #[inline]
225    fn from(original: PiecePosition) -> Self {
226        usize::from(original.0)
227    }
228}
229
230/// Piece offset in a sector
231#[derive(
232    Debug,
233    Display,
234    Default,
235    Copy,
236    Clone,
237    Ord,
238    PartialOrd,
239    Eq,
240    PartialEq,
241    Hash,
242    From,
243    Into,
244    Add,
245    AddAssign,
246    Sub,
247    SubAssign,
248    Mul,
249    MulAssign,
250    Div,
251    DivAssign,
252    TrivialType,
253)]
254#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
255#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
256#[repr(C)]
257pub struct PieceOffset(u16);
258
259impl Step for PieceOffset {
260    #[inline]
261    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
262        u16::steps_between(&start.0, &end.0)
263    }
264
265    #[inline]
266    fn forward_checked(start: Self, count: usize) -> Option<Self> {
267        u16::forward_checked(start.0, count).map(Self)
268    }
269
270    #[inline(always)]
271    fn forward_overflowing(start: Self, count: usize) -> (Self, bool) {
272        let (n, overflowing) = u16::forward_overflowing(start.0, count);
273        (Self(n), overflowing)
274    }
275
276    #[inline]
277    fn backward_checked(start: Self, count: usize) -> Option<Self> {
278        u16::backward_checked(start.0, count).map(Self)
279    }
280
281    #[inline(always)]
282    fn backward_overflowing(start: Self, count: usize) -> (Self, bool) {
283        let (n, overflowing) = u16::backward_overflowing(start.0, count);
284        (Self(n), overflowing)
285    }
286}
287
288impl From<PieceOffset> for u32 {
289    #[inline]
290    fn from(original: PieceOffset) -> Self {
291        Self::from(original.0)
292    }
293}
294
295impl From<PieceOffset> for u64 {
296    #[inline]
297    fn from(original: PieceOffset) -> Self {
298        Self::from(original.0)
299    }
300}
301
302impl From<PieceOffset> for usize {
303    #[inline]
304    fn from(original: PieceOffset) -> Self {
305        usize::from(original.0)
306    }
307}
308
309impl PieceOffset {
310    /// Piece index 0
311    pub const ZERO: Self = Self(0);
312    /// Piece index 1
313    pub const ONE: Self = Self(1);
314    /// Size in bytes
315    pub const SIZE: usize = size_of::<u16>();
316
317    /// Convert piece offset to bytes
318    #[inline]
319    pub const fn to_bytes(self) -> [u8; Self::SIZE] {
320        self.0.to_le_bytes()
321    }
322}
323
324/// Chunk contained in a record
325#[derive(
326    Default,
327    Copy,
328    Clone,
329    Eq,
330    PartialEq,
331    Ord,
332    PartialOrd,
333    Hash,
334    From,
335    Into,
336    AsRef,
337    AsMut,
338    Deref,
339    DerefMut,
340    TrivialType,
341)]
342#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
343#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
344#[cfg_attr(feature = "serde", serde(transparent))]
345#[repr(C)]
346pub struct RecordChunk([u8; RecordChunk::SIZE]);
347
348impl fmt::Debug for RecordChunk {
349    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350        for byte in self.0 {
351            write!(f, "{byte:02x}")?;
352        }
353        Ok(())
354    }
355}
356
357impl RecordChunk {
358    /// Size of the chunk in bytes
359    pub const SIZE: usize = 32;
360
361    /// Convenient conversion from slice to underlying representation for efficiency purposes
362    #[inline]
363    pub fn slice_to_repr(value: &[Self]) -> &[[u8; Self::SIZE]] {
364        // SAFETY: `RecordChunk` is `#[repr(C)]` and guaranteed to have the same memory layout
365        unsafe { mem::transmute(value) }
366    }
367
368    /// Convenient conversion from slice of underlying representation for efficiency purposes
369    #[inline]
370    pub fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
371        // SAFETY: `RecordChunk` is `#[repr(C)]` and guaranteed to have the same memory layout
372        unsafe { mem::transmute(value) }
373    }
374
375    /// Convenient conversion from mutable slice to underlying representation for efficiency
376    /// purposes
377    #[inline]
378    pub fn slice_mut_to_repr(value: &mut [Self]) -> &mut [[u8; Self::SIZE]] {
379        // SAFETY: `RecordChunk` is `#[repr(C)]` and guaranteed to have the same memory layout
380        unsafe { mem::transmute(value) }
381    }
382
383    /// Convenient conversion from mutable slice of underlying representation for efficiency
384    /// purposes
385    #[inline]
386    pub fn slice_mut_from_repr(value: &mut [[u8; Self::SIZE]]) -> &mut [Self] {
387        // SAFETY: `RecordChunk` is `#[repr(C)]` and guaranteed to have the same memory layout
388        unsafe { mem::transmute(value) }
389    }
390}
391
392/// Record contained within a piece.
393///
394/// NOTE: This is a stack-allocated data structure and can cause stack overflow!
395#[derive(Copy, Clone, Eq, PartialEq, Deref, DerefMut, TrivialType)]
396#[repr(C)]
397pub struct Record([[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]);
398
399impl fmt::Debug for Record {
400    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
401        for byte in self.0.as_flattened() {
402            write!(f, "{byte:02x}")?;
403        }
404        Ok(())
405    }
406}
407
408impl AsRef<[u8]> for Record {
409    #[inline]
410    fn as_ref(&self) -> &[u8] {
411        self.0.as_flattened()
412    }
413}
414
415impl AsMut<[u8]> for Record {
416    #[inline]
417    fn as_mut(&mut self) -> &mut [u8] {
418        self.0.as_flattened_mut()
419    }
420}
421
422impl From<&Record> for &[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS] {
423    #[inline]
424    fn from(value: &Record) -> Self {
425        // SAFETY: `Record` is `#[repr(C)]` and guaranteed to have the same memory layout
426        unsafe { mem::transmute(value) }
427    }
428}
429
430impl From<&[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]> for &Record {
431    #[inline]
432    fn from(value: &[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]) -> Self {
433        // SAFETY: `Record` is `#[repr(C)]` and guaranteed to have the same memory layout
434        unsafe { mem::transmute(value) }
435    }
436}
437
438impl From<&mut Record> for &mut [[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS] {
439    #[inline]
440    fn from(value: &mut Record) -> Self {
441        // SAFETY: `Record` is `#[repr(C)]` and guaranteed to have the same memory layout
442        unsafe { mem::transmute(value) }
443    }
444}
445
446impl From<&mut [[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]> for &mut Record {
447    #[inline]
448    fn from(value: &mut [[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]) -> Self {
449        // SAFETY: `Record` is `#[repr(C)]` and guaranteed to have the same memory layout
450        unsafe { mem::transmute(value) }
451    }
452}
453
454impl Record {
455    /// Number of chunks within one record.
456    pub const NUM_CHUNKS: usize = 2usize.pow(15);
457    /// Number of s-buckets contained within one sector record.
458    ///
459    /// Essentially we chunk records and erasure code them.
460    pub const NUM_S_BUCKETS: usize = Record::NUM_CHUNKS
461        * RecordedHistorySegment::ERASURE_CODING_RATE.1
462        / RecordedHistorySegment::ERASURE_CODING_RATE.0;
463    /// Size of a segment record, it is guaranteed to be a multiple of [`RecordChunk::SIZE`]
464    pub const SIZE: usize = RecordChunk::SIZE * Record::NUM_CHUNKS;
465
466    /// Create boxed value without hitting stack overflow
467    #[inline]
468    #[cfg(feature = "alloc")]
469    pub fn new_boxed() -> Box<Self> {
470        // TODO: Should have been just `::new()`, but https://github.com/rust-lang/rust/issues/53827
471        // SAFETY: Data structure filled with zeroes is a valid invariant
472        unsafe { Box::new_zeroed().assume_init() }
473    }
474
475    /// Create vector filled with zeroed records without hitting stack overflow
476    #[inline]
477    #[cfg(feature = "alloc")]
478    pub fn new_zero_vec(length: usize) -> Vec<Self> {
479        // TODO: Should have been just `vec![Self::default(); length]`, but
480        //  https://github.com/rust-lang/rust/issues/53827
481        let mut records = Vec::with_capacity(length);
482        {
483            let slice = records.spare_capacity_mut();
484            // SAFETY: Same memory layout due to `#[repr(C)]` on `Record` and
485            // `MaybeUninit<[[T; M]; N]>` is guaranteed to have the same layout as
486            // `[[MaybeUninit<T>; M]; N]`
487            let slice = unsafe {
488                slice::from_raw_parts_mut(
489                    slice
490                        .as_mut_ptr()
491                        .cast::<[[MaybeUninit<u8>; RecordChunk::SIZE]; Record::NUM_CHUNKS]>(),
492                    length,
493                )
494            };
495            for byte in slice.as_flattened_mut().as_flattened_mut() {
496                byte.write(0);
497            }
498        }
499        // SAFETY: All values are initialized above.
500        unsafe {
501            records.set_len(records.capacity());
502        }
503
504        records
505    }
506
507    /// Convenient conversion from slice of record to underlying representation for efficiency
508    /// purposes.
509    #[inline(always)]
510    pub fn slice_to_repr(value: &[Self]) -> &[[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]] {
511        // SAFETY: `Record` is `#[repr(C)]` and guaranteed to have the same memory layout
512        unsafe { mem::transmute(value) }
513    }
514
515    /// Convenient conversion from slice of underlying representation to record for efficiency
516    /// purposes.
517    #[inline(always)]
518    pub fn slice_from_repr(value: &[[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]]) -> &[Self] {
519        // SAFETY: `Record` is `#[repr(C)]` and guaranteed to have the same memory layout
520        unsafe { mem::transmute(value) }
521    }
522
523    /// Convenient conversion from mutable slice of record to underlying representation for
524    /// efficiency purposes.
525    #[inline(always)]
526    pub fn slice_mut_to_repr(
527        value: &mut [Self],
528    ) -> &mut [[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]] {
529        // SAFETY: `Record` is `#[repr(C)]` and guaranteed to have the same memory layout
530        unsafe { mem::transmute(value) }
531    }
532
533    /// Convenient conversion from mutable slice of underlying representation to record for
534    /// efficiency purposes.
535    #[inline(always)]
536    pub fn slice_mut_from_repr(
537        value: &mut [[[u8; RecordChunk::SIZE]; Record::NUM_CHUNKS]],
538    ) -> &mut [Self] {
539        // SAFETY: `Record` is `#[repr(C)]` and guaranteed to have the same memory layout
540        unsafe { mem::transmute(value) }
541    }
542
543    /// Derive source chunks root on-demand
544    #[inline(always)]
545    pub fn source_chunks_root(&self) -> RecordChunksRoot {
546        RecordChunksRoot(BalancedMerkleTree::compute_root_only(self))
547    }
548}
549
550/// Root of the record contained within a piece.
551///
552/// This is a Merkle Tree root of the roots of source and parity record chunks.
553#[derive(Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, From, Into, TrivialType)]
554#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
555#[repr(C)]
556pub struct RecordRoot([u8; RecordRoot::SIZE]);
557
558impl fmt::Debug for RecordRoot {
559    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
560        for byte in self.0 {
561            write!(f, "{byte:02x}")?;
562        }
563        Ok(())
564    }
565}
566
567#[cfg(feature = "serde")]
568#[derive(Serialize, Deserialize)]
569#[serde(transparent)]
570struct RecordRootBinary(#[serde(with = "BigArray")] [u8; RecordRoot::SIZE]);
571
572#[cfg(feature = "serde")]
573#[derive(Serialize, Deserialize)]
574#[serde(transparent)]
575struct RecordRootHex(#[serde(with = "hex")] [u8; RecordRoot::SIZE]);
576
577#[cfg(feature = "serde")]
578impl Serialize for RecordRoot {
579    #[inline]
580    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
581    where
582        S: Serializer,
583    {
584        if serializer.is_human_readable() {
585            RecordRootHex(self.0).serialize(serializer)
586        } else {
587            RecordRootBinary(self.0).serialize(serializer)
588        }
589    }
590}
591
592#[cfg(feature = "serde")]
593impl<'de> Deserialize<'de> for RecordRoot {
594    #[inline]
595    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
596    where
597        D: Deserializer<'de>,
598    {
599        Ok(Self(if deserializer.is_human_readable() {
600            RecordRootHex::deserialize(deserializer)?.0
601        } else {
602            RecordRootBinary::deserialize(deserializer)?.0
603        }))
604    }
605}
606
607impl Default for RecordRoot {
608    #[inline]
609    fn default() -> Self {
610        Self([0; _])
611    }
612}
613
614impl TryFrom<&[u8]> for RecordRoot {
615    type Error = TryFromSliceError;
616
617    #[inline]
618    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
619        <[u8; Self::SIZE]>::try_from(slice).map(Self)
620    }
621}
622
623impl AsRef<[u8]> for RecordRoot {
624    #[inline]
625    fn as_ref(&self) -> &[u8] {
626        &self.0
627    }
628}
629
630impl AsMut<[u8]> for RecordRoot {
631    #[inline]
632    fn as_mut(&mut self) -> &mut [u8] {
633        &mut self.0
634    }
635}
636
637impl From<&RecordRoot> for &[u8; RecordRoot::SIZE] {
638    #[inline]
639    fn from(value: &RecordRoot) -> Self {
640        // SAFETY: `RecordRoot` is `#[repr(C)]` and guaranteed to have the same
641        // memory layout
642        unsafe { mem::transmute(value) }
643    }
644}
645
646impl From<&[u8; RecordRoot::SIZE]> for &RecordRoot {
647    #[inline]
648    fn from(value: &[u8; RecordRoot::SIZE]) -> Self {
649        // SAFETY: `RecordRoot` is `#[repr(C)]` and guaranteed to have the same
650        // memory layout
651        unsafe { mem::transmute(value) }
652    }
653}
654
655impl From<&mut RecordRoot> for &mut [u8; RecordRoot::SIZE] {
656    #[inline]
657    fn from(value: &mut RecordRoot) -> Self {
658        // SAFETY: `RecordRoot` is `#[repr(C)]` and guaranteed to have the same
659        // memory layout
660        unsafe { mem::transmute(value) }
661    }
662}
663
664impl From<&mut [u8; RecordRoot::SIZE]> for &mut RecordRoot {
665    #[inline]
666    fn from(value: &mut [u8; RecordRoot::SIZE]) -> Self {
667        // SAFETY: `RecordRoot` is `#[repr(C)]` and guaranteed to have the same
668        // memory layout
669        unsafe { mem::transmute(value) }
670    }
671}
672
673impl RecordRoot {
674    /// Size of record root in bytes.
675    pub const SIZE: usize = 32;
676
677    /// Validate record root hash produced by the archiver
678    pub fn is_valid(
679        &self,
680        segment_root: &SegmentRoot,
681        record_proof: &RecordProof,
682        position: PiecePosition,
683    ) -> bool {
684        BalancedMerkleTree::<{ RecordedHistorySegment::NUM_PIECES }>::verify(
685            segment_root,
686            record_proof,
687            usize::from(position),
688            self.0,
689        )
690    }
691}
692
693/// Root of source or parity record chunks
694#[derive(Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, From, Into, TrivialType)]
695#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
696#[repr(C)]
697pub struct RecordChunksRoot([u8; RecordChunksRoot::SIZE]);
698
699impl fmt::Debug for RecordChunksRoot {
700    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
701        for byte in self.0 {
702            write!(f, "{byte:02x}")?;
703        }
704        Ok(())
705    }
706}
707
708#[cfg(feature = "serde")]
709#[derive(Serialize, Deserialize)]
710#[serde(transparent)]
711struct RecordChunksRootBinary(#[serde(with = "BigArray")] [u8; RecordChunksRoot::SIZE]);
712
713#[cfg(feature = "serde")]
714#[derive(Serialize, Deserialize)]
715#[serde(transparent)]
716struct RecordChunksRootHex(#[serde(with = "hex")] [u8; RecordChunksRoot::SIZE]);
717
718#[cfg(feature = "serde")]
719impl Serialize for RecordChunksRoot {
720    #[inline]
721    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
722    where
723        S: Serializer,
724    {
725        if serializer.is_human_readable() {
726            RecordChunksRootHex(self.0).serialize(serializer)
727        } else {
728            RecordChunksRootBinary(self.0).serialize(serializer)
729        }
730    }
731}
732
733#[cfg(feature = "serde")]
734impl<'de> Deserialize<'de> for RecordChunksRoot {
735    #[inline]
736    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
737    where
738        D: Deserializer<'de>,
739    {
740        Ok(Self(if deserializer.is_human_readable() {
741            RecordChunksRootHex::deserialize(deserializer)?.0
742        } else {
743            RecordChunksRootBinary::deserialize(deserializer)?.0
744        }))
745    }
746}
747
748impl Default for RecordChunksRoot {
749    #[inline]
750    fn default() -> Self {
751        Self([0; _])
752    }
753}
754
755impl TryFrom<&[u8]> for RecordChunksRoot {
756    type Error = TryFromSliceError;
757
758    #[inline]
759    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
760        <[u8; Self::SIZE]>::try_from(slice).map(Self)
761    }
762}
763
764impl AsRef<[u8]> for RecordChunksRoot {
765    #[inline]
766    fn as_ref(&self) -> &[u8] {
767        &self.0
768    }
769}
770
771impl AsMut<[u8]> for RecordChunksRoot {
772    #[inline]
773    fn as_mut(&mut self) -> &mut [u8] {
774        &mut self.0
775    }
776}
777
778impl From<&RecordChunksRoot> for &[u8; RecordChunksRoot::SIZE] {
779    #[inline]
780    fn from(value: &RecordChunksRoot) -> Self {
781        // SAFETY: `RecordChunksRoot` is `#[repr(C)]` and guaranteed to have the same
782        // memory layout
783        unsafe { mem::transmute(value) }
784    }
785}
786
787impl From<&[u8; RecordChunksRoot::SIZE]> for &RecordChunksRoot {
788    #[inline]
789    fn from(value: &[u8; RecordChunksRoot::SIZE]) -> Self {
790        // SAFETY: `RecordChunksRoot` is `#[repr(C)]` and guaranteed to have the same
791        // memory layout
792        unsafe { mem::transmute(value) }
793    }
794}
795
796impl From<&mut RecordChunksRoot> for &mut [u8; RecordChunksRoot::SIZE] {
797    #[inline]
798    fn from(value: &mut RecordChunksRoot) -> Self {
799        // SAFETY: `RecordChunksRoot` is `#[repr(C)]` and guaranteed to have the same
800        // memory layout
801        unsafe { mem::transmute(value) }
802    }
803}
804
805impl From<&mut [u8; RecordChunksRoot::SIZE]> for &mut RecordChunksRoot {
806    #[inline]
807    fn from(value: &mut [u8; RecordChunksRoot::SIZE]) -> Self {
808        // SAFETY: `RecordChunksRoot` is `#[repr(C)]` and guaranteed to have the same
809        // memory layout
810        unsafe { mem::transmute(value) }
811    }
812}
813
814impl RecordChunksRoot {
815    /// Size of record chunks root in bytes.
816    pub const SIZE: usize = 32;
817}
818
819/// Proof that the record (root) belongs to a segment
820#[derive(Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, From, Into, TrivialType)]
821#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
822#[repr(C)]
823pub struct RecordProof([[u8; OUT_LEN]; RecordProof::NUM_HASHES]);
824
825impl fmt::Debug for RecordProof {
826    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
827        write!(f, "[")?;
828        for hash in self.0 {
829            for byte in hash {
830                write!(f, "{byte:02x}")?;
831            }
832            write!(f, ", ")?;
833        }
834        write!(f, "]")?;
835        Ok(())
836    }
837}
838
839#[cfg(feature = "serde")]
840#[derive(Serialize, Deserialize)]
841#[serde(transparent)]
842struct RecordProofBinary([[u8; OUT_LEN]; RecordProof::NUM_HASHES]);
843
844#[cfg(feature = "serde")]
845#[derive(Serialize, Deserialize)]
846#[serde(transparent)]
847struct RecordProofHexHash(#[serde(with = "hex")] [u8; OUT_LEN]);
848
849#[cfg(feature = "serde")]
850#[derive(Serialize, Deserialize)]
851#[serde(transparent)]
852struct RecordProofHex([RecordProofHexHash; RecordProof::NUM_HASHES]);
853
854#[cfg(feature = "serde")]
855impl Serialize for RecordProof {
856    #[inline]
857    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
858    where
859        S: Serializer,
860    {
861        if serializer.is_human_readable() {
862            // SAFETY: `RecordProofHexHash` is `#[repr(C)]` and guaranteed to have the
863            // same memory layout
864            RecordProofHex(unsafe {
865                mem::transmute::<
866                    [[u8; OUT_LEN]; Self::NUM_HASHES],
867                    [RecordProofHexHash; Self::NUM_HASHES],
868                >(self.0)
869            })
870            .serialize(serializer)
871        } else {
872            RecordProofBinary(self.0).serialize(serializer)
873        }
874    }
875}
876
877#[cfg(feature = "serde")]
878impl<'de> Deserialize<'de> for RecordProof {
879    #[inline]
880    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
881    where
882        D: Deserializer<'de>,
883    {
884        Ok(Self(if deserializer.is_human_readable() {
885            // SAFETY: `RecordProofHexHash` is `#[repr(C)]` and guaranteed to have the
886            // same memory layout
887            unsafe {
888                mem::transmute::<
889                    [RecordProofHexHash; Self::NUM_HASHES],
890                    [[u8; OUT_LEN]; Self::NUM_HASHES],
891                >(RecordProofHex::deserialize(deserializer)?.0)
892            }
893        } else {
894            RecordProofBinary::deserialize(deserializer)?.0
895        }))
896    }
897}
898
899impl Default for RecordProof {
900    #[inline]
901    fn default() -> Self {
902        Self([[0; OUT_LEN]; _])
903    }
904}
905
906impl AsRef<[u8]> for RecordProof {
907    #[inline]
908    fn as_ref(&self) -> &[u8] {
909        self.0.as_flattened()
910    }
911}
912
913impl AsMut<[u8]> for RecordProof {
914    #[inline]
915    fn as_mut(&mut self) -> &mut [u8] {
916        self.0.as_flattened_mut()
917    }
918}
919
920impl From<&RecordProof> for &[u8; RecordProof::SIZE] {
921    #[inline]
922    fn from(value: &RecordProof) -> Self {
923        // SAFETY: `RecordProof` is `#[repr(C)]` and guaranteed to have the same
924        // memory layout
925        unsafe { mem::transmute(value) }
926    }
927}
928
929impl From<&[u8; RecordProof::SIZE]> for &RecordProof {
930    #[inline]
931    fn from(value: &[u8; RecordProof::SIZE]) -> Self {
932        // SAFETY: `RecordProof` is `#[repr(C)]` and guaranteed to have the same
933        // memory layout
934        unsafe { mem::transmute(value) }
935    }
936}
937
938impl From<&mut RecordProof> for &mut [u8; RecordProof::SIZE] {
939    #[inline]
940    fn from(value: &mut RecordProof) -> Self {
941        // SAFETY: `RecordProof` is `#[repr(C)]` and guaranteed to have the same
942        // memory layout
943        unsafe { mem::transmute(value) }
944    }
945}
946
947impl From<&mut [u8; RecordProof::SIZE]> for &mut RecordProof {
948    #[inline]
949    fn from(value: &mut [u8; RecordProof::SIZE]) -> Self {
950        // SAFETY: `RecordProof` is `#[repr(C)]` and guaranteed to have the same
951        // memory layout
952        unsafe { mem::transmute(value) }
953    }
954}
955
956impl RecordProof {
957    /// Size of record proof in bytes
958    pub const SIZE: usize = OUT_LEN * Self::NUM_HASHES;
959    const NUM_HASHES: usize = RecordedHistorySegment::NUM_PIECES.ilog2() as usize;
960}
961
962/// Proof that the segment belongs to a super segment
963#[derive(Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, From, Into, TrivialType)]
964#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
965#[repr(C)]
966pub struct SegmentProof([[u8; OUT_LEN]; SegmentProof::NUM_HASHES]);
967
968impl fmt::Debug for SegmentProof {
969    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
970        write!(f, "[")?;
971        for hash in self.0 {
972            for byte in hash {
973                write!(f, "{byte:02x}")?;
974            }
975            write!(f, ", ")?;
976        }
977        write!(f, "]")?;
978        Ok(())
979    }
980}
981
982#[cfg(feature = "serde")]
983#[derive(Serialize, Deserialize)]
984#[serde(transparent)]
985struct SegmentProofBinary([[u8; OUT_LEN]; SegmentProof::NUM_HASHES]);
986
987#[cfg(feature = "serde")]
988#[derive(Serialize, Deserialize)]
989#[serde(transparent)]
990struct SegmentProofHexHash(#[serde(with = "hex")] [u8; OUT_LEN]);
991
992#[cfg(feature = "serde")]
993#[derive(Serialize, Deserialize)]
994#[serde(transparent)]
995struct SegmentProofHex([SegmentProofHexHash; SegmentProof::NUM_HASHES]);
996
997#[cfg(feature = "serde")]
998impl Serialize for SegmentProof {
999    #[inline]
1000    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1001    where
1002        S: Serializer,
1003    {
1004        if serializer.is_human_readable() {
1005            // SAFETY: `SegmentProofHexHash` is `#[repr(C)]` and guaranteed to have the
1006            // same memory layout
1007            SegmentProofHex(unsafe {
1008                mem::transmute::<
1009                    [[u8; OUT_LEN]; Self::NUM_HASHES],
1010                    [SegmentProofHexHash; Self::NUM_HASHES],
1011                >(self.0)
1012            })
1013            .serialize(serializer)
1014        } else {
1015            SegmentProofBinary(self.0).serialize(serializer)
1016        }
1017    }
1018}
1019
1020#[cfg(feature = "serde")]
1021impl<'de> Deserialize<'de> for SegmentProof {
1022    #[inline]
1023    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1024    where
1025        D: Deserializer<'de>,
1026    {
1027        Ok(Self(if deserializer.is_human_readable() {
1028            // SAFETY: `SegmentProofHexHash` is `#[repr(C)]` and guaranteed to have the
1029            // same memory layout
1030            unsafe {
1031                mem::transmute::<
1032                    [SegmentProofHexHash; Self::NUM_HASHES],
1033                    [[u8; OUT_LEN]; Self::NUM_HASHES],
1034                >(SegmentProofHex::deserialize(deserializer)?.0)
1035            }
1036        } else {
1037            SegmentProofBinary::deserialize(deserializer)?.0
1038        }))
1039    }
1040}
1041
1042impl Default for SegmentProof {
1043    #[inline]
1044    fn default() -> Self {
1045        Self([[0; OUT_LEN]; _])
1046    }
1047}
1048
1049impl AsRef<[u8]> for SegmentProof {
1050    #[inline]
1051    fn as_ref(&self) -> &[u8] {
1052        self.0.as_flattened()
1053    }
1054}
1055
1056impl AsMut<[u8]> for SegmentProof {
1057    #[inline]
1058    fn as_mut(&mut self) -> &mut [u8] {
1059        self.0.as_flattened_mut()
1060    }
1061}
1062
1063impl From<&SegmentProof> for &[u8; SegmentProof::SIZE] {
1064    #[inline]
1065    fn from(value: &SegmentProof) -> Self {
1066        // SAFETY: `SegmentProof` is `#[repr(C)]` and guaranteed to have the same
1067        // memory layout
1068        unsafe { mem::transmute(value) }
1069    }
1070}
1071
1072impl From<&[u8; SegmentProof::SIZE]> for &SegmentProof {
1073    #[inline]
1074    fn from(value: &[u8; SegmentProof::SIZE]) -> Self {
1075        // SAFETY: `SegmentProof` is `#[repr(C)]` and guaranteed to have the same
1076        // memory layout
1077        unsafe { mem::transmute(value) }
1078    }
1079}
1080
1081impl From<&mut SegmentProof> for &mut [u8; SegmentProof::SIZE] {
1082    #[inline]
1083    fn from(value: &mut SegmentProof) -> Self {
1084        // SAFETY: `SegmentProof` is `#[repr(C)]` and guaranteed to have the same
1085        // memory layout
1086        unsafe { mem::transmute(value) }
1087    }
1088}
1089
1090impl From<&mut [u8; SegmentProof::SIZE]> for &mut SegmentProof {
1091    #[inline]
1092    fn from(value: &mut [u8; SegmentProof::SIZE]) -> Self {
1093        // SAFETY: `SegmentProof` is `#[repr(C)]` and guaranteed to have the same
1094        // memory layout
1095        unsafe { mem::transmute(value) }
1096    }
1097}
1098
1099impl SegmentProof {
1100    /// Size of segment proof in bytes
1101    pub const SIZE: usize = OUT_LEN * Self::NUM_HASHES;
1102    const NUM_HASHES: usize = SuperSegmentRoot::MAX_SEGMENTS.next_power_of_two().ilog2() as usize;
1103
1104    /// Returns a mutable reference to an internal array as uninitialized memory.
1105    ///
1106    /// This is a convenience method for proof generation.
1107    pub fn as_uninit_repr(
1108        &mut self,
1109    ) -> &mut [MaybeUninit<[u8; OUT_LEN]>; SegmentProof::NUM_HASHES] {
1110        // SAFETY: Casting initialized memory into uninitialized memory of the same size is safe
1111        unsafe { mem::transmute(&mut self.0) }
1112    }
1113}
1114
1115/// Header for a piece of archival history.
1116///
1117/// Primarily contains information needed for piece verification.
1118#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, TrivialType)]
1119#[cfg_attr(feature = "scale-codec", derive(Encode, Decode))]
1120#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1121#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1122#[repr(C)]
1123pub struct PieceHeader {
1124    /// Shard index
1125    pub shard_index: Unaligned<ShardIndex>,
1126    /// Local segment index
1127    pub local_segment_index: Unaligned<LocalSegmentIndex>,
1128    /// Super segment index
1129    pub super_segment_index: Unaligned<SuperSegmentIndex>,
1130    /// Position of the segment in the super segment
1131    pub segment_position: Unaligned<SegmentPosition>,
1132    /// Segment root
1133    pub segment_root: SegmentRoot,
1134    /// Segment proof
1135    pub segment_proof: SegmentProof,
1136    /// Root of parity record chunks.
1137    ///
1138    /// Technically redundant, but helps to avoid repeating erasure coding during verification.
1139    pub parity_chunks_root: RecordChunksRoot,
1140    /// Proof that the record (root) belongs to a segment
1141    pub record_proof: RecordProof,
1142}
1143
1144const {
1145    // Must have minimal alignment for various conversions to/from bytes
1146    assert!(align_of::<PieceHeader>() == 1);
1147}
1148
1149/// A piece of archival history.
1150///
1151/// This version is allocated on the stack, for a heap-allocated piece that can be moved around
1152/// efficiently, see [`Piece`].
1153///
1154/// Internally, a piece contains a record, supplementary record chunk root, and a proof proving this
1155/// piece belongs to can be used to verify that a piece belongs to the actual archival history of
1156/// the blockchain.
1157#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
1158#[repr(C)]
1159pub struct InnerPiece {
1160    /// Piece header
1161    pub header: PieceHeader,
1162    /// Record contained within a piece
1163    pub record: Record,
1164}
1165
1166const {
1167    // Must have minimal alignment for various conversions to/from bytes
1168    assert!(align_of::<InnerPiece>() == 1);
1169}
1170
1171impl InnerPiece {
1172    /// Size of a piece (in bytes)
1173    pub const SIZE: usize = size_of::<Self>();
1174
1175    /// Create boxed value without hitting stack overflow
1176    #[inline]
1177    #[cfg(feature = "alloc")]
1178    pub fn new_boxed() -> Box<Self> {
1179        // TODO: Should have been just `::new()`, but https://github.com/rust-lang/rust/issues/53827
1180        // SAFETY: Data structure filled with zeroes is a valid invariant
1181        unsafe { Box::<Self>::new_zeroed().assume_init() }
1182    }
1183
1184    /// Check whether the piece is valid against the matching super segment root
1185    pub fn is_valid(
1186        &self,
1187        super_segment_root: &SuperSegmentRoot,
1188        num_segments: u32,
1189        position: PiecePosition,
1190    ) -> bool {
1191        if !self.header.segment_root.is_valid(
1192            self.header.shard_index.as_inner(),
1193            self.header.local_segment_index.as_inner(),
1194            self.header.segment_position.as_inner(),
1195            &self.header.segment_proof,
1196            num_segments,
1197            super_segment_root,
1198        ) {
1199            return false;
1200        }
1201        self.record_root().is_valid(
1202            &self.header.segment_root,
1203            &self.header.record_proof,
1204            position,
1205        )
1206    }
1207
1208    /// Root of the record contained within a piece.
1209    ///
1210    /// It is re-derived on every call of this function.
1211    #[inline]
1212    pub fn record_root(&self) -> RecordRoot {
1213        let record_merkle_tree_root = BalancedMerkleTree::compute_root_only(&[
1214            *self.record.source_chunks_root(),
1215            *self.header.parity_chunks_root,
1216        ]);
1217
1218        RecordRoot::from(record_merkle_tree_root)
1219    }
1220
1221    /// Convenient conversion from slice of piece array to underlying representation for efficiency
1222    /// purposes.
1223    #[inline]
1224    pub fn slice_to_repr(value: &[Self]) -> &[[u8; Self::SIZE]] {
1225        // SAFETY: `PieceArray` is `#[repr(C)]` and guaranteed to have the same memory
1226        // layout
1227        unsafe { mem::transmute(value) }
1228    }
1229
1230    /// Convenient conversion from slice of underlying representation to piece array for efficiency
1231    /// purposes.
1232    #[inline]
1233    pub fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
1234        // SAFETY: `PieceArray` is `#[repr(C)]` and guaranteed to have the same memory
1235        // layout
1236        unsafe { mem::transmute(value) }
1237    }
1238
1239    /// Convenient conversion from mutable slice of piece array to underlying representation for
1240    /// efficiency purposes.
1241    #[inline]
1242    pub fn slice_mut_to_repr(value: &mut [Self]) -> &mut [[u8; Self::SIZE]] {
1243        // SAFETY: `PieceArray` is `#[repr(C)]` and guaranteed to have the same memory
1244        // layout
1245        unsafe { mem::transmute(value) }
1246    }
1247
1248    /// Convenient conversion from mutable slice of underlying representation to piece array for
1249    /// efficiency purposes.
1250    #[inline]
1251    pub fn slice_mut_from_repr(value: &mut [[u8; Self::SIZE]]) -> &mut [Self] {
1252        // SAFETY: `PieceArray` is `#[repr(C)]` and guaranteed to have the same memory
1253        // layout
1254        unsafe { mem::transmute(value) }
1255    }
1256}