@ -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 = 51 2
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 = 10 0
blocksRequestMaxIdleRounds = 2 0
// 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
@ -149,6 +157,15 @@ func New(
}
}
}
}
func severity ( code int ) ethlogger . LogLevel {
switch code {
case ErrUnrequestedBlock :
return ethlogger . WarnLevel
default :
return ethlogger . ErrorLevel
}
}
// allows restart
// allows restart
func ( self * BlockPool ) Start ( ) {
func ( self * BlockPool ) Start ( ) {
self . lock . Lock ( )
self . lock . Lock ( )
@ -169,6 +186,7 @@ func (self *BlockPool) Start() {
errors : & errs . Errors {
errors : & errs . Errors {
Package : "Blockpool" ,
Package : "Blockpool" ,
Errors : errorToString ,
Errors : errorToString ,
Level : severity ,
} ,
} ,
peers : make ( map [ string ] * peer ) ,
peers : make ( map [ string ] * peer ) ,
status : self . status ,
status : self . status ,
@ -363,6 +381,8 @@ LOOP:
// check if known block connecting the downloaded chain to our blockchain
// check if known block connecting the downloaded chain to our blockchain
plog . DebugDetailf ( "AddBlockHashes: peer <%s> (head: %s) found block %s in the blockchain" , peerId , hex ( bestpeer . currentBlockHash ) , hex ( hash ) )
plog . DebugDetailf ( "AddBlockHashes: peer <%s> (head: %s) found block %s in the blockchain" , peerId , hex ( bestpeer . currentBlockHash ) , hex ( hash ) )
if len ( nodes ) == 1 {
if len ( nodes ) == 1 {
plog . DebugDetailf ( "AddBlockHashes: singleton section pushed to blockchain peer <%s> (head: %s) found block %s in the blockchain" , peerId , hex ( bestpeer . currentBlockHash ) , hex ( hash ) )
// create new section if needed and push it to the blockchain
// create new section if needed and push it to the blockchain
sec = self . newSection ( nodes )
sec = self . newSection ( nodes )
sec . addSectionToBlockChain ( bestpeer )
sec . addSectionToBlockChain ( bestpeer )
@ -379,6 +399,8 @@ LOOP:
and td together with blockBy are recorded on the node
and td together with blockBy are recorded on the node
* /
* /
if len ( nodes ) == 0 && child != nil {
if len ( nodes ) == 0 && child != nil {
plog . DebugDetailf ( "AddBlockHashes: child section [%s] pushed to blockchain peer <%s> (head: %s) found block %s in the blockchain" , sectionhex ( child ) , peerId , hex ( bestpeer . currentBlockHash ) , hex ( hash ) )
child . addSectionToBlockChain ( bestpeer )
child . addSectionToBlockChain ( bestpeer )
}
}
}
}
@ -446,10 +468,12 @@ LOOP:
* /
* /
sec = self . linkSections ( nodes , parent , child )
sec = self . linkSections ( nodes , parent , child )
self . status . lock . Lock ( )
if sec != nil {
self . status . values . BlockHashes += len ( nodes )
self . status . lock . Lock ( )
self . status . lock . Unlock ( )
self . status . values . BlockHashes += len ( nodes )
plog . DebugDetailf ( "AddBlockHashes: peer <%s> (head: %s): section [%s] created" , peerId , hex ( bestpeer . currentBlockHash ) , sectionhex ( sec ) )
self . status . lock . Unlock ( )
plog . DebugDetailf ( "AddBlockHashes: peer <%s> (head: %s): section [%s] created" , peerId , hex ( bestpeer . currentBlockHash ) , sectionhex ( sec ) )
}
self . chainLock . Unlock ( )
self . chainLock . Unlock ( )
@ -549,6 +573,7 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
self . status . lock . Unlock ( )
self . status . lock . Unlock ( )
} else {
} else {
plog . DebugDetailf ( "AddBlock: head block %s for peer <%s> (head: %s) already known" , hex ( hash ) , peerId , hex ( sender . currentBlockHash ) )
plog . DebugDetailf ( "AddBlock: head block %s for peer <%s> (head: %s) already known" , hex ( hash ) , peerId , hex ( sender . currentBlockHash ) )
sender . currentBlockC <- block
}
}
} else {
} else {
@ -644,11 +669,15 @@ LOOP:
we need to relink both complete and incomplete sections
we need to relink both complete and incomplete sections
the latter could have been blockHashesRequestsComplete before being delinked from its parent
the latter could have been blockHashesRequestsComplete before being delinked from its parent
* /
* /
if parent == nil && sec . bottom . block != nil {
if parent == nil {
if entry := self . get ( sec . bottom . block . ParentHash ( ) ) ; entry != nil {
if sec . bottom . block != nil {
parent = entry . section
if entry := self . get ( sec . bottom . block . ParentHash ( ) ) ; entry != nil {
plog . DebugDetailf ( "activateChain: [%s]-[%s] relink" , sectionhex ( parent ) , sectionhex ( sec ) )
parent = entry . section
link ( parent , sec )
plog . DebugDetailf ( "activateChain: [%s]-[%s] link" , sectionhex ( parent ) , sectionhex ( sec ) )
link ( parent , sec )
}
} else {
plog . DebugDetailf ( "activateChain: section [%s] activated by peer <%s> has missing root block" , sectionhex ( sec ) , p . id )
}
}
}
}
sec = parent
sec = parent
@ -704,9 +733,15 @@ func (self *BlockPool) remove(sec *section) {
// delete node entries from pool index under pool lock
// delete node entries from pool index under pool lock
self . lock . Lock ( )
self . lock . Lock ( )
defer self . lock . Unlock ( )
defer self . lock . Unlock ( )
for _ , node := range sec . nodes {
for _ , node := range sec . nodes {
delete ( self . pool , string ( node . hash ) )
delete ( self . pool , string ( node . hash ) )
}
}
if sec . initialised && sec . poolRootIndex != 0 {
self . status . lock . Lock ( )
self . status . values . BlocksInPool -= len ( sec . nodes ) - sec . missing
self . status . lock . Unlock ( )
}
}
}
func ( self * BlockPool ) getHashSlice ( ) ( s [ ] [ ] byte ) {
func ( self * BlockPool ) getHashSlice ( ) ( s [ ] [ ] byte ) {