Fix issues during block sync (#11265)
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user