algae_mmr/
mmr.rs

1/*
2    Appellation: mmr <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4    Description: ... summary ...
5*/
6use crate::cmp::{Node, Position};
7use crate::{is_node_right, sibling_index, RangeMap};
8use decanter::prelude::{hasher, Hashable, H256};
9use digest::Digest;
10use serde::{Deserialize, Serialize};
11use std::convert::From;
12
13#[derive(Clone, Debug, Default, Deserialize, Eq, Hashable, PartialEq, Serialize)]
14pub struct MerkleMountainRange<T = String>
15where
16    T: ToString,
17{
18    data: RangeMap<T>,
19    mmr: Vec<Node>, // todo convert these to a bitmap
20    position: Position,
21}
22
23impl<T> MerkleMountainRange<T>
24where
25    T: ToString,
26{
27    pub fn new(mmr: Vec<Node>, data: RangeMap<T>, position: Position) -> Self {
28        Self {
29            mmr,
30            data,
31            position,
32        }
33    }
34    /// This function adds a vec of leaf nodes to the mmr.
35    pub fn add_vec<D: Digest>(&mut self, objects: Vec<T>) {
36        for object in objects {
37            self.add_single::<D>(object);
38        }
39    }
40    /// This function adds a new leaf node to the mmr.
41    pub fn add_single<D: Digest>(&mut self, object: T) {
42        let node_hash: H256 = hasher(object.to_string()).into();
43        let node = Node::from(node_hash);
44        self.data.insert(node_hash, object);
45        self.mmr.push(node);
46        if is_node_right(self.get_last_added_index()) {
47            self.add_single_no_leaf::<D>(self.get_last_added_index())
48        }
49    }
50    // This function adds non leaf nodes, eg nodes that are not directly a hash of data
51    // This is iterative and will continue to up and till it hits the top, will be a future left child
52    fn add_single_no_leaf<D: Digest>(&mut self, index: usize) {
53        let mut hasher = D::new();
54        hasher.update(self.mmr[sibling_index(index)].hash);
55        hasher.update(self.mmr[index].hash);
56        let new_hash: H256 = hasher.finalize().to_vec().into();
57        let new_node = Node::from(new_hash);
58        self.mmr.push(new_node);
59        if is_node_right(self.get_last_added_index()) {
60            self.add_single_no_leaf::<D>(self.get_last_added_index())
61        } else {
62            self.position = self.calc_peak_height().into(); // because we have now stopped adding right nodes, we need to update the height of the mmr
63        }
64    }
65    fn bag_mmr(&self) -> Vec<H256> {
66        // lets find all peaks of the mmr
67        let mut peaks = Vec::new();
68        self.find_bagging_indexes(self.position.height as i64, self.position.index, &mut peaks);
69        peaks
70    }
71    // This function calculates the peak height of the mmr
72    fn calc_peak_height(&self) -> (usize, usize) {
73        let mut height_counter = 0;
74        let mmr_len = self.get_last_added_index();
75        let mut index: usize = (1 << (height_counter + 2)) - 2;
76        let mut actual_height_index = 0;
77        while mmr_len >= index {
78            // find the height of the tree by finding if we can subtract the  height +1
79            height_counter += 1;
80            actual_height_index = index;
81            index = (1 << (height_counter + 2)) - 2;
82        }
83        (height_counter, actual_height_index)
84    }
85
86    fn find_bagging_indexes(&self, mut height: i64, index: usize, peaks: &mut Vec<H256>) {
87        let mut new_index = index + (1 << (height + 1)) - 1; // go the potential right sibling
88        while (new_index > self.get_last_added_index()) && (height > 0) {
89            // lets go down left child till we hit a valid node or we reach height 0
90            new_index -= 1 << height;
91            height -= 1;
92        }
93        if (new_index <= self.get_last_added_index()) && (height >= 0) {
94            // is this a valid peak which needs to be bagged
95            peaks.push(self.mmr[new_index].hash);
96            self.find_bagging_indexes(height, new_index, peaks); // lets go look for more peaks
97        }
98    }
99    /// This function returns a reference to the data stored in the mmr
100    /// It will return none if the hash does not exist
101    pub fn get_object(&self, hash: &H256) -> Option<&T> {
102        self.data.get(hash)
103    }
104
105    /// This function returns a mut reference to the data stored in the MMR
106    /// It will return none if the hash does not exist
107    pub fn get_mut_object(&mut self, hash: &H256) -> Option<&mut T> {
108        self.data.get_mut(hash)
109    }
110
111    pub fn get_hash(&self, index: usize) -> Option<H256> {
112        if index > self.get_last_added_index() {
113            return None;
114        };
115        Some(self.mmr[index].hash)
116    }
117
118    /// This function returns the hash proof tree of a given hash.
119    /// If the given hash is not in the tree, the vec will be empty.
120    /// The Vec will be created in form of the Lchild-Rchild-parent(Lchild)-Rchild-parent-..
121    /// This pattern will be repeated until the parent is the root of the MMR
122    pub fn get_hash_proof<D: Digest>(&self, hash: &H256) -> Vec<H256> {
123        let mut result = Vec::new();
124        let mut i = self.mmr.len();
125        for counter in 0..self.mmr.len() {
126            if self.mmr[counter].hash == *hash {
127                i = counter;
128                break;
129            }
130        }
131        if i == self.mmr.len() {
132            return result;
133        };
134        self.get_ordered_hash_proof(i, &mut result);
135
136        if self.position.index == self.get_last_added_index() {
137            // we know there is no bagging as the mmr is a balanced binary tree
138            return result;
139        }
140
141        let mut peaks = self.bag_mmr();
142        let mut i = peaks.len();
143        let mut was_on_correct_height = false;
144        while i > 1 {
145            // was_on_correct_height is used to track should we add from this point onwards both left and right
146            // siblings. This loop tracks from bottom of the peaks, so we keep going up until we hit a known
147            // point, we then add the missing sibling from that point
148            if was_on_correct_height {
149                result.push(peaks[i - 2]);
150                result.push(peaks[i - 1]);
151            } else if peaks[i - 1] == result[result.len() - 1] {
152                result.insert(result.len() - 1, peaks[i - 2]);
153                was_on_correct_height = true;
154            } else if peaks[i - 2] == result[result.len() - 1] {
155                result.push(peaks[i - 1]);
156                was_on_correct_height = true;
157            }
158
159            let mut hasher = D::new();
160            hasher.update(peaks[i - 2]);
161            hasher.update(peaks[i - 1]);
162            peaks[i - 2] = hasher.finalize().to_vec().into();
163            i -= 1;
164        }
165        // lets calculate the final new peak
166        let mut hasher = D::new();
167        hasher.update(self.mmr[self.position.index].hash);
168        hasher.update(peaks[0]);
169        if was_on_correct_height {
170            // edge case, our node is in the largest peak, we have already added it
171            result.push(self.mmr[self.position.index].hash);
172        }
173        result.push(peaks[0]);
174        result.push(hasher.finalize().to_vec().into());
175
176        result
177    }
178
179    // This function is an iterative function. It will add the left node first then the right node to the provided array
180    // on the index. It will return when it reaches a single highest point.
181    // this function will return the index of the local peak, negating the need to search for it again.
182    fn get_ordered_hash_proof(&self, index: usize, results: &mut Vec<H256>) {
183        let sibling = sibling_index(index);
184        let mut next_index = index + 1;
185        if sibling >= self.mmr.len() {
186            // we are at a peak
187            results.push(self.mmr[index].hash);
188            return;
189        }
190        if sibling < index {
191            results.push(self.mmr[sibling].hash);
192            results.push(self.mmr[index].hash);
193        } else {
194            results.push(self.mmr[index].hash);
195            results.push(self.mmr[sibling].hash);
196            next_index = sibling + 1;
197        }
198        self.get_ordered_hash_proof(next_index, results);
199    }
200    /// This function returns the peak height of the mmr
201    pub fn get_peak_height(&self) -> usize {
202        self.position.height
203    }
204    /// This function will return the single merkle root of the MMR.
205    pub fn get_merkle_root<D: Digest>(&self) -> H256 {
206        let mut peaks = self.bag_mmr();
207        let mut i = peaks.len();
208        while i > 1 {
209            // lets bag all the other peaks
210            let mut hasher = D::new();
211            hasher.update(peaks[i - 2]);
212            hasher.update(peaks[i - 1]);
213            peaks[i - 2] = hasher.finalize().to_vec().into();
214            i -= 1;
215        }
216        if !peaks.is_empty() {
217            // if there was other peaks, lets bag them with the highest peak
218            let mut hasher = D::new();
219            hasher.update(self.mmr[self.position.index].hash);
220            hasher.update(peaks[0]);
221            return hasher.finalize().to_vec().into();
222        }
223        // there was no other peaks, return the highest peak
224        self.mmr[self.position.index].hash
225    }
226    // This function is just a private function to return the index of the last added node
227    fn get_last_added_index(&self) -> usize {
228        self.mmr.len() - 1
229    }
230    /// This function will verify the provided proof. Internally it uses the get_hash_proof function to construct a
231    /// similar proof. This function will return true if the proof is valid
232    /// If the order does not match Lchild-Rchild-parent(Lchild)-Rchild-parent-.. the validation will fail
233    /// This function will only succeed if the given hash is of height 0
234    pub fn verify_proof<D: Digest>(&self, hashes: &Vec<H256>) -> bool {
235        if hashes.is_empty() {
236            return false;
237        }
238        if self.get_object(&hashes[0]).is_none() && self.get_object(&hashes[1]).is_none() {
239            // we only want to search for valid object's proofs, either 0 or 1 must be a valid object
240            return false;
241        }
242        let proof = self.get_hash_proof::<D>(&hashes[0]);
243        hashes.eq(&proof)
244    }
245}
246
247impl<T> std::fmt::Display for MerkleMountainRange<T>
248where
249    T: ToString,
250{
251    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
252        write!(f, "{:?}", self.mmr)
253    }
254}