[NOD-1418] Implement DAG Traversal (#953)

* Implement DAG Traversal

* Update the DAGTraversalManager interface
This commit is contained in:
Elichai Turkel 2020-10-29 16:48:41 +02:00 committed by GitHub
parent 9cf1557c37
commit 971d50b684
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 4 deletions

View File

@ -6,6 +6,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// in the DAG
type DAGTraversalManager interface {
HighestChainBlockBelowBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error)
SelectedParentIterator(highHash *externalapi.DomainHash) (SelectedParentIterator, error)
SelectedParentIterator(highHash *externalapi.DomainHash) SelectedParentIterator
BlueWindow(highHash *externalapi.DomainHash, windowSize uint64) ([]*externalapi.DomainHash, error)
}

View File

@ -1,6 +1,7 @@
package dagtraversalmanager
import (
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
@ -14,6 +15,29 @@ type dagTraversalManager struct {
ghostdagDataStore model.GHOSTDAGDataStore
}
// selectedParentIterator implements the `model.SelectedParentIterator` API
type selectedParentIterator struct {
databaseContext model.DBReader
ghostdagDataStore model.GHOSTDAGDataStore
current *externalapi.DomainHash
}
func (spi *selectedParentIterator) Next() bool {
if spi.current == nil {
return false
}
ghostdagData, err := spi.ghostdagDataStore.Get(spi.databaseContext, spi.current)
if err != nil {
panic(fmt.Sprintf("ghostdagDataStore is missing ghostdagData for: %v. '%s' ", spi.current, err))
}
spi.current = ghostdagData.SelectedParent
return spi.current != nil
}
func (spi *selectedParentIterator) Get() *externalapi.DomainHash {
return spi.current
}
// New instantiates a new DAGTraversalManager
func New(
databaseContext model.DBReader,
@ -28,8 +52,12 @@ func New(
// SelectedParentIterator creates an iterator over the selected
// parent chain of the given highHash
func (dtm *dagTraversalManager) SelectedParentIterator(highHash *externalapi.DomainHash) (model.SelectedParentIterator, error) {
return nil, nil
func (dtm *dagTraversalManager) SelectedParentIterator(highHash *externalapi.DomainHash) model.SelectedParentIterator {
return &selectedParentIterator{
databaseContext: dtm.databaseContext,
ghostdagDataStore: dtm.ghostdagDataStore,
current: highHash,
}
}
// HighestChainBlockBelowBlueScore returns the hash of the
@ -37,5 +65,28 @@ func (dtm *dagTraversalManager) SelectedParentIterator(highHash *externalapi.Dom
// blueScore in the block with the given highHash's selected
// parent chain
func (dtm *dagTraversalManager) HighestChainBlockBelowBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error) {
return nil, nil
blockHash := highHash
chainBlock, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, highHash)
if err != nil {
return nil, err
}
if chainBlock.BlueScore < blueScore { // will practically return genesis.
blueScore = chainBlock.BlueScore
}
requiredBlueScore := chainBlock.BlueScore - blueScore
// If we used `SelectedParentIterator` 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
}
blockHash = chainBlock.SelectedParent
chainBlock, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, highHash)
if err != nil {
return nil, err
}
}
return blockHash, nil
}