mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
[NOD-1511] Implement missingBlockBodyHashes (#1000)
* [NOD-1511] Implement missingBlockBodyHashes * [NOD-1511] Rename selectedparentiterator.go to blockiterator.go * [NOD-1511] Fix condition * [NOD-1511] Simplify missingBlocks logic
This commit is contained in:
parent
baf8d25656
commit
52c73d3a08
@ -183,6 +183,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
genesisHash,
|
||||
dagTraversalManager,
|
||||
dagTopologyManager,
|
||||
consensusStateManager,
|
||||
|
||||
ghostdagDataStore,
|
||||
blockStatusStore)
|
||||
|
||||
|
@ -2,9 +2,8 @@ package model
|
||||
|
||||
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
// SelectedParentIterator is an iterator over the selected parent
|
||||
// chain of some block
|
||||
type SelectedParentIterator interface {
|
||||
// BlockIterator is an iterator over blocks according to some order.
|
||||
type BlockIterator interface {
|
||||
Next() bool
|
||||
Get() *externalapi.DomainHash
|
||||
}
|
@ -8,4 +8,5 @@ type ConsensusStateManager interface {
|
||||
PopulateTransactionWithUTXOEntries(transaction *externalapi.DomainTransaction) error
|
||||
SetPruningPointUTXOSet(serializedUTXOSet []byte) error
|
||||
RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error)
|
||||
HeaderTipsPruningPoint() (*externalapi.DomainHash, error)
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
type DAGTraversalManager interface {
|
||||
HighestChainBlockBelowBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error)
|
||||
LowestChainBlockAboveOrEqualToBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error)
|
||||
SelectedParentIterator(highHash *externalapi.DomainHash) SelectedParentIterator
|
||||
SelectedParentIterator(highHash *externalapi.DomainHash) BlockIterator
|
||||
SelectedChildIterator(highHash, lowHash *externalapi.DomainHash) (BlockIterator, error)
|
||||
AnticoneFromContext(context, lowHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
|
||||
BlueWindow(highHash *externalapi.DomainHash, windowSize uint64) ([]*externalapi.DomainHash, error)
|
||||
NewDownHeap() BlockHeap
|
||||
NewUpHeap() BlockHeap
|
||||
|
@ -29,7 +29,7 @@ func (csm *consensusStateManager) SetPruningPointUTXOSet(serializedUTXOSet []byt
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byte) error {
|
||||
headerTipsPruningPoint, err := csm.headerTipsPruningPoint()
|
||||
headerTipsPruningPoint, err := csm.HeaderTipsPruningPoint()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -98,7 +98,7 @@ func deserializeUTXOSet(serializedUTXOSet []byte) model.ReadOnlyUTXOSetIterator
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) headerTipsPruningPoint() (*externalapi.DomainHash, error) {
|
||||
func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainHash, error) {
|
||||
headerTips, err := csm.headerTipsStore.Tips(csm.databaseContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
53
domain/consensus/processes/dagtraversalmanager/anticone.go
Normal file
53
domain/consensus/processes/dagtraversalmanager/anticone.go
Normal file
@ -0,0 +1,53 @@
|
||||
package dagtraversalmanager
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashset"
|
||||
)
|
||||
|
||||
// AnticoneFromContext returns blocks in (context.Past ⋂ block.Anticone)
|
||||
func (dtm *dagTraversalManager) AnticoneFromContext(context, block *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
|
||||
anticone := []*externalapi.DomainHash{}
|
||||
queue := []*externalapi.DomainHash{context}
|
||||
visited := hashset.New()
|
||||
|
||||
for len(queue) > 0 {
|
||||
var current *externalapi.DomainHash
|
||||
current, queue = queue[0], queue[1:]
|
||||
|
||||
if visited.Contains(current) {
|
||||
continue
|
||||
}
|
||||
|
||||
visited.Add(current)
|
||||
|
||||
currentIsAncestorOfBlock, err := dtm.dagTopologyManager.IsAncestorOf(current, block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if currentIsAncestorOfBlock {
|
||||
continue
|
||||
}
|
||||
|
||||
blockIsAncestorOfCurrent, err := dtm.dagTopologyManager.IsAncestorOf(block, current)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !blockIsAncestorOfCurrent {
|
||||
anticone = append(anticone, current)
|
||||
}
|
||||
|
||||
currentParents, err := dtm.dagTopologyManager.Parents(current)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, parent := range currentParents {
|
||||
queue = append(queue, parent)
|
||||
}
|
||||
}
|
||||
|
||||
return anticone, nil
|
||||
}
|
@ -16,7 +16,7 @@ type dagTraversalManager struct {
|
||||
ghostdagManager model.GHOSTDAGManager
|
||||
}
|
||||
|
||||
// selectedParentIterator implements the `model.SelectedParentIterator` API
|
||||
// selectedParentIterator implements the `model.BlockIterator` API
|
||||
type selectedParentIterator struct {
|
||||
databaseContext model.DBReader
|
||||
ghostdagDataStore model.GHOSTDAGDataStore
|
||||
@ -55,7 +55,7 @@ func New(
|
||||
|
||||
// SelectedParentIterator creates an iterator over the selected
|
||||
// parent chain of the given highHash
|
||||
func (dtm *dagTraversalManager) SelectedParentIterator(highHash *externalapi.DomainHash) model.SelectedParentIterator {
|
||||
func (dtm *dagTraversalManager) SelectedParentIterator(highHash *externalapi.DomainHash) model.BlockIterator {
|
||||
return &selectedParentIterator{
|
||||
databaseContext: dtm.databaseContext,
|
||||
ghostdagDataStore: dtm.ghostdagDataStore,
|
||||
@ -79,7 +79,7 @@ func (dtm *dagTraversalManager) HighestChainBlockBelowBlueScore(highHash *extern
|
||||
|
||||
requiredBlueScore := chainBlock.BlueScore - blueScore
|
||||
|
||||
// If we used `SelectedParentIterator` we'd need to do more calls to `ghostdagDataStore` so we can get the blueScore
|
||||
// If we used `BlockIterator` we'd need to do more calls to `ghostdagDataStore` so we can get the blueScore
|
||||
for chainBlock.BlueScore >= requiredBlueScore {
|
||||
if chainBlock.SelectedParent == nil { // genesis
|
||||
return blockHash, nil
|
||||
|
@ -0,0 +1,55 @@
|
||||
package dagtraversalmanager
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type selectedChildIterator struct {
|
||||
databaseContext model.DBReader
|
||||
dagTopologyManager model.DAGTopologyManager
|
||||
highHash *externalapi.DomainHash
|
||||
current *externalapi.DomainHash
|
||||
}
|
||||
|
||||
func (s selectedChildIterator) Next() bool {
|
||||
children, err := s.dagTopologyManager.Children(s.current)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, child := range children {
|
||||
isChildInSelectedParentChainOfHighHash, err := s.dagTopologyManager.IsInSelectedParentChainOf(child, s.highHash)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if isChildInSelectedParentChainOfHighHash {
|
||||
s.current = child
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s selectedChildIterator) Get() *externalapi.DomainHash {
|
||||
return s.current
|
||||
}
|
||||
|
||||
func (dtm *dagTraversalManager) SelectedChildIterator(highHash, lowHash *externalapi.DomainHash) (model.BlockIterator, error) {
|
||||
isLowHashInSelectedParentChainOfHighHash, err := dtm.dagTopologyManager.IsInSelectedParentChainOf(lowHash, highHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isLowHashInSelectedParentChainOfHighHash {
|
||||
return nil, errors.Errorf("%s is not in the selected parent chain of %s", highHash, lowHash)
|
||||
}
|
||||
return &selectedChildIterator{
|
||||
databaseContext: dtm.databaseContext,
|
||||
dagTopologyManager: dtm.dagTopologyManager,
|
||||
highHash: highHash,
|
||||
current: lowHash,
|
||||
}, nil
|
||||
}
|
@ -99,7 +99,83 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
|
||||
}
|
||||
|
||||
func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
|
||||
panic("implement me")
|
||||
headerTipsPruningPoint, err := sm.consensusStateManager.HeaderTipsPruningPoint()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
selectedChildIterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, headerTipsPruningPoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lowHash := headerTipsPruningPoint
|
||||
for selectedChildIterator.Next() {
|
||||
lowHash = selectedChildIterator.Get()
|
||||
}
|
||||
|
||||
hashesBetween, err := sm.antiPastHashesBetween(lowHash, highHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lowHashAnticone, err := sm.dagTraversalManager.AnticoneFromContext(highHash, lowHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blockToRemoveFromHashesBetween := hashset.New()
|
||||
for _, blockHash := range lowHashAnticone {
|
||||
isHeaderOnlyBlock, err := sm.isHeaderOnlyBlock(blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isHeaderOnlyBlock {
|
||||
blockToRemoveFromHashesBetween.Add(blockHash)
|
||||
}
|
||||
}
|
||||
|
||||
missingBlocks := make([]*externalapi.DomainHash, 0, len(hashesBetween)-len(lowHashAnticone))
|
||||
for i, blockHash := range hashesBetween {
|
||||
// If blockToRemoveFromHashesBetween is empty, no more blocks should be
|
||||
// filtered, so we can copy the rest of hashesBetween into missingBlocks
|
||||
if blockToRemoveFromHashesBetween.Length() == 0 {
|
||||
missingBlocks = append(missingBlocks, hashesBetween[i:]...)
|
||||
break
|
||||
}
|
||||
|
||||
if blockToRemoveFromHashesBetween.Contains(blockHash) {
|
||||
blockToRemoveFromHashesBetween.Remove(blockHash)
|
||||
continue
|
||||
}
|
||||
|
||||
missingBlocks = append(missingBlocks, blockHash)
|
||||
}
|
||||
|
||||
if blockToRemoveFromHashesBetween.Length() != 0 {
|
||||
return nil, errors.Errorf("blockToRemoveFromHashesBetween.Length() is expected to be 0")
|
||||
}
|
||||
|
||||
return missingBlocks, nil
|
||||
}
|
||||
|
||||
func (sm *syncManager) isHeaderOnlyBlock(blockHash *externalapi.DomainHash) (bool, error) {
|
||||
exists, err := sm.blockStatusStore.Exists(sm.databaseContext, blockHash)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
status, err := sm.blockStatusStore.Get(sm.databaseContext, blockHash)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return status == externalapi.StatusHeaderOnly, nil
|
||||
}
|
||||
|
||||
func (sm *syncManager) isBlockInHeaderPruningPointFutureAndVirtualPast(blockHash *externalapi.DomainHash) (bool, error) {
|
||||
|
@ -10,8 +10,9 @@ type syncManager struct {
|
||||
databaseContext model.DBReader
|
||||
genesisBlockHash *externalapi.DomainHash
|
||||
|
||||
dagTraversalManager model.DAGTraversalManager
|
||||
dagTopologyManager model.DAGTopologyManager
|
||||
dagTraversalManager model.DAGTraversalManager
|
||||
dagTopologyManager model.DAGTopologyManager
|
||||
consensusStateManager model.ConsensusStateManager
|
||||
|
||||
ghostdagDataStore model.GHOSTDAGDataStore
|
||||
blockStatusStore model.BlockStatusStore
|
||||
@ -23,6 +24,8 @@ func New(
|
||||
genesisBlockHash *externalapi.DomainHash,
|
||||
dagTraversalManager model.DAGTraversalManager,
|
||||
dagTopologyManager model.DAGTopologyManager,
|
||||
consensusStateManager model.ConsensusStateManager,
|
||||
|
||||
ghostdagDataStore model.GHOSTDAGDataStore,
|
||||
blockStatusStore model.BlockStatusStore) model.SyncManager {
|
||||
|
||||
@ -30,8 +33,9 @@ func New(
|
||||
databaseContext: databaseContext,
|
||||
genesisBlockHash: genesisBlockHash,
|
||||
|
||||
dagTraversalManager: dagTraversalManager,
|
||||
dagTopologyManager: dagTopologyManager,
|
||||
dagTraversalManager: dagTraversalManager,
|
||||
dagTopologyManager: dagTopologyManager,
|
||||
consensusStateManager: consensusStateManager,
|
||||
|
||||
ghostdagDataStore: ghostdagDataStore,
|
||||
blockStatusStore: blockStatusStore,
|
||||
|
@ -84,3 +84,8 @@ func (hs HashSet) ToSlice() []*externalapi.DomainHash {
|
||||
|
||||
return slice
|
||||
}
|
||||
|
||||
// Length returns the length of this HashSet
|
||||
func (hs HashSet) Length() int {
|
||||
return hs.Length()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user