// lastPoolNode is nil if and only if the node with stored root hash is already cleaned up
// validate block for PoW
// after valid block insertion, therefore in this case the blockpool active chain is connected to the blockchain, so no need to request further hashes or request blocks
// - periodically polls the chain section for missing blocks which are then requested from peers
ifn.block!=nil{
// - registers the process controller on the peer so that if the peer is promoted as best peer the second time (after a disconnect of a better one), all active processes are switched back on unless they expire and killed ()
iflen(nodes)==0{
// - when turned off (if peer disconnects and new peer connects with alternative chain), no blockrequests are made but absolute expiry timer is ticking
// nil control indicates that node is not needed anymore
// - when turned back on it recursively calls itself on the root of the next chain section
// block can be inserted to blockchain and deleted if knownParent
poolLogger.Debugf("[%x] block requests had %v idle rounds (%v total attempts): missing %v/%v/%v\ngiving up...",hash[0:4],idle,blocksRequests,missing,total,depth)
self.killChain(node,nil)
break
}
}
}else{
}else{
nodes=append(nodes,n)
idle=0
n.blockRequestControl=control
}
}
n=n.child
same=true
}else{
ifmissing==0{
// no missing nodes
poolLogger.Debugf("block request process complete on section %x... (%v total blocksRequests): missing %v/%v/%v",hash[0:4],blockHashesRequests,blocksRequests,missing,total,depth)
node.Lock()
orignode.complete=true
node.Unlock()
blocksRequestTimer=nil
ifblockHashesRequestTimer==nil{
// not waiting for hashes any more
poolLogger.Debugf("hash request on root %x... successful (%v total attempts)\nquitting...",hash[0:4],blockHashesRequests)
break
}// otherwise suicide if no hashes coming
}
same=false
}
lastMissing=missing
i=0
missing=0
// ready for next round
done=true
}
ifdone&&alarm{
poolLogger.Debugf("start checking if new blocks arrived (attempt %v): missing %v/%v/%v",blocksRequests,missing,total,depth)
// if currentPoolNode existed as a non-leaf node the earlier fork is delinked
self.lock.Lock()
// if same parent hash is found, we can abort, we do not allow the same peer to change minds about parent of same hash, if errored first time round, will get penalized.
deferself.lock.Unlock()
// if lastPoolNode had a different parent the earlier parent (with entire subtree) is delinked, this situation cannot normally arise though
self.sections[string(hash)]=section
// just in case reset lastPoolNode as non-root (unlikely)
}
func(self*peerInfo)addRoot(node*poolNode){
self.lock.Lock()
deferself.lock.Unlock()
self.roots=append(self.roots,node)
}
// (re)starts processes registered for this peer (self)
func(self*peerInfo)start(peer*peerInfo){
self.lock.Lock()
deferself.lock.Unlock()
self.quitC=make(chanbool)
for_,root:=rangeself.roots{
root.sectionRLock()
ifroot.section.bottom!=nil{
ifroot.parent==nil{
self.requestBlockHashes(root.hash)
}
}
root.sectionRUnlock()
}
self.roots=nil
self.controlSections(peer,true)
}
// (re)starts process without requests, only suicide timer