partial fix to idle best peer issue

- best peer cannot be idle for more than idleBestPeerTimeout
- introduce ErrIdleTooLong fatal error
- modify default values
This commit is contained in:
zelig 2015-03-04 02:06:15 +07:00
parent 47278a6e4e
commit 2c616bd279
3 changed files with 33 additions and 13 deletions

View File

@ -17,7 +17,7 @@ var plog = ethlogger.NewLogger("Blockpool")
var ( var (
// max number of block hashes sent in one request // max number of block hashes sent in one request
blockHashesBatchSize = 512 blockHashesBatchSize = 256
// max number of blocks sent in one request // max number of blocks sent in one request
blockBatchSize = 64 blockBatchSize = 64
// interval between two consecutive block checks (and requests) // interval between two consecutive block checks (and requests)
@ -27,11 +27,13 @@ var (
// interval between two consecutive block hash checks (and requests) // interval between two consecutive block hash checks (and requests)
blockHashesRequestInterval = 3 * time.Second blockHashesRequestInterval = 3 * time.Second
// max number of idle iterations, ie., check through a section without new blocks coming in // max number of idle iterations, ie., check through a section without new blocks coming in
blocksRequestMaxIdleRounds = 100 blocksRequestMaxIdleRounds = 20
// timeout interval: max time allowed for peer without sending a block hash // timeout interval: max time allowed for peer without sending a block hash
blockHashesTimeout = 60 * time.Second blockHashesTimeout = 60 * time.Second
// timeout interval: max time allowed for peer without sending a block // timeout interval: max time allowed for peer without sending a block
blocksTimeout = 120 * time.Second blocksTimeout = 60 * time.Second
//
idleBestPeerTimeout = 60 * time.Second
) )
// config embedded in components, by default fall back to constants // config embedded in components, by default fall back to constants
@ -45,6 +47,7 @@ type Config struct {
BlocksRequestInterval time.Duration BlocksRequestInterval time.Duration
BlockHashesTimeout time.Duration BlockHashesTimeout time.Duration
BlocksTimeout time.Duration BlocksTimeout time.Duration
IdleBestPeerTimeout time.Duration
} }
// blockpool errors // blockpool errors
@ -53,6 +56,7 @@ const (
ErrInvalidPoW ErrInvalidPoW
ErrUnrequestedBlock ErrUnrequestedBlock
ErrInsufficientChainInfo ErrInsufficientChainInfo
ErrIdleTooLong
) )
var errorToString = map[int]string{ var errorToString = map[int]string{
@ -60,6 +64,7 @@ var errorToString = map[int]string{
ErrInvalidPoW: "Invalid PoW", ErrInvalidPoW: "Invalid PoW",
ErrUnrequestedBlock: "Unrequested block", ErrUnrequestedBlock: "Unrequested block",
ErrInsufficientChainInfo: "Insufficient chain info", ErrInsufficientChainInfo: "Insufficient chain info",
ErrIdleTooLong: "Idle too long",
} }
// init initialises all your laundry // init initialises all your laundry
@ -88,6 +93,9 @@ func (self *Config) init() {
if self.BlocksTimeout == 0 { if self.BlocksTimeout == 0 {
self.BlocksTimeout = blocksTimeout self.BlocksTimeout = blocksTimeout
} }
if self.IdleBestPeerTimeout == 0 {
self.IdleBestPeerTimeout = idleBestPeerTimeout
}
} }
// node is the basic unit of the internal model of block chain/tree in the blockpool // node is the basic unit of the internal model of block chain/tree in the blockpool

View File

@ -20,12 +20,13 @@ func TestBlockPoolConfig(t *testing.T) {
test.CheckDuration("BlocksRequestInterval", c.BlocksRequestInterval, blocksRequestInterval, t) test.CheckDuration("BlocksRequestInterval", c.BlocksRequestInterval, blocksRequestInterval, t)
test.CheckDuration("BlockHashesTimeout", c.BlockHashesTimeout, blockHashesTimeout, t) test.CheckDuration("BlockHashesTimeout", c.BlockHashesTimeout, blockHashesTimeout, t)
test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t) test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t)
test.CheckDuration("IdleBestPeerTimeout", c.IdleBestPeerTimeout, idleBestPeerTimeout, t)
} }
func TestBlockPoolOverrideConfig(t *testing.T) { func TestBlockPoolOverrideConfig(t *testing.T) {
test.LogInit() test.LogInit()
blockPool := &BlockPool{Config: &Config{}} blockPool := &BlockPool{Config: &Config{}}
c := &Config{128, 32, 1, 0, 300 * time.Millisecond, 100 * time.Millisecond, 90 * time.Second, 0} c := &Config{128, 32, 1, 0, 300 * time.Millisecond, 100 * time.Millisecond, 90 * time.Second, 0, 30 * time.Second}
blockPool.Config = c blockPool.Config = c
blockPool.Start() blockPool.Start()
@ -37,4 +38,5 @@ func TestBlockPoolOverrideConfig(t *testing.T) {
test.CheckDuration("BlocksRequestInterval", c.BlocksRequestInterval, 100*time.Millisecond, t) test.CheckDuration("BlocksRequestInterval", c.BlocksRequestInterval, 100*time.Millisecond, t)
test.CheckDuration("BlockHashesTimeout", c.BlockHashesTimeout, 90*time.Second, t) test.CheckDuration("BlockHashesTimeout", c.BlockHashesTimeout, 90*time.Second, t)
test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t) test.CheckDuration("BlocksTimeout", c.BlocksTimeout, blocksTimeout, t)
test.CheckDuration("IdleBestPeerTimeout", c.IdleBestPeerTimeout, 30*time.Second, t)
} }

View File

@ -37,7 +37,7 @@ type peer struct {
currentBlockC chan *types.Block currentBlockC chan *types.Block
headSectionC chan *section headSectionC chan *section
// channels to signal peers witch and peer quit // channels to signal peer switch and peer quit to section processes
idleC chan bool idleC chan bool
switchC chan bool switchC chan bool
@ -47,7 +47,7 @@ type peer struct {
// timers for head section process // timers for head section process
blockHashesRequestTimer <-chan time.Time blockHashesRequestTimer <-chan time.Time
blocksRequestTimer <-chan time.Time blocksRequestTimer <-chan time.Time
suicide <-chan time.Time suicideC <-chan time.Time
idle bool idle bool
} }
@ -286,8 +286,7 @@ func (self *peers) removePeer(id string) {
} }
} }
// switchPeer launches section processes based on information about // switchPeer launches section processes
// shared interest and legacy of peers
func (self *BlockPool) switchPeer(oldp, newp *peer) { func (self *BlockPool) switchPeer(oldp, newp *peer) {
// first quit AddBlockHashes, requestHeadSection and activateChain // first quit AddBlockHashes, requestHeadSection and activateChain
@ -372,16 +371,16 @@ func (self *peer) handleSection(sec *section) {
self.bp.syncing() self.bp.syncing()
} }
self.suicide = time.After(self.bp.Config.BlockHashesTimeout) self.suicideC = time.After(self.bp.Config.BlockHashesTimeout)
plog.DebugDetailf("HeadSection: <%s> head block hash changed (mined block received). New head %s", self.id, hex(self.currentBlockHash)) plog.DebugDetailf("HeadSection: <%s> head block hash changed (mined block received). New head %s", self.id, hex(self.currentBlockHash))
} else { } else {
if !self.idle { if !self.idle {
self.idle = true self.idle = true
self.suicide = nil
self.bp.wg.Done() self.bp.wg.Done()
} }
plog.DebugDetailf("HeadSection: <%s> head section [%s] created", self.id, sectionhex(sec)) plog.DebugDetailf("HeadSection: <%s> head section [%s] created", self.id, sectionhex(sec))
self.suicideC = time.After(self.bp.Config.IdleBestPeerTimeout)
} }
} }
@ -451,7 +450,7 @@ func (self *peer) getBlockHashes() {
self.blockHashesRequestTimer = nil self.blockHashesRequestTimer = nil
if !self.idle { if !self.idle {
self.idle = true self.idle = true
self.suicide = nil self.suicideC = time.After(self.bp.Config.IdleBestPeerTimeout)
self.bp.wg.Done() self.bp.wg.Done()
} }
} }
@ -467,7 +466,7 @@ func (self *peer) run() {
self.blockHashesRequestTimer = nil self.blockHashesRequestTimer = nil
self.blocksRequestTimer = time.After(0) self.blocksRequestTimer = time.After(0)
self.suicide = time.After(self.bp.Config.BlockHashesTimeout) self.suicideC = time.After(self.bp.Config.BlockHashesTimeout)
var quit chan bool var quit chan bool
@ -476,9 +475,20 @@ func (self *peer) run() {
LOOP: LOOP:
for { for {
select { select {
// to minitor section process behaviou
case <-ping.C: case <-ping.C:
plog.Debugf("HeadSection: <%s> section with head %s, idle: %v", self.id, hex(self.currentBlockHash), self.idle) plog.Debugf("HeadSection: <%s> section with head %s, idle: %v", self.id, hex(self.currentBlockHash), self.idle)
// idle timer started when process goes idle
case <-self.idleC:
if self.idle {
self.peerError(self.bp.peers.errors.New(ErrIdleTooLong, "timed out without providing new blocks...quitting", currentBlockHash))
self.bp.status.lock.Lock()
self.bp.status.badPeers[self.id]++
self.bp.status.lock.Unlock()
}
// signal from AddBlockHashes that head section for current best peer is created // signal from AddBlockHashes that head section for current best peer is created
// if sec == nil, it signals that chain info has updated (new block message) // if sec == nil, it signals that chain info has updated (new block message)
case sec := <-self.headSectionC: case sec := <-self.headSectionC:
@ -503,7 +513,7 @@ LOOP:
self.getCurrentBlock(nil) self.getCurrentBlock(nil)
// quitting on timeout // quitting on timeout
case <-self.suicide: case <-self.suicideC:
self.peerError(self.bp.peers.errors.New(ErrInsufficientChainInfo, "timed out without providing block hashes or head block %x", currentBlockHash)) self.peerError(self.bp.peers.errors.New(ErrInsufficientChainInfo, "timed out without providing block hashes or head block %x", currentBlockHash))
self.bp.status.lock.Lock() self.bp.status.lock.Lock()