Fix issues during block sync (#11265)

This commit is contained in:
rakita
2020-09-05 19:45:31 +02:00
committed by Artem Vorotnikov
parent c58b52c21c
commit 506cee52e8
12 changed files with 259 additions and 52 deletions

View File

@@ -2051,6 +2051,13 @@ impl BlockChainClient for Client {
}
}
fn is_processing_fork(&self) -> bool {
let chain = self.chain.read();
self.importer
.block_queue
.is_processing_fork(&chain.best_block_hash(), &chain)
}
fn block_total_difficulty(&self, id: BlockId) -> Option<U256> {
let chain = self.chain.read();

View File

@@ -887,6 +887,10 @@ impl BlockChainClient for TestBlockChainClient {
}
}
fn is_processing_fork(&self) -> bool {
false
}
// works only if blocks are one after another 1 -> 2 -> 3
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
Some(TreeRoute {

View File

@@ -427,6 +427,9 @@ pub trait BlockChainClient:
/// Get the address of the registry itself.
fn registrar_address(&self) -> Option<Address>;
/// Returns true, if underlying import queue is processing possible fork at the moment
fn is_processing_fork(&self) -> bool;
}
/// Provides `reopen_block` method

View File

@@ -17,6 +17,7 @@
//! A queue of blocks. Sits between network or other I/O and the `BlockChain`.
//! Sorts them ready for blockchain insertion.
use blockchain::BlockChain;
use client::ClientIoMessage;
use engines::EthEngine;
use error::{BlockError, Error, ErrorKind, ImportErrorKind};
@@ -43,6 +44,9 @@ pub mod kind;
const MIN_MEM_LIMIT: usize = 16384;
const MIN_QUEUE_LIMIT: usize = 512;
/// Empiric estimation of the minimal length of the processing queue,
/// That definitely doesn't contain forks inside.
const MAX_QUEUE_WITH_FORK: usize = 8;
/// Type alias for block queue convenience.
pub type BlockQueue = VerificationQueue<self::kind::Blocks>;
@@ -148,7 +152,7 @@ pub struct VerificationQueue<K: Kind> {
deleting: Arc<AtomicBool>,
ready_signal: Arc<QueueSignal>,
empty: Arc<Condvar>,
processing: RwLock<HashMap<H256, U256>>, // hash to difficulty
processing: RwLock<HashMap<H256, (U256, H256)>>, // item's hash to difficulty and parent item hash
ticks_since_adjustment: AtomicUsize,
max_queue_size: usize,
max_mem_use: usize,
@@ -540,7 +544,7 @@ impl<K: Kind> VerificationQueue<K> {
if self
.processing
.write()
.insert(hash, item.difficulty())
.insert(hash, (item.difficulty(), item.parent_hash()))
.is_some()
{
bail!((
@@ -553,6 +557,7 @@ impl<K: Kind> VerificationQueue<K> {
.unverified
.fetch_add(item.heap_size_of_children(), AtomicOrdering::SeqCst);
//self.processing.write().insert(hash, item.difficulty());
{
let mut td = self.total_difficulty.write();
*td = *td + item.difficulty();
@@ -597,7 +602,7 @@ impl<K: Kind> VerificationQueue<K> {
bad.reserve(hashes.len());
for hash in hashes {
bad.insert(hash.clone());
if let Some(difficulty) = processing.remove(hash) {
if let Some((difficulty, _)) = processing.remove(hash) {
let mut td = self.total_difficulty.write();
*td = *td - difficulty;
}
@@ -609,7 +614,7 @@ impl<K: Kind> VerificationQueue<K> {
if bad.contains(&output.parent_hash()) {
removed_size += output.heap_size_of_children();
bad.insert(output.hash());
if let Some(difficulty) = processing.remove(&output.hash()) {
if let Some((difficulty, _)) = processing.remove(&output.hash()) {
let mut td = self.total_difficulty.write();
*td = *td - difficulty;
}
@@ -633,7 +638,7 @@ impl<K: Kind> VerificationQueue<K> {
}
let mut processing = self.processing.write();
for hash in hashes {
if let Some(difficulty) = processing.remove(hash) {
if let Some((difficulty, _)) = processing.remove(hash) {
let mut td = self.total_difficulty.write();
*td = *td - difficulty;
}
@@ -670,6 +675,24 @@ impl<K: Kind> VerificationQueue<K> {
v.unverified.load_len() == 0 && v.verifying.load_len() == 0 && v.verified.load_len() == 0
}
/// Returns true if there are descendants of the current best block in the processing queue
pub fn is_processing_fork(&self, best_block_hash: &H256, chain: &BlockChain) -> bool {
let processing = self.processing.read();
if processing.is_empty() || processing.len() > MAX_QUEUE_WITH_FORK {
// Assume, that long enough processing queue doesn't have fork blocks
return false;
}
for (_, item_parent_hash) in processing.values() {
if chain
.tree_route(*best_block_hash, *item_parent_hash)
.map_or(true, |route| route.ancestor != *best_block_hash)
{
return true;
}
}
false
}
/// Get queue status.
pub fn queue_info(&self) -> QueueInfo {
use std::mem::size_of;