diff --git a/src/merkle/mmr/full.rs b/src/merkle/mmr/full.rs index 2549ddb9..ca2dee26 100644 --- a/src/merkle/mmr/full.rs +++ b/src/merkle/mmr/full.rs @@ -164,32 +164,32 @@ impl Mmr { /// /// The result is a packed sequence of the authentication elements required to update the trees /// that have been merged together, followed by the new peaks of the [Mmr]. - pub fn get_delta(&self, original_forest: usize) -> Result { - if original_forest > self.forest { + pub fn get_delta(&self, from_forest: usize, to_forest: usize) -> Result { + if to_forest > self.forest || from_forest > to_forest { return Err(MmrError::InvalidPeaks); } - if original_forest == self.forest { - return Ok(MmrDelta { forest: self.forest, data: Vec::new() }); + if from_forest == to_forest { + return Ok(MmrDelta { forest: to_forest, data: Vec::new() }); } let mut result = Vec::new(); - // Find the largest tree in this [Mmr] which is new to `original_forest`. - let candidate_trees = self.forest ^ original_forest; + // Find the largest tree in this [Mmr] which is new to `from_forest`. + let candidate_trees = to_forest ^ from_forest; let mut new_high = 1 << candidate_trees.ilog2(); // Collect authentication nodes used for tree merges // ---------------------------------------------------------------------------------------- - // Find the trees from `original_forest` that have been merged into `new_high`. - let mut merges = original_forest & (new_high - 1); + // Find the trees from `from_forest` that have been merged into `new_high`. + let mut merges = from_forest & (new_high - 1); - // Find the peaks that are common to `original_forest` and this [Mmr] - let common_trees = original_forest ^ merges; + // Find the peaks that are common to `from_forest` and this [Mmr] + let common_trees = from_forest ^ merges; if merges != 0 { - // Skip the smallest trees unknown to `original_forest`. + // Skip the smallest trees unknown to `from_forest`. let mut target = 1 << merges.trailing_zeros(); // Collect siblings required to computed the merged tree's peak @@ -214,15 +214,15 @@ impl Mmr { } } else { // The new high tree may not be the result of any merges, if it is smaller than all the - // trees of `original_forest`. + // trees of `from_forest`. new_high = 0; } // Collect the new [Mmr] peaks // ---------------------------------------------------------------------------------------- - let mut new_peaks = self.forest ^ common_trees ^ new_high; - let old_peaks = self.forest ^ new_peaks; + let mut new_peaks = to_forest ^ common_trees ^ new_high; + let old_peaks = to_forest ^ new_peaks; let mut offset = nodes_in_forest(old_peaks); while new_peaks != 0 { let target = 1 << new_peaks.ilog2(); @@ -231,7 +231,7 @@ impl Mmr { new_peaks ^= target; } - Ok(MmrDelta { forest: self.forest, data: result }) + Ok(MmrDelta { forest: to_forest, data: result }) } /// An iterator over inner nodes in the MMR. The order of iteration is unspecified. diff --git a/src/merkle/mmr/tests.rs b/src/merkle/mmr/tests.rs index aee7e4aa..ab22054b 100644 --- a/src/merkle/mmr/tests.rs +++ b/src/merkle/mmr/tests.rs @@ -573,42 +573,42 @@ fn test_mmr_peaks_hash_odd() { } #[test] -fn test_mmr_updates() { +fn test_mmr_delta() { let mmr: Mmr = LEAVES.into(); let acc = mmr.accumulator(); // original_forest can't have more elements assert!( - mmr.get_delta(LEAVES.len() + 1).is_err(), + mmr.get_delta(LEAVES.len() + 1, mmr.forest()).is_err(), "Can not provide updates for a newer Mmr" ); // if the number of elements is the same there is no change assert!( - mmr.get_delta(LEAVES.len()).unwrap().data.is_empty(), + mmr.get_delta(LEAVES.len(), mmr.forest()).unwrap().data.is_empty(), "There are no updates for the same Mmr version" ); // missing the last element added, which is itself a tree peak - assert_eq!(mmr.get_delta(6).unwrap().data, vec![acc.peaks()[2]], "one peak"); + assert_eq!(mmr.get_delta(6, mmr.forest()).unwrap().data, vec![acc.peaks()[2]], "one peak"); // missing the sibling to complete the tree of depth 2, and the last element assert_eq!( - mmr.get_delta(5).unwrap().data, + mmr.get_delta(5, mmr.forest()).unwrap().data, vec![LEAVES[5], acc.peaks()[2]], "one sibling, one peak" ); // missing the whole last two trees, only send the peaks assert_eq!( - mmr.get_delta(4).unwrap().data, + mmr.get_delta(4, mmr.forest()).unwrap().data, vec![acc.peaks()[1], acc.peaks()[2]], "two peaks" ); // missing the sibling to complete the first tree, and the two last trees assert_eq!( - mmr.get_delta(3).unwrap().data, + mmr.get_delta(3, mmr.forest()).unwrap().data, vec![LEAVES[3], acc.peaks()[1], acc.peaks()[2]], "one sibling, two peaks" ); @@ -616,18 +616,60 @@ fn test_mmr_updates() { // missing half of the first tree, only send the computed element (not the leaves), and the new // peaks assert_eq!( - mmr.get_delta(2).unwrap().data, + mmr.get_delta(2, mmr.forest()).unwrap().data, vec![mmr.nodes[5], acc.peaks()[1], acc.peaks()[2]], "one sibling, two peaks" ); assert_eq!( - mmr.get_delta(1).unwrap().data, + mmr.get_delta(1, mmr.forest()).unwrap().data, vec![LEAVES[1], mmr.nodes[5], acc.peaks()[1], acc.peaks()[2]], "one sibling, two peaks" ); - assert_eq!(&mmr.get_delta(0).unwrap().data, acc.peaks(), "all peaks"); + assert_eq!(&mmr.get_delta(0, mmr.forest()).unwrap().data, acc.peaks(), "all peaks"); +} + +#[test] +fn test_mmr_delta_old_forest() { + let mmr: Mmr = LEAVES.into(); + + // from_forest must be smaller-or-equal to to_forest + for version in 1..=mmr.forest() { + assert!(mmr.get_delta(version + 1, version).is_err()); + } + + // when from_forest and to_forest are equal, there are no updates + for version in 1..=mmr.forest() { + let delta = mmr.get_delta(version, version).unwrap(); + assert!(delta.data.is_empty()); + assert_eq!(delta.forest, version); + } + + // test update which merges the odd peak to the right + for count in 0..(mmr.forest() / 2) { + // *2 because every iteration tests a pair + // +1 because the Mmr is 1-indexed + let from_forest = (count * 2) + 1; + let to_forest = (count * 2) + 2; + let delta = mmr.get_delta(from_forest, to_forest).unwrap(); + + // *2 because every iteration tests a pair + // +1 because sibling is the odd element + let sibling = (count * 2) + 1; + assert_eq!(delta.data, [LEAVES[sibling]]); + assert_eq!(delta.forest, to_forest); + } + + let version = 4; + let delta = mmr.get_delta(1, version).unwrap(); + assert_eq!(delta.data, [mmr.nodes[1], mmr.nodes[5]]); + assert_eq!(delta.forest, version); + + let version = 5; + let delta = mmr.get_delta(1, version).unwrap(); + assert_eq!(delta.data, [mmr.nodes[1], mmr.nodes[5], mmr.nodes[7]]); + assert_eq!(delta.forest, version); } #[test] @@ -682,7 +724,7 @@ fn test_partial_mmr_update_single() { for i in 1..100 { let node = int_to_node(i); full.add(node); - let delta = full.get_delta(partial.forest()).unwrap(); + let delta = full.get_delta(partial.forest(), full.forest()).unwrap(); partial.apply(delta).unwrap(); assert_eq!(partial.forest(), full.forest());