Log a chain-reorg. (#1715)

* Log a chain-reorg.

* Nicer output

* Use imported rather than enacted.

Enacted can include previously imported blocks which makes the
info incorrect.
This commit is contained in:
Gav Wood 2016-07-26 00:20:37 +02:00 committed by GitHub
parent 431ba5e260
commit 856657e39a
2 changed files with 52 additions and 45 deletions

View File

@ -514,6 +514,13 @@ impl BlockChain {
let info = self.block_info(bytes);
if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location {
info!(target: "reorg", "{} Using {} (#{})", Colour::Yellow.bold().paint("Switching fork to a new branch."), info.hash, info.number);
info!(target: "reorg", "{}{}", Colour::Red.bold().paint("Retracting"), d.retracted.iter().fold(String::new(), |acc, h| format!("{} {}", acc, h)));
info!(target: "reorg", "{} {} (#{})", Colour::Blue.bold().paint("Leaving"), d.ancestor, self.block_details(&d.ancestor).expect("`ancestor` is in the route; qed").number);
info!(target: "reorg", "{}{}", Colour::Green.bold().paint("Enacting"), d.enacted.iter().fold(String::new(), |acc, h| format!("{} {}", acc, h)));
}
self.apply_update(ExtrasUpdate {
block_hashes: self.prepare_block_hashes_update(bytes, &info),
block_details: self.prepare_block_details_update(bytes, &info),
@ -526,6 +533,48 @@ impl BlockChain {
ImportRoute::from(info)
}
/// Get inserted block info which is critical to prepare extras updates.
fn block_info(&self, block_bytes: &[u8]) -> BlockInfo {
let block = BlockView::new(block_bytes);
let header = block.header_view();
let hash = block.sha3();
let number = header.number();
let parent_hash = header.parent_hash();
let parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash));
let total_difficulty = parent_details.total_difficulty + header.difficulty();
let is_new_best = total_difficulty > self.best_block_total_difficulty();
BlockInfo {
hash: hash,
number: number,
total_difficulty: total_difficulty,
location: if is_new_best {
// on new best block we need to make sure that all ancestors
// are moved to "canon chain"
// find the route between old best block and the new one
let best_hash = self.best_block_hash();
let route = self.tree_route(best_hash, parent_hash);
assert_eq!(number, parent_details.number + 1);
match route.blocks.len() {
0 => BlockLocation::CanonChain,
_ => {
let retracted = route.blocks.iter().take(route.index).cloned().collect::<Vec<_>>().into_iter().collect::<Vec<_>>();
let enacted = route.blocks.into_iter().skip(route.index).collect::<Vec<_>>();
BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData {
ancestor: route.ancestor,
enacted: enacted,
retracted: retracted,
})
}
}
} else {
BlockLocation::Branch
}
}
}
/// Applies extras update.
fn apply_update(&self, update: ExtrasUpdate) {
let batch = DBTransaction::new();
@ -613,48 +662,6 @@ impl BlockChain {
Some(ret)
}
/// Get inserted block info which is critical to prepare extras updates.
fn block_info(&self, block_bytes: &[u8]) -> BlockInfo {
let block = BlockView::new(block_bytes);
let header = block.header_view();
let hash = block.sha3();
let number = header.number();
let parent_hash = header.parent_hash();
let parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash));
let total_difficulty = parent_details.total_difficulty + header.difficulty();
let is_new_best = total_difficulty > self.best_block_total_difficulty();
BlockInfo {
hash: hash,
number: number,
total_difficulty: total_difficulty,
location: if is_new_best {
// on new best block we need to make sure that all ancestors
// are moved to "canon chain"
// find the route between old best block and the new one
let best_hash = self.best_block_hash();
let route = self.tree_route(best_hash, parent_hash);
assert_eq!(number, parent_details.number + 1);
match route.blocks.len() {
0 => BlockLocation::CanonChain,
_ => {
let retracted = route.blocks.iter().take(route.index).cloned().collect::<Vec<H256>>();
BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData {
ancestor: route.ancestor,
enacted: route.blocks.into_iter().skip(route.index).collect(),
retracted: retracted.into_iter().rev().collect(),
})
}
}
} else {
BlockLocation::Branch
}
}
}
/// This function returns modified block hashes.
fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<BlockNumber, H256> {
let mut block_hashes = HashMap::new();

View File

@ -154,13 +154,13 @@ impl Informant {
}
impl ChainNotify for Informant {
fn new_blocks(&self, _imported: Vec<H256>, _invalid: Vec<H256>, enacted: Vec<H256>, _retracted: Vec<H256>, _sealed: Vec<H256>, duration: u64) {
fn new_blocks(&self, imported: Vec<H256>, _invalid: Vec<H256>, _enacted: Vec<H256>, _retracted: Vec<H256>, _sealed: Vec<H256>, duration: u64) {
let mut last_import = self.last_import.lock();
let queue_info = self.client.queue_info();
let importing = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3
|| self.sync.as_ref().map_or(false, |s| s.status().is_major_syncing());
if Instant::now() > *last_import + Duration::from_secs(1) && !importing {
if let Some(block) = enacted.last().and_then(|h| self.client.block(BlockID::Hash(h.clone()))) {
if let Some(block) = imported.last().and_then(|h| self.client.block(BlockID::Hash(h.clone()))) {
let view = BlockView::new(&block);
let header = view.header();
let tx_count = view.transactions_count();
@ -179,7 +179,7 @@ impl ChainNotify for Informant {
}
self.skipped.store(0, AtomicOrdering::Relaxed);
} else {
self.skipped.fetch_add(enacted.len(), AtomicOrdering::Relaxed);
self.skipped.fetch_add(imported.len(), AtomicOrdering::Relaxed);
}
}
}