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