diff --git a/domain/consensus/model/interface_processes_dagtraversalmanager.go b/domain/consensus/model/interface_processes_dagtraversalmanager.go index ce52a225f..2bf5e6726 100644 --- a/domain/consensus/model/interface_processes_dagtraversalmanager.go +++ b/domain/consensus/model/interface_processes_dagtraversalmanager.go @@ -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) } diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index 203148e06..461d136fe 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -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 }