mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
hash with the pos for non-leaf nodes (#788)
* hash_with_index on non-leaf nodes rework the Merkle proof to include the pos of each sibling in the path * rustfmt * cleanup * cleanup * use get_from_file in validate (children may have been "removed") * rustfmt * fixup store tests
This commit is contained in:
parent
efae2d8ce6
commit
cb71386097
4 changed files with 167 additions and 138 deletions
|
@ -105,11 +105,9 @@ pub struct MerkleProof {
|
||||||
pub node: Hash,
|
pub node: Hash,
|
||||||
/// The full list of peak hashes in the MMR
|
/// The full list of peak hashes in the MMR
|
||||||
pub peaks: Vec<Hash>,
|
pub peaks: Vec<Hash>,
|
||||||
/// The siblings along the path of the tree as we traverse from node to peak
|
/// The sibling (hash, pos) along the path of the tree
|
||||||
pub path: Vec<Hash>,
|
/// as we traverse from node to peak
|
||||||
/// Order of siblings (left vs right) matters, so track this here for each
|
pub path: Vec<(Hash, u64)>,
|
||||||
/// path element
|
|
||||||
pub left_right: Vec<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Writeable for MerkleProof {
|
impl Writeable for MerkleProof {
|
||||||
|
@ -119,22 +117,12 @@ impl Writeable for MerkleProof {
|
||||||
[write_fixed_bytes, &self.root],
|
[write_fixed_bytes, &self.root],
|
||||||
[write_fixed_bytes, &self.node],
|
[write_fixed_bytes, &self.node],
|
||||||
[write_u64, self.peaks.len() as u64],
|
[write_u64, self.peaks.len() as u64],
|
||||||
// note: path length used for both path and left_right vecs
|
|
||||||
[write_u64, self.path.len() as u64]
|
[write_u64, self.path.len() as u64]
|
||||||
);
|
);
|
||||||
|
|
||||||
try!(self.peaks.write(writer));
|
try!(self.peaks.write(writer));
|
||||||
try!(self.path.write(writer));
|
try!(self.path.write(writer));
|
||||||
|
|
||||||
// TODO - how to serialize/deserialize these boolean values as bytes?
|
|
||||||
for x in &self.left_right {
|
|
||||||
if *x {
|
|
||||||
try!(writer.write_u8(1));
|
|
||||||
} else {
|
|
||||||
try!(writer.write_u8(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,19 +138,19 @@ impl Readable for MerkleProof {
|
||||||
for _ in 0..peaks_len {
|
for _ in 0..peaks_len {
|
||||||
peaks.push(Hash::read(reader)?);
|
peaks.push(Hash::read(reader)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut path = Vec::with_capacity(path_len as usize);
|
let mut path = Vec::with_capacity(path_len as usize);
|
||||||
for _ in 0..path_len {
|
for _ in 0..path_len {
|
||||||
path.push(Hash::read(reader)?);
|
let hash = Hash::read(reader)?;
|
||||||
|
let pos = reader.read_u64()?;
|
||||||
|
path.push((hash, pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
let left_right_bytes = reader.read_fixed_bytes(path_len as usize)?;
|
|
||||||
let left_right = left_right_bytes.iter().map(|&x| x == 1).collect();
|
|
||||||
Ok(MerkleProof {
|
Ok(MerkleProof {
|
||||||
root,
|
root,
|
||||||
node,
|
node,
|
||||||
peaks,
|
peaks,
|
||||||
path,
|
path,
|
||||||
left_right,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +170,6 @@ impl MerkleProof {
|
||||||
node: Hash::zero(),
|
node: Hash::zero(),
|
||||||
peaks: vec![],
|
peaks: vec![],
|
||||||
path: vec![],
|
path: vec![],
|
||||||
left_right: vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,26 +203,25 @@ impl MerkleProof {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bagged = None;
|
let mut bagged = None;
|
||||||
for peak in self.peaks.iter().map(|&x| Some(x)) {
|
for peak in self.peaks.iter().cloned() {
|
||||||
bagged = match (bagged, peak) {
|
bagged = match (bagged, peak) {
|
||||||
(None, rhs) => rhs,
|
(None, rhs) => Some(rhs),
|
||||||
(lhs, None) => lhs,
|
(Some(lhs), rhs) => Some(lhs.hash_with(rhs)),
|
||||||
(Some(lhs), Some(rhs)) => Some(lhs.hash_with(rhs)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bagged == Some(self.root);
|
return bagged == Some(self.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut path = self.path.clone();
|
let mut path = self.path.clone();
|
||||||
let sibling = path.remove(0);
|
let (sibling, sibling_pos) = path.remove(0);
|
||||||
let mut left_right = self.left_right.clone();
|
let (parent_pos, _) = family(sibling_pos);
|
||||||
|
|
||||||
// hash our node and sibling together (noting left/right position of the
|
// hash our node and sibling together (noting left/right position of the
|
||||||
// sibling)
|
// sibling)
|
||||||
let parent = if left_right.remove(0) {
|
let parent = if is_left_sibling(sibling_pos) {
|
||||||
self.node.hash_with(sibling)
|
(sibling, self.node).hash_with_index(parent_pos)
|
||||||
} else {
|
} else {
|
||||||
sibling.hash_with(self.node)
|
(self.node, sibling).hash_with_index(parent_pos)
|
||||||
};
|
};
|
||||||
|
|
||||||
let proof = MerkleProof {
|
let proof = MerkleProof {
|
||||||
|
@ -243,7 +229,6 @@ impl MerkleProof {
|
||||||
node: parent,
|
node: parent,
|
||||||
peaks: self.peaks.clone(),
|
peaks: self.peaks.clone(),
|
||||||
path,
|
path,
|
||||||
left_right,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
proof.verify()
|
proof.verify()
|
||||||
|
@ -293,28 +278,30 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the root of the MMR. Find all the peaks in the current
|
/// Returns a vec of the peaks of this MMR.
|
||||||
/// tree and "bags" them to get a single peak.
|
pub fn peaks(&self) -> Vec<Hash> {
|
||||||
pub fn root(&self) -> Hash {
|
|
||||||
let peaks_pos = peaks(self.last_pos);
|
let peaks_pos = peaks(self.last_pos);
|
||||||
let peaks: Vec<Option<Hash>> = peaks_pos
|
peaks_pos
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|pi| {
|
.filter_map(|pi| {
|
||||||
// here we want to get from underlying hash file
|
// here we want to get from underlying hash file
|
||||||
// as the pos *may* have been "removed"
|
// as the pos *may* have been "removed"
|
||||||
self.backend.get_from_file(pi)
|
self.backend.get_from_file(pi)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
let mut ret = None;
|
/// Computes the root of the MMR. Find all the peaks in the current
|
||||||
for peak in peaks {
|
/// tree and "bags" them to get a single peak.
|
||||||
ret = match (ret, peak) {
|
pub fn root(&self) -> Hash {
|
||||||
(None, x) => x,
|
let mut res = None;
|
||||||
(Some(hash), None) => Some(hash),
|
for peak in self.peaks() {
|
||||||
(Some(lhash), Some(rhash)) => Some(lhash.hash_with(rhash)),
|
res = match (res, peak) {
|
||||||
|
(None, rhash) => Some(rhash),
|
||||||
|
(Some(lhash), rhash) => Some(lhash.hash_with(rhash)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret.expect("no root, invalid tree")
|
res.expect("no root, invalid tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a Merkle proof for the element at the given position in the MMR
|
/// Build a Merkle proof for the element at the given position in the MMR
|
||||||
|
@ -335,15 +322,10 @@ where
|
||||||
.0;
|
.0;
|
||||||
|
|
||||||
let family_branch = family_branch(pos, self.last_pos);
|
let family_branch = family_branch(pos, self.last_pos);
|
||||||
let left_right = family_branch.iter().map(|x| x.2).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let path = family_branch
|
let path = family_branch
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|x| {
|
.map(|x| (self.get_from_file(x.1).unwrap_or(Hash::zero()), x.1))
|
||||||
// we want to find siblings here even if they
|
|
||||||
// have been "removed" from the MMR
|
|
||||||
self.get_from_file(x.1)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let peaks = peaks(self.last_pos)
|
let peaks = peaks(self.last_pos)
|
||||||
|
@ -357,9 +339,8 @@ where
|
||||||
let proof = MerkleProof {
|
let proof = MerkleProof {
|
||||||
root,
|
root,
|
||||||
node,
|
node,
|
||||||
path,
|
|
||||||
peaks,
|
peaks,
|
||||||
left_right,
|
path,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(proof)
|
Ok(proof)
|
||||||
|
@ -386,11 +367,12 @@ where
|
||||||
.get_from_file(left_sibling)
|
.get_from_file(left_sibling)
|
||||||
.ok_or("missing left sibling in tree, should not have been pruned")?;
|
.ok_or("missing left sibling in tree, should not have been pruned")?;
|
||||||
|
|
||||||
current_hash = left_hash + current_hash;
|
|
||||||
|
|
||||||
to_append.push((current_hash.clone(), None));
|
|
||||||
height += 1;
|
height += 1;
|
||||||
pos += 1;
|
pos += 1;
|
||||||
|
|
||||||
|
current_hash = (left_hash, current_hash).hash_with_index(pos);
|
||||||
|
|
||||||
|
to_append.push((current_hash.clone(), None));
|
||||||
}
|
}
|
||||||
|
|
||||||
// append all the new nodes and update the MMR index
|
// append all the new nodes and update the MMR index
|
||||||
|
@ -436,7 +418,7 @@ where
|
||||||
|
|
||||||
let mut current = position;
|
let mut current = position;
|
||||||
while current + 1 <= self.last_pos {
|
while current + 1 <= self.last_pos {
|
||||||
let (parent, sibling, _) = family(current);
|
let (parent, sibling) = family(current);
|
||||||
|
|
||||||
to_prune.push(current);
|
to_prune.push(current);
|
||||||
|
|
||||||
|
@ -517,10 +499,12 @@ where
|
||||||
let left_pos = bintree_move_down_left(n).ok_or(format!("left_pos not found"))?;
|
let left_pos = bintree_move_down_left(n).ok_or(format!("left_pos not found"))?;
|
||||||
let right_pos = bintree_jump_right_sibling(left_pos);
|
let right_pos = bintree_jump_right_sibling(left_pos);
|
||||||
|
|
||||||
if let Some(left_child_hs) = self.get(left_pos, false) {
|
// using get_from_file here for the children (they may have been "removed")
|
||||||
if let Some(right_child_hs) = self.get(right_pos, false) {
|
if let Some(left_child_hs) = self.get_from_file(left_pos) {
|
||||||
// add hashes and compare
|
if let Some(right_child_hs) = self.get_from_file(right_pos) {
|
||||||
if left_child_hs.0 + right_child_hs.0 != hs.0 {
|
// hash the two child nodes together with parent_pos and compare
|
||||||
|
let (parent_pos, _) = family(left_pos);
|
||||||
|
if (left_child_hs, right_child_hs).hash_with_index(parent_pos) != hs.0 {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Invalid MMR, hash of parent at {} does \
|
"Invalid MMR, hash of parent at {} does \
|
||||||
not match children.",
|
not match children.",
|
||||||
|
@ -703,7 +687,7 @@ impl PruneList {
|
||||||
pub fn add(&mut self, pos: u64) {
|
pub fn add(&mut self, pos: u64) {
|
||||||
let mut current = pos;
|
let mut current = pos;
|
||||||
loop {
|
loop {
|
||||||
let (parent, sibling, _) = family(current);
|
let (parent, sibling) = family(current);
|
||||||
|
|
||||||
match self.pruned_nodes.binary_search(&sibling) {
|
match self.pruned_nodes.binary_search(&sibling) {
|
||||||
Ok(idx) => {
|
Ok(idx) => {
|
||||||
|
@ -734,7 +718,7 @@ impl PruneList {
|
||||||
let next_peak_pos = self.pruned_nodes[idx];
|
let next_peak_pos = self.pruned_nodes[idx];
|
||||||
let mut cursor = pos;
|
let mut cursor = pos;
|
||||||
loop {
|
loop {
|
||||||
let (parent, _, _) = family(cursor);
|
let (parent, _) = family(cursor);
|
||||||
if next_peak_pos == parent {
|
if next_peak_pos == parent {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -885,36 +869,41 @@ pub fn is_leaf(pos: u64) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the positions of the parent and sibling of the node at the
|
/// Calculates the positions of the parent and sibling of the node at the
|
||||||
/// provided position. Also returns a boolean representing whether the sibling is on left
|
/// provided position.
|
||||||
/// branch or right branch (left=0, right=1)
|
pub fn family(pos: u64) -> (u64, u64) {
|
||||||
pub fn family(pos: u64) -> (u64, u64, bool) {
|
|
||||||
let pos_height = bintree_postorder_height(pos);
|
let pos_height = bintree_postorder_height(pos);
|
||||||
let next_height = bintree_postorder_height(pos + 1);
|
let next_height = bintree_postorder_height(pos + 1);
|
||||||
if next_height > pos_height {
|
if next_height > pos_height {
|
||||||
let sibling = bintree_jump_left_sibling(pos);
|
let sibling = bintree_jump_left_sibling(pos);
|
||||||
let parent = pos + 1;
|
let parent = pos + 1;
|
||||||
(parent, sibling, false)
|
(parent, sibling)
|
||||||
} else {
|
} else {
|
||||||
let sibling = bintree_jump_right_sibling(pos);
|
let sibling = bintree_jump_right_sibling(pos);
|
||||||
let parent = sibling + 1;
|
let parent = sibling + 1;
|
||||||
(parent, sibling, true)
|
(parent, sibling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is the node at this pos the "left" sibling of its parent?
|
||||||
|
pub fn is_left_sibling(pos: u64) -> bool {
|
||||||
|
let (_, sibling_pos) = family(pos);
|
||||||
|
sibling_pos > pos
|
||||||
|
}
|
||||||
|
|
||||||
/// For a given starting position calculate the parent and sibling positions
|
/// For a given starting position calculate the parent and sibling positions
|
||||||
/// for the branch/path from that position to the peak of the tree.
|
/// for the branch/path from that position to the peak of the tree.
|
||||||
/// We will use the sibling positions to generate the "path" of a Merkle proof.
|
/// We will use the sibling positions to generate the "path" of a Merkle proof.
|
||||||
pub fn family_branch(pos: u64, last_pos: u64) -> Vec<(u64, u64, bool)> {
|
pub fn family_branch(pos: u64, last_pos: u64) -> Vec<(u64, u64)> {
|
||||||
// loop going up the tree, from node to parent, as long as we stay inside
|
// loop going up the tree, from node to parent, as long as we stay inside
|
||||||
// the tree (as defined by last_pos).
|
// the tree (as defined by last_pos).
|
||||||
let mut branch = vec![];
|
let mut branch = vec![];
|
||||||
let mut current = pos;
|
let mut current = pos;
|
||||||
while current + 1 <= last_pos {
|
while current + 1 <= last_pos {
|
||||||
let (parent, sibling, sibling_branch) = family(current);
|
let (parent, sibling) = family(current);
|
||||||
if parent > last_pos {
|
if parent > last_pos {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
branch.push((parent, sibling, sibling_branch));
|
branch.push((parent, sibling));
|
||||||
|
|
||||||
current = parent;
|
current = parent;
|
||||||
}
|
}
|
||||||
|
@ -1148,39 +1137,46 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn various_families() {
|
fn various_families() {
|
||||||
// 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3
|
// 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3
|
||||||
assert_eq!(family(1), (3, 2, true));
|
assert_eq!(family(1), (3, 2));
|
||||||
assert_eq!(family(2), (3, 1, false));
|
assert_eq!(family(2), (3, 1));
|
||||||
assert_eq!(family(3), (7, 6, true));
|
assert_eq!(family(3), (7, 6));
|
||||||
assert_eq!(family(4), (6, 5, true));
|
assert_eq!(family(4), (6, 5));
|
||||||
assert_eq!(family(5), (6, 4, false));
|
assert_eq!(family(5), (6, 4));
|
||||||
assert_eq!(family(6), (7, 3, false));
|
assert_eq!(family(6), (7, 3));
|
||||||
assert_eq!(family(7), (15, 14, true));
|
assert_eq!(family(7), (15, 14));
|
||||||
assert_eq!(family(1_000), (1_001, 997, false));
|
assert_eq!(family(1_000), (1_001, 997));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_is_left_sibling() {
|
||||||
|
assert_eq!(is_left_sibling(1), true);
|
||||||
|
assert_eq!(is_left_sibling(2), false);
|
||||||
|
assert_eq!(is_left_sibling(3), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn various_branches() {
|
fn various_branches() {
|
||||||
// the two leaf nodes in a 3 node tree (height 1)
|
// the two leaf nodes in a 3 node tree (height 1)
|
||||||
assert_eq!(family_branch(1, 3), [(3, 2, true)]);
|
assert_eq!(family_branch(1, 3), [(3, 2)]);
|
||||||
assert_eq!(family_branch(2, 3), [(3, 1, false)]);
|
assert_eq!(family_branch(2, 3), [(3, 1)]);
|
||||||
|
|
||||||
// the root node in a 3 node tree
|
// the root node in a 3 node tree
|
||||||
assert_eq!(family_branch(3, 3), []);
|
assert_eq!(family_branch(3, 3), []);
|
||||||
|
|
||||||
// leaf node in a larger tree of 7 nodes (height 2)
|
// leaf node in a larger tree of 7 nodes (height 2)
|
||||||
assert_eq!(family_branch(1, 7), [(3, 2, true), (7, 6, true)]);
|
assert_eq!(family_branch(1, 7), [(3, 2), (7, 6)]);
|
||||||
|
|
||||||
// note these only go as far up as the local peak, not necessarily the single
|
// note these only go as far up as the local peak, not necessarily the single
|
||||||
// root
|
// root
|
||||||
assert_eq!(family_branch(1, 4), [(3, 2, true)]);
|
assert_eq!(family_branch(1, 4), [(3, 2)]);
|
||||||
// pos 4 in a tree of size 4 is a local peak
|
// pos 4 in a tree of size 4 is a local peak
|
||||||
assert_eq!(family_branch(4, 4), []);
|
assert_eq!(family_branch(4, 4), []);
|
||||||
// pos 4 in a tree of size 5 is also still a local peak
|
// pos 4 in a tree of size 5 is also still a local peak
|
||||||
assert_eq!(family_branch(4, 5), []);
|
assert_eq!(family_branch(4, 5), []);
|
||||||
// pos 4 in a tree of size 6 has a parent and a sibling
|
// pos 4 in a tree of size 6 has a parent and a sibling
|
||||||
assert_eq!(family_branch(4, 6), [(6, 5, true)]);
|
assert_eq!(family_branch(4, 6), [(6, 5)]);
|
||||||
// a tree of size 7 is all under a single root
|
// a tree of size 7 is all under a single root
|
||||||
assert_eq!(family_branch(4, 7), [(6, 5, true), (7, 3, false)]);
|
assert_eq!(family_branch(4, 7), [(6, 5), (7, 3)]);
|
||||||
|
|
||||||
// ok now for a more realistic one, a tree with over a million nodes in it
|
// ok now for a more realistic one, a tree with over a million nodes in it
|
||||||
// find the "family path" back up the tree from a leaf node at 0
|
// find the "family path" back up the tree from a leaf node at 0
|
||||||
|
@ -1191,25 +1187,25 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
family_branch(1, 1_049_000),
|
family_branch(1, 1_049_000),
|
||||||
[
|
[
|
||||||
(3, 2, true),
|
(3, 2),
|
||||||
(7, 6, true),
|
(7, 6),
|
||||||
(15, 14, true),
|
(15, 14),
|
||||||
(31, 30, true),
|
(31, 30),
|
||||||
(63, 62, true),
|
(63, 62),
|
||||||
(127, 126, true),
|
(127, 126),
|
||||||
(255, 254, true),
|
(255, 254),
|
||||||
(511, 510, true),
|
(511, 510),
|
||||||
(1023, 1022, true),
|
(1023, 1022),
|
||||||
(2047, 2046, true),
|
(2047, 2046),
|
||||||
(4095, 4094, true),
|
(4095, 4094),
|
||||||
(8191, 8190, true),
|
(8191, 8190),
|
||||||
(16383, 16382, true),
|
(16383, 16382),
|
||||||
(32767, 32766, true),
|
(32767, 32766),
|
||||||
(65535, 65534, true),
|
(65535, 65534),
|
||||||
(131071, 131070, true),
|
(131071, 131070),
|
||||||
(262143, 262142, true),
|
(262143, 262142),
|
||||||
(524287, 524286, true),
|
(524287, 524286),
|
||||||
(1048575, 1048574, true),
|
(1048575, 1048574),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1295,7 +1291,6 @@ mod test {
|
||||||
let root = pmmr.root();
|
let root = pmmr.root();
|
||||||
assert_eq!(proof.peaks, [root]);
|
assert_eq!(proof.peaks, [root]);
|
||||||
assert!(proof.path.is_empty());
|
assert!(proof.path.is_empty());
|
||||||
assert!(proof.left_right.is_empty());
|
|
||||||
assert!(proof.verify());
|
assert!(proof.verify());
|
||||||
|
|
||||||
// push two more elements into the PMMR
|
// push two more elements into the PMMR
|
||||||
|
@ -1306,13 +1301,11 @@ mod test {
|
||||||
let proof1 = pmmr.merkle_proof(1).unwrap();
|
let proof1 = pmmr.merkle_proof(1).unwrap();
|
||||||
assert_eq!(proof1.peaks.len(), 2);
|
assert_eq!(proof1.peaks.len(), 2);
|
||||||
assert_eq!(proof1.path.len(), 1);
|
assert_eq!(proof1.path.len(), 1);
|
||||||
assert_eq!(proof1.left_right, [true]);
|
|
||||||
assert!(proof1.verify());
|
assert!(proof1.verify());
|
||||||
|
|
||||||
let proof2 = pmmr.merkle_proof(2).unwrap();
|
let proof2 = pmmr.merkle_proof(2).unwrap();
|
||||||
assert_eq!(proof2.peaks.len(), 2);
|
assert_eq!(proof2.peaks.len(), 2);
|
||||||
assert_eq!(proof2.path.len(), 1);
|
assert_eq!(proof2.path.len(), 1);
|
||||||
assert_eq!(proof2.left_right, [false]);
|
|
||||||
assert!(proof2.verify());
|
assert!(proof2.verify());
|
||||||
|
|
||||||
// check that we cannot generate a merkle proof for pos 3 (not a leaf node)
|
// check that we cannot generate a merkle proof for pos 3 (not a leaf node)
|
||||||
|
@ -1324,7 +1317,6 @@ mod test {
|
||||||
let proof4 = pmmr.merkle_proof(4).unwrap();
|
let proof4 = pmmr.merkle_proof(4).unwrap();
|
||||||
assert_eq!(proof4.peaks.len(), 2);
|
assert_eq!(proof4.peaks.len(), 2);
|
||||||
assert!(proof4.path.is_empty());
|
assert!(proof4.path.is_empty());
|
||||||
assert!(proof4.left_right.is_empty());
|
|
||||||
assert!(proof4.verify());
|
assert!(proof4.verify());
|
||||||
|
|
||||||
// now add a few more elements to the PMMR to build a larger merkle proof
|
// now add a few more elements to the PMMR to build a larger merkle proof
|
||||||
|
@ -1334,7 +1326,6 @@ mod test {
|
||||||
let proof = pmmr.merkle_proof(1).unwrap();
|
let proof = pmmr.merkle_proof(1).unwrap();
|
||||||
assert_eq!(proof.peaks.len(), 8);
|
assert_eq!(proof.peaks.len(), 8);
|
||||||
assert_eq!(proof.path.len(), 9);
|
assert_eq!(proof.path.len(), 9);
|
||||||
assert_eq!(proof.left_right.len(), 9);
|
|
||||||
assert!(proof.verify());
|
assert!(proof.verify());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1390,64 +1381,79 @@ mod test {
|
||||||
|
|
||||||
// one element
|
// one element
|
||||||
pmmr.push(elems[0]).unwrap();
|
pmmr.push(elems[0]).unwrap();
|
||||||
let node_hash = elems[0].hash_with_index(1);
|
|
||||||
assert_eq!(pmmr.root(), node_hash);
|
|
||||||
assert_eq!(pmmr.unpruned_size(), 1);
|
|
||||||
pmmr.dump(false);
|
pmmr.dump(false);
|
||||||
|
let pos_1 = elems[0].hash_with_index(1);
|
||||||
|
assert_eq!(pmmr.peaks(), vec![pos_1]);
|
||||||
|
assert_eq!(pmmr.root(), pos_1);
|
||||||
|
assert_eq!(pmmr.unpruned_size(), 1);
|
||||||
|
|
||||||
// two elements
|
// two elements
|
||||||
pmmr.push(elems[1]).unwrap();
|
pmmr.push(elems[1]).unwrap();
|
||||||
let sum2 = elems[0].hash_with_index(1) + elems[1].hash_with_index(2);
|
|
||||||
pmmr.dump(false);
|
pmmr.dump(false);
|
||||||
assert_eq!(pmmr.root(), sum2);
|
let pos_2 = elems[1].hash_with_index(2);
|
||||||
|
let pos_3 = (pos_1, pos_2).hash_with_index(3);
|
||||||
|
assert_eq!(pmmr.peaks(), vec![pos_3]);
|
||||||
|
assert_eq!(pmmr.root(), pos_3);
|
||||||
assert_eq!(pmmr.unpruned_size(), 3);
|
assert_eq!(pmmr.unpruned_size(), 3);
|
||||||
|
|
||||||
// three elements
|
// three elements
|
||||||
pmmr.push(elems[2]).unwrap();
|
pmmr.push(elems[2]).unwrap();
|
||||||
let sum3 = sum2 + elems[2].hash_with_index(4);
|
|
||||||
pmmr.dump(false);
|
pmmr.dump(false);
|
||||||
assert_eq!(pmmr.root(), sum3);
|
let pos_4 = elems[2].hash_with_index(4);
|
||||||
|
assert_eq!(pmmr.peaks(), vec![pos_3, pos_4]);
|
||||||
|
let root = pos_3 + pos_4;
|
||||||
|
assert_eq!(pmmr.root(), pos_3 + pos_4);
|
||||||
assert_eq!(pmmr.unpruned_size(), 4);
|
assert_eq!(pmmr.unpruned_size(), 4);
|
||||||
|
|
||||||
// four elements
|
// four elements
|
||||||
pmmr.push(elems[3]).unwrap();
|
pmmr.push(elems[3]).unwrap();
|
||||||
let sum_one = elems[2].hash_with_index(4) + elems[3].hash_with_index(5);
|
|
||||||
let sum4 = sum2 + sum_one;
|
|
||||||
pmmr.dump(false);
|
pmmr.dump(false);
|
||||||
assert_eq!(pmmr.root(), sum4);
|
let pos_5 = elems[3].hash_with_index(5);
|
||||||
|
let pos_6 = (pos_4, pos_5).hash_with_index(6);
|
||||||
|
let pos_7 = (pos_3, pos_6).hash_with_index(7);
|
||||||
|
assert_eq!(pmmr.peaks(), vec![pos_7]);
|
||||||
|
assert_eq!(pmmr.root(), pos_7);
|
||||||
assert_eq!(pmmr.unpruned_size(), 7);
|
assert_eq!(pmmr.unpruned_size(), 7);
|
||||||
|
|
||||||
// five elements
|
// five elements
|
||||||
pmmr.push(elems[4]).unwrap();
|
pmmr.push(elems[4]).unwrap();
|
||||||
let sum3 = sum4 + elems[4].hash_with_index(8);
|
|
||||||
pmmr.dump(false);
|
pmmr.dump(false);
|
||||||
assert_eq!(pmmr.root(), sum3);
|
let pos_8 = elems[4].hash_with_index(8);
|
||||||
|
assert_eq!(pmmr.peaks(), vec![pos_7, pos_8]);
|
||||||
|
assert_eq!(pmmr.root(), pos_7 + pos_8);
|
||||||
assert_eq!(pmmr.unpruned_size(), 8);
|
assert_eq!(pmmr.unpruned_size(), 8);
|
||||||
|
|
||||||
// six elements
|
// six elements
|
||||||
pmmr.push(elems[5]).unwrap();
|
pmmr.push(elems[5]).unwrap();
|
||||||
let sum6 = sum4 + (elems[4].hash_with_index(8) + elems[5].hash_with_index(9));
|
let pos_9 = elems[5].hash_with_index(9);
|
||||||
assert_eq!(pmmr.root(), sum6.clone());
|
let pos_10 = (pos_8, pos_9).hash_with_index(10);
|
||||||
|
assert_eq!(pmmr.peaks(), vec![pos_7, pos_10]);
|
||||||
|
assert_eq!(pmmr.root(), pos_7 + pos_10);
|
||||||
assert_eq!(pmmr.unpruned_size(), 10);
|
assert_eq!(pmmr.unpruned_size(), 10);
|
||||||
|
|
||||||
// seven elements
|
// seven elements
|
||||||
pmmr.push(elems[6]).unwrap();
|
pmmr.push(elems[6]).unwrap();
|
||||||
let sum7 = sum6 + elems[6].hash_with_index(11);
|
let pos_11 = elems[6].hash_with_index(11);
|
||||||
assert_eq!(pmmr.root(), sum7);
|
assert_eq!(pmmr.peaks(), vec![pos_7, pos_10, pos_11]);
|
||||||
|
assert_eq!(pmmr.root(), pos_7 + pos_10 + pos_11);
|
||||||
assert_eq!(pmmr.unpruned_size(), 11);
|
assert_eq!(pmmr.unpruned_size(), 11);
|
||||||
|
|
||||||
|
// 001001200100123
|
||||||
// eight elements
|
// eight elements
|
||||||
pmmr.push(elems[7]).unwrap();
|
pmmr.push(elems[7]).unwrap();
|
||||||
let sum8 = sum4
|
let pos_12 = elems[7].hash_with_index(12);
|
||||||
+ ((elems[4].hash_with_index(8) + elems[5].hash_with_index(9))
|
let pos_13 = (pos_11, pos_12).hash_with_index(13);
|
||||||
+ (elems[6].hash_with_index(11) + elems[7].hash_with_index(12)));
|
let pos_14 = (pos_10, pos_13).hash_with_index(14);
|
||||||
assert_eq!(pmmr.root(), sum8);
|
let pos_15 = (pos_7, pos_14).hash_with_index(15);
|
||||||
|
assert_eq!(pmmr.peaks(), vec![pos_15]);
|
||||||
|
assert_eq!(pmmr.root(), pos_15);
|
||||||
assert_eq!(pmmr.unpruned_size(), 15);
|
assert_eq!(pmmr.unpruned_size(), 15);
|
||||||
|
|
||||||
// nine elements
|
// nine elements
|
||||||
pmmr.push(elems[8]).unwrap();
|
pmmr.push(elems[8]).unwrap();
|
||||||
let sum9 = sum8 + elems[8].hash_with_index(16);
|
let pos_16 = elems[8].hash_with_index(16);
|
||||||
assert_eq!(pmmr.root(), sum9);
|
assert_eq!(pmmr.peaks(), vec![pos_15, pos_16]);
|
||||||
|
assert_eq!(pmmr.root(), pos_15 + pos_16);
|
||||||
assert_eq!(pmmr.unpruned_size(), 16);
|
assert_eq!(pmmr.unpruned_size(), 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -562,7 +562,14 @@ pub trait PMMRIndexHashable {
|
||||||
|
|
||||||
impl<T: PMMRable> PMMRIndexHashable for T {
|
impl<T: PMMRable> PMMRIndexHashable for T {
|
||||||
fn hash_with_index(&self, index: u64) -> Hash {
|
fn hash_with_index(&self, index: u64) -> Hash {
|
||||||
(index, self).hash()
|
(self, index).hash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenient way to hash two existing hashes together with an index.
|
||||||
|
impl PMMRIndexHashable for (Hash, Hash) {
|
||||||
|
fn hash_with_index(&self, index: u64) -> Hash {
|
||||||
|
(&self.0, &self.1, index).hash()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -445,7 +445,7 @@ fn removed_excl_roots(removed: Vec<u64>) -> Vec<u64> {
|
||||||
removed
|
removed
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&pos| {
|
.filter(|&pos| {
|
||||||
let (parent_pos, _, _) = family(*pos);
|
let (parent_pos, _) = family(*pos);
|
||||||
removed.binary_search(&parent_pos).is_ok()
|
removed.binary_search(&parent_pos).is_ok()
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
|
|
|
@ -41,16 +41,32 @@ fn pmmr_append() {
|
||||||
let node_hash = elems[0].hash_with_index(1);
|
let node_hash = elems[0].hash_with_index(1);
|
||||||
assert_eq!(backend.get(1, false).expect("").0, node_hash);
|
assert_eq!(backend.get(1, false).expect("").0, node_hash);
|
||||||
|
|
||||||
let sum2 = elems[0].hash_with_index(1) + elems[1].hash_with_index(2);
|
// 0010012001001230
|
||||||
let sum4 = sum2 + (elems[2].hash_with_index(4) + elems[3].hash_with_index(5));
|
|
||||||
let sum8 = sum4
|
let pos_1 = elems[0].hash_with_index(1);
|
||||||
+ ((elems[4].hash_with_index(8) + elems[5].hash_with_index(9))
|
let pos_2 = elems[1].hash_with_index(2);
|
||||||
+ (elems[6].hash_with_index(11) + elems[7].hash_with_index(12)));
|
let pos_3 = (pos_1, pos_2).hash_with_index(3);
|
||||||
let sum9 = sum8 + elems[8].hash_with_index(16);
|
|
||||||
|
let pos_4 = elems[2].hash_with_index(4);
|
||||||
|
let pos_5 = elems[3].hash_with_index(5);
|
||||||
|
let pos_6 = (pos_4, pos_5).hash_with_index(6);
|
||||||
|
let pos_7 = (pos_3, pos_6).hash_with_index(7);
|
||||||
|
|
||||||
|
let pos_8 = elems[4].hash_with_index(8);
|
||||||
|
let pos_9 = elems[5].hash_with_index(9);
|
||||||
|
let pos_10 = (pos_8, pos_9).hash_with_index(10);
|
||||||
|
|
||||||
|
let pos_11 = elems[6].hash_with_index(11);
|
||||||
|
let pos_12 = elems[7].hash_with_index(12);
|
||||||
|
let pos_13 = (pos_11, pos_12).hash_with_index(13);
|
||||||
|
let pos_14 = (pos_10, pos_13).hash_with_index(14);
|
||||||
|
let pos_15 = (pos_7, pos_14).hash_with_index(15);
|
||||||
|
|
||||||
|
let pos_16 = elems[8].hash_with_index(16);
|
||||||
|
|
||||||
{
|
{
|
||||||
let pmmr: PMMR<TestElem, _> = PMMR::at(&mut backend, mmr_size);
|
let pmmr: PMMR<TestElem, _> = PMMR::at(&mut backend, mmr_size);
|
||||||
assert_eq!(pmmr.root(), sum9);
|
assert_eq!(pmmr.root(), pos_15 + pos_16);
|
||||||
}
|
}
|
||||||
|
|
||||||
teardown(data_dir);
|
teardown(data_dir);
|
||||||
|
|
Loading…
Reference in a new issue