Always request orphan roots, even when you get an inv of a known orphan (#1436)

Co-authored-by: Svarog <feanorr@gmail.com>
This commit is contained in:
Ori Newman 2021-01-20 10:58:45 +02:00 committed by GitHub
parent abef96e3de
commit 319ab6cfcd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 14 deletions

View File

@ -4,6 +4,8 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashset"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/pkg/errors"
)
@ -160,3 +162,49 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externa
log.Infof("Unorphaned block %s", orphanHash)
return blockInsertionResult, true, nil
}
// GetOrphanRoots returns the roots of the missing ancestors DAG of the given orphan
func (f *FlowContext) GetOrphanRoots(orphan *externalapi.DomainHash) ([]*externalapi.DomainHash, bool, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "GetOrphanRoots")
defer onEnd()
f.orphansMutex.RLock()
defer f.orphansMutex.RUnlock()
_, ok := f.orphans[*orphan]
if !ok {
return nil, false, nil
}
queue := []*externalapi.DomainHash{orphan}
addedToQueueSet := hashset.New()
addedToQueueSet.Add(orphan)
roots := []*externalapi.DomainHash{}
for len(queue) > 0 {
var current *externalapi.DomainHash
current, queue = queue[0], queue[1:]
block, ok := f.orphans[*current]
if !ok {
blockInfo, err := f.domain.Consensus().GetBlockInfo(current)
if err != nil {
return nil, false, err
}
if !blockInfo.Exists || blockInfo.BlockStatus == externalapi.StatusHeaderOnly {
roots = append(roots, current)
}
continue
}
for _, parent := range block.Header.ParentHashes() {
if !addedToQueueSet.Contains(parent) {
queue = append(queue, parent)
addedToQueueSet.Add(parent)
}
}
}
return roots, true, nil
}

View File

@ -29,6 +29,7 @@ type RelayInvsContext interface {
SharedRequestedBlocks() *SharedRequestedBlocks
Broadcast(message appmessage.Message) error
AddOrphan(orphanBlock *externalapi.DomainBlock)
GetOrphanRoots(orphanHash *externalapi.DomainHash) ([]*externalapi.DomainHash, bool, error)
IsOrphan(blockHash *externalapi.DomainHash) bool
IsIBDRunning() bool
TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool
@ -71,7 +72,7 @@ func (flow *handleRelayInvsFlow) start() error {
if err != nil {
return err
}
if blockInfo.Exists {
if blockInfo.Exists && blockInfo.BlockStatus != externalapi.StatusHeaderOnly {
if blockInfo.BlockStatus == externalapi.StatusInvalid {
return protocolerrors.Errorf(true, "sent inv of an invalid block %s",
inv.Hash)
@ -81,7 +82,11 @@ func (flow *handleRelayInvsFlow) start() error {
}
if flow.IsOrphan(inv.Hash) {
log.Debugf("Block %s is a known orphan. continuing...", inv.Hash)
log.Debugf("Block %s is a known orphan. Requesting its missing ancestors", inv.Hash)
err := flow.AddOrphanRootsToQueue(inv.Hash)
if err != nil {
return err
}
continue
}
@ -107,7 +112,7 @@ func (flow *handleRelayInvsFlow) start() error {
return err
}
if len(missingParents) > 0 {
log.Debugf("Block %s contains orphans: %s", inv.Hash, missingParents)
log.Debugf("Block %s is orphan and has missing parents: %s", inv.Hash, missingParents)
err := flow.processOrphan(block, missingParents)
if err != nil {
return err
@ -238,9 +243,10 @@ func (flow *handleRelayInvsFlow) processOrphan(block *externalapi.DomainBlock, m
}
if isBlockInOrphanResolutionRange {
log.Debugf("Block %s is within orphan resolution range. "+
"Adding it to the orphan set and requesting its missing parents", blockHash)
flow.addToOrphanSetAndRequestMissingParents(block, missingParents)
return nil
"Adding it to the orphan set", blockHash)
flow.AddOrphan(block)
log.Debugf("Requesting block %s missing ancestors", blockHash)
return flow.AddOrphanRootsToQueue(blockHash)
}
// Start IBD unless we already are in IBD
@ -277,13 +283,25 @@ func (flow *handleRelayInvsFlow) isBlockInOrphanResolutionRange(blockHash *exter
return false, nil
}
func (flow *handleRelayInvsFlow) addToOrphanSetAndRequestMissingParents(
block *externalapi.DomainBlock, missingParents []*externalapi.DomainHash) {
flow.AddOrphan(block)
invMessages := make([]*appmessage.MsgInvRelayBlock, len(missingParents))
for i, missingParent := range missingParents {
invMessages[i] = appmessage.NewMsgInvBlock(missingParent)
func (flow *handleRelayInvsFlow) AddOrphanRootsToQueue(orphan *externalapi.DomainHash) error {
orphanRoots, orphanExists, err := flow.GetOrphanRoots(orphan)
if err != nil {
return err
}
if !orphanExists {
log.Infof("Orphan block %s was missing from the orphan pool while requesting for its roots. This "+
"probably happened because it was randomly evicted immediately after it was added.", orphan)
}
log.Infof("Block %s has %d missing ancestors. Adding them to the invs queue...", orphan, len(orphanRoots))
invMessages := make([]*appmessage.MsgInvRelayBlock, len(orphanRoots))
for i, root := range orphanRoots {
log.Debugf("Adding block %s missing ancestor %s to the invs queue", orphan, root)
invMessages[i] = appmessage.NewMsgInvBlock(root)
}
flow.invsQueue = append(invMessages, flow.invsQueue...)
return nil
}

View File

@ -10,7 +10,8 @@ import (
// current virtual. This process may result in a new virtual block
// getting created
func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) {
logger.LogAndMeasureExecutionTime(log, "csm.AddBlock")
onEnd := logger.LogAndMeasureExecutionTime(log, "csm.AddBlock")
defer onEnd()
log.Debugf("Resolving whether the block %s is the next virtual selected parent", blockHash)
isCandidateToBeNextVirtualSelectedParent, err := csm.isCandidateToBeNextVirtualSelectedParent(blockHash)