From 95038fc62dc73da3f04bd37c0bdc29170eec0169 Mon Sep 17 00:00:00 2001
From: zelig <viktor.tron@gmail.com>
Date: Fri, 20 Mar 2015 20:52:29 +0000
Subject: Idle too long error incorrectly triggered even when peer sending new
 blocks - fix status chain map uses common.Hash as key - add badPeers
 increment to IncorrectTD errors (forgotten) - signal head info update to head
 section process even if parent hash is not in pool (inserted), so that idle
 timer can be set to nil - suicideC -> peer.headInfoTimer - quit ->
 peer.bestIdleTimer - and they are properly set from within getBlockHashes and
 handleSection

---
 blockpool/blockpool.go |  3 +++
 blockpool/peers.go     | 46 ++++++++++++++++++++++------------------------
 blockpool/section.go   |  4 ++--
 blockpool/status.go    |  6 ++++--
 4 files changed, 31 insertions(+), 28 deletions(-)

(limited to 'blockpool')

diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go
index 09b9e7b0b..1ca97e0ca 100644
--- a/blockpool/blockpool.go
+++ b/blockpool/blockpool.go
@@ -757,6 +757,9 @@ func (self *BlockPool) checkTD(nodes ...*node) {
 			plog.DebugDetailf("peer td %v =?= block td %v", n.td, n.block.Td)
 			if n.td.Cmp(n.block.Td) != 0 {
 				self.peers.peerError(n.blockBy, ErrIncorrectTD, "on block %x", n.hash)
+				self.status.lock.Lock()
+				self.status.badPeers[n.blockBy]++
+				self.status.lock.Unlock()
 			}
 		}
 	}
diff --git a/blockpool/peers.go b/blockpool/peers.go
index 80168b206..6bff38e87 100644
--- a/blockpool/peers.go
+++ b/blockpool/peers.go
@@ -46,7 +46,8 @@ type peer struct {
 	// timers for head section process
 	blockHashesRequestTimer <-chan time.Time
 	blocksRequestTimer      <-chan time.Time
-	suicideC                <-chan time.Time
+	headInfoTimer           <-chan time.Time
+	bestIdleTimer           <-chan time.Time
 
 	addToBlacklist func(id string)
 
@@ -256,8 +257,10 @@ func (self *peers) addPeer(
 		plog.Debugf("addPeer: <%s> already the best peer. Request new head section info from %s", id, hex(currentBlockHash))
 
 		if (previousBlockHash != common.Hash{}) {
+			plog.DebugDetailf("addPeer: <%s> head changed: %s -> %s ", id, hex(previousBlockHash), hex(currentBlockHash))
+			p.headSectionC <- nil
 			if entry := self.bp.get(previousBlockHash); entry != nil {
-				p.headSectionC <- nil
+				plog.DebugDetailf("addPeer: <%s> previous head : %v found in pool, activate", id, hex(previousBlockHash))
 				self.bp.activateChain(entry.section, p, nil)
 				p.sections = append(p.sections, previousBlockHash)
 			}
@@ -410,7 +413,8 @@ func (self *peer) handleSection(sec *section) {
 			self.bp.syncing()
 		}
 
-		self.suicideC = time.After(self.bp.Config.BlockHashesTimeout)
+		self.headInfoTimer = time.After(self.bp.Config.BlockHashesTimeout)
+		self.bestIdleTimer = nil
 
 		plog.DebugDetailf("HeadSection: <%s> head block hash changed (mined block received). New head %s", self.id, hex(self.currentBlockHash))
 	} else {
@@ -418,8 +422,10 @@ func (self *peer) handleSection(sec *section) {
 			self.idle = true
 			self.bp.wg.Done()
 		}
-		plog.DebugDetailf("HeadSection: <%s> (head: %s) head section [%s] created", self.id, hex(self.currentBlockHash), sectionhex(sec))
-		self.suicideC = time.After(self.bp.Config.IdleBestPeerTimeout)
+
+		self.headInfoTimer = nil
+		self.bestIdleTimer = time.After(self.bp.Config.IdleBestPeerTimeout)
+		plog.DebugDetailf("HeadSection: <%s> (head: %s) head section [%s] created. Idle...", self.id, hex(self.currentBlockHash), sectionhex(sec))
 	}
 }
 
@@ -452,14 +458,13 @@ func (self *peer) getCurrentBlock(currentBlock *types.Block) {
 	self.blocksRequestTimer = nil
 }
 
-func (self *peer) getBlockHashes() {
+func (self *peer) getBlockHashes() bool {
 	//if connecting parent is found
 	if self.bp.hasBlock(self.parentHash) {
 		plog.DebugDetailf("HeadSection: <%s> parent block %s found in blockchain", self.id, hex(self.parentHash))
 		err := self.bp.insertChain(types.Blocks([]*types.Block{self.currentBlock}))
 
 		self.bp.status.lock.Lock()
-		self.bp.status.badPeers[self.id]++
 		self.bp.status.values.BlocksInChain++
 		self.bp.status.values.BlocksInPool--
 		if err != nil {
@@ -469,18 +474,18 @@ func (self *peer) getBlockHashes() {
 			if self.currentBlock.Td != nil {
 				if self.td.Cmp(self.currentBlock.Td) != 0 {
 					self.addError(ErrIncorrectTD, "on block %x", self.currentBlockHash)
+					self.bp.status.badPeers[self.id]++
 				}
 			}
-			headKey := self.parentHash.Str()
+			headKey := self.parentHash
 			height := self.bp.status.chain[headKey] + 1
-			self.bp.status.chain[self.currentBlockHash.Str()] = height
+			self.bp.status.chain[self.currentBlockHash] = height
 			if height > self.bp.status.values.LongestChain {
 				self.bp.status.values.LongestChain = height
 			}
 			delete(self.bp.status.chain, headKey)
 		}
 		self.bp.status.lock.Unlock()
-
 	} else {
 		if parent := self.bp.get(self.parentHash); parent != nil {
 			if self.bp.get(self.currentBlockHash) == nil {
@@ -501,15 +506,17 @@ func (self *peer) getBlockHashes() {
 			plog.DebugDetailf("HeadSection: <%s> section [%s] requestBlockHashes", self.id, sectionhex(self.headSection))
 			self.requestBlockHashes(self.currentBlockHash)
 			self.blockHashesRequestTimer = time.After(self.bp.Config.BlockHashesRequestInterval)
-			return
+			return false
 		}
 	}
 	self.blockHashesRequestTimer = nil
 	if !self.idle {
 		self.idle = true
-		self.suicideC = nil
+		self.headInfoTimer = nil
+		self.bestIdleTimer = time.After(self.bp.Config.IdleBestPeerTimeout)
 		self.bp.wg.Done()
 	}
+	return true
 }
 
 // main loop for head section process
@@ -522,9 +529,7 @@ func (self *peer) run() {
 	self.blockHashesRequestTimer = nil
 
 	self.blocksRequestTimer = time.After(0)
-	self.suicideC = time.After(self.bp.Config.BlockHashesTimeout)
-
-	var quit <-chan time.Time
+	self.headInfoTimer = time.After(self.bp.Config.BlockHashesTimeout)
 
 	var ping = time.NewTicker(5 * time.Second)
 
@@ -539,13 +544,6 @@ LOOP:
 		// if sec == nil, it signals that chain info has updated (new block message)
 		case sec := <-self.headSectionC:
 			self.handleSection(sec)
-			if sec == nil {
-				plog.Debugf("HeadSection: <%s> (headsection [%s], received: [%s]) quit channel set to nil, catchup happening", self.id, sectionhex(self.headSection), sectionhex(sec))
-				quit = nil
-			} else {
-				plog.Debugf("HeadSection: <%s> (headsection [%s], received: [%s]) quit channel set to go off in IdleBestPeerTimeout", self.id, sectionhex(self.headSection), sectionhex(sec))
-				quit = time.After(self.bp.Config.IdleBestPeerTimeout)
-			}
 
 		// periodic check for block hashes or parent block/section
 		case <-self.blockHashesRequestTimer:
@@ -560,7 +558,7 @@ LOOP:
 			self.getCurrentBlock(nil)
 
 		// quitting on timeout
-		case <-self.suicideC:
+		case <-self.headInfoTimer:
 			self.peerError(self.bp.peers.errors.New(ErrInsufficientChainInfo, "timed out without providing block hashes or head block (td: %v, head: %s)", self.td, hex(self.currentBlockHash)))
 
 			self.bp.status.lock.Lock()
@@ -583,7 +581,7 @@ LOOP:
 			break LOOP
 
 		// quit
-		case <-quit:
+		case <-self.bestIdleTimer:
 			self.peerError(self.bp.peers.errors.New(ErrIdleTooLong, "timed out without providing new blocks (td: %v, head: %s)...quitting", self.td, hex(self.currentBlockHash)))
 
 			self.bp.status.lock.Lock()
diff --git a/blockpool/section.go b/blockpool/section.go
index bcbd71cfc..14e91cf33 100644
--- a/blockpool/section.go
+++ b/blockpool/section.go
@@ -176,9 +176,9 @@ func (self *section) addSectionToBlockChain(p *peer) {
 
 		self.bp.status.lock.Lock()
 		if err == nil {
-			headKey := blocks[0].ParentHash().Str()
+			headKey := blocks[0].ParentHash()
 			height := self.bp.status.chain[headKey] + len(blocks)
-			self.bp.status.chain[blocks[len(blocks)-1].Hash().Str()] = height
+			self.bp.status.chain[blocks[len(blocks)-1].Hash()] = height
 			if height > self.bp.status.values.LongestChain {
 				self.bp.status.values.LongestChain = height
 			}
diff --git a/blockpool/status.go b/blockpool/status.go
index 4529c77fe..02e358510 100644
--- a/blockpool/status.go
+++ b/blockpool/status.go
@@ -3,6 +3,8 @@ package blockpool
 import (
 	"fmt"
 	"sync"
+
+	"github.com/ethereum/go-ethereum/common"
 )
 
 type statusValues struct {
@@ -26,7 +28,7 @@ type statusValues struct {
 type status struct {
 	lock        sync.Mutex
 	values      statusValues
-	chain       map[string]int
+	chain       map[common.Hash]int
 	peers       map[string]int
 	bestPeers   map[string]int
 	badPeers    map[string]int
@@ -35,7 +37,7 @@ type status struct {
 
 func newStatus() *status {
 	return &status{
-		chain:       make(map[string]int),
+		chain:       make(map[common.Hash]int),
 		peers:       make(map[string]int),
 		bestPeers:   make(map[string]int),
 		badPeers:    make(map[string]int),
-- 
cgit v1.2.3