mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 08:51:08 +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, _> =
|
||||
PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_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)
|
||||
} else {
|
||||
Err(Error::TxHashSetErr(format!("txhashset hash mismatch")))
|
||||
|
@ -386,7 +386,7 @@ impl<'a> Extension<'a> {
|
|||
let commit = input.commitment();
|
||||
let pos_res = self.get_output_pos(&commit);
|
||||
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) {
|
||||
// check hash from pmmr matches hash from input (or corresponding output)
|
||||
// if not then the input is not being honest about
|
||||
|
@ -398,7 +398,7 @@ impl<'a> Extension<'a> {
|
|||
|| output_id_hash
|
||||
!= read_elem
|
||||
.expect("no output at position")
|
||||
.hash_with_index(pos)
|
||||
.hash_with_index(pos-1)
|
||||
{
|
||||
return Err(Error::TxHashSetErr(format!("output pmmr hash mismatch")));
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
use std::clone::Clone;
|
||||
use std::marker::PhantomData;
|
||||
use core::hash::{Hash, Hashed};
|
||||
use core::hash::{Hash};
|
||||
use ser;
|
||||
use ser::{Readable, Reader, Writeable, Writer};
|
||||
use ser::{PMMRIndexHashable, PMMRable};
|
||||
|
@ -111,6 +111,8 @@ pub struct MerkleProof {
|
|||
pub root: Hash,
|
||||
/// The hash of the element in the tree we care about
|
||||
pub node: Hash,
|
||||
/// The size of the full Merkle tree
|
||||
pub mmr_size: u64,
|
||||
/// The full list of peak hashes in the MMR
|
||||
pub peaks: Vec<Hash>,
|
||||
/// The sibling (hash, pos) along the path of the tree
|
||||
|
@ -124,6 +126,7 @@ impl Writeable for MerkleProof {
|
|||
writer,
|
||||
[write_fixed_bytes, &self.root],
|
||||
[write_fixed_bytes, &self.node],
|
||||
[write_u64, self.mmr_size],
|
||||
[write_u64, self.peaks.len() as u64],
|
||||
[write_u64, self.path.len() as u64]
|
||||
);
|
||||
|
@ -140,7 +143,7 @@ impl Readable for MerkleProof {
|
|||
let root = 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 {
|
||||
return Err(ser::Error::CorruptedData);
|
||||
|
@ -161,6 +164,7 @@ impl Readable for MerkleProof {
|
|||
Ok(MerkleProof {
|
||||
root,
|
||||
node,
|
||||
mmr_size,
|
||||
peaks,
|
||||
path,
|
||||
})
|
||||
|
@ -180,6 +184,7 @@ impl MerkleProof {
|
|||
MerkleProof {
|
||||
root: Hash::default(),
|
||||
node: Hash::default(),
|
||||
mmr_size: 0,
|
||||
peaks: vec![],
|
||||
path: vec![],
|
||||
}
|
||||
|
@ -215,10 +220,10 @@ impl MerkleProof {
|
|||
}
|
||||
|
||||
let mut bagged = None;
|
||||
for peak in self.peaks.iter().cloned() {
|
||||
bagged = match (bagged, peak) {
|
||||
(None, rhs) => Some(rhs),
|
||||
(Some(lhs), rhs) => Some(lhs.hash_with(rhs)),
|
||||
for peak in self.peaks.iter().rev() {
|
||||
bagged = match bagged {
|
||||
None => Some(*peak),
|
||||
Some(rhs) => Some((*peak,rhs).hash_with_index(self.mmr_size)),
|
||||
}
|
||||
}
|
||||
return bagged == Some(self.root);
|
||||
|
@ -231,14 +236,15 @@ impl MerkleProof {
|
|||
// hash our node and sibling together (noting left/right position of the
|
||||
// sibling)
|
||||
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 {
|
||||
(self.node, sibling).hash_with_index(parent_pos)
|
||||
(self.node, sibling).hash_with_index(parent_pos-1)
|
||||
};
|
||||
|
||||
let proof = MerkleProof {
|
||||
root: self.root,
|
||||
node: parent,
|
||||
mmr_size: self.mmr_size,
|
||||
peaks: self.peaks.clone(),
|
||||
path,
|
||||
};
|
||||
|
@ -307,10 +313,10 @@ where
|
|||
/// tree and "bags" them to get a single peak.
|
||||
pub fn root(&self) -> Hash {
|
||||
let mut res = None;
|
||||
for peak in self.peaks() {
|
||||
res = match (res, peak) {
|
||||
(None, rhash) => Some(rhash),
|
||||
(Some(lhash), rhash) => Some(lhash.hash_with(rhash)),
|
||||
for peak in self.peaks().iter().rev() {
|
||||
res = match res {
|
||||
None => Some(*peak),
|
||||
Some(rhash) => Some((*peak,rhash).hash_with_index(self.unpruned_size())),
|
||||
}
|
||||
}
|
||||
res.expect("no root, invalid tree")
|
||||
|
@ -332,6 +338,8 @@ where
|
|||
let node = self.get_hash(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 path = family_branch
|
||||
|
@ -350,6 +358,7 @@ where
|
|||
let proof = MerkleProof {
|
||||
root,
|
||||
node,
|
||||
mmr_size,
|
||||
peaks,
|
||||
path,
|
||||
};
|
||||
|
@ -361,7 +370,7 @@ where
|
|||
/// the same time if applicable.
|
||||
pub fn push(&mut self, elmt: T) -> Result<u64, String> {
|
||||
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 height = 0;
|
||||
|
@ -381,7 +390,7 @@ where
|
|||
height += 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));
|
||||
}
|
||||
|
@ -531,7 +540,7 @@ where
|
|||
if let Some(right_child_hs) = self.get_from_file(right_pos) {
|
||||
// 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) != hash {
|
||||
if (left_child_hs, right_child_hs).hash_with_index(parent_pos-1) != hash {
|
||||
return Err(format!(
|
||||
"Invalid MMR, hash of parent at {} does \
|
||||
not match children.",
|
||||
|
@ -1426,78 +1435,77 @@ mod test {
|
|||
// one element
|
||||
pmmr.push(elems[0]).unwrap();
|
||||
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);
|
||||
let pos_0 = elems[0].hash_with_index(0);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_0]);
|
||||
assert_eq!(pmmr.root(), pos_0);
|
||||
assert_eq!(pmmr.unpruned_size(), 1);
|
||||
|
||||
// two elements
|
||||
pmmr.push(elems[1]).unwrap();
|
||||
pmmr.dump(false);
|
||||
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);
|
||||
let pos_1 = elems[1].hash_with_index(1);
|
||||
let pos_2 = (pos_0, pos_1).hash_with_index(2);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_2]);
|
||||
assert_eq!(pmmr.root(), pos_2);
|
||||
assert_eq!(pmmr.unpruned_size(), 3);
|
||||
|
||||
// three elements
|
||||
pmmr.push(elems[2]).unwrap();
|
||||
pmmr.dump(false);
|
||||
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);
|
||||
let pos_3 = elems[2].hash_with_index(3);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_2, pos_3]);
|
||||
assert_eq!(pmmr.root(), (pos_2, pos_3).hash_with_index(4));
|
||||
assert_eq!(pmmr.unpruned_size(), 4);
|
||||
|
||||
// four elements
|
||||
pmmr.push(elems[3]).unwrap();
|
||||
pmmr.dump(false);
|
||||
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);
|
||||
let pos_4 = elems[3].hash_with_index(4);
|
||||
let pos_5 = (pos_3, pos_4).hash_with_index(5);
|
||||
let pos_6 = (pos_2, pos_5).hash_with_index(6);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_6]);
|
||||
assert_eq!(pmmr.root(), pos_6);
|
||||
assert_eq!(pmmr.unpruned_size(), 7);
|
||||
|
||||
// five elements
|
||||
pmmr.push(elems[4]).unwrap();
|
||||
pmmr.dump(false);
|
||||
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);
|
||||
let pos_7 = elems[4].hash_with_index(7);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_6, pos_7]);
|
||||
assert_eq!(pmmr.root(), (pos_6, pos_7).hash_with_index(8));
|
||||
assert_eq!(pmmr.unpruned_size(), 8);
|
||||
|
||||
// six elements
|
||||
pmmr.push(elems[5]).unwrap();
|
||||
let pos_9 = elems[5].hash_with_index(9);
|
||||
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);
|
||||
let pos_8 = elems[5].hash_with_index(8);
|
||||
let pos_9 = (pos_7, pos_8).hash_with_index(9);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_6, pos_9]);
|
||||
assert_eq!(pmmr.root(), (pos_6, pos_9).hash_with_index(10));
|
||||
assert_eq!(pmmr.unpruned_size(), 10);
|
||||
|
||||
// seven elements
|
||||
pmmr.push(elems[6]).unwrap();
|
||||
let pos_11 = elems[6].hash_with_index(11);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_7, pos_10, pos_11]);
|
||||
assert_eq!(pmmr.root(), pos_7 + pos_10 + pos_11);
|
||||
let pos_10 = elems[6].hash_with_index(10);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_6, pos_9, pos_10]);
|
||||
assert_eq!(pmmr.root(), (pos_6, (pos_9, pos_10).hash_with_index(11)).hash_with_index(11));
|
||||
assert_eq!(pmmr.unpruned_size(), 11);
|
||||
|
||||
// 001001200100123
|
||||
// eight elements
|
||||
pmmr.push(elems[7]).unwrap();
|
||||
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);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_15]);
|
||||
assert_eq!(pmmr.root(), pos_15);
|
||||
let pos_11 = elems[7].hash_with_index(11);
|
||||
let pos_12 = (pos_10, pos_11).hash_with_index(12);
|
||||
let pos_13 = (pos_9, pos_12).hash_with_index(13);
|
||||
let pos_14 = (pos_6, pos_13).hash_with_index(14);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_14]);
|
||||
assert_eq!(pmmr.root(), pos_14);
|
||||
assert_eq!(pmmr.unpruned_size(), 15);
|
||||
|
||||
// nine elements
|
||||
pmmr.push(elems[8]).unwrap();
|
||||
let pos_16 = elems[8].hash_with_index(16);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_15, pos_16]);
|
||||
assert_eq!(pmmr.root(), pos_15 + pos_16);
|
||||
let pos_15 = elems[8].hash_with_index(15);
|
||||
assert_eq!(pmmr.peaks(), vec![pos_14, pos_15]);
|
||||
assert_eq!(pmmr.root(), (pos_14, pos_15).hash_with_index(16));
|
||||
assert_eq!(pmmr.unpruned_size(), 16);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,35 +38,35 @@ fn pmmr_append() {
|
|||
backend.sync().unwrap();
|
||||
|
||||
// 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);
|
||||
|
||||
// 0010012001001230
|
||||
|
||||
let pos_1 = elems[0].hash_with_index(1);
|
||||
let pos_2 = elems[1].hash_with_index(2);
|
||||
let pos_3 = (pos_1, pos_2).hash_with_index(3);
|
||||
let pos_0 = elems[0].hash_with_index(0);
|
||||
let pos_1 = elems[1].hash_with_index(1);
|
||||
let pos_2 = (pos_0, pos_1).hash_with_index(2);
|
||||
|
||||
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_3 = elems[2].hash_with_index(3);
|
||||
let pos_4 = elems[3].hash_with_index(4);
|
||||
let pos_5 = (pos_3, pos_4).hash_with_index(5);
|
||||
let pos_6 = (pos_2, pos_5).hash_with_index(6);
|
||||
|
||||
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_7 = elems[4].hash_with_index(7);
|
||||
let pos_8 = elems[5].hash_with_index(8);
|
||||
let pos_9 = (pos_7, pos_8).hash_with_index(9);
|
||||
|
||||
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_10 = elems[6].hash_with_index(10);
|
||||
let pos_11 = elems[7].hash_with_index(11);
|
||||
let pos_12 = (pos_10, pos_11).hash_with_index(12);
|
||||
let pos_13 = (pos_9, pos_12).hash_with_index(13);
|
||||
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);
|
||||
assert_eq!(pmmr.root(), pos_15 + pos_16);
|
||||
assert_eq!(pmmr.root(), (pos_14, pos_15).hash_with_index(16));
|
||||
}
|
||||
|
||||
teardown(data_dir);
|
||||
|
|
Loading…
Reference in a new issue