mirror of
https://github.com/pezkuwichain/merkle-mountain-range.git
synced 2026-06-12 09:11:01 +00:00
feat: verify a old root and all incremental items after it
This commit is contained in:
+61
-1
@@ -6,7 +6,10 @@
|
||||
|
||||
use crate::borrow::Cow;
|
||||
use crate::collections::VecDeque;
|
||||
use crate::helper::{get_peak_map, get_peaks, parent_offset, pos_height_in_tree, sibling_offset};
|
||||
use crate::helper::{
|
||||
get_peak_map, get_peaks, leaf_index_to_mmr_size, leaf_index_to_pos, parent_offset,
|
||||
pos_height_in_tree, sibling_offset,
|
||||
};
|
||||
use crate::mmr_store::{MMRBatch, MMRStoreReadOps, MMRStoreWriteOps};
|
||||
use crate::vec;
|
||||
use crate::vec::Vec;
|
||||
@@ -291,6 +294,63 @@ impl<T: Clone + PartialEq, M: Merge<Item = T>> MerkleProof<T, M> {
|
||||
self.calculate_root(leaves)
|
||||
.map(|calculated_root| calculated_root == root)
|
||||
}
|
||||
|
||||
/// Verifies a old root and all incremental leaves.
|
||||
///
|
||||
/// If this method returns `true`, it means the following assertion are true:
|
||||
/// - The old root could be generated in the history of the current MMR.
|
||||
/// - All incremental leaves are on the current MMR.
|
||||
/// - The MMR, which could generate the old root, appends all incremental leaves, becomes the
|
||||
/// current MMR.
|
||||
pub fn verify_incremental(&self, root: T, prev_root: T, incremental: Vec<T>) -> Result<bool> {
|
||||
let current_leaves_count = get_peak_map(self.mmr_size);
|
||||
if current_leaves_count <= incremental.len() as u64 {
|
||||
return Err(Error::CorruptedProof);
|
||||
}
|
||||
// Test if previous root is correct.
|
||||
let prev_leaves_count = current_leaves_count - incremental.len() as u64;
|
||||
let prev_peaks_positions = {
|
||||
let prev_index = prev_leaves_count - 1;
|
||||
let prev_mmr_size = leaf_index_to_mmr_size(prev_index);
|
||||
let prev_peaks_positions = get_peaks(prev_mmr_size);
|
||||
if prev_peaks_positions.len() != self.proof.len() {
|
||||
return Err(Error::CorruptedProof);
|
||||
}
|
||||
prev_peaks_positions
|
||||
};
|
||||
let current_peaks_positions = get_peaks(self.mmr_size);
|
||||
|
||||
let mut reverse_index = prev_peaks_positions.len();
|
||||
for (i, position) in prev_peaks_positions.iter().enumerate() {
|
||||
if *position < current_peaks_positions[i] {
|
||||
reverse_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if reverse_index == prev_peaks_positions.len() {
|
||||
reverse_index = prev_peaks_positions.len() - 1;
|
||||
}
|
||||
let mut prev_peaks: Vec<_> = self.proof_items().to_vec();
|
||||
let mut reverse_peaks = prev_peaks.split_off(reverse_index);
|
||||
reverse_peaks.reverse();
|
||||
prev_peaks.extend(reverse_peaks);
|
||||
|
||||
let calculated_prev_root = bagging_peaks_hashes::<T, M>(prev_peaks)?;
|
||||
if calculated_prev_root != prev_root {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Test if incremental leaves are correct.
|
||||
let leaves = incremental
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, leaf)| {
|
||||
let pos = leaf_index_to_pos(prev_leaves_count + index as u64);
|
||||
(pos, leaf)
|
||||
})
|
||||
.collect();
|
||||
self.verify(root, leaves)
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_peak_root<'a, T: 'a, M: Merge<Item = T>, I: Iterator<Item = &'a T>>(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
mod test_accumulate_headers;
|
||||
mod test_helper;
|
||||
mod test_incremental;
|
||||
mod test_mmr;
|
||||
mod test_sequence;
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
use proptest::proptest;
|
||||
|
||||
use super::{MergeNumberHash, NumberHash};
|
||||
use crate::util::{MemMMR, MemStore};
|
||||
|
||||
proptest! {
|
||||
#[test]
|
||||
fn test_incremental(start in 1u32..500, steps in 1usize..50, turns in 10usize..20) {
|
||||
test_incremental_with_params(start, steps, turns);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_incremental_with_params(start: u32, steps: usize, turns: usize) {
|
||||
let store = MemStore::default();
|
||||
let mut mmr = MemMMR::<_, MergeNumberHash>::new(0, &store);
|
||||
|
||||
let mut curr = 0;
|
||||
|
||||
let _positions: Vec<u64> = (0u32..start)
|
||||
.map(|_| {
|
||||
let pos = mmr.push(NumberHash::from(curr)).unwrap();
|
||||
curr += 1;
|
||||
pos
|
||||
})
|
||||
.collect();
|
||||
mmr.commit().expect("commit changes");
|
||||
|
||||
for turn in 0..turns {
|
||||
let prev_root = mmr.get_root().expect("get root");
|
||||
let (positions, leaves) = (0..steps).fold(
|
||||
(Vec::new(), Vec::new()),
|
||||
|(mut positions, mut leaves), _| {
|
||||
let leaf = NumberHash::from(curr);
|
||||
let pos = mmr.push(leaf.clone()).unwrap();
|
||||
curr += 1;
|
||||
positions.push(pos);
|
||||
leaves.push(leaf);
|
||||
(positions, leaves)
|
||||
},
|
||||
);
|
||||
mmr.commit().expect("commit changes");
|
||||
let proof = mmr.gen_proof(positions).expect("gen proof");
|
||||
let root = mmr.get_root().expect("get root");
|
||||
let result = proof.verify_incremental(root, prev_root, leaves).unwrap();
|
||||
assert!(
|
||||
result,
|
||||
"start: {}, steps: {}, turn: {}, curr: {}",
|
||||
start, steps, turn, curr
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user