@ -169,6 +169,9 @@ type BlockPool struct {
// alloc-easy pool of hash slices
// alloc-easy pool of hash slices
hashSlicePool chan [ ] common . Hash
hashSlicePool chan [ ] common . Hash
nodeCache map [ common . Hash ] * node
nodeCacheLock sync . RWMutex
// waitgroup is used in tests to wait for result-critical routines
// waitgroup is used in tests to wait for result-critical routines
// as well as in determining idle / syncing status
// as well as in determining idle / syncing status
wg sync . WaitGroup //
wg sync . WaitGroup //
@ -210,6 +213,7 @@ func (self *BlockPool) Start() {
self . Config . init ( )
self . Config . init ( )
self . hashSlicePool = make ( chan [ ] common . Hash , 150 )
self . hashSlicePool = make ( chan [ ] common . Hash , 150 )
self . nodeCache = make ( map [ common . Hash ] * node )
self . status = newStatus ( )
self . status = newStatus ( )
self . quit = make ( chan bool )
self . quit = make ( chan bool )
self . pool = make ( map [ common . Hash ] * entry )
self . pool = make ( map [ common . Hash ] * entry )
@ -615,127 +619,104 @@ LOOP:
If the block received is the head block of the current best peer , signal it to the head section process
If the block received is the head block of the current best peer , signal it to the head section process
* /
* /
func ( self * BlockPool ) AddBlock ( block * types . Block , peerId string ) {
func ( self * BlockPool ) AddBlock ( block * types . Block , peerId string ) {
hash := block . Hash ( )
sender , _ := self . peers . getPeer ( peerId )
if sender == nil {
return
}
self . status . lock . Lock ( )
self . status . lock . Lock ( )
self . status . activePeers [ peerId ] ++
self . status . activePeers [ peerId ] ++
self . status . lock . Unlock ( )
self . status . lock . Unlock ( )
entry := self . get ( hash )
hash := block . Hash ( )
blockIsCurrentHead := false
sender . lock . RLock ( )
currentBlockHash := sender . currentBlockHash
currentBlock := sender . currentBlock
currentBlockC := sender . currentBlockC
switchC := sender . switchC
sender . lock . RUnlock ( )
// a peer's current head block is appearing the first time
if hash == currentBlockHash {
// this happens when block came in a newblock message but
// also if sent in a blockmsg (for instance, if we requested, only if we
// dont apply on blockrequests the restriction of flood control)
blockIsCurrentHead = true
if currentBlock == nil {
sender . lock . Lock ( )
sender . setChainInfoFromBlock ( block )
sender . lock . Unlock ( )
self . status . lock . Lock ( )
self . status . values . BlockHashes ++
self . status . values . Blocks ++
self . status . values . BlocksInPool ++
self . status . lock . Unlock ( )
// signal to head section process
select {
case currentBlockC <- block :
case <- switchC :
}
} else {
plog . DebugDetailf ( "AddBlock: head block %s for peer <%s> (head: %s) already known" , hex ( hash ) , peerId , hex ( currentBlockHash ) )
}
} else {
plog . DebugDetailf ( "AddBlock: block %s received from peer <%s> (head: %s)" , hex ( hash ) , peerId , hex ( currentBlockHash ) )
/ * @ zelig ! ! !
requested 5 hashes from both A & B . A responds sooner then B , process blocks . Close section .
delayed B sends you block ... UNREQUESTED . Blocked
if entry == nil {
plog . DebugDetailf ( "AddBlock: unrequested block %s received from peer <%s> (head: %s)" , hex ( hash ) , peerId , hex ( sender . currentBlockHash ) )
sender . addError ( ErrUnrequestedBlock , "%x" , hash )
self . status . lock . Lock ( )
self . status . badPeers [ peerId ] ++
self . status . lock . Unlock ( )
return
}
* /
}
if entry == nil {
// check if block is already inserted in the blockchain
// FIXME: here check the cache find or create node -
if self . hasBlock ( hash ) {
// put peer as blockBy!
return
return
}
}
node := entry . node
sender , _ := self . peers . getPeer ( peerId )
node . lock . Lock ( )
if sender == nil {
defer node . lock . Unlock ( )
// register peer on node as source
if node . peers == nil {
node . peers = make ( map [ string ] bool )
}
FoundBlockCurrentHead , found := node . peers [ sender . id ]
if ! found || FoundBlockCurrentHead {
// if found but not FoundBlockCurrentHead, then no update
// necessary (||)
node . peers [ sender . id ] = blockIsCurrentHead
// for those that are false, TD will update their head
// for those that are true, TD is checked !
// this is checked at the time of TD calculation in checkTD
}
// check if block already received
if node . block != nil {
plog . DebugDetailf ( "AddBlock: block %s from peer <%s> (head: %s) already sent by <%s> " , hex ( hash ) , peerId , hex ( sender . currentBlockHash ) , node . blockBy )
}
// check if block is already inserted in the blockchain
if self . hasBlock ( hash ) {
plog . DebugDetailf ( "AddBlock: block %s from peer <%s> (head: %s) already in the blockchain" , hex ( hash ) , peerId , hex ( sender . currentBlockHash ) )
return
return
}
}
tdFromCurrentHead , currentBlockHash := sender . setChainInfoFromBlock ( block )
/ *
entry := self . get ( hash )
@ zelig needs discussing
Viktor : pow check can be delayed in a go routine and therefore cache
creation is not blocking
// validate block for PoW
if ! self . verifyPoW ( block ) {
plog . Warnf ( "AddBlock: invalid PoW on block %s from peer <%s> (head: %s)" , hex ( hash ) , peerId , hex ( sender . currentBlockHash ) )
sender . addError ( ErrInvalidPoW , "%x" , hash )
self . status . lock . Lock ( )
/ * @ zelig ! ! !
self . status . badPeers [ peerId ] ++
requested 5 hashes from both A & B . A responds sooner then B , process blocks . Close section .
self . status . lock . Unlock ( )
delayed B sends you block ... UNREQUESTED . Blocked
if entry == nil {
plog . DebugDetailf ( "AddBlock: unrequested block %s received from peer <%s> (head: %s)" , hex ( hash ) , peerId , hex ( sender . currentBlockHash ) )
sender . addError ( ErrUnrequestedBlock , "%x" , hash )
self . status . lock . Lock ( )
self . status . badPeers [ peerId ] ++
self . status . lock . Unlock ( )
return
}
* /
return
var bnode * node
if entry == nil {
self . nodeCacheLock . Lock ( )
bnode , _ = self . nodeCache [ hash ]
if bnode == nil {
bnode = & node {
hash : currentBlockHash ,
block : block ,
hashBy : peerId ,
blockBy : peerId ,
td : tdFromCurrentHead ,
}
}
* /
self . nodeCache [ hash ] = bnode
}
self . nodeCacheLock . Unlock ( )
} else {
bnode = entry . node
}
node . block = block
bnode . lock . Lock ( )
node . blockBy = peerId
defer bnode . lock . Unlock ( )
self . status . lock . Lock ( )
// check if block already received
self . status . values . Blocks ++
if bnode . block != nil {
self . status . values . BlocksInPool ++
plog . DebugDetailf ( "AddBlock: block %s from peer <%s> (head: %s) already sent by <%s> " , hex ( hash ) , peerId , hex ( sender . currentBlockHash ) , bnode . blockBy )
self . status . lock . Unlock ( )
// register peer on node as source
if bnode . peers == nil {
bnode . peers = make ( map [ string ] bool )
}
foundBlockCurrentHead , found := bnode . peers [ sender . id ]
if ! found || foundBlockCurrentHead {
// if found but not FoundBlockCurrentHead, then no update
// necessary (||)
bnode . peers [ sender . id ] = ( currentBlockHash == hash )
// for those that are false, TD will update their head
// for those that are true, TD is checked !
// this is checked at the time of TD calculation in checkTD
}
sender . setChainInfoFromNode ( bnode )
} else {
/ *
@ zelig needs discussing
Viktor : pow check can be delayed in a go routine and therefore cache
creation is not blocking
// validate block for PoW
if ! self . verifyPoW ( block ) {
plog . Warnf ( "AddBlock: invalid PoW on block %s from peer <%s> (head: %s)" , hex ( hash ) , peerId , hex ( sender . currentBlockHash ) )
sender . addError ( ErrInvalidPoW , "%x" , hash )
self . status . lock . Lock ( )
self . status . badPeers [ peerId ] ++
self . status . lock . Unlock ( )
return
}
* /
bnode . block = block
bnode . blockBy = peerId
bnode . td = tdFromCurrentHead
self . status . lock . Lock ( )
self . status . values . Blocks ++
self . status . values . BlocksInPool ++
self . status . lock . Unlock ( )
}
}
}