From 8948567c23ebbbd06d9d3dad612ee346dac23016 Mon Sep 17 00:00:00 2001
From: Arkadiy Paronyan <arkady.paronyan@gmail.com>
Date: Sun, 6 Jan 2019 19:45:41 +0300
Subject: [PATCH] Fixed ancestry search/block queue interaction (#1337)

* Fixed ancestry search - block queue interaction

* Style
---
 substrate/core/network/src/sync.rs | 34 ++++++++++++++++++------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/substrate/core/network/src/sync.rs b/substrate/core/network/src/sync.rs
index 315156588ed..54da778266f 100644
--- a/substrate/core/network/src/sync.rs
+++ b/substrate/core/network/src/sync.rs
@@ -23,7 +23,7 @@ use consensus::BlockOrigin;
 use consensus::import_queue::{ImportQueue, IncomingBlock};
 use client::error::Error as ClientError;
 use blocks::BlockCollection;
-use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberFor};
+use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberFor, Zero};
 use runtime_primitives::generic::BlockId;
 use message::{self, generic::Message as GenericMessage};
 use config::Roles;
@@ -32,9 +32,10 @@ use config::Roles;
 const MAX_BLOCKS_TO_REQUEST: usize = 128;
 // Maximum blocks to store in the import queue.
 const MAX_IMPORTING_BLOCKS: usize = 2048;
+// Number of blocks in the queue that prevents ancestry search.
+const MAJOR_SYNC_BLOCKS: usize = 5;
 
 struct PeerSync<B: BlockT> {
-	pub common_hash: B::Hash,
 	pub common_number: NumberFor<B>,
 	pub best_hash: B::Hash,
 	pub best_number: NumberFor<B>,
@@ -141,16 +142,25 @@ impl<B: BlockT> ChainSync<B> {
 				(Ok(BlockStatus::KnownBad), _) => {
 					protocol.report_peer(who, Severity::Bad(&format!("New peer with known bad best block {} ({}).", info.best_hash, info.best_number)));
 				},
-				(Ok(BlockStatus::Unknown), b) if b == As::sa(0) => {
+				(Ok(BlockStatus::Unknown), b) if b.is_zero() => {
 					protocol.report_peer(who, Severity::Bad(&format!("New peer with unknown genesis hash {} ({}).", info.best_hash, info.best_number)));
 				},
+				(Ok(BlockStatus::Unknown), _) if self.import_queue.status().importing_count > MAJOR_SYNC_BLOCKS => {
+					// when actively syncing the common point moves too fast.
+					debug!(target:"sync", "New peer with unknown best hash {} ({}), assuming common block.", self.best_queued_hash, self.best_queued_number);
+					self.peers.insert(who, PeerSync {
+						common_number: self.best_queued_number,
+						best_hash: info.best_hash,
+						best_number: info.best_number,
+						state: PeerSyncState::Available,
+					});
+				}
 				(Ok(BlockStatus::Unknown), _) => {
 					let our_best = self.best_queued_number;
 					if our_best > As::sa(0) {
 						let common_best = ::std::cmp::min(our_best, info.best_number);
 						debug!(target:"sync", "New peer with unknown best hash {} ({}), searching for common ancestor.", info.best_hash, info.best_number);
 						self.peers.insert(who, PeerSync {
-							common_hash: self.genesis_hash,
 							common_number: As::sa(0),
 							best_hash: info.best_hash,
 							best_number: info.best_number,
@@ -161,7 +171,6 @@ impl<B: BlockT> ChainSync<B> {
 						// We are at genesis, just start downloading
 						debug!(target:"sync", "New peer with best hash {} ({}).", info.best_hash, info.best_number);
 						self.peers.insert(who, PeerSync {
-							common_hash: self.genesis_hash,
 							common_number: As::sa(0),
 							best_hash: info.best_hash,
 							best_number: info.best_number,
@@ -173,7 +182,6 @@ impl<B: BlockT> ChainSync<B> {
 				(Ok(BlockStatus::Queued), _) | (Ok(BlockStatus::InChain), _) => {
 					debug!(target:"sync", "New peer with known best hash {} ({}).", info.best_hash, info.best_number);
 					self.peers.insert(who, PeerSync {
-						common_hash: info.best_hash,
 						common_number: info.best_number,
 						best_hash: info.best_hash,
 						best_number: info.best_number,
@@ -230,7 +238,6 @@ impl<B: BlockT> ChainSync<B> {
 							match protocol.client().block_hash(n) {
 								Ok(Some(block_hash)) if block_hash == block.hash => {
 									if peer.common_number < n {
-										peer.common_hash = block.hash;
 										peer.common_number = n;
 									}
 									peer.state = PeerSyncState::Available;
@@ -300,15 +307,14 @@ impl<B: BlockT> ChainSync<B> {
 		// Update common blocks
 		for (n, peer) in self.peers.iter_mut() {
 			if let PeerSyncState::AncestorSearch(_) = peer.state {
-				continue;
+				// Abort search.
+				peer.state = PeerSyncState::Available;
 			}
 			trace!(target: "sync", "Updating peer {} info, ours={}, common={}, their best={}", n, number, peer.common_number, peer.best_number);
 			if peer.best_number >= number {
 				peer.common_number = number;
-				peer.common_hash = *hash;
 			} else {
 				peer.common_number = peer.best_number;
-				peer.common_hash = peer.best_hash;
 			}
 		}
 	}
@@ -379,10 +385,6 @@ impl<B: BlockT> ChainSync<B> {
 	pub(crate) fn restart(&mut self, protocol: &mut Context<B>) {
 		self.import_queue.clear();
 		self.blocks.clear();
-		let ids: Vec<NodeIndex> = self.peers.keys().map(|p| *p).collect();
-		for id in ids {
-			self.new_peer(protocol, id);
-		}
 		match protocol.client().info() {
 			Ok(info) => {
 				self.best_queued_hash = info.best_queued_hash.unwrap_or(info.chain.best_hash);
@@ -395,6 +397,10 @@ impl<B: BlockT> ChainSync<B> {
 				self.best_queued_number = As::sa(0);
 			}
 		}
+		let ids: Vec<NodeIndex> = self.peers.drain().map(|(id, _)| id).collect();
+		for id in ids {
+			self.new_peer(protocol, id);
+		}
 	}
 
 	pub(crate) fn clear(&mut self) {
-- 
GitLab