feat: add a trait method to control how to merge peaks

This commit is contained in:
Boyu Yang
2022-03-22 18:00:43 +08:00
parent 09092d0039
commit 0b37e46871
4 changed files with 106 additions and 2 deletions
+5
View File
@@ -1,4 +1,9 @@
pub trait Merge {
type Item;
fn merge(left: &Self::Item, right: &Self::Item) -> Self::Item;
fn merge_peaks(peak1: &Self::Item, peak2: &Self::Item) -> Self::Item {
Self::merge(peak1, peak2)
}
}
+2 -2
View File
@@ -96,7 +96,7 @@ impl<'a, T: Clone + PartialEq + Debug, M: Merge<Item = T>, S: MMRStore<T>> MMR<T
while rhs_peaks.len() > 1 {
let right_peak = rhs_peaks.pop().expect("pop");
let left_peak = rhs_peaks.pop().expect("pop");
rhs_peaks.push(M::merge(&right_peak, &left_peak));
rhs_peaks.push(M::merge_peaks(&right_peak, &left_peak));
}
Ok(rhs_peaks.pop())
}
@@ -394,7 +394,7 @@ fn bagging_peaks_hashes<'a, T: 'a + PartialEq + Debug + Clone, M: Merge<Item = T
while peaks_hashes.len() > 1 {
let right_peak = peaks_hashes.pop().expect("pop");
let left_peak = peaks_hashes.pop().expect("pop");
peaks_hashes.push(M::merge(&right_peak, &left_peak));
peaks_hashes.push(M::merge_peaks(&right_peak, &left_peak));
}
peaks_hashes.pop().ok_or(Error::CorruptedProof)
}
+1
View File
@@ -1,6 +1,7 @@
mod test_accumulate_headers;
mod test_helper;
mod test_mmr;
mod test_sequence;
use crate::Merge;
use blake2b_rs::{Blake2b, Blake2bBuilder};
+98
View File
@@ -0,0 +1,98 @@
use std::fmt;
use proptest::proptest;
use rand::{prelude::*, thread_rng};
use crate::{util::MemStore, Merge, MMR};
#[derive(Eq, PartialEq, Clone, Default)]
struct NumberRange {
start: u32,
end: u32,
}
struct MergeNumberRange;
impl fmt::Debug for NumberRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "NumberRange({}, {})", self.start, self.end)
}
}
impl fmt::Debug for MergeNumberRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "MergeNumberRange")
}
}
impl From<u32> for NumberRange {
fn from(num: u32) -> Self {
Self {
start: num,
end: num,
}
}
}
impl NumberRange {
fn is_normalized(&self) -> bool {
self.start <= self.end
}
}
impl Merge for MergeNumberRange {
type Item = NumberRange;
fn merge(lhs: &Self::Item, rhs: &Self::Item) -> Self::Item {
Self::Item {
start: lhs.start,
end: rhs.end,
}
}
fn merge_peaks(lhs: &Self::Item, rhs: &Self::Item) -> Self::Item {
Self::merge(rhs, lhs)
}
}
fn test_sequence_sub_func(count: u32, proof_elem: Vec<u32>) {
let store = MemStore::default();
let mut mmr = MMR::<_, MergeNumberRange, _>::new(0, &store);
let positions = (0..count)
.map(|i| mmr.push(NumberRange::from(i)).expect("push"))
.collect::<Vec<_>>();
let root = mmr.get_root().expect("get_root");
assert!(root.is_normalized());
let proof = mmr
.gen_proof(
proof_elem
.iter()
.map(|elem| positions[*elem as usize])
.collect(),
)
.expect("gen_proof");
for item in proof.proof_items() {
assert!(item.is_normalized())
}
mmr.commit().expect("commit");
let result = proof
.verify(
root,
proof_elem
.iter()
.map(|elem| (positions[*elem as usize], NumberRange::from(*elem)))
.collect(),
)
.expect("verify");
assert!(result);
}
proptest! {
#[test]
fn test_sequence(count in 10u32..500u32) {
let mut leaves: Vec<u32> = (0..count).collect();
let mut rng = thread_rng();
leaves.shuffle(&mut rng);
let leaves_count = rng.gen_range(1, count - 1);
leaves.truncate(leaves_count as usize);
test_sequence_sub_func(count, leaves);
}
}