Fix bad case of trying to rewind to block at height 0 (#271)

* bad case of trying to rewind to block header height 0
* rewind_to_genesis appears to work
* do not assume genesis block at height 0 is empty, pass full block in to rewind, check for last output and kernel, use index 0 if block is empty
This commit is contained in:
AntiochP 2017-11-15 15:37:40 -05:00 committed by Ignotus Peverell
parent f663340628
commit 6fb085a823
4 changed files with 70 additions and 19 deletions

View file

@ -237,14 +237,17 @@ fn validate_block(
}
}
// rewind the sum trees up the forking block, providing the height of the
// forked block and the last commitment we want to rewind to
let forked_block = ctx.store.get_block(&current)?;
if forked_block.header.height > 0 {
let last_output = &forked_block.outputs[forked_block.outputs.len() - 1];
let last_kernel = &forked_block.kernels[forked_block.kernels.len() - 1];
ext.rewind(forked_block.header.height, last_output, last_kernel)?;
}
debug!(
LOGGER,
"validate_block: forked_block: {} at {}",
forked_block.header.hash(),
forked_block.header.height,
);
// rewind the sum trees up to the forking block
ext.rewind(&forked_block)?;
// apply all forked blocks, including this new one
for h in hashes {
@ -259,6 +262,26 @@ fn validate_block(
|| kernel_root.hash != b.header.kernel_root
{
ext.dump(false);
debug!(
LOGGER,
"validate_block: utxo roots - {:?}, {:?}",
utxo_root.hash,
b.header.utxo_root,
);
debug!(
LOGGER,
"validate_block: rproof roots - {:?}, {:?}",
rproof_root.hash,
b.header.range_proof_root,
);
debug!(
LOGGER,
"validate_block: kernel roots - {:?}, {:?}",
kernel_root.hash,
b.header.kernel_root,
);
return Err(Error::InvalidRoot);
}

View file

@ -22,8 +22,9 @@ use std::sync::Arc;
use util::secp::pedersen::{RangeProof, Commitment};
use core::core::{Block, Output, SumCommit, TxKernel};
use core::core::{Block, SumCommit, TxKernel};
use core::core::pmmr::{Backend, HashSum, NoSum, Summable, PMMR};
use core::core::hash::Hashed;
use grin_store;
use grin_store::sumtree::PMMRBackend;
use types::ChainStore;
@ -297,11 +298,33 @@ impl<'a> Extension<'a> {
/// Rewinds the MMRs to the provided position, given the last output and
/// last kernel of the block we want to rewind to.
pub fn rewind(&mut self, height: u64, output: &Output, kernel: &TxKernel) -> Result<(), Error> {
let out_pos_rew = self.commit_index.get_output_pos(&output.commitment())?;
let kern_pos_rew = self.commit_index.get_kernel_pos(&kernel.excess)?;
pub fn rewind(&mut self, block: &Block) -> Result<(), Error> {
debug!(
LOGGER,
"Rewind sumtrees to header {} at {}",
block.header.hash(),
block.header.height,
);
let out_pos_rew = match block.outputs.last() {
Some(output) => self.commit_index.get_output_pos(&output.commitment())?,
None => 0,
};
let kern_pos_rew = match block.kernels.last() {
Some(kernel) => self.commit_index.get_kernel_pos(&kernel.excess)?,
None => 0,
};
debug!(
LOGGER,
"Rewind sumtrees to output pos: {}, kernel pos: {}",
out_pos_rew,
kern_pos_rew,
);
let height = block.header.height;
debug!(LOGGER, "Rewind sumtrees to {}", out_pos_rew);
self.output_pmmr
.rewind(out_pos_rew, height as u32)
.map_err(&Error::SumTreeErr)?;
@ -311,6 +334,7 @@ impl<'a> Extension<'a> {
self.kernel_pmmr
.rewind(kern_pos_rew, height as u32)
.map_err(&Error::SumTreeErr)?;
self.dump(true);
Ok(())
}

View file

@ -167,8 +167,8 @@ impl NetAdapter for NetToChainAdapter {
debug!(
LOGGER,
"locate_headers: {:?}",
header,
"locate_headers: common header: {:?}",
header.hash(),
);
// looks like we know one, getting as many following headers as allowed

View file

@ -247,10 +247,9 @@ impl Syncer {
if let Some(p) = peer {
debug!(
LOGGER,
"Asking peer {} for more block headers starting from {} at {}.",
"Asking peer {} for more block headers, locator: {:?}",
p.info.addr,
tip.last_block_h,
tip.height
locator,
);
p.send_header_request(locator)?;
} else {
@ -288,6 +287,11 @@ impl Syncer {
})
.collect::<Vec<_>>();
heights.append(&mut tail);
// Include the genesis block (height 0) here as a fallback to guarantee
// both nodes share at least one common header hash in the locator
heights.push(0);
debug!(LOGGER, "Loc heights: {:?}", heights);
// Iteratively travel the header chain back from our head and retain the