mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 11:31:08 +03:00
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:
parent
f663340628
commit
6fb085a823
4 changed files with 70 additions and 19 deletions
|
@ -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(¤t)?;
|
let forked_block = ctx.store.get_block(¤t)?;
|
||||||
if forked_block.header.height > 0 {
|
|
||||||
let last_output = &forked_block.outputs[forked_block.outputs.len() - 1];
|
debug!(
|
||||||
let last_kernel = &forked_block.kernels[forked_block.kernels.len() - 1];
|
LOGGER,
|
||||||
ext.rewind(forked_block.header.height, last_output, last_kernel)?;
|
"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
|
// apply all forked blocks, including this new one
|
||||||
for h in hashes {
|
for h in hashes {
|
||||||
|
@ -259,6 +262,26 @@ fn validate_block(
|
||||||
|| kernel_root.hash != b.header.kernel_root
|
|| kernel_root.hash != b.header.kernel_root
|
||||||
{
|
{
|
||||||
ext.dump(false);
|
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);
|
return Err(Error::InvalidRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,9 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use util::secp::pedersen::{RangeProof, Commitment};
|
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::pmmr::{Backend, HashSum, NoSum, Summable, PMMR};
|
||||||
|
use core::core::hash::Hashed;
|
||||||
use grin_store;
|
use grin_store;
|
||||||
use grin_store::sumtree::PMMRBackend;
|
use grin_store::sumtree::PMMRBackend;
|
||||||
use types::ChainStore;
|
use types::ChainStore;
|
||||||
|
@ -297,11 +298,33 @@ impl<'a> Extension<'a> {
|
||||||
|
|
||||||
/// Rewinds the MMRs to the provided position, given the last output and
|
/// Rewinds the MMRs to the provided position, given the last output and
|
||||||
/// last kernel of the block we want to rewind to.
|
/// last kernel of the block we want to rewind to.
|
||||||
pub fn rewind(&mut self, height: u64, output: &Output, kernel: &TxKernel) -> Result<(), Error> {
|
pub fn rewind(&mut self, block: &Block) -> Result<(), Error> {
|
||||||
let out_pos_rew = self.commit_index.get_output_pos(&output.commitment())?;
|
debug!(
|
||||||
let kern_pos_rew = self.commit_index.get_kernel_pos(&kernel.excess)?;
|
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
|
self.output_pmmr
|
||||||
.rewind(out_pos_rew, height as u32)
|
.rewind(out_pos_rew, height as u32)
|
||||||
.map_err(&Error::SumTreeErr)?;
|
.map_err(&Error::SumTreeErr)?;
|
||||||
|
@ -311,6 +334,7 @@ impl<'a> Extension<'a> {
|
||||||
self.kernel_pmmr
|
self.kernel_pmmr
|
||||||
.rewind(kern_pos_rew, height as u32)
|
.rewind(kern_pos_rew, height as u32)
|
||||||
.map_err(&Error::SumTreeErr)?;
|
.map_err(&Error::SumTreeErr)?;
|
||||||
|
|
||||||
self.dump(true);
|
self.dump(true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,8 +167,8 @@ impl NetAdapter for NetToChainAdapter {
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
LOGGER,
|
LOGGER,
|
||||||
"locate_headers: {:?}",
|
"locate_headers: common header: {:?}",
|
||||||
header,
|
header.hash(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// looks like we know one, getting as many following headers as allowed
|
// looks like we know one, getting as many following headers as allowed
|
||||||
|
|
|
@ -247,10 +247,9 @@ impl Syncer {
|
||||||
if let Some(p) = peer {
|
if let Some(p) = peer {
|
||||||
debug!(
|
debug!(
|
||||||
LOGGER,
|
LOGGER,
|
||||||
"Asking peer {} for more block headers starting from {} at {}.",
|
"Asking peer {} for more block headers, locator: {:?}",
|
||||||
p.info.addr,
|
p.info.addr,
|
||||||
tip.last_block_h,
|
locator,
|
||||||
tip.height
|
|
||||||
);
|
);
|
||||||
p.send_header_request(locator)?;
|
p.send_header_request(locator)?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -277,7 +276,7 @@ impl Syncer {
|
||||||
/// us the right block headers.
|
/// us the right block headers.
|
||||||
fn get_locator(&self, tip: &chain::Tip) -> Result<Vec<Hash>, Error> {
|
fn get_locator(&self, tip: &chain::Tip) -> Result<Vec<Hash>, Error> {
|
||||||
// Prepare the heights we want as the latests height minus increasing powers
|
// Prepare the heights we want as the latests height minus increasing powers
|
||||||
// of 2 up to max.
|
// of 2 up to max.
|
||||||
let mut heights = vec![tip.height];
|
let mut heights = vec![tip.height];
|
||||||
let mut tail = (1..p2p::MAX_LOCATORS)
|
let mut tail = (1..p2p::MAX_LOCATORS)
|
||||||
.map(|n| 2u64.pow(n))
|
.map(|n| 2u64.pow(n))
|
||||||
|
@ -288,10 +287,15 @@ impl Syncer {
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
heights.append(&mut tail);
|
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);
|
debug!(LOGGER, "Loc heights: {:?}", heights);
|
||||||
|
|
||||||
// Iteratively travel the header chain back from our head and retain the
|
// Iteratively travel the header chain back from our head and retain the
|
||||||
// headers at the wanted heights.
|
// headers at the wanted heights.
|
||||||
let mut header = self.chain.get_block_header(&tip.last_block_h)?;
|
let mut header = self.chain.get_block_header(&tip.last_block_h)?;
|
||||||
let mut locator = vec![];
|
let mut locator = vec![];
|
||||||
while heights.len() > 0 {
|
while heights.len() > 0 {
|
||||||
|
|
Loading…
Reference in a new issue