// lastPoolNode is nil if and only if the node with stored root hash is already cleaned up
// 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
// if same peer gave different chain before, this will overwrite it
// if currentPoolNode existed as a non-leaf node the earlier fork is delinked
// 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.
// if lastPoolNode had a different parent the earlier parent (with entire subtree) is delinked, this situation cannot normally arise though
// just in case reset lastPoolNode as non-root (unlikely)
func(self*BlockPool)link(parent,child*poolNode){
// reactivate node scheduled for suicide
ifparent.suicide!=nil{
close(parent.suicide)
parent.suicide=nil
}
ifparent.child!=child{
orphan:=parent.child
orphan.parent=nil
goself.killChain(orphan)
parent.child=child
}
ifchild!=nil{
ifchild.parent!=parent{
orphan:=child.parent
orphan.child=nil
gofunc(){
// if it is a aberrant reverse fork, zip down to bottom
fororphan.parent!=nil{
orphan=orphan.parent
}
self.killChain(orphan)
}()
child.parent=parent
}
child.knownParent=false
}
}
func(self*BlockPool)killChain(node*poolNode){
ifnode==nil{
return
}
poolLogger.Debugf("suicide scheduled on node %v",node)
suicide:=make(chanbool)
self.lock.Lock()
node.suicide=suicide
self.lock.Unlock()
timer:=time.After(cacheTimeout*time.Minute)
self.wg.Add(1)
select{
case<-self.quit:
case<-suicide:
// cancel suicide = close node.suicide to reactivate node
case<-timer:
poolLogger.Debugf("suicide on node %v",node)
self.lock.Lock()
deferself.lock.Unlock()
// proceed up via child links until another suicide root found or chain ends
// abort request blocks loops that start above
// and delete nodes from pool then quit the suicide process