mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
0-based positions, bag peaks right-to-left with mmr size as index (#863)
* 0-based positions, bag peaks right-to-left with mmr size as index * fix remaining instances of hash_with_index * fix pmmr test
This commit is contained in:
parent
ccf0c11da6
commit
a327427178
3 changed files with 79 additions and 71 deletions
|
@ -146,7 +146,7 @@ impl TxHashSet {
|
||||||
let output_pmmr: PMMR<OutputIdentifier, _> =
|
let output_pmmr: PMMR<OutputIdentifier, _> =
|
||||||
PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
|
PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
|
||||||
if let Some(hash) = output_pmmr.get_hash(pos) {
|
if let Some(hash) = output_pmmr.get_hash(pos) {
|
||||||
if hash == output_id.hash_with_index(pos) {
|
if hash == output_id.hash_with_index(pos-1) {
|
||||||
Ok(hash)
|
Ok(hash)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::TxHashSetErr(format!("txhashset hash mismatch")))
|
Err(Error::TxHashSetErr(format!("txhashset hash mismatch")))
|
||||||
|
@ -386,7 +386,7 @@ impl<'a> Extension<'a> {
|
||||||
let commit = input.commitment();
|
let commit = input.commitment();
|
||||||
let pos_res = self.get_output_pos(&commit);
|
let pos_res = self.get_output_pos(&commit);
|
||||||
if let Ok(pos) = pos_res {
|
if let Ok(pos) = pos_res {
|
||||||
let output_id_hash = OutputIdentifier::from_input(input).hash_with_index(pos);
|
let output_id_hash = OutputIdentifier::from_input(input).hash_with_index(pos-1);
|
||||||
if let Some(read_hash) = self.output_pmmr.get_hash(pos) {
|
if let Some(read_hash) = self.output_pmmr.get_hash(pos) {
|
||||||
// check hash from pmmr matches hash from input (or corresponding output)
|
// check hash from pmmr matches hash from input (or corresponding output)
|
||||||
// if not then the input is not being honest about
|
// if not then the input is not being honest about
|
||||||
|
@ -398,7 +398,7 @@ impl<'a> Extension<'a> {
|
||||||
|| output_id_hash
|
|| output_id_hash
|
||||||
!= read_elem
|
!= read_elem
|
||||||
.expect("no output at position")
|
.expect("no output at position")
|
||||||
.hash_with_index(pos)
|
.hash_with_index(pos-1)
|
||||||
{
|
{
|
||||||
return Err(Error::TxHashSetErr(format!("output pmmr hash mismatch")));
|
return Err(Error::TxHashSetErr(format!("output pmmr hash mismatch")));
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use core::hash::{Hash, Hashed};
|
use core::hash::{Hash};
|
||||||
use ser;
|
use ser;
|
||||||
use ser::{Readable, Reader, Writeable, Writer};
|
use ser::{Readable, Reader, Writeable, Writer};
|
||||||
use ser::{PMMRIndexHashable, PMMRable};
|
use ser::{PMMRIndexHashable, PMMRable};
|
||||||
|
@ -111,6 +111,8 @@ pub struct MerkleProof {
|
||||||
pub root: Hash,
|
pub root: Hash,
|
||||||
/// The hash of the element in the tree we care about
|
/// The hash of the element in the tree we care about
|
||||||
pub node: Hash,
|
pub node: Hash,
|
||||||
|
/// The size of the full Merkle tree
|
||||||
|
pub mmr_size: u64,
|
||||||
/// 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 sibling (hash, pos) along the path of the tree
|
/// The sibling (hash, pos) along the path of the tree
|
||||||
|
@ -124,6 +126,7 @@ impl Writeable for MerkleProof {
|
||||||
writer,
|
writer,
|
||||||
[write_fixed_bytes, &self.root],
|
[write_fixed_bytes, &self.root],
|
||||||
[write_fixed_bytes, &self.node],
|
[write_fixed_bytes, &self.node],
|
||||||
|
[write_u64, self.mmr_size],
|
||||||
[write_u64, self.peaks.len() as u64],
|
[write_u64, self.peaks.len() as u64],
|
||||||
[write_u64, self.path.len() as u64]
|
[write_u64, self.path.len() as u64]
|
||||||
);
|
);
|
||||||
|
@ -140,7 +143,7 @@ impl Readable for MerkleProof {
|
||||||
let root = Hash::read(reader)?;
|
let root = Hash::read(reader)?;
|
||||||
let node = Hash::read(reader)?;
|
let node = Hash::read(reader)?;
|
||||||
|
|
||||||
let (peaks_len, path_len) = ser_multiread!(reader, read_u64, read_u64);
|
let (mmr_size, peaks_len, path_len) = ser_multiread!(reader, read_u64, read_u64, read_u64);
|
||||||
|
|
||||||
if peaks_len > MAX_PEAKS || path_len > MAX_PATH {
|
if peaks_len > MAX_PEAKS || path_len > MAX_PATH {
|
||||||
return Err(ser::Error::CorruptedData);
|
return Err(ser::Error::CorruptedData);
|
||||||
|
@ -161,6 +164,7 @@ impl Readable for MerkleProof {
|
||||||
Ok(MerkleProof {
|
Ok(MerkleProof {
|
||||||
root,
|
root,
|
||||||
node,
|
node,
|
||||||
|
mmr_size,
|
||||||
peaks,
|
peaks,
|
||||||
path,
|
path,
|
||||||
})
|
})
|
||||||
|
@ -180,6 +184,7 @@ impl MerkleProof {
|
||||||
MerkleProof {
|
MerkleProof {
|
||||||
root: Hash::default(),
|
root: Hash::default(),
|
||||||
node: Hash::default(),
|
node: Hash::default(),
|
||||||
|
mmr_size: 0,
|
||||||
peaks: vec![],
|
peaks: vec![],
|
||||||
path: vec![],
|
path: vec![],
|
||||||
}
|
}
|
||||||
|
@ -215,10 +220,10 @@ impl MerkleProof {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bagged = None;
|
let mut bagged = None;
|
||||||
for peak in self.peaks.iter().cloned() {
|
for peak in self.peaks.iter().rev() {
|
||||||
bagged = match (bagged, peak) {
|
bagged = match bagged {
|
||||||
(None, rhs) => Some(rhs),
|
None => Some(*peak),
|
||||||
(Some(lhs), rhs) => Some(lhs.hash_with(rhs)),
|
Some(rhs) => Some((*peak,rhs).hash_with_index(self.mmr_size)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bagged == Some(self.root);
|
return bagged == Some(self.root);
|
||||||
|
@ -231,14 +236,15 @@ impl MerkleProof {
|
||||||
// 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 is_left_sibling(sibling_pos) {
|
let parent = if is_left_sibling(sibling_pos) {
|
||||||
(sibling, self.node).hash_with_index(parent_pos)
|
(sibling, self.node).hash_with_index(parent_pos-1)
|
||||||
} else {
|
} else {
|
||||||
(self.node, sibling).hash_with_index(parent_pos)
|
(self.node, sibling).hash_with_index(parent_pos-1)
|
||||||
};
|
};
|
||||||
|
|
||||||
let proof = MerkleProof {
|
let proof = MerkleProof {
|
||||||
root: self.root,
|
root: self.root,
|
||||||
node: parent,
|
node: parent,
|
||||||
|
mmr_size: self.mmr_size,
|
||||||
peaks: self.peaks.clone(),
|
peaks: self.peaks.clone(),
|
||||||
path,
|
path,
|
||||||
};
|
};
|
||||||
|
@ -307,10 +313,10 @@ where
|
||||||
/// tree and "bags" them to get a single peak.
|
/// tree and "bags" them to get a single peak.
|
||||||
pub fn root(&self) -> Hash {
|
pub fn root(&self) -> Hash {
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
for peak in self.peaks() {
|
for peak in self.peaks().iter().rev() {
|
||||||
res = match (res, peak) {
|
res = match res {
|
||||||
(None, rhash) => Some(rhash),
|
None => Some(*peak),
|
||||||
(Some(lhash), rhash) => Some(lhash.hash_with(rhash)),
|
Some(rhash) => Some((*peak,rhash).hash_with_index(self.unpruned_size())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.expect("no root, invalid tree")
|
res.expect("no root, invalid tree")
|
||||||
|
@ -332,6 +338,8 @@ where
|
||||||
let node = self.get_hash(pos)
|
let node = self.get_hash(pos)
|
||||||
.ok_or(format!("no element at pos {}", pos))?;
|
.ok_or(format!("no element at pos {}", pos))?;
|
||||||
|
|
||||||
|
let mmr_size = self.unpruned_size();
|
||||||
|
|
||||||
let family_branch = family_branch(pos, self.last_pos);
|
let family_branch = family_branch(pos, self.last_pos);
|
||||||
|
|
||||||
let path = family_branch
|
let path = family_branch
|
||||||
|
@ -350,6 +358,7 @@ where
|
||||||
let proof = MerkleProof {
|
let proof = MerkleProof {
|
||||||
root,
|
root,
|
||||||
node,
|
node,
|
||||||
|
mmr_size,
|
||||||
peaks,
|
peaks,
|
||||||
path,
|
path,
|
||||||
};
|
};
|
||||||
|
@ -361,7 +370,7 @@ where
|
||||||
/// the same time if applicable.
|
/// the same time if applicable.
|
||||||
pub fn push(&mut self, elmt: T) -> Result<u64, String> {
|
pub fn push(&mut self, elmt: T) -> Result<u64, String> {
|
||||||
let elmt_pos = self.last_pos + 1;
|
let elmt_pos = self.last_pos + 1;
|
||||||
let mut current_hash = elmt.hash_with_index(elmt_pos);
|
let mut current_hash = elmt.hash_with_index(elmt_pos-1);
|
||||||
|
|
||||||
let mut to_append = vec![(current_hash, Some(elmt))];
|
let mut to_append = vec![(current_hash, Some(elmt))];
|
||||||
let mut height = 0;
|
let mut height = 0;
|
||||||
|
@ -381,7 +390,7 @@ where
|
||||||
height += 1;
|
height += 1;
|
||||||
pos += 1;
|
pos += 1;
|
||||||
|
|
||||||
current_hash = (left_hash, current_hash).hash_with_index(pos);
|
current_hash = (left_hash, current_hash).hash_with_index(pos-1);
|
||||||
|
|
||||||
to_append.push((current_hash.clone(), None));
|
to_append.push((current_hash.clone(), None));
|
||||||
}
|
}
|
||||||
|
@ -531,7 +540,7 @@ where
|
||||||
if let Some(right_child_hs) = self.get_from_file(right_pos) {
|
if let Some(right_child_hs) = self.get_from_file(right_pos) {
|
||||||
// hash the two child nodes together with parent_pos and compare
|
// hash the two child nodes together with parent_pos and compare
|
||||||
let (parent_pos, _) = family(left_pos);
|
let (parent_pos, _) = family(left_pos);
|
||||||
if (left_child_hs, right_child_hs).hash_with_index(parent_pos) != hash {
|
if (left_child_hs, right_child_hs).hash_with_index(parent_pos-1) != hash {
|
||||||
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.",
|
||||||
|
@ -1426,78 +1435,77 @@ mod test {
|
||||||
// one element
|
// one element
|
||||||
pmmr.push(elems[0]).unwrap();
|
pmmr.push(elems[0]).unwrap();
|
||||||
pmmr.dump(false);
|
pmmr.dump(false);
|
||||||
let pos_1 = elems[0].hash_with_index(1);
|
let pos_0 = elems[0].hash_with_index(0);
|
||||||
assert_eq!(pmmr.peaks(), vec![pos_1]);
|
assert_eq!(pmmr.peaks(), vec![pos_0]);
|
||||||
assert_eq!(pmmr.root(), pos_1);
|
assert_eq!(pmmr.root(), pos_0);
|
||||||
assert_eq!(pmmr.unpruned_size(), 1);
|
assert_eq!(pmmr.unpruned_size(), 1);
|
||||||
|
|
||||||
// two elements
|
// two elements
|
||||||
pmmr.push(elems[1]).unwrap();
|
pmmr.push(elems[1]).unwrap();
|
||||||
pmmr.dump(false);
|
pmmr.dump(false);
|
||||||
let pos_2 = elems[1].hash_with_index(2);
|
let pos_1 = elems[1].hash_with_index(1);
|
||||||
let pos_3 = (pos_1, pos_2).hash_with_index(3);
|
let pos_2 = (pos_0, pos_1).hash_with_index(2);
|
||||||
assert_eq!(pmmr.peaks(), vec![pos_3]);
|
assert_eq!(pmmr.peaks(), vec![pos_2]);
|
||||||
assert_eq!(pmmr.root(), pos_3);
|
assert_eq!(pmmr.root(), pos_2);
|
||||||
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();
|
||||||
pmmr.dump(false);
|
pmmr.dump(false);
|
||||||
let pos_4 = elems[2].hash_with_index(4);
|
let pos_3 = elems[2].hash_with_index(3);
|
||||||
assert_eq!(pmmr.peaks(), vec![pos_3, pos_4]);
|
assert_eq!(pmmr.peaks(), vec![pos_2, pos_3]);
|
||||||
let root = pos_3 + pos_4;
|
assert_eq!(pmmr.root(), (pos_2, pos_3).hash_with_index(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();
|
||||||
pmmr.dump(false);
|
pmmr.dump(false);
|
||||||
let pos_5 = elems[3].hash_with_index(5);
|
let pos_4 = elems[3].hash_with_index(4);
|
||||||
let pos_6 = (pos_4, pos_5).hash_with_index(6);
|
let pos_5 = (pos_3, pos_4).hash_with_index(5);
|
||||||
let pos_7 = (pos_3, pos_6).hash_with_index(7);
|
let pos_6 = (pos_2, pos_5).hash_with_index(6);
|
||||||
assert_eq!(pmmr.peaks(), vec![pos_7]);
|
assert_eq!(pmmr.peaks(), vec![pos_6]);
|
||||||
assert_eq!(pmmr.root(), pos_7);
|
assert_eq!(pmmr.root(), pos_6);
|
||||||
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();
|
||||||
pmmr.dump(false);
|
pmmr.dump(false);
|
||||||
let pos_8 = elems[4].hash_with_index(8);
|
let pos_7 = elems[4].hash_with_index(7);
|
||||||
assert_eq!(pmmr.peaks(), vec![pos_7, pos_8]);
|
assert_eq!(pmmr.peaks(), vec![pos_6, pos_7]);
|
||||||
assert_eq!(pmmr.root(), pos_7 + pos_8);
|
assert_eq!(pmmr.root(), (pos_6, pos_7).hash_with_index(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 pos_9 = elems[5].hash_with_index(9);
|
let pos_8 = elems[5].hash_with_index(8);
|
||||||
let pos_10 = (pos_8, pos_9).hash_with_index(10);
|
let pos_9 = (pos_7, pos_8).hash_with_index(9);
|
||||||
assert_eq!(pmmr.peaks(), vec![pos_7, pos_10]);
|
assert_eq!(pmmr.peaks(), vec![pos_6, pos_9]);
|
||||||
assert_eq!(pmmr.root(), pos_7 + pos_10);
|
assert_eq!(pmmr.root(), (pos_6, pos_9).hash_with_index(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 pos_11 = elems[6].hash_with_index(11);
|
let pos_10 = elems[6].hash_with_index(10);
|
||||||
assert_eq!(pmmr.peaks(), vec![pos_7, pos_10, pos_11]);
|
assert_eq!(pmmr.peaks(), vec![pos_6, pos_9, pos_10]);
|
||||||
assert_eq!(pmmr.root(), pos_7 + pos_10 + pos_11);
|
assert_eq!(pmmr.root(), (pos_6, (pos_9, pos_10).hash_with_index(11)).hash_with_index(11));
|
||||||
assert_eq!(pmmr.unpruned_size(), 11);
|
assert_eq!(pmmr.unpruned_size(), 11);
|
||||||
|
|
||||||
// 001001200100123
|
// 001001200100123
|
||||||
// eight elements
|
// eight elements
|
||||||
pmmr.push(elems[7]).unwrap();
|
pmmr.push(elems[7]).unwrap();
|
||||||
let pos_12 = elems[7].hash_with_index(12);
|
let pos_11 = elems[7].hash_with_index(11);
|
||||||
let pos_13 = (pos_11, pos_12).hash_with_index(13);
|
let pos_12 = (pos_10, pos_11).hash_with_index(12);
|
||||||
let pos_14 = (pos_10, pos_13).hash_with_index(14);
|
let pos_13 = (pos_9, pos_12).hash_with_index(13);
|
||||||
let pos_15 = (pos_7, pos_14).hash_with_index(15);
|
let pos_14 = (pos_6, pos_13).hash_with_index(14);
|
||||||
assert_eq!(pmmr.peaks(), vec![pos_15]);
|
assert_eq!(pmmr.peaks(), vec![pos_14]);
|
||||||
assert_eq!(pmmr.root(), pos_15);
|
assert_eq!(pmmr.root(), pos_14);
|
||||||
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 pos_16 = elems[8].hash_with_index(16);
|
let pos_15 = elems[8].hash_with_index(15);
|
||||||
assert_eq!(pmmr.peaks(), vec![pos_15, pos_16]);
|
assert_eq!(pmmr.peaks(), vec![pos_14, pos_15]);
|
||||||
assert_eq!(pmmr.root(), pos_15 + pos_16);
|
assert_eq!(pmmr.root(), (pos_14, pos_15).hash_with_index(16));
|
||||||
assert_eq!(pmmr.unpruned_size(), 16);
|
assert_eq!(pmmr.unpruned_size(), 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,35 +38,35 @@ fn pmmr_append() {
|
||||||
backend.sync().unwrap();
|
backend.sync().unwrap();
|
||||||
|
|
||||||
// check the resulting backend store and the computation of the root
|
// check the resulting backend store and the computation of the root
|
||||||
let node_hash = elems[0].hash_with_index(1);
|
let node_hash = elems[0].hash_with_index(0);
|
||||||
assert_eq!(backend.get_hash(1).unwrap(), node_hash);
|
assert_eq!(backend.get_hash(1).unwrap(), node_hash);
|
||||||
|
|
||||||
// 0010012001001230
|
// 0010012001001230
|
||||||
|
|
||||||
let pos_1 = elems[0].hash_with_index(1);
|
let pos_0 = elems[0].hash_with_index(0);
|
||||||
let pos_2 = elems[1].hash_with_index(2);
|
let pos_1 = elems[1].hash_with_index(1);
|
||||||
let pos_3 = (pos_1, pos_2).hash_with_index(3);
|
let pos_2 = (pos_0, pos_1).hash_with_index(2);
|
||||||
|
|
||||||
let pos_4 = elems[2].hash_with_index(4);
|
let pos_3 = elems[2].hash_with_index(3);
|
||||||
let pos_5 = elems[3].hash_with_index(5);
|
let pos_4 = elems[3].hash_with_index(4);
|
||||||
let pos_6 = (pos_4, pos_5).hash_with_index(6);
|
let pos_5 = (pos_3, pos_4).hash_with_index(5);
|
||||||
let pos_7 = (pos_3, pos_6).hash_with_index(7);
|
let pos_6 = (pos_2, pos_5).hash_with_index(6);
|
||||||
|
|
||||||
let pos_8 = elems[4].hash_with_index(8);
|
let pos_7 = elems[4].hash_with_index(7);
|
||||||
let pos_9 = elems[5].hash_with_index(9);
|
let pos_8 = elems[5].hash_with_index(8);
|
||||||
let pos_10 = (pos_8, pos_9).hash_with_index(10);
|
let pos_9 = (pos_7, pos_8).hash_with_index(9);
|
||||||
|
|
||||||
let pos_11 = elems[6].hash_with_index(11);
|
let pos_10 = elems[6].hash_with_index(10);
|
||||||
let pos_12 = elems[7].hash_with_index(12);
|
let pos_11 = elems[7].hash_with_index(11);
|
||||||
let pos_13 = (pos_11, pos_12).hash_with_index(13);
|
let pos_12 = (pos_10, pos_11).hash_with_index(12);
|
||||||
let pos_14 = (pos_10, pos_13).hash_with_index(14);
|
let pos_13 = (pos_9, pos_12).hash_with_index(13);
|
||||||
let pos_15 = (pos_7, pos_14).hash_with_index(15);
|
let pos_14 = (pos_6, pos_13).hash_with_index(14);
|
||||||
|
|
||||||
let pos_16 = elems[8].hash_with_index(16);
|
let pos_15 = elems[8].hash_with_index(15);
|
||||||
|
|
||||||
{
|
{
|
||||||
let pmmr: PMMR<TestElem, _> = PMMR::at(&mut backend, mmr_size);
|
let pmmr: PMMR<TestElem, _> = PMMR::at(&mut backend, mmr_size);
|
||||||
assert_eq!(pmmr.root(), pos_15 + pos_16);
|
assert_eq!(pmmr.root(), (pos_14, pos_15).hash_with_index(16));
|
||||||
}
|
}
|
||||||
|
|
||||||
teardown(data_dir);
|
teardown(data_dir);
|
||||||
|
|
Loading…
Reference in a new issue