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:
parent
431ba5e260
commit
856657e39a
@ -514,6 +514,13 @@ impl BlockChain {
|
|||||||
|
|
||||||
let info = self.block_info(bytes);
|
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 {
|
self.apply_update(ExtrasUpdate {
|
||||||
block_hashes: self.prepare_block_hashes_update(bytes, &info),
|
block_hashes: self.prepare_block_hashes_update(bytes, &info),
|
||||||
block_details: self.prepare_block_details_update(bytes, &info),
|
block_details: self.prepare_block_details_update(bytes, &info),
|
||||||
@ -526,6 +533,48 @@ impl BlockChain {
|
|||||||
ImportRoute::from(info)
|
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.
|
/// Applies extras update.
|
||||||
fn apply_update(&self, update: ExtrasUpdate) {
|
fn apply_update(&self, update: ExtrasUpdate) {
|
||||||
let batch = DBTransaction::new();
|
let batch = DBTransaction::new();
|
||||||
@ -613,48 +662,6 @@ impl BlockChain {
|
|||||||
Some(ret)
|
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.
|
/// This function returns modified block hashes.
|
||||||
fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<BlockNumber, H256> {
|
fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<BlockNumber, H256> {
|
||||||
let mut block_hashes = HashMap::new();
|
let mut block_hashes = HashMap::new();
|
||||||
|
@ -154,13 +154,13 @@ impl Informant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChainNotify for 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 mut last_import = self.last_import.lock();
|
||||||
let queue_info = self.client.queue_info();
|
let queue_info = self.client.queue_info();
|
||||||
let importing = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3
|
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());
|
|| self.sync.as_ref().map_or(false, |s| s.status().is_major_syncing());
|
||||||
if Instant::now() > *last_import + Duration::from_secs(1) && !importing {
|
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 view = BlockView::new(&block);
|
||||||
let header = view.header();
|
let header = view.header();
|
||||||
let tx_count = view.transactions_count();
|
let tx_count = view.transactions_count();
|
||||||
@ -179,7 +179,7 @@ impl ChainNotify for Informant {
|
|||||||
}
|
}
|
||||||
self.skipped.store(0, AtomicOrdering::Relaxed);
|
self.skipped.store(0, AtomicOrdering::Relaxed);
|
||||||
} else {
|
} else {
|
||||||
self.skipped.fetch_add(enacted.len(), AtomicOrdering::Relaxed);
|
self.skipped.fetch_add(imported.len(), AtomicOrdering::Relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user