From 856657e39a237906be2c0d1a047914b84a2ebf3b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 26 Jul 2016 00:20:37 +0200 Subject: [PATCH] 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. --- ethcore/src/blockchain/blockchain.rs | 91 +++++++++++++++------------- parity/informant.rs | 6 +- 2 files changed, 52 insertions(+), 45 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 12bacbd43..be447b13d 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -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::>().into_iter().collect::>(); + let enacted = route.blocks.into_iter().skip(route.index).collect::>(); + 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::>(); - - 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 { let mut block_hashes = HashMap::new(); diff --git a/parity/informant.rs b/parity/informant.rs index 9d5c7bf27..ef83b8b77 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -154,13 +154,13 @@ impl Informant { } impl ChainNotify for Informant { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, _retracted: Vec, _sealed: Vec, duration: u64) { + fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, 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); } } }