Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize get_peaks_and_heights for archival MMR. #141

Merged
merged 3 commits into from
Apr 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 14 additions & 66 deletions src/util_types/mutator_set/archival_mmr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use itertools::Itertools;

use twenty_first::util_types::mmr::{
mmr_accumulator::MmrAccumulator, mmr_membership_proof::MmrMembershipProof, mmr_trait::Mmr,
shared_advanced, shared_basic,
shared_advanced,
};

/// A Merkle Mountain Range is a datastructure for storing a list of hashes.
Expand All @@ -41,8 +41,9 @@ where

/// Return the digests of the peaks of the MMR
pub async fn get_peaks(&self) -> Vec<Digest> {
let peaks_and_heights = self.get_peaks_with_heights_async().await;
peaks_and_heights.into_iter().map(|x| x.0).collect()
let leaf_count = self.count_leaves().await;
let (_, peak_node_indices) = get_peak_heights_and_peak_node_indices(leaf_count);
self.digests.get_many(&peak_node_indices).await
}

/// Whether the MMR is empty. Note that since indexing starts at
Expand Down Expand Up @@ -226,43 +227,6 @@ impl<H: AlgebraicHasher, Storage: StorageVec<Digest>> ArchivalMmr<H, Storage> {
MmrMembershipProof::new(leaf_index, authentication_path)
}

/// Return a list of tuples (peaks, height)
pub async fn get_peaks_with_heights_async(&self) -> Vec<(Digest, u32)> {
if self.is_empty().await {
return vec![];
}

// 1. Find top peak
// 2. Jump to right sibling (will not be included)
// 3. Take left child of sibling, continue until a node in tree is found
// 4. Once new node is found, jump to right sibling (will not be included)
// 5. Take left child of sibling, continue until a node in tree is found
let mut peaks_and_heights: Vec<(Digest, u32)> = vec![];
let (mut top_peak, mut top_height) =
shared_advanced::leftmost_ancestor(self.digests.len().await - 1);
if top_peak > self.digests.len().await - 1 {
top_peak = shared_basic::left_child(top_peak, top_height);
top_height -= 1;
}

peaks_and_heights.push((self.digests.get(top_peak).await, top_height));
let mut height = top_height;
let mut candidate = shared_advanced::right_sibling(top_peak, height);
'outer: while height > 0 {
'_inner: while candidate > self.digests.len().await && height > 0 {
candidate = shared_basic::left_child(candidate, height);
height -= 1;
if candidate < self.digests.len().await {
peaks_and_heights.push((self.digests.get(candidate).await, height));
candidate = shared_advanced::right_sibling(candidate, height);
continue 'outer;
}
}
}

peaks_and_heights
}

/// Remove the last leaf from the archival MMR
pub async fn remove_last_leaf_async(&mut self) -> Option<Digest> {
if self.is_empty().await {
Expand Down Expand Up @@ -302,7 +266,6 @@ pub(crate) mod mmr_test {
use twenty_first::util_types::merkle_tree_maker::MerkleTreeMaker;
use twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator;
use twenty_first::util_types::mmr::shared_advanced::get_peak_heights;
use twenty_first::util_types::mmr::shared_advanced::get_peak_heights_and_peak_node_indices;

type Storage = OrdinaryVec<Digest>;

Expand Down Expand Up @@ -796,10 +759,8 @@ pub(crate) mod mmr_test {
assert_eq!(1, mmr.count_leaves().await);
assert_eq!(1, mmr.count_nodes().await);

let original_peaks_and_heights: Vec<(Digest, u32)> =
mmr.get_peaks_with_heights_async().await;
assert_eq!(1, original_peaks_and_heights.len());
assert_eq!(0, original_peaks_and_heights[0].1);
let original_peaks: Vec<Digest> = mmr.get_peaks().await;
assert_eq!(1, original_peaks.len());

{
let leaf_index = 0;
Expand All @@ -813,11 +774,9 @@ pub(crate) mod mmr_test {
assert_eq!(2, mmr.count_leaves().await);
assert_eq!(3, mmr.count_nodes().await);

let new_peaks_and_heights = mmr.get_peaks_with_heights_async().await;
assert_eq!(1, new_peaks_and_heights.len());
assert_eq!(1, new_peaks_and_heights[0].1);
let new_peaks = mmr.get_peaks().await;
assert_eq!(1, new_peaks.len());

let new_peaks: Vec<Digest> = new_peaks_and_heights.iter().map(|x| x.0).collect();
assert!(
original_mmr
.verify_batch_update(&new_peaks, &[new_input_hash], &[])
Expand Down Expand Up @@ -867,10 +826,9 @@ pub(crate) mod mmr_test {
assert_eq!(num_leaves, mmr.count_leaves().await);
assert_eq!(1 + num_leaves, mmr.count_nodes().await);

let original_peaks_and_heights: Vec<(Digest, u32)> =
mmr.get_peaks_with_heights_async().await;
let original_peaks: Vec<Digest> = mmr.get_peaks().await;
let expected_peaks = 2;
assert_eq!(expected_peaks, original_peaks_and_heights.len());
assert_eq!(expected_peaks, original_peaks.len());

{
let leaf_index = 0;
Expand Down Expand Up @@ -926,13 +884,8 @@ pub(crate) mod mmr_test {
assert_eq!(leaf_count, mmr.count_leaves().await);
assert_eq!(node_count, mmr.count_nodes().await);

let original_peaks_and_heights = mmr.get_peaks_with_heights_async().await;
let peak_heights_1: Vec<u32> = original_peaks_and_heights.iter().map(|x| x.1).collect();

let (peak_heights_2, _) = get_peak_heights_and_peak_node_indices(leaf_count);
assert_eq!(peak_heights_1, peak_heights_2);

let actual_peak_count = original_peaks_and_heights.len() as u64;
let original_peaks = mmr.get_peaks().await;
let actual_peak_count = original_peaks.len() as u64;
assert_eq!(peak_count, actual_peak_count);

// Verify that MMR root from odd number of digests and MMR bagged peaks agree
Expand Down Expand Up @@ -1053,12 +1006,8 @@ pub(crate) mod mmr_test {
mock::get_ammr_from_digests::<H>(input_digests.clone()).await;
assert_eq!(size, mmr.count_leaves().await);
assert_eq!(node_count, mmr.count_nodes().await);
let original_peaks_and_heights: Vec<(Digest, u32)> =
mmr.get_peaks_with_heights_async().await;
let peak_heights_1: Vec<u32> = original_peaks_and_heights.iter().map(|x| x.1).collect();
let (peak_heights_2, _) = get_peak_heights_and_peak_node_indices(size);
assert_eq!(peak_heights_1, peak_heights_2);
assert_eq!(peak_count, original_peaks_and_heights.len() as u64);
let original_peaks: Vec<Digest> = mmr.get_peaks().await;
assert_eq!(peak_count, original_peaks.len() as u64);

// Verify that MMR root from odd number of digests and MMR bagged peaks agree
let mmra_root = mmr.bag_peaks().await;
Expand All @@ -1076,7 +1025,6 @@ pub(crate) mod mmr_test {
let valid_res =
membership_proof.verify(&peaks, input_digests[leaf_index as usize], size);
assert!(valid_res);

let new_leaf: Digest = random();

// The below verify_modify tests should only fail if `wrong_leaf_index` is
Expand Down
Loading