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