apply the traversal limit logic and sort headers

This commit is contained in:
msutton
2022-03-11 15:05:26 +02:00
parent 8f68d5c606
commit 047fa30183
6 changed files with 38 additions and 15 deletions

View File

@@ -1,18 +1,20 @@
package blockrelay
import (
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/app/protocol/peer"
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/domain"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/infrastructure/config"
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
"sort"
)
// RequestPastDiffContext is the interface for the context needed for the HandleRequestHeaders flow.
type RequestPastDiffContext interface {
Domain() domain.Domain
Config() *config.Config
}
type handleRequestPastDiffFlow struct {
@@ -43,13 +45,13 @@ func (flow *handleRequestPastDiffFlow) start() error {
log.Debugf("Received requestPastDiff with hasHash: %s, requestedHash: %s", hasHash, requestedHash)
log.Debugf("Getting past(%s) setminus past(%s) to %s", requestedHash, hasHash, flow.peer)
// GetPastDiff is a relatively heavy operation so we limit it
// in order to avoid locking the consensus for too long
// maxBlocks MUST be >= MergeSetSizeLimit + 1
const maxBlocks = 1 << 10
blockHashes, err := flow.Domain().Consensus().GetPastDiff(hasHash, requestedHash, maxBlocks)
// GetPastDiff is expected to be called by the syncee for getting the anticone of the header selected tip
// intersected by past of relayed block, and is thus expected to be bounded by mergeset limit since
// we relay blocks only if they enter virtual's mergeset. We add 2 for a small margin error.
blockHashes, err := flow.Domain().Consensus().GetPastDiff(hasHash, requestedHash,
flow.Config().ActiveNetParams.MergeSetSizeLimit+2)
if err != nil {
return protocolerrors.Wrap(true, err, "Expected hashes in anticone one of the other")
return protocolerrors.Wrap(true, err, "Failed querying anticone")
}
log.Debugf("Got %d header hashes in past(%s) setminus past(%s)", len(blockHashes), requestedHash, hasHash)
@@ -62,6 +64,14 @@ func (flow *handleRequestPastDiffFlow) start() error {
blockHeaders[i] = appmessage.DomainBlockHeaderToBlockHeader(blockHeader)
}
// We sort the headers in bottom-up topological order before sending
sort.Slice(blockHeaders, func(i, j int) bool {
return blockHeaders[i].BlueWork.Cmp(blockHeaders[j].BlueWork) < 0
})
if err != nil {
return err
}
blockHeadersMessage := appmessage.NewBlockHeadersMessage(blockHeaders)
err = flow.outgoingRoute.Enqueue(blockHeadersMessage)
if err != nil {

View File

@@ -720,7 +720,7 @@ func (s *consensus) Anticone(blockHash *externalapi.DomainHash) ([]*externalapi.
return nil, err
}
return s.dagTraversalManager.AnticoneFromBlocks(stagingArea, tips, blockHash)
return s.dagTraversalManager.AnticoneFromBlocks(stagingArea, tips, blockHash, 0)
}
func (s *consensus) EstimateNetworkHashesPerSecond(startHash *externalapi.DomainHash, windowSize int) (uint64, error) {

View File

@@ -5,3 +5,7 @@ import "github.com/pkg/errors"
// ErrBlockNotInSelectedParentChain is returned from CreateHeadersSelectedChainBlockLocator if one of the parameters
// passed to it are not in the headers selected parent chain
var ErrBlockNotInSelectedParentChain = errors.New("Block is not in selected parent chain")
// ErrReachedMaxTraversalAllowed is returned from AnticoneFromBlocks if `maxTraversalAllowed` was specified
// and the traversal passed it
var ErrReachedMaxTraversalAllowed = errors.New("Traversal searching for anticone passed the maxTraversalAllowed limit")

View File

@@ -10,7 +10,7 @@ type DAGTraversalManager interface {
// from lowHash (exclusive) to highHash (inclusive) over highHash's selected parent chain
SelectedChildIterator(stagingArea *StagingArea, highHash, lowHash *externalapi.DomainHash, includeLowHash bool) (BlockIterator, error)
SelectedChild(stagingArea *StagingArea, highHash, lowHash *externalapi.DomainHash) (*externalapi.DomainHash, error)
AnticoneFromBlocks(stagingArea *StagingArea, tips []*externalapi.DomainHash, blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
AnticoneFromBlocks(stagingArea *StagingArea, tips []*externalapi.DomainHash, blockHash *externalapi.DomainHash, maxTraversalAllowed uint64) ([]*externalapi.DomainHash, error)
AnticoneFromVirtualPOV(stagingArea *StagingArea, blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
BlockWindow(stagingArea *StagingArea, highHash *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error)
DAABlockWindow(stagingArea *StagingArea, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)

View File

@@ -14,16 +14,18 @@ func (dtm *dagTraversalManager) AnticoneFromVirtualPOV(stagingArea *model.Stagin
return nil, err
}
return dtm.AnticoneFromBlocks(stagingArea, virtualParents, blockHash)
return dtm.AnticoneFromBlocks(stagingArea, virtualParents, blockHash, 0)
}
func (dtm *dagTraversalManager) AnticoneFromBlocks(stagingArea *model.StagingArea, tips []*externalapi.DomainHash, blockHash *externalapi.DomainHash) (
func (dtm *dagTraversalManager) AnticoneFromBlocks(stagingArea *model.StagingArea, tips []*externalapi.DomainHash,
blockHash *externalapi.DomainHash, maxTraversalAllowed uint64) (
[]*externalapi.DomainHash, error) {
anticone := []*externalapi.DomainHash{}
queue := tips
visited := hashset.New()
traversalCounter := uint64(0)
for len(queue) > 0 {
var current *externalapi.DomainHash
current, queue = queue[0], queue[1:]
@@ -48,6 +50,13 @@ func (dtm *dagTraversalManager) AnticoneFromBlocks(stagingArea *model.StagingAre
return nil, err
}
// We count the number of blocks in past(tips) \setminus past(blockHash).
// We don't use `len(visited)` since it includes some maximal blocks in past(blockHash) as well.
traversalCounter++
if maxTraversalAllowed > 0 && traversalCounter > maxTraversalAllowed {
return nil, model.ErrReachedMaxTraversalAllowed
}
if !blockIsAncestorOfCurrent {
anticone = append(anticone, current)
}

View File

@@ -92,8 +92,8 @@ func (sm *syncManager) GetPastDiff(stagingArea *model.StagingArea, hasHash,
hasHash,
requestedHash)
}
// TODO: use maxBlocks limit
return sm.dagTraversalManager.AnticoneFromBlocks(stagingArea, []*externalapi.DomainHash{requestedHash}, hasHash)
return sm.dagTraversalManager.AnticoneFromBlocks(stagingArea,
[]*externalapi.DomainHash{requestedHash}, hasHash, maxBlocks)
}
func (sm *syncManager) GetMissingBlockBodyHashes(stagingArea *model.StagingArea, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {