Take the 'Sum' out of 'Sumtree' (#702)

* beginning to remove sum

* continuing to remove sumtree sums

* finished removing sums from pmmr core

* renamed sumtree files, and completed changes+test updates in core and store

* updating grin/chain to include removelogs

* integration of flatfile structure, changes to chain/sumtree to start using them

* tests on chain, core and store passing

* cleaning up api and tests

* formatting

* flatfiles stored as part of PMMR backend instead

* all compiling and tests running

* documentation

* added remove + pruning to flatfiles

* remove unneeded enum

* adding sumtree root struct
This commit is contained in:
Yeastplume
2018-02-22 13:45:13 +00:00
committed by GitHub
parent c2ca6ad03f
commit 05d1c6c817
17 changed files with 893 additions and 879 deletions
+14 -17
View File
@@ -20,21 +20,18 @@ use std::fs::File;
use std::sync::{Arc, Mutex, RwLock};
use std::time::{Duration, Instant};
use util::secp::pedersen::RangeProof;
use core::core::{Input, OutputIdentifier, SumCommit};
use core::core::hash::Hashed;
use core::core::pmmr::{HashSum, NoSum};
use core::core::{Input, OutputIdentifier, OutputStoreable, TxKernel};
use core::core::hash::{Hash, Hashed};
use core::global;
use core::core::{Block, BlockHeader, TxKernel};
use core::core::{Block, BlockHeader};
use core::core::target::Difficulty;
use core::core::hash::Hash;
use grin_store::Error::NotFoundErr;
use pipe;
use store;
use sumtree;
use types::*;
use util::secp::pedersen::RangeProof;
use util::LOGGER;
@@ -428,9 +425,9 @@ impl Chain {
Ok(extension.roots())
})?;
b.header.utxo_root = roots.0.hash;
b.header.range_proof_root = roots.1.hash;
b.header.kernel_root = roots.2.hash;
b.header.utxo_root = roots.utxo_root;
b.header.range_proof_root = roots.rproof_root;
b.header.kernel_root = roots.kernel_root;
Ok(())
}
@@ -438,9 +435,9 @@ impl Chain {
pub fn get_sumtree_roots(
&self,
) -> (
HashSum<SumCommit>,
HashSum<NoSum<RangeProof>>,
HashSum<NoSum<TxKernel>>,
Hash,
Hash,
Hash,
) {
let mut sumtrees = self.sumtrees.write().unwrap();
sumtrees.roots()
@@ -507,7 +504,7 @@ impl Chain {
{
let mut head = self.head.lock().unwrap();
*head = Tip::from_block(&header);
self.store.save_body_head(&head)?;
let _ = self.store.save_body_head(&head);
self.store.save_header_height(&header)?;
}
@@ -517,19 +514,19 @@ impl Chain {
}
/// returns the last n nodes inserted into the utxo sum tree
pub fn get_last_n_utxo(&self, distance: u64) -> Vec<HashSum<SumCommit>> {
pub fn get_last_n_utxo(&self, distance: u64) -> Vec<(Hash, Option<OutputStoreable>)> {
let mut sumtrees = self.sumtrees.write().unwrap();
sumtrees.last_n_utxo(distance)
}
/// as above, for rangeproofs
pub fn get_last_n_rangeproof(&self, distance: u64) -> Vec<HashSum<NoSum<RangeProof>>> {
pub fn get_last_n_rangeproof(&self, distance: u64) -> Vec<(Hash, Option<RangeProof>)> {
let mut sumtrees = self.sumtrees.write().unwrap();
sumtrees.last_n_rangeproof(distance)
}
/// as above, for kernels
pub fn get_last_n_kernel(&self, distance: u64) -> Vec<HashSum<NoSum<TxKernel>>> {
pub fn get_last_n_kernel(&self, distance: u64) -> Vec<(Hash, Option<TxKernel>)> {
let mut sumtrees = self.sumtrees.write().unwrap();
sumtrees.last_n_kernel(distance)
}
+6 -6
View File
@@ -305,28 +305,28 @@ fn validate_block(
// apply the new block to the MMR trees and check the new root hashes
ext.apply_block(&b)?;
let (utxo_root, rproof_root, kernel_root) = ext.roots();
if utxo_root.hash != b.header.utxo_root || rproof_root.hash != b.header.range_proof_root
|| kernel_root.hash != b.header.kernel_root
let roots = ext.roots();
if roots.utxo_root != b.header.utxo_root || roots.rproof_root != b.header.range_proof_root
|| roots.kernel_root != b.header.kernel_root
{
ext.dump(false);
debug!(
LOGGER,
"validate_block: utxo roots - {:?}, {:?}",
utxo_root.hash,
roots.utxo_root,
b.header.utxo_root,
);
debug!(
LOGGER,
"validate_block: rproof roots - {:?}, {:?}",
rproof_root.hash,
roots.rproof_root,
b.header.range_proof_root,
);
debug!(
LOGGER,
"validate_block: kernel roots - {:?}, {:?}",
kernel_root.hash,
roots.kernel_root,
b.header.kernel_root,
);
+136 -118
View File
@@ -1,4 +1,3 @@
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -26,26 +25,26 @@ use util::static_secp_instance;
use util::secp::pedersen::{RangeProof, Commitment};
use core::consensus::reward;
use core::core::{Block, BlockHeader, SumCommit, Input, Output, OutputIdentifier, OutputFeatures, TxKernel};
use core::core::pmmr::{self, HashSum, NoSum, Summable, PMMR};
use core::core::hash::Hashed;
use core::ser;
use core::core::{Block, BlockHeader, Input, Output, OutputIdentifier,
OutputFeatures, OutputStoreable, TxKernel};
use core::core::pmmr::{self, PMMR};
use core::core::hash::{Hash, Hashed};
use core::ser::{self, PMMRable};
use grin_store;
use grin_store::sumtree::{PMMRBackend, AppendOnlyFile};
use types::ChainStore;
use types::Error;
use grin_store::pmmr::PMMRBackend;
use types::{ChainStore, SumTreeRoots, Error};
use util::{LOGGER, zip};
const SUMTREES_SUBDIR: &'static str = "sumtrees";
const UTXO_SUBDIR: &'static str = "utxo";
const RANGE_PROOF_SUBDIR: &'static str = "rangeproof";
const KERNEL_SUBDIR: &'static str = "kernel";
const KERNEL_FILE: &'static str = "kernel_full_data.bin";
const SUMTREES_ZIP: &'static str = "sumtrees_snapshot.zip";
struct PMMRHandle<T>
where
T: Summable + Clone,
T: PMMRable,
{
backend: PMMRBackend<T>,
last_pos: u64,
@@ -53,7 +52,7 @@ where
impl<T> PMMRHandle<T>
where
T: Summable + Clone,
T: PMMRable,
{
fn new(root_dir: String, file_name: &str) -> Result<PMMRHandle<T>, Error> {
let path = Path::new(&root_dir).join(SUMTREES_SUBDIR).join(file_name);
@@ -70,20 +69,17 @@ where
/// An easy to manipulate structure holding the 3 sum trees necessary to
/// validate blocks and capturing the UTXO set, the range proofs and the
/// kernels. Also handles the index of Commitments to positions in the
/// output and range proof sum trees.
/// output and range proof pmmr trees.
///
/// Note that the index is never authoritative, only the trees are
/// guaranteed to indicate whether an output is spent or not. The index
/// may have commitments that have already been spent, even with
/// pruning enabled.
///
/// In addition of the sumtrees, this maintains the full list of kernel
/// data so it can be easily packaged for sync or validation.
pub struct SumTrees {
output_pmmr_h: PMMRHandle<SumCommit>,
rproof_pmmr_h: PMMRHandle<NoSum<RangeProof>>,
kernel_pmmr_h: PMMRHandle<NoSum<TxKernel>>,
kernel_file: AppendOnlyFile,
utxo_pmmr_h: PMMRHandle<OutputStoreable>,
rproof_pmmr_h: PMMRHandle<RangeProof>,
kernel_pmmr_h: PMMRHandle<TxKernel>,
// chain store used as index of commitments to MMR positions
commit_index: Arc<ChainStore>,
@@ -92,16 +88,20 @@ pub struct SumTrees {
impl SumTrees {
/// Open an existing or new set of backends for the SumTrees
pub fn open(root_dir: String, commit_index: Arc<ChainStore>) -> Result<SumTrees, Error> {
let mut kernel_file_path: PathBuf = [&root_dir, SUMTREES_SUBDIR, KERNEL_SUBDIR].iter().collect();
let utxo_file_path: PathBuf = [&root_dir, SUMTREES_SUBDIR, UTXO_SUBDIR].iter().collect();
fs::create_dir_all(utxo_file_path.clone())?;
let rproof_file_path: PathBuf = [&root_dir, SUMTREES_SUBDIR, RANGE_PROOF_SUBDIR].iter().collect();
fs::create_dir_all(rproof_file_path.clone())?;
let kernel_file_path: PathBuf = [&root_dir, SUMTREES_SUBDIR, KERNEL_SUBDIR].iter().collect();
fs::create_dir_all(kernel_file_path.clone())?;
kernel_file_path.push(KERNEL_FILE);
let kernel_file = AppendOnlyFile::open(kernel_file_path.to_str().unwrap().to_owned())?;
Ok(SumTrees {
output_pmmr_h: PMMRHandle::new(root_dir.clone(), UTXO_SUBDIR)?,
utxo_pmmr_h: PMMRHandle::new(root_dir.clone(), UTXO_SUBDIR)?,
rproof_pmmr_h: PMMRHandle::new(root_dir.clone(), RANGE_PROOF_SUBDIR)?,
kernel_pmmr_h: PMMRHandle::new(root_dir.clone(), KERNEL_SUBDIR)?,
kernel_file: kernel_file,
commit_index: commit_index,
})
}
@@ -109,19 +109,19 @@ impl SumTrees {
/// Check is an output is unspent.
/// We look in the index to find the output MMR pos.
/// Then we check the entry in the output MMR and confirm the hash matches.
pub fn is_unspent(&mut self, output: &OutputIdentifier) -> Result<(), Error> {
match self.commit_index.get_output_pos(&output.commit) {
pub fn is_unspent(&mut self, output_id: &OutputIdentifier) -> Result<(), Error> {
match self.commit_index.get_output_pos(&output_id.commit) {
Ok(pos) => {
let output_pmmr = PMMR::at(
&mut self.output_pmmr_h.backend,
self.output_pmmr_h.last_pos,
let output_pmmr:PMMR<OutputStoreable, _> = PMMR::at(
&mut self.utxo_pmmr_h.backend,
self.utxo_pmmr_h.last_pos,
);
if let Some(HashSum { hash, sum: _ }) = output_pmmr.get(pos) {
let sum_commit = output.as_sum_commit();
let hash_sum = HashSum::from_summable(pos, &sum_commit);
if hash == hash_sum.hash {
if let Some((hash, _)) = output_pmmr.get(pos, false) {
println!("Getting output ID hash");
if hash == output_id.hash() {
Ok(())
} else {
println!("MISMATCH BECAUSE THE BLOODY THING MISMATCHES");
Err(Error::SumTreeErr(format!("sumtree hash mismatch")))
}
} else {
@@ -164,20 +164,21 @@ impl SumTrees {
/// returns the last N nodes inserted into the tree (i.e. the 'bottom'
/// nodes at level 0
pub fn last_n_utxo(&mut self, distance: u64) -> Vec<HashSum<SumCommit>> {
let output_pmmr = PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
output_pmmr.get_last_n_insertions(distance)
/// TODO: These need to return the actual data from the flat-files instead of hashes now
pub fn last_n_utxo(&mut self, distance: u64) -> Vec<(Hash, Option<OutputStoreable>)> {
let utxo_pmmr:PMMR<OutputStoreable, _> = PMMR::at(&mut self.utxo_pmmr_h.backend, self.utxo_pmmr_h.last_pos);
utxo_pmmr.get_last_n_insertions(distance)
}
/// as above, for range proofs
pub fn last_n_rangeproof(&mut self, distance: u64) -> Vec<HashSum<NoSum<RangeProof>>> {
let rproof_pmmr = PMMR::at(&mut self.rproof_pmmr_h.backend, self.rproof_pmmr_h.last_pos);
pub fn last_n_rangeproof(&mut self, distance: u64) -> Vec<(Hash, Option<RangeProof>)> {
let rproof_pmmr:PMMR<RangeProof, _> = PMMR::at(&mut self.rproof_pmmr_h.backend, self.rproof_pmmr_h.last_pos);
rproof_pmmr.get_last_n_insertions(distance)
}
/// as above, for kernels
pub fn last_n_kernel(&mut self, distance: u64) -> Vec<HashSum<NoSum<TxKernel>>> {
let kernel_pmmr = PMMR::at(&mut self.kernel_pmmr_h.backend, self.kernel_pmmr_h.last_pos);
pub fn last_n_kernel(&mut self, distance: u64) -> Vec<(Hash, Option<TxKernel>)> {
let kernel_pmmr:PMMR<TxKernel, _> = PMMR::at(&mut self.kernel_pmmr_h.backend, self.kernel_pmmr_h.last_pos);
kernel_pmmr.get_last_n_insertions(distance)
}
@@ -186,17 +187,19 @@ impl SumTrees {
indexes_at(block, self.commit_index.deref())
}
/// Get sum tree roots
/// TODO: Return data instead of hashes
pub fn roots(
&mut self,
) -> (
HashSum<SumCommit>,
HashSum<NoSum<RangeProof>>,
HashSum<NoSum<TxKernel>>,
Hash,
Hash,
Hash,
) {
let output_pmmr = PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
let rproof_pmmr = PMMR::at(&mut self.rproof_pmmr_h.backend, self.rproof_pmmr_h.last_pos);
let kernel_pmmr = PMMR::at(&mut self.kernel_pmmr_h.backend, self.kernel_pmmr_h.last_pos);
let output_pmmr:PMMR<OutputStoreable, _> = PMMR::at(&mut self.utxo_pmmr_h.backend, self.utxo_pmmr_h.last_pos);
let rproof_pmmr:PMMR<RangeProof, _> = PMMR::at(&mut self.rproof_pmmr_h.backend, self.rproof_pmmr_h.last_pos);
let kernel_pmmr:PMMR<TxKernel, _> = PMMR::at(&mut self.kernel_pmmr_h.backend, self.kernel_pmmr_h.last_pos);
(output_pmmr.root(), rproof_pmmr.root(), kernel_pmmr.root())
}
}
@@ -231,26 +234,23 @@ where
match res {
Err(e) => {
debug!(LOGGER, "Error returned, discarding sumtree extension.");
trees.output_pmmr_h.backend.discard();
trees.utxo_pmmr_h.backend.discard();
trees.rproof_pmmr_h.backend.discard();
trees.kernel_pmmr_h.backend.discard();
trees.kernel_file.discard();
Err(e)
}
Ok(r) => {
if rollback {
debug!(LOGGER, "Rollbacking sumtree extension.");
trees.output_pmmr_h.backend.discard();
trees.utxo_pmmr_h.backend.discard();
trees.rproof_pmmr_h.backend.discard();
trees.kernel_pmmr_h.backend.discard();
trees.kernel_file.discard();
} else {
debug!(LOGGER, "Committing sumtree extension.");
trees.output_pmmr_h.backend.sync()?;
trees.utxo_pmmr_h.backend.sync()?;
trees.rproof_pmmr_h.backend.sync()?;
trees.kernel_pmmr_h.backend.sync()?;
trees.kernel_file.flush()?;
trees.output_pmmr_h.last_pos = sizes.0;
trees.utxo_pmmr_h.last_pos = sizes.0;
trees.rproof_pmmr_h.last_pos = sizes.1;
trees.kernel_pmmr_h.last_pos = sizes.2;
}
@@ -265,11 +265,10 @@ where
/// reversible manner within a unit of work provided by the `extending`
/// function.
pub struct Extension<'a> {
output_pmmr: PMMR<'a, SumCommit, PMMRBackend<SumCommit>>,
rproof_pmmr: PMMR<'a, NoSum<RangeProof>, PMMRBackend<NoSum<RangeProof>>>,
kernel_pmmr: PMMR<'a, NoSum<TxKernel>, PMMRBackend<NoSum<TxKernel>>>,
utxo_pmmr: PMMR<'a, OutputStoreable, PMMRBackend<OutputStoreable>>,
rproof_pmmr: PMMR<'a, RangeProof, PMMRBackend<RangeProof>>,
kernel_pmmr: PMMR<'a, TxKernel, PMMRBackend<TxKernel>>,
kernel_file: &'a mut AppendOnlyFile,
commit_index: Arc<ChainStore>,
new_output_commits: HashMap<Commitment, u64>,
new_kernel_excesses: HashMap<Commitment, u64>,
@@ -284,9 +283,9 @@ impl<'a> Extension<'a> {
) -> Extension<'a> {
Extension {
output_pmmr: PMMR::at(
&mut trees.output_pmmr_h.backend,
trees.output_pmmr_h.last_pos,
utxo_pmmr: PMMR::at(
&mut trees.utxo_pmmr_h.backend,
trees.utxo_pmmr_h.last_pos,
),
rproof_pmmr: PMMR::at(
&mut trees.rproof_pmmr_h.backend,
@@ -296,10 +295,10 @@ impl<'a> Extension<'a> {
&mut trees.kernel_pmmr_h.backend,
trees.kernel_pmmr_h.last_pos,
),
kernel_file: &mut trees.kernel_file,
commit_index: commit_index,
new_output_commits: HashMap::new(),
new_kernel_excesses: HashMap::new(),
rollback: false,
}
}
@@ -354,15 +353,14 @@ impl<'a> Extension<'a> {
fn apply_input(&mut self, input: &Input, height: u64) -> Result<(), Error> {
let commit = input.commitment();
let pos_res = self.get_output_pos(&commit);
let output_id_hash = OutputIdentifier::from_input(input).hash();
if let Ok(pos) = pos_res {
if let Some(HashSum { hash, sum: _ }) = self.output_pmmr.get(pos) {
let sum_commit = SumCommit::from_input(&input);
// check hash from pmmr matches hash from input
if let Some((read_hash, read_elem)) = self.utxo_pmmr.get(pos, true) {
// check hash from pmmr matches hash from input (or corresponding output)
// if not then the input is not being honest about
// what it is attempting to spend...
let hash_sum = HashSum::from_summable(pos, &sum_commit);
if hash != hash_sum.hash {
if output_id_hash != read_hash ||
output_id_hash != read_elem.expect("no output at position").hash() {
return Err(Error::SumTreeErr(format!("output pmmr hash mismatch")));
}
@@ -379,9 +377,10 @@ impl<'a> Extension<'a> {
}
}
// Now prune the output_pmmr and rproof_pmmr.
// Now prune the utxo_pmmr, rproof_pmmr and their storage.
// Input is not valid if we cannot prune successfully (to spend an unspent output).
match self.output_pmmr.prune(pos, height as u32) {
// TODO: rm log, skip list for utxo and range proofs
match self.utxo_pmmr.prune(pos, height as u32) {
Ok(true) => {
self.rproof_pmmr
.prune(pos, height as u32)
@@ -398,7 +397,6 @@ impl<'a> Extension<'a> {
fn apply_output(&mut self, out: &Output) -> Result<(), Error> {
let commit = out.commitment();
let sum_commit = SumCommit::from_output(out);
if let Ok(pos) = self.get_output_pos(&commit) {
// we need to check whether the commitment is in the current MMR view
@@ -406,27 +404,24 @@ impl<'a> Extension<'a> {
// (non-historical node will have a much smaller one)
// note that this doesn't show the commitment *never* existed, just
// that this is not an existing unspent commitment right now
if let Some(c) = self.output_pmmr.get(pos) {
let hash_sum = HashSum::from_summable(pos, &sum_commit);
if let Some((hash, _)) = self.utxo_pmmr.get(pos, false) {
// processing a new fork so we may get a position on the old
// fork that exists but matches a different node
// filtering that case out
if c.hash == hash_sum.hash {
if hash == OutputStoreable::from_output(out).hash() {
return Err(Error::DuplicateCommitment(commit));
}
}
}
// push new outputs commitments in their MMR and save them in the index
let pos = self.output_pmmr
.push(sum_commit)
// push new outputs in their MMR and save them in the index
let pos = self.utxo_pmmr
.push(OutputStoreable::from_output(out))
.map_err(&Error::SumTreeErr)?;
self.new_output_commits.insert(out.commitment(), pos);
// push range proofs in their MMR
// push range proofs in their MMR and file
self.rproof_pmmr
.push(NoSum(out.proof))
.push(out.proof)
.map_err(&Error::SumTreeErr)?;
Ok(())
}
@@ -434,9 +429,8 @@ impl<'a> Extension<'a> {
fn apply_kernel(&mut self, kernel: &TxKernel) -> Result<(), Error> {
if let Ok(pos) = self.get_kernel_pos(&kernel.excess) {
// same as outputs
if let Some(k) = self.kernel_pmmr.get(pos) {
let hashsum = HashSum::from_summable(pos, &NoSum(kernel));
if k.hash == hashsum.hash {
if let Some((h,_)) = self.kernel_pmmr.get(pos, false) {
if h == kernel.hash() {
return Err(Error::DuplicateKernel(kernel.excess.clone()));
}
}
@@ -444,10 +438,9 @@ impl<'a> Extension<'a> {
// push kernels in their MMR and file
let pos = self.kernel_pmmr
.push(NoSum(kernel.clone()))
.push(kernel.clone())
.map_err(&Error::SumTreeErr)?;
self.new_kernel_excesses.insert(kernel.excess, pos);
self.kernel_file.append(&mut ser::ser_vec(&kernel).unwrap());
Ok(())
}
@@ -465,13 +458,6 @@ impl<'a> Extension<'a> {
// rewind each MMR
let (out_pos_rew, kern_pos_rew) = indexes_at(block, self.commit_index.deref())?;
self.rewind_pos(block.header.height, out_pos_rew, kern_pos_rew)?;
// rewind the kernel file store, the position is the number of kernels
// multiplied by their size
// the number of kernels is the number of leaves in the MMR
let pos = pmmr::n_leaves(kern_pos_rew);
self.kernel_file.rewind(pos * (TxKernel::size() as u64));
Ok(())
}
@@ -485,7 +471,7 @@ impl<'a> Extension<'a> {
kern_pos_rew,
);
self.output_pmmr
self.utxo_pmmr
.rewind(out_pos_rew, height as u32)
.map_err(&Error::SumTreeErr)?;
self.rproof_pmmr
@@ -495,7 +481,6 @@ impl<'a> Extension<'a> {
.rewind(kern_pos_rew, height as u32)
.map_err(&Error::SumTreeErr)?;
self.dump(true);
Ok(())
}
@@ -515,26 +500,23 @@ impl<'a> Extension<'a> {
}
}
/// Current root hashes and sums (if applicable) for the UTXO, range proof
/// and kernel sum trees.
pub fn roots(
&self,
) -> (
HashSum<SumCommit>,
HashSum<NoSum<RangeProof>>,
HashSum<NoSum<TxKernel>>,
) {
(
self.output_pmmr.root(),
self.rproof_pmmr.root(),
self.kernel_pmmr.root(),
)
) -> SumTreeRoots {
SumTreeRoots {
utxo_root: self.utxo_pmmr.root(),
rproof_root: self.rproof_pmmr.root(),
kernel_root: self.kernel_pmmr.root(),
}
}
/// Validate the current sumtree state against a block header
pub fn validate(&self, header: &BlockHeader) -> Result<(), Error> {
// validate all hashes and sums within the trees
if let Err(e) = self.output_pmmr.validate() {
if let Err(e) = self.utxo_pmmr.validate() {
return Err(Error::InvalidSumtree(e));
}
if let Err(e) = self.rproof_pmmr.validate() {
@@ -545,9 +527,9 @@ impl<'a> Extension<'a> {
}
// validate the tree roots against the block header
let (utxo_root, rproof_root, kernel_root) = self.roots();
if utxo_root.hash != header.utxo_root || rproof_root.hash != header.range_proof_root
|| kernel_root.hash != header.kernel_root
let roots = self.roots();
if roots.utxo_root != header.utxo_root || roots.rproof_root != header.range_proof_root
|| roots.kernel_root != header.kernel_root
{
return Err(Error::InvalidRoot);
}
@@ -574,11 +556,11 @@ impl<'a> Extension<'a> {
/// by iterating over the whole MMR data. This is a costly operation
/// performed only when we receive a full new chain state.
pub fn rebuild_index(&self) -> Result<(), Error> {
for n in 1..self.output_pmmr.unpruned_size()+1 {
for n in 1..self.utxo_pmmr.unpruned_size()+1 {
// non-pruned leaves only
if pmmr::bintree_postorder_height(n) == 0 {
if let Some(hs) = self.output_pmmr.get(n) {
self.commit_index.save_output_pos(&hs.sum.commit, n)?;
if let Some((_, out)) = self.utxo_pmmr.get(n, true) {
self.commit_index.save_output_pos(&out.expect("not a leaf node").commit, n)?;
}
}
}
@@ -594,7 +576,7 @@ impl<'a> Extension<'a> {
/// version only prints the UTXO tree.
pub fn dump(&self, short: bool) {
debug!(LOGGER, "-- outputs --");
self.output_pmmr.dump(short);
self.utxo_pmmr.dump(short);
if !short {
debug!(LOGGER, "-- range proofs --");
self.rproof_pmmr.dump(short);
@@ -606,7 +588,7 @@ impl<'a> Extension<'a> {
// Sizes of the sum trees, used by `extending` on rollback.
fn sizes(&self) -> (u64, u64, u64) {
(
self.output_pmmr.unpruned_size(),
self.utxo_pmmr.unpruned_size(),
self.rproof_pmmr.unpruned_size(),
self.kernel_pmmr.unpruned_size(),
)
@@ -619,7 +601,7 @@ impl<'a> Extension<'a> {
let mmr_sz = self.kernel_pmmr.unpruned_size();
let count = pmmr::n_leaves(mmr_sz);
let mut kernel_file = File::open(self.kernel_file.path())?;
let mut kernel_file = File::open(self.kernel_pmmr.data_file_path())?;
let first: TxKernel = ser::deserialize(&mut kernel_file)?;
first.verify()?;
let mut sum_kernel = first.excess;
@@ -651,14 +633,14 @@ impl<'a> Extension<'a> {
let mut sum_utxo = None;
let mut utxo_count = 0;
let secp = static_secp_instance();
for n in 1..self.output_pmmr.unpruned_size()+1 {
for n in 1..self.utxo_pmmr.unpruned_size()+1 {
if pmmr::bintree_postorder_height(n) == 0 {
if let Some(hs) = self.output_pmmr.get(n) {
if let Some((_,output)) = self.utxo_pmmr.get(n, true) {
if n == 1 {
sum_utxo = Some(hs.sum.commit);
sum_utxo = Some(output.expect("not a leaf node").commit);
} else {
let secp = secp.lock().unwrap();
sum_utxo = Some(secp.commit_sum(vec![sum_utxo.unwrap(), hs.sum.commit], vec![])?);
sum_utxo = Some(secp.commit_sum(vec![sum_utxo.unwrap(), output.expect("not a leaf node").commit], vec![])?);
}
utxo_count += 1;
}
@@ -669,6 +651,42 @@ impl<'a> Extension<'a> {
}
}
/*fn store_element<T>(file_store: &mut FlatFileStore<T>, data: T)
-> Result<(), String>
where
T: ser::Readable + ser::Writeable + Clone
{
file_store.append(vec![data])
}
fn read_element_at_pmmr_index<T>(file_store: &FlatFileStore<T>, pos: u64) -> Option<T>
where
T: ser::Readable + ser::Writeable + Clone
{
let leaf_index = pmmr::leaf_index(pos);
// flat files are zero indexed
file_store.get(leaf_index - 1)
}
fn _remove_element_at_pmmr_index<T>(file_store: &mut FlatFileStore<T>, pos: u64)
-> Result<(), String>
where
T: ser::Readable + ser::Writeable + Clone
{
let leaf_index = pmmr::leaf_index(pos);
// flat files are zero indexed
file_store.remove(vec![leaf_index - 1])
}
fn rewind_to_pmmr_index<T>(file_store: &mut FlatFileStore<T>, pos: u64) -> Result<(), String>
where
T: ser::Readable + ser::Writeable + Clone
{
let leaf_index = pmmr::leaf_index(pos);
// flat files are zero indexed
file_store.rewind(leaf_index - 1)
}*/
/// Output and kernel MMR indexes at the end of the provided block
fn indexes_at(block: &Block, commit_index: &ChainStore) -> Result<(u64, u64), Error> {
let out_idx = match block.outputs.last() {
+13
View File
@@ -40,6 +40,17 @@ bitflags! {
}
}
/// A helper to hold the roots of the sumtrees in order to keep them
/// readable
pub struct SumTreeRoots {
/// UTXO root
pub utxo_root: Hash,
/// Range Proof root
pub rproof_root: Hash,
/// Kernel root
pub kernel_root: Hash,
}
/// Errors
#[derive(Debug)]
pub enum Error {
@@ -81,6 +92,8 @@ pub enum Error {
InvalidSumtree(String),
/// Internal issue when trying to save or load data from store
StoreErr(grin_store::Error, String),
/// Internal issue when trying to save or load data from append only files
FileReadErr(String),
/// Error serializing or deserializing a type
SerErr(ser::Error),
/// Error with the sumtrees