cloud_mmr/pmmr/
segment.rs

1// Copyright 2021 The Grin Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Segment of a PMMR.
16
17use crate::hash::Hash;
18use crate::pmmr::{self, Backend, ReadablePMMR, ReadonlyPMMR};
19use crate::ser::{Error, PMMRIndexHashable, PMMRable, Readable, Reader, Writeable, Writer};
20use croaring::Bitmap;
21use std::cmp::min;
22use std::fmt::Debug;
23
24#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
25/// Error related to segment creation or validation
26pub enum SegmentError {
27    /// An expected leaf was missing
28    #[error("Missing leaf at pos {0}")]
29    MissingLeaf(u64),
30    /// An expected hash was missing
31    #[error("Missing hash at pos {0}")]
32    MissingHash(u64),
33    /// The segment does not exist
34    #[error("Segment does not exist")]
35    NonExistent,
36    /// Mismatch between expected and actual root hash
37    #[error("Root hash mismatch")]
38    Mismatch,
39}
40
41/// Tuple that defines a segment of a given PMMR
42#[derive(Copy, Clone, Debug, Eq, PartialEq)]
43pub struct SegmentIdentifier {
44    /// Height of a segment
45    pub height: u8,
46    /// Zero-based index of the segment
47    pub idx: u64,
48}
49
50impl Readable for SegmentIdentifier {
51    fn read<R: Reader>(reader: &mut R) -> Result<Self, Error> {
52        let height = reader.read_u8()?;
53        let idx = reader.read_u64()?;
54        Ok(Self { height, idx })
55    }
56}
57
58impl Writeable for SegmentIdentifier {
59    fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
60        writer.write_u8(self.height)?;
61        writer.write_u64(self.idx)
62    }
63}
64
65impl SegmentIdentifier {
66    /// Test helper to get an iterator of SegmentIdentifiers required to read a
67    /// pmmr of size `target_mmr_size` in segments of height `segment_height`
68    pub fn traversal_iter(
69        target_mmr_size: u64,
70        segment_height: u8,
71    ) -> impl Iterator<Item = SegmentIdentifier> {
72        (0..SegmentIdentifier::count_segments_required(target_mmr_size, segment_height)).map(
73            move |idx| SegmentIdentifier {
74                height: segment_height,
75                idx: idx as u64,
76            },
77        )
78    }
79
80    /// Returns number of segments required that would needed in order to read a
81    /// pmmr of size `target_mmr_size` in segments of height `segment_height`
82    pub fn count_segments_required(target_mmr_size: u64, segment_height: u8) -> usize {
83        let d = 1 << segment_height;
84        ((pmmr::n_leaves(target_mmr_size) + d - 1) / d) as usize
85    }
86}
87
88/// Segment of a PMMR: unpruned leaves and the necessary data to verify
89/// segment membership in the original MMR.
90#[derive(Clone, Debug, Eq, PartialEq)]
91pub struct Segment<T> {
92    identifier: SegmentIdentifier,
93    hash_pos: Vec<u64>,
94    hashes: Vec<Hash>,
95    leaf_pos: Vec<u64>,
96    leaf_data: Vec<T>,
97    proof: SegmentProof,
98}
99
100impl<T> Segment<T> {
101    /// Creates an empty segment
102    fn empty(identifier: SegmentIdentifier) -> Self {
103        Segment {
104            identifier,
105            hash_pos: Vec::new(),
106            hashes: Vec::new(),
107            leaf_pos: Vec::new(),
108            leaf_data: Vec::new(),
109            proof: SegmentProof::empty(),
110        }
111    }
112
113    /// Maximum number of leaves in a segment, given by `2**height`
114    fn segment_capacity(&self) -> u64 {
115        1 << self.identifier.height
116    }
117
118    /// Offset (in leaf idx) of first leaf in the segment
119    fn leaf_offset(&self) -> u64 {
120        self.identifier.idx * self.segment_capacity()
121    }
122
123    // Number of leaves in this segment. Equal to capacity except for the final segment, which can be smaller
124    fn segment_unpruned_size(&self, mmr_size: u64) -> u64 {
125        min(
126            self.segment_capacity(),
127            pmmr::n_leaves(mmr_size).saturating_sub(self.leaf_offset()),
128        )
129    }
130
131    /// Whether the segment is full (segment size == capacity)
132    fn full_segment(&self, mmr_size: u64) -> bool {
133        self.segment_unpruned_size(mmr_size) == self.segment_capacity()
134    }
135
136    /// Inclusive range of MMR positions for this segment
137    pub fn segment_pos_range(&self, mmr_size: u64) -> (u64, u64) {
138        let segment_size = self.segment_unpruned_size(mmr_size);
139        let leaf_offset = self.leaf_offset();
140        let first = pmmr::insertion_to_pmmr_index(leaf_offset);
141        let last = if self.full_segment(mmr_size) {
142            pmmr::insertion_to_pmmr_index(leaf_offset + segment_size - 1)
143                + (self.identifier.height as u64)
144        } else {
145            mmr_size - 1
146        };
147        (first, last)
148    }
149
150    /// TODO - binary_search_by_key() here (can we assume these are sorted by pos?)
151    fn get_hash(&self, pos0: u64) -> Result<Hash, SegmentError> {
152        self.hash_pos
153            .iter()
154            .zip(&self.hashes)
155            .find(|&(&p, _)| p == pos0)
156            .map(|(_, &h)| h)
157            .ok_or_else(|| SegmentError::MissingHash(pos0))
158    }
159
160    /// Get the identifier associated with this segment
161    pub fn identifier(&self) -> SegmentIdentifier {
162        self.identifier
163    }
164
165    /// Consume the segment and return its parts
166    pub fn parts(
167        self,
168    ) -> (
169        SegmentIdentifier,
170        Vec<u64>,
171        Vec<Hash>,
172        Vec<u64>,
173        Vec<T>,
174        SegmentProof,
175    ) {
176        (
177            self.identifier,
178            self.hash_pos,
179            self.hashes,
180            self.leaf_pos,
181            self.leaf_data,
182            self.proof,
183        )
184    }
185
186    /// Construct a segment from its parts
187    pub fn from_parts(
188        identifier: SegmentIdentifier,
189        hash_pos: Vec<u64>,
190        hashes: Vec<Hash>,
191        leaf_pos: Vec<u64>,
192        leaf_data: Vec<T>,
193        proof: SegmentProof,
194    ) -> Self {
195        assert_eq!(hash_pos.len(), hashes.len());
196        let mut last = 0;
197        for &pos in &hash_pos {
198            assert!(last == 0 || pos > last);
199            last = pos;
200        }
201        assert_eq!(leaf_pos.len(), leaf_data.len());
202        last = 0;
203        for &pos in &leaf_pos {
204            assert!(last == 0 || pos > last);
205            last = pos;
206        }
207
208        Self {
209            identifier,
210            hash_pos,
211            hashes,
212            leaf_pos,
213            leaf_data,
214            proof,
215        }
216    }
217
218    /// Iterator of all the leaves in the segment
219    pub fn leaf_iter(&self) -> impl Iterator<Item = (u64, &T)> + '_ {
220        self.leaf_pos.iter().map(|&p| p).zip(&self.leaf_data)
221    }
222
223    /// Iterator of all the hashes in the segment
224    pub fn hash_iter(&self) -> impl Iterator<Item = (u64, Hash)> + '_ {
225        self.hash_pos
226            .iter()
227            .zip(&self.hashes)
228            .map(|(&p, &h)| (p, h))
229    }
230
231    /// Segment proof
232    pub fn proof(&self) -> &SegmentProof {
233        &self.proof
234    }
235
236    /// Segment identifier
237    pub fn id(&self) -> SegmentIdentifier {
238        self.identifier
239    }
240}
241
242impl<T> Segment<T>
243where
244    T: Readable + Writeable + Debug,
245{
246    /// Generate a segment from a PMMR
247    pub fn from_pmmr<U, B>(
248        segment_id: SegmentIdentifier,
249        pmmr: &ReadonlyPMMR<'_, U, B>,
250        prunable: bool,
251    ) -> Result<Self, SegmentError>
252    where
253        U: PMMRable<E = T>,
254        B: Backend<U>,
255    {
256        let mut segment = Segment::empty(segment_id);
257
258        let mmr_size = pmmr.unpruned_size();
259        if segment.segment_unpruned_size(mmr_size) == 0 {
260            return Err(SegmentError::NonExistent);
261        }
262
263        // Fill leaf data and hashes
264        let (segment_first_pos, segment_last_pos) = segment.segment_pos_range(mmr_size);
265        for pos0 in segment_first_pos..=segment_last_pos {
266            if pmmr::is_leaf(pos0) {
267                if let Some(data) = pmmr.get_data_from_file(pos0) {
268                    segment.leaf_data.push(data);
269                    segment.leaf_pos.push(pos0);
270                    continue;
271                } else if !prunable {
272                    return Err(SegmentError::MissingLeaf(pos0));
273                }
274            }
275            // TODO: optimize, no need to send every intermediary hash
276            if prunable {
277                if let Some(hash) = pmmr.get_from_file(pos0) {
278                    segment.hashes.push(hash);
279                    segment.hash_pos.push(pos0);
280                }
281            }
282        }
283
284        let mut start_pos = None;
285        // Fully pruned segment: only include a single hash, the first unpruned parent
286        if segment.leaf_data.is_empty() && segment.hashes.is_empty() {
287            let family_branch = pmmr::family_branch(segment_last_pos, mmr_size);
288            for (pos0, _) in family_branch {
289                if let Some(hash) = pmmr.get_from_file(pos0) {
290                    segment.hashes.push(hash);
291                    segment.hash_pos.push(pos0);
292                    start_pos = Some(1 + pos0);
293                    break;
294                }
295            }
296        }
297
298        // Segment merkle proof
299        segment.proof = SegmentProof::generate(
300            pmmr,
301            mmr_size,
302            1 + segment_first_pos,
303            1 + segment_last_pos,
304            start_pos,
305        )?;
306
307        Ok(segment)
308    }
309}
310
311impl<T> Segment<T>
312where
313    T: PMMRIndexHashable,
314{
315    /// Calculate root hash of this segment
316    /// Returns `None` iff the segment is full and completely pruned
317    pub fn root(
318        &self,
319        mmr_size: u64,
320        bitmap: Option<&Bitmap>,
321    ) -> Result<Option<Hash>, SegmentError> {
322        let (segment_first_pos, segment_last_pos) = self.segment_pos_range(mmr_size);
323        let mut hashes = Vec::<Option<Hash>>::with_capacity(2 * (self.identifier.height as usize));
324        let mut leaves0 = self.leaf_pos.iter().zip(&self.leaf_data);
325        for pos0 in segment_first_pos..=segment_last_pos {
326            let height = pmmr::bintree_postorder_height(pos0);
327            let hash = if height == 0 {
328                // Leaf
329                if bitmap
330                    .map(|b| {
331                        let idx_1 = pmmr::n_leaves(pos0 + 1) - 1;
332                        let idx_2 = if pmmr::is_left_sibling(pos0) {
333                            idx_1 + 1
334                        } else {
335                            idx_1 - 1
336                        };
337                        b.contains(idx_1 as u32) || b.contains(idx_2 as u32) || pos0 == mmr_size - 1
338                    })
339                    .unwrap_or(true)
340                {
341                    // We require the data of this leaf if either the mmr is not prunable or if
342                    //  the bitmap indicates it (or its sibling) should be here.
343                    // Edge case: if the final segment has an uneven number of leaves, we
344                    //  require the last leaf to be present regardless of the status in the bitmap.
345                    // TODO: possibly remove requirement on the sibling when we no longer support
346                    //  syncing through the txhashset.zip method.
347                    let data = leaves0
348                        .find(|&(&p, _)| p == pos0)
349                        .map(|(_, l)| l)
350                        .ok_or_else(|| SegmentError::MissingLeaf(pos0))?;
351                    Some(data.hash_with_index(pos0))
352                } else {
353                    None
354                }
355            } else {
356                let left_child_pos = 1 + pos0 - (1 << height);
357                let right_child_pos = pos0;
358
359                let right_child = hashes.pop().unwrap();
360                let left_child = hashes.pop().unwrap();
361
362                if bitmap.is_some() {
363                    // Prunable MMR
364                    match (left_child, right_child) {
365                        (None, None) => None,
366                        (Some(l), Some(r)) => Some((l, r).hash_with_index(pos0)),
367                        (None, Some(r)) => {
368                            let l = self.get_hash(left_child_pos - 1)?;
369                            Some((l, r).hash_with_index(pos0))
370                        }
371                        (Some(l), None) => {
372                            let r = self.get_hash(right_child_pos - 1)?;
373                            Some((l, r).hash_with_index(pos0))
374                        }
375                    }
376                } else {
377                    // Non-prunable MMR: require both children
378                    Some(
379                        (
380                            left_child.ok_or_else(|| SegmentError::MissingHash(left_child_pos))?,
381                            right_child
382                                .ok_or_else(|| SegmentError::MissingHash(right_child_pos))?,
383                        )
384                            .hash_with_index(pos0),
385                    )
386                }
387            };
388            hashes.push(hash);
389        }
390
391        if self.full_segment(mmr_size) {
392            // Full segment: last position of segment is subtree root
393            Ok(hashes.pop().unwrap())
394        } else {
395            // Not full (only final segment): peaks in segment, bag them together
396            let peaks = pmmr::peaks(mmr_size)
397                .into_iter()
398                .filter(|&pos0| pos0 >= segment_first_pos && pos0 <= segment_last_pos)
399                .rev();
400            let mut hash = None;
401            for pos0 in peaks {
402                let mut lhash = hashes
403                    .pop()
404                    .ok_or_else(|| SegmentError::MissingHash(1 + pos0))?;
405                if lhash.is_none() && bitmap.is_some() {
406                    // If this entire peak is pruned, load it from the segment hashes
407                    lhash = Some(self.get_hash(pos0)?);
408                }
409                let lhash = lhash.ok_or_else(|| SegmentError::MissingHash(1 + pos0))?;
410
411                hash = match hash {
412                    None => Some(lhash),
413                    Some(rhash) => Some((lhash, rhash).hash_with_index(mmr_size)),
414                };
415            }
416            Ok(Some(hash.unwrap()))
417        }
418    }
419
420    /// Get the first 1-based (sucks) unpruned parent hash of this segment
421    pub fn first_unpruned_parent(
422        &self,
423        mmr_size: u64,
424        bitmap: Option<&Bitmap>,
425    ) -> Result<(Hash, u64), SegmentError> {
426        let root = self.root(mmr_size, bitmap)?;
427        let (_, last) = self.segment_pos_range(mmr_size);
428        if let Some(root) = root {
429            return Ok((root, 1 + last));
430        }
431        let bitmap = bitmap.unwrap();
432        let n_leaves = pmmr::n_leaves(mmr_size);
433
434        let mut cardinality = 0;
435        let mut pos0 = last;
436        let mut hash = Err(SegmentError::MissingHash(last));
437        let mut family_branch = pmmr::family_branch(last, mmr_size).into_iter();
438        while cardinality == 0 {
439            hash = self.get_hash(pos0).map(|h| (h, 1 + pos0));
440            if hash.is_ok() {
441                // Return early in case a lower level hash is already present
442                // This can occur if both child trees are pruned but compaction hasn't run yet
443                return hash;
444            }
445
446            if let Some((p0, _)) = family_branch.next() {
447                pos0 = p0;
448                let range = (pmmr::n_leaves(1 + pmmr::bintree_leftmost(p0)) - 1)
449                    ..min(pmmr::n_leaves(1 + pmmr::bintree_rightmost(p0)), n_leaves);
450                cardinality = bitmap.range_cardinality(range);
451            } else {
452                break;
453            }
454        }
455        hash
456    }
457
458    /// Check validity of the segment by calculating its root and validating the merkle proof
459    pub fn validate(
460        &self,
461        mmr_size: u64,
462        bitmap: Option<&Bitmap>,
463        mmr_root: Hash,
464    ) -> Result<(), SegmentError> {
465        let (first, last) = self.segment_pos_range(mmr_size);
466        let (segment_root, segment_unpruned_pos) = self.first_unpruned_parent(mmr_size, bitmap)?;
467        self.proof.validate(
468            mmr_size,
469            mmr_root,
470            first,
471            last,
472            segment_root,
473            segment_unpruned_pos,
474        )
475    }
476
477    /// Check validity of the segment by calculating its root and validating the merkle proof
478    /// This function assumes a final hashing step together with `other_root`
479    pub fn validate_with(
480        &self,
481        mmr_size: u64,
482        bitmap: Option<&Bitmap>,
483        mmr_root: Hash,
484        hash_last_pos: u64,
485        other_root: Hash,
486        other_is_left: bool,
487    ) -> Result<(), SegmentError> {
488        let (first, last) = self.segment_pos_range(mmr_size);
489        let (segment_root, segment_unpruned_pos) = self.first_unpruned_parent(mmr_size, bitmap)?;
490        self.proof.validate_with(
491            mmr_size,
492            mmr_root,
493            first,
494            last,
495            segment_root,
496            segment_unpruned_pos,
497            hash_last_pos,
498            other_root,
499            other_is_left,
500        )
501    }
502}
503
504impl<T: Readable> Readable for Segment<T> {
505    fn read<R: Reader>(reader: &mut R) -> Result<Self, Error> {
506        let identifier = Readable::read(reader)?;
507
508        let n_hashes = reader.read_u64()? as usize;
509        let mut hash_pos = Vec::with_capacity(n_hashes);
510        let mut last_pos = 0;
511        for _ in 0..n_hashes {
512            let pos = reader.read_u64()?;
513            if pos <= last_pos {
514                return Err(Error::SortError);
515            }
516            last_pos = pos;
517            hash_pos.push(pos - 1);
518        }
519
520        let mut hashes = Vec::<Hash>::with_capacity(n_hashes);
521        for _ in 0..n_hashes {
522            hashes.push(Readable::read(reader)?);
523        }
524
525        let n_leaves = reader.read_u64()? as usize;
526        let mut leaf_pos = Vec::with_capacity(n_leaves);
527        last_pos = 0;
528        for _ in 0..n_leaves {
529            let pos = reader.read_u64()?;
530            if pos <= last_pos {
531                return Err(Error::SortError);
532            }
533            last_pos = pos;
534            leaf_pos.push(pos - 1);
535        }
536
537        let mut leaf_data = Vec::<T>::with_capacity(n_leaves);
538        for _ in 0..n_leaves {
539            leaf_data.push(Readable::read(reader)?);
540        }
541
542        let proof = Readable::read(reader)?;
543
544        Ok(Self {
545            identifier,
546            hash_pos,
547            hashes,
548            leaf_pos,
549            leaf_data,
550            proof,
551        })
552    }
553}
554
555impl<T: Writeable> Writeable for Segment<T> {
556    fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
557        Writeable::write(&self.identifier, writer)?;
558        writer.write_u64(self.hashes.len() as u64)?;
559        for &pos in &self.hash_pos {
560            writer.write_u64(1 + pos)?;
561        }
562        for hash in &self.hashes {
563            Writeable::write(hash, writer)?;
564        }
565        writer.write_u64(self.leaf_data.len() as u64)?;
566        for &pos in &self.leaf_pos {
567            writer.write_u64(1 + pos)?;
568        }
569        for data in &self.leaf_data {
570            Writeable::write(data, writer)?;
571        }
572        Writeable::write(&self.proof, writer)?;
573        Ok(())
574    }
575}
576
577/// Merkle proof of a segment
578#[derive(Clone, Debug, Eq, PartialEq)]
579pub struct SegmentProof {
580    hashes: Vec<Hash>,
581}
582
583impl SegmentProof {
584    fn empty() -> Self {
585        Self { hashes: Vec::new() }
586    }
587
588    fn generate<U, B>(
589        pmmr: &ReadonlyPMMR<'_, U, B>,
590        last_pos: u64,
591        segment_first_pos: u64,
592        segment_last_pos: u64,
593        start_pos: Option<u64>,
594    ) -> Result<Self, SegmentError>
595    where
596        U: PMMRable,
597        B: Backend<U>,
598    {
599        let family_branch = pmmr::family_branch(segment_last_pos - 1, last_pos);
600
601        // 1. siblings along the path from the subtree root to the peak
602        let hashes: Result<Vec<_>, _> = family_branch
603            .iter()
604            .filter(|&&(p0, _)| start_pos.map(|s| p0 >= s).unwrap_or(true))
605            .map(|&(_, s0)| {
606                pmmr.get_hash(s0)
607                    .ok_or_else(|| SegmentError::MissingHash(s0))
608            })
609            .collect();
610        let mut proof = Self { hashes: hashes? };
611
612        // 2. bagged peaks to the right
613        let peak_pos = family_branch
614            .last()
615            .map(|&(p0, _)| p0)
616            .unwrap_or(segment_last_pos - 1);
617        if let Some(h) = pmmr.bag_the_rhs(peak_pos) {
618            proof.hashes.push(h);
619        }
620
621        // 3. peaks to the left
622        let peaks: Result<Vec<_>, _> = pmmr::peaks(last_pos)
623            .into_iter()
624            .filter(|&x| 1 + x < segment_first_pos)
625            .rev()
626            .map(|p| pmmr.get_hash(p).ok_or_else(|| SegmentError::MissingHash(p)))
627            .collect();
628        proof.hashes.extend(peaks?);
629
630        Ok(proof)
631    }
632
633    /// Size of the proof in hashes.
634    pub fn size(&self) -> usize {
635        self.hashes.len()
636    }
637
638    /// Reconstruct PMMR root using this proof
639    pub fn reconstruct_root(
640        &self,
641        last_pos: u64,
642        segment_first_pos0: u64,
643        segment_last_pos0: u64,
644        segment_root: Hash,
645        segment_unpruned_pos: u64,
646    ) -> Result<Hash, SegmentError> {
647        let mut iter = self.hashes.iter();
648        let family_branch = pmmr::family_branch(segment_last_pos0, last_pos);
649
650        // 1. siblings along the path from the subtree root to the peak
651        let mut root = segment_root;
652        for &(p0, s0) in family_branch
653            .iter()
654            .filter(|&&(p0, _)| p0 >= segment_unpruned_pos)
655        {
656            let sibling_hash = iter
657                .next()
658                .ok_or_else(|| SegmentError::MissingHash(1 + s0))?;
659            root = if pmmr::is_left_sibling(s0) {
660                (sibling_hash, root).hash_with_index(p0)
661            } else {
662                (root, sibling_hash).hash_with_index(p0)
663            };
664        }
665
666        // 2. bagged peaks to the right
667        let peak_pos0 = family_branch
668            .last()
669            .map(|&(p0, _)| p0)
670            .unwrap_or(segment_last_pos0);
671
672        let rhs = pmmr::peaks(last_pos)
673            .into_iter()
674            .filter(|&x| x > peak_pos0)
675            .next();
676
677        if let Some(pos0) = rhs {
678            root = (
679                root,
680                iter.next()
681                    .ok_or_else(|| SegmentError::MissingHash(1 + pos0))?,
682            )
683                .hash_with_index(last_pos)
684        }
685
686        // 3. peaks to the left
687        let peaks = pmmr::peaks(last_pos)
688            .into_iter()
689            .filter(|&x| x < segment_first_pos0)
690            .rev();
691        for pos0 in peaks {
692            root = (
693                iter.next()
694                    .ok_or_else(|| SegmentError::MissingHash(1 + pos0))?,
695                root,
696            )
697                .hash_with_index(last_pos);
698        }
699
700        Ok(root)
701    }
702
703    /// Check validity of the proof by equating the reconstructed root with the actual root
704    pub fn validate(
705        &self,
706        last_pos: u64,
707        mmr_root: Hash,
708        segment_first_pos: u64,
709        segment_last_pos: u64,
710        segment_root: Hash,
711        segment_unpruned_pos: u64,
712    ) -> Result<(), SegmentError> {
713        let root = self.reconstruct_root(
714            last_pos,
715            segment_first_pos,
716            segment_last_pos,
717            segment_root,
718            segment_unpruned_pos,
719        )?;
720        if root == mmr_root {
721            Ok(())
722        } else {
723            Err(SegmentError::Mismatch)
724        }
725    }
726
727    /// Check validity of the proof by equating the reconstructed root with the actual root
728    /// This function assumes a final hashing step together with `other_root`
729    pub fn validate_with(
730        &self,
731        last_pos: u64,
732        mmr_root: Hash,
733        segment_first_pos: u64,
734        segment_last_pos: u64,
735        segment_root: Hash,
736        segment_unpruned_pos: u64,
737        hash_last_pos: u64,
738        other_root: Hash,
739        other_is_left: bool,
740    ) -> Result<(), SegmentError> {
741        let root = self.reconstruct_root(
742            last_pos,
743            segment_first_pos,
744            segment_last_pos,
745            segment_root,
746            segment_unpruned_pos,
747        )?;
748        let root = if other_is_left {
749            (other_root, root).hash_with_index(hash_last_pos)
750        } else {
751            (root, other_root).hash_with_index(hash_last_pos)
752        };
753        if root == mmr_root {
754            Ok(())
755        } else {
756            Err(SegmentError::Mismatch)
757        }
758    }
759}
760
761impl Readable for SegmentProof {
762    fn read<R: Reader>(reader: &mut R) -> Result<Self, Error> {
763        let n_hashes = reader.read_u64()? as usize;
764        let mut hashes = Vec::with_capacity(n_hashes);
765        for _ in 0..n_hashes {
766            let hash: Hash = Readable::read(reader)?;
767            hashes.push(hash);
768        }
769        Ok(Self { hashes })
770    }
771}
772
773impl Writeable for SegmentProof {
774    fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
775        writer.write_u64(self.hashes.len() as u64)?;
776        for hash in &self.hashes {
777            Writeable::write(hash, writer)?;
778        }
779        Ok(())
780    }
781}