[NOD-1548] Re-add test difficulty + Make GHOSTDAGData immutable + don't clone in store (#1178)

* [NOD-1548] Readd TestDifficulty

* [NOD-1548] Make GHOSTDAGData immutable + don't clone in store

Co-authored-by: Ori Newman <orinewman1@gmail.com>
This commit is contained in:
Svarog 2020-12-06 12:35:14 +02:00 committed by GitHub
parent f97b8f7580
commit 33eaf9edac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 445 additions and 214 deletions

View File

@ -134,7 +134,7 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap
return nil, err return nil, err
} }
blockInfo.BlueScore = ghostdagData.BlueScore blockInfo.BlueScore = ghostdagData.BlueScore()
isBlockInHeaderPruningPointFuture, err := s.syncManager.IsBlockInHeaderPruningPointFuture(blockHash) isBlockInHeaderPruningPointFuture, err := s.syncManager.IsBlockInHeaderPruningPointFuture(blockHash)
if err != nil { if err != nil {
@ -196,7 +196,7 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent) return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent())
} }
func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) {

View File

@ -3,26 +3,27 @@ package serialization
import ( import (
"github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
) )
// BlockGHOSTDAGDataToDBBlockGHOSTDAGData converts BlockGHOSTDAGData to DbBlockGhostdagData // BlockGHOSTDAGDataToDBBlockGHOSTDAGData converts BlockGHOSTDAGData to DbBlockGhostdagData
func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData *model.BlockGHOSTDAGData) *DbBlockGhostdagData { func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDAGData) *DbBlockGhostdagData {
var selectedParent *DbHash var selectedParent *DbHash
if blockGHOSTDAGData.SelectedParent != nil { if blockGHOSTDAGData.SelectedParent() != nil {
selectedParent = DomainHashToDbHash(blockGHOSTDAGData.SelectedParent) selectedParent = DomainHashToDbHash(blockGHOSTDAGData.SelectedParent())
} }
return &DbBlockGhostdagData{ return &DbBlockGhostdagData{
BlueScore: blockGHOSTDAGData.BlueScore, BlueScore: blockGHOSTDAGData.BlueScore(),
SelectedParent: selectedParent, SelectedParent: selectedParent,
MergeSetBlues: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetBlues), MergeSetBlues: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetBlues()),
MergeSetReds: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetReds), MergeSetReds: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetReds()),
BluesAnticoneSizes: bluesAnticoneSizesToDBBluesAnticoneSizes(blockGHOSTDAGData.BluesAnticoneSizes), BluesAnticoneSizes: bluesAnticoneSizesToDBBluesAnticoneSizes(blockGHOSTDAGData.BluesAnticoneSizes()),
} }
} }
// DBBlockGHOSTDAGDataToBlockGHOSTDAGData converts DbBlockGhostdagData to BlockGHOSTDAGData // DBBlockGHOSTDAGDataToBlockGHOSTDAGData converts DbBlockGhostdagData to BlockGHOSTDAGData
func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (*model.BlockGHOSTDAGData, error) { func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (model.BlockGHOSTDAGData, error) {
var selectedParent *externalapi.DomainHash var selectedParent *externalapi.DomainHash
if dbBlockGHOSTDAGData.SelectedParent != nil { if dbBlockGHOSTDAGData.SelectedParent != nil {
var err error var err error
@ -47,11 +48,11 @@ func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdag
return nil, err return nil, err
} }
return &model.BlockGHOSTDAGData{ return ghostdagmanager.NewBlockGHOSTDAGData(
BlueScore: dbBlockGHOSTDAGData.BlueScore, dbBlockGHOSTDAGData.BlueScore,
SelectedParent: selectedParent, selectedParent,
MergeSetBlues: mergetSetBlues, mergetSetBlues,
MergeSetReds: mergetSetReds, mergetSetReds,
BluesAnticoneSizes: bluesAnticoneSizes, bluesAnticoneSizes,
}, nil ), nil
} }

View File

@ -13,21 +13,21 @@ var bucket = dbkeys.MakeBucket([]byte("block-ghostdag-data"))
// ghostdagDataStore represents a store of BlockGHOSTDAGData // ghostdagDataStore represents a store of BlockGHOSTDAGData
type ghostdagDataStore struct { type ghostdagDataStore struct {
staging map[externalapi.DomainHash]*model.BlockGHOSTDAGData staging map[externalapi.DomainHash]model.BlockGHOSTDAGData
cache *lrucache.LRUCache cache *lrucache.LRUCache
} }
// New instantiates a new GHOSTDAGDataStore // New instantiates a new GHOSTDAGDataStore
func New(cacheSize int) model.GHOSTDAGDataStore { func New(cacheSize int) model.GHOSTDAGDataStore {
return &ghostdagDataStore{ return &ghostdagDataStore{
staging: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData), staging: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData),
cache: lrucache.New(cacheSize), cache: lrucache.New(cacheSize),
} }
} }
// Stage stages the given blockGHOSTDAGData for the given blockHash // Stage stages the given blockGHOSTDAGData for the given blockHash
func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) { func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData model.BlockGHOSTDAGData) {
gds.staging[*blockHash] = blockGHOSTDAGData.Clone() gds.staging[*blockHash] = blockGHOSTDAGData
} }
func (gds *ghostdagDataStore) IsStaged() bool { func (gds *ghostdagDataStore) IsStaged() bool {
@ -35,7 +35,7 @@ func (gds *ghostdagDataStore) IsStaged() bool {
} }
func (gds *ghostdagDataStore) Discard() { func (gds *ghostdagDataStore) Discard() {
gds.staging = make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData) gds.staging = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData)
} }
func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error { func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error {
@ -56,13 +56,13 @@ func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error {
} }
// Get gets the blockGHOSTDAGData associated with the given blockHash // Get gets the blockGHOSTDAGData associated with the given blockHash
func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) {
if blockGHOSTDAGData, ok := gds.staging[*blockHash]; ok { if blockGHOSTDAGData, ok := gds.staging[*blockHash]; ok {
return blockGHOSTDAGData.Clone(), nil return blockGHOSTDAGData, nil
} }
if blockGHOSTDAGData, ok := gds.cache.Get(blockHash); ok { if blockGHOSTDAGData, ok := gds.cache.Get(blockHash); ok {
return blockGHOSTDAGData.(*model.BlockGHOSTDAGData).Clone(), nil return blockGHOSTDAGData.(model.BlockGHOSTDAGData), nil
} }
blockGHOSTDAGDataBytes, err := dbContext.Get(gds.hashAsKey(blockHash)) blockGHOSTDAGDataBytes, err := dbContext.Get(gds.hashAsKey(blockHash))
@ -75,18 +75,18 @@ func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externala
return nil, err return nil, err
} }
gds.cache.Add(blockHash, blockGHOSTDAGData) gds.cache.Add(blockHash, blockGHOSTDAGData)
return blockGHOSTDAGData.Clone(), nil return blockGHOSTDAGData, nil
} }
func (gds *ghostdagDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { func (gds *ghostdagDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey {
return bucket.Key(hash[:]) return bucket.Key(hash[:])
} }
func (gds *ghostdagDataStore) serializeBlockGHOSTDAGData(blockGHOSTDAGData *model.BlockGHOSTDAGData) ([]byte, error) { func (gds *ghostdagDataStore) serializeBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDAGData) ([]byte, error) {
return proto.Marshal(serialization.BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData)) return proto.Marshal(serialization.BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData))
} }
func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes []byte) (*model.BlockGHOSTDAGData, error) { func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes []byte) (model.BlockGHOSTDAGData, error) {
dbBlockGHOSTDAGData := &serialization.DbBlockGhostdagData{} dbBlockGHOSTDAGData := &serialization.DbBlockGhostdagData{}
err := proto.Unmarshal(blockGHOSTDAGDataBytes, dbBlockGHOSTDAGData) err := proto.Unmarshal(blockGHOSTDAGDataBytes, dbBlockGHOSTDAGData)
if err != nil { if err != nil {

View File

@ -63,24 +63,23 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
dbManager := consensusdatabase.New(db) dbManager := consensusdatabase.New(db)
// Data Structures // Data Structures
storeCacheSize := 200 acceptanceDataStore := acceptancedatastore.New(200)
acceptanceDataStore := acceptancedatastore.New(storeCacheSize) blockStore, err := blockstore.New(dbManager, 200)
blockStore, err := blockstore.New(dbManager, storeCacheSize)
if err != nil { if err != nil {
return nil, err return nil, err
} }
blockHeaderStore, err := blockheaderstore.New(dbManager, storeCacheSize) blockHeaderStore, err := blockheaderstore.New(dbManager, 10_000)
if err != nil { if err != nil {
return nil, err return nil, err
} }
blockRelationStore := blockrelationstore.New(storeCacheSize) blockRelationStore := blockrelationstore.New(200)
blockStatusStore := blockstatusstore.New(storeCacheSize) blockStatusStore := blockstatusstore.New(200)
multisetStore := multisetstore.New(storeCacheSize) multisetStore := multisetstore.New(200)
pruningStore := pruningstore.New() pruningStore := pruningstore.New()
reachabilityDataStore := reachabilitydatastore.New(storeCacheSize) reachabilityDataStore := reachabilitydatastore.New(200)
utxoDiffStore := utxodiffstore.New(storeCacheSize) utxoDiffStore := utxodiffstore.New(200)
consensusStateStore := consensusstatestore.New() consensusStateStore := consensusstatestore.New()
ghostdagDataStore := ghostdagdatastore.New(storeCacheSize) ghostdagDataStore := ghostdagdatastore.New(10_000)
headerTipsStore := headertipsstore.New() headerTipsStore := headertipsstore.New()
// Processes // Processes

View File

@ -155,7 +155,7 @@ func TestFinality(t *testing.T) {
t.Fatalf("TestFinality: Failed getting the ghost dag data of the sidechain tip: %v", err) t.Fatalf("TestFinality: Failed getting the ghost dag data of the sidechain tip: %v", err)
} }
if selectedTipGhostDagData.BlueScore > sideChainTipGhostDagData.BlueScore { if selectedTipGhostDagData.BlueScore() > sideChainTipGhostDagData.BlueScore() {
t.Fatalf("sideChainTip is not the bluest tip when it is expected to be") t.Fatalf("sideChainTip is not the bluest tip when it is expected to be")
} }
@ -308,7 +308,7 @@ func TestBoundedMergeDepth(t *testing.T) {
} }
// Make sure it's actually blue // Make sure it's actually blue
found := false found := false
for _, blue := range virtualGhotDagData.MergeSetBlues { for _, blue := range virtualGhotDagData.MergeSetBlues() {
if *blue == *kosherizingBlockHash { if *blue == *kosherizingBlockHash {
found = true found = true
break break
@ -356,7 +356,7 @@ func TestBoundedMergeDepth(t *testing.T) {
} }
// Make sure it's actually blue // Make sure it's actually blue
found = false found = false
for _, blue := range virtualGhotDagData.MergeSetBlues { for _, blue := range virtualGhotDagData.MergeSetBlues() {
if *blue == *kosherizingBlockHash { if *blue == *kosherizingBlockHash {
found = true found = true
break break

View File

@ -3,32 +3,12 @@ package model
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// BlockGHOSTDAGData represents GHOSTDAG data for some block // BlockGHOSTDAGData represents GHOSTDAG data for some block
type BlockGHOSTDAGData struct { type BlockGHOSTDAGData interface {
BlueScore uint64 BlueScore() uint64
SelectedParent *externalapi.DomainHash SelectedParent() *externalapi.DomainHash
MergeSetBlues []*externalapi.DomainHash MergeSetBlues() []*externalapi.DomainHash
MergeSetReds []*externalapi.DomainHash MergeSetReds() []*externalapi.DomainHash
BluesAnticoneSizes map[externalapi.DomainHash]KType BluesAnticoneSizes() map[externalapi.DomainHash]KType
}
// Clone returns a clone of BlockGHOSTDAGData
func (bgd *BlockGHOSTDAGData) Clone() *BlockGHOSTDAGData {
if bgd == nil {
return nil
}
bluesAnticoneSizesClone := make(map[externalapi.DomainHash]KType, len(bgd.BluesAnticoneSizes))
for hash, size := range bgd.BluesAnticoneSizes {
bluesAnticoneSizesClone[hash] = size
}
return &BlockGHOSTDAGData{
BlueScore: bgd.BlueScore,
SelectedParent: bgd.SelectedParent.Clone(),
MergeSetBlues: externalapi.CloneHashes(bgd.MergeSetBlues),
MergeSetReds: externalapi.CloneHashes(bgd.MergeSetReds),
BluesAnticoneSizes: bluesAnticoneSizesClone,
}
} }
// KType defines the size of GHOSTDAG consensus algorithm K parameter. // KType defines the size of GHOSTDAG consensus algorithm K parameter.

View File

@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// GHOSTDAGDataStore represents a store of BlockGHOSTDAGData // GHOSTDAGDataStore represents a store of BlockGHOSTDAGData
type GHOSTDAGDataStore interface { type GHOSTDAGDataStore interface {
Store Store
Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *BlockGHOSTDAGData) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData BlockGHOSTDAGData)
IsStaged() bool IsStaged() bool
Get(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockGHOSTDAGData, error) Get(dbContext DBReader, blockHash *externalapi.DomainHash) (BlockGHOSTDAGData, error)
} }

View File

@ -6,6 +6,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
type GHOSTDAGManager interface { type GHOSTDAGManager interface {
GHOSTDAG(blockHash *externalapi.DomainHash) error GHOSTDAG(blockHash *externalapi.DomainHash) error
ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error)
Less(blockHashA *externalapi.DomainHash, ghostdagDataA *BlockGHOSTDAGData, Less(blockHashA *externalapi.DomainHash, ghostdagDataA BlockGHOSTDAGData,
blockHashB *externalapi.DomainHash, ghostdagDataB *BlockGHOSTDAGData) bool blockHashB *externalapi.DomainHash, ghostdagDataB BlockGHOSTDAGData) bool
} }

View File

@ -96,13 +96,13 @@ func (bb *testBlockBuilder) buildBlockWithParents(parentHashes []*externalapi.Do
return nil, nil, err return nil, nil, err
} }
selectedParentStatus, err := bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) selectedParentStatus, err := bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent())
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if selectedParentStatus == externalapi.StatusDisqualifiedFromChain { if selectedParentStatus == externalapi.StatusDisqualifiedFromChain {
return nil, nil, errors.Errorf("Error building block with selectedParent %s with status DisqualifiedFromChain", return nil, nil, errors.Errorf("Error building block with selectedParent %s with status DisqualifiedFromChain",
ghostdagData.SelectedParent) ghostdagData.SelectedParent())
} }
pastUTXO, acceptanceData, multiset, err := bb.consensusStateManager.CalculatePastUTXOAndAcceptanceData(tempBlockHash) pastUTXO, acceptanceData, multiset, err := bb.consensusStateManager.CalculatePastUTXOAndAcceptanceData(tempBlockHash)

View File

@ -170,7 +170,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
return fmt.Sprintf("Failed to get sync info: %s", err) return fmt.Sprintf("Failed to get sync info: %s", err)
} }
return fmt.Sprintf("New virtual's blue score: %d. Sync state: %s. Block count: %d. Header count: %d", return fmt.Sprintf("New virtual's blue score: %d. Sync state: %s. Block count: %d. Header count: %d",
virtualGhostDAGData.BlueScore, syncInfo.State, syncInfo.BlockCount, syncInfo.HeaderCount) virtualGhostDAGData.BlueScore(), syncInfo.State, syncInfo.BlockCount, syncInfo.HeaderCount)
})) }))
if logClosureErr != nil { if logClosureErr != nil {
return logClosureErr return logClosureErr

View File

@ -39,7 +39,7 @@ func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi.
// Ensure all transactions in the block are finalized. // Ensure all transactions in the block are finalized.
for _, tx := range block.Transactions { for _, tx := range block.Transactions {
if !v.isFinalizedTransaction(tx, ghostdagData.BlueScore, blockTime) { if !v.isFinalizedTransaction(tx, ghostdagData.BlueScore(), blockTime) {
txID := consensushashing.TransactionID(tx) txID := consensushashing.TransactionID(tx)
return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains unfinalized "+ return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains unfinalized "+
"transaction %s", txID) "transaction %s", txID)

View File

@ -115,7 +115,7 @@ func (v *blockValidator) checkMergeSizeLimit(hash *externalapi.DomainHash) error
return err return err
} }
mergeSetSize := len(ghostdagData.MergeSetReds) + len(ghostdagData.MergeSetBlues) mergeSetSize := len(ghostdagData.MergeSetReds()) + len(ghostdagData.MergeSetBlues())
if uint64(mergeSetSize) > v.mergeSetSizeLimit { if uint64(mergeSetSize) > v.mergeSetSizeLimit {
return errors.Wrapf(ruleerrors.ErrViolatingMergeLimit, return errors.Wrapf(ruleerrors.ErrViolatingMergeLimit,

View File

@ -31,8 +31,8 @@ func (c coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Doma
return nil, err return nil, err
} }
txOuts := make([]*externalapi.DomainTransactionOutput, 0, len(ghostdagData.MergeSetBlues)) txOuts := make([]*externalapi.DomainTransactionOutput, 0, len(ghostdagData.MergeSetBlues()))
for i, blue := range ghostdagData.MergeSetBlues { for i, blue := range ghostdagData.MergeSetBlues() {
txOut, hasReward, err := c.coinbaseOutputForBlueBlock(blue, acceptanceData[i]) txOut, hasReward, err := c.coinbaseOutputForBlueBlock(blue, acceptanceData[i])
if err != nil { if err != nil {
return nil, err return nil, err
@ -43,7 +43,7 @@ func (c coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Doma
} }
} }
payload, err := c.serializeCoinbasePayload(ghostdagData.BlueScore, coinbaseData) payload, err := c.serializeCoinbasePayload(ghostdagData.BlueScore(), coinbaseData)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -120,7 +120,7 @@ func (c coinbaseManager) calcBlockSubsidy(blockHash *externalapi.DomainHash) (ui
} }
// Equivalent to: baseSubsidy / 2^(blueScore/subsidyHalvingInterval) // Equivalent to: baseSubsidy / 2^(blueScore/subsidyHalvingInterval)
return c.baseSubsidy >> uint(ghostdagData.BlueScore/c.subsidyReductionInterval), nil return c.baseSubsidy >> uint(ghostdagData.BlueScore()/c.subsidyReductionInterval), nil
} }
// New instantiates a new CoinbaseManager // New instantiates a new CoinbaseManager

View File

@ -80,8 +80,8 @@ func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externa
} }
log.Tracef("Selecting the next selected parent between "+ log.Tracef("Selecting the next selected parent between "+
"the block %s the current selected parent %s", blockHash, virtualGhostdagData.SelectedParent) "the block %s the current selected parent %s", blockHash, virtualGhostdagData.SelectedParent())
nextVirtualSelectedParent, err := csm.ghostdagManager.ChooseSelectedParent(virtualGhostdagData.SelectedParent, blockHash) nextVirtualSelectedParent, err := csm.ghostdagManager.ChooseSelectedParent(virtualGhostdagData.SelectedParent(), blockHash)
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@ -30,8 +30,8 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *
} }
log.Tracef("Restoring the past UTXO of block %s with selectedParent %s", log.Tracef("Restoring the past UTXO of block %s with selectedParent %s",
blockHash, blockGHOSTDAGData.SelectedParent) blockHash, blockGHOSTDAGData.SelectedParent())
selectedParentPastUTXO, err := csm.restorePastUTXO(blockGHOSTDAGData.SelectedParent) selectedParentPastUTXO, err := csm.restorePastUTXO(blockGHOSTDAGData.SelectedParent())
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
@ -108,13 +108,13 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH
} }
func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainHash, func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainHash,
selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData *model.BlockGHOSTDAGData) ( selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData model.BlockGHOSTDAGData) (
model.AcceptanceData, model.MutableUTXODiff, error) { model.AcceptanceData, model.MutableUTXODiff, error) {
log.Tracef("applyBlueBlocks start for block %s", blockHash) log.Tracef("applyBlueBlocks start for block %s", blockHash)
defer log.Tracef("applyBlueBlocks end for block %s", blockHash) defer log.Tracef("applyBlueBlocks end for block %s", blockHash)
blueBlocks, err := csm.blockStore.Blocks(csm.databaseContext, ghostdagData.MergeSetBlues) blueBlocks, err := csm.blockStore.Blocks(csm.databaseContext, ghostdagData.MergeSetBlues())
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -146,7 +146,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH
transactionID, blueBlockHash) transactionID, blueBlockHash)
isAccepted, accumulatedMass, err = csm.maybeAcceptTransaction(transaction, blockHash, isSelectedParent, isAccepted, accumulatedMass, err = csm.maybeAcceptTransaction(transaction, blockHash, isSelectedParent,
accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, ghostdagData.BlueScore) accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, ghostdagData.BlueScore())
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@ -10,22 +10,22 @@ import (
) )
func (csm *consensusStateManager) calculateMultiset( func (csm *consensusStateManager) calculateMultiset(
acceptanceData model.AcceptanceData, blockGHOSTDAGData *model.BlockGHOSTDAGData) (model.Multiset, error) { acceptanceData model.AcceptanceData, blockGHOSTDAGData model.BlockGHOSTDAGData) (model.Multiset, error) {
log.Tracef("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent) log.Tracef("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent())
defer log.Tracef("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent) defer log.Tracef("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent())
if blockGHOSTDAGData.SelectedParent == nil { if blockGHOSTDAGData.SelectedParent() == nil {
log.Tracef("Selected parent is nil, which could only happen for the genesis. " + log.Tracef("Selected parent is nil, which could only happen for the genesis. " +
"The genesis, by definition, has an empty multiset") "The genesis, by definition, has an empty multiset")
return multiset.New(), nil return multiset.New(), nil
} }
ms, err := csm.multisetStore.Get(csm.databaseContext, blockGHOSTDAGData.SelectedParent) ms, err := csm.multisetStore.Get(csm.databaseContext, blockGHOSTDAGData.SelectedParent())
if err != nil { if err != nil {
return nil, err return nil, err
} }
log.Tracef("The multiset for the selected parent %s is: %s", blockGHOSTDAGData.SelectedParent, ms.Hash()) log.Tracef("The multiset for the selected parent %s is: %s", blockGHOSTDAGData.SelectedParent(), ms.Hash())
for _, blockAcceptanceData := range acceptanceData { for _, blockAcceptanceData := range acceptanceData {
for i, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData { for i, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData {
@ -40,7 +40,7 @@ func (csm *consensusStateManager) calculateMultiset(
log.Tracef("Is transaction %s a coinbase transaction: %t", transactionID, isCoinbase) log.Tracef("Is transaction %s a coinbase transaction: %t", transactionID, isCoinbase)
var err error var err error
err = addTransactionToMultiset(ms, transaction, blockGHOSTDAGData.BlueScore, isCoinbase) err = addTransactionToMultiset(ms, transaction, blockGHOSTDAGData.BlueScore(), isCoinbase)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -214,7 +214,7 @@ func (csm *consensusStateManager) boundedMergeBreakingParents(
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, redBlock := range virtualGHOSTDAGData.MergeSetReds { for _, redBlock := range virtualGHOSTDAGData.MergeSetReds() {
log.Tracef("Check whether red block %s is kosherized", redBlock) log.Tracef("Check whether red block %s is kosherized", redBlock)
isFinalityPointInPast, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, redBlock) isFinalityPointInPast, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, redBlock)
if err != nil { if err != nil {

View File

@ -79,7 +79,7 @@ func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*e
if err != nil { if err != nil {
return 0, err return 0, err
} }
return csm.blockStatusStore.Get(csm.databaseContext, lastUnverifiedBlockGHOSTDAGData.SelectedParent) return csm.blockStatusStore.Get(csm.databaseContext, lastUnverifiedBlockGHOSTDAGData.SelectedParent())
} }
func (csm *consensusStateManager) getUnverifiedChainBlocks( func (csm *consensusStateManager) getUnverifiedChainBlocks(
@ -110,13 +110,13 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks(
return nil, err return nil, err
} }
if currentBlockGHOSTDAGData.SelectedParent == nil { if currentBlockGHOSTDAGData.SelectedParent() == nil {
log.Tracef("Genesis block reached. Returning all the "+ log.Tracef("Genesis block reached. Returning all the "+
"unverified blocks prior to it: %s", unverifiedBlocks) "unverified blocks prior to it: %s", unverifiedBlocks)
return unverifiedBlocks, nil return unverifiedBlocks, nil
} }
currentHash = currentBlockGHOSTDAGData.SelectedParent currentHash = currentBlockGHOSTDAGData.SelectedParent()
} }
} }

View File

@ -9,7 +9,7 @@ import (
type blockHeapNode struct { type blockHeapNode struct {
hash *externalapi.DomainHash hash *externalapi.DomainHash
ghostdagData *model.BlockGHOSTDAGData ghostdagData model.BlockGHOSTDAGData
} }
// baseHeap is an implementation for heap.Interface that sorts blocks by their height // baseHeap is an implementation for heap.Interface that sorts blocks by their height

View File

@ -32,7 +32,7 @@ func (spi *selectedParentIterator) Next() bool {
if err != nil { if err != nil {
panic(fmt.Sprintf("ghostdagDataStore is missing ghostdagData for: %v. '%s' ", spi.current, err)) panic(fmt.Sprintf("ghostdagDataStore is missing ghostdagData for: %v. '%s' ", spi.current, err))
} }
spi.current = ghostdagData.SelectedParent spi.current = ghostdagData.SelectedParent()
return spi.current != nil return spi.current != nil
} }
@ -75,17 +75,17 @@ func (dtm *dagTraversalManager) BlockAtDepth(highHash *externalapi.DomainHash, d
} }
requiredBlueScore := uint64(0) requiredBlueScore := uint64(0)
if highBlockGHOSTDAGData.BlueScore > depth { if highBlockGHOSTDAGData.BlueScore() > depth {
requiredBlueScore = highBlockGHOSTDAGData.BlueScore - depth requiredBlueScore = highBlockGHOSTDAGData.BlueScore() - depth
} }
currentBlockGHOSTDAGData := highBlockGHOSTDAGData currentBlockGHOSTDAGData := highBlockGHOSTDAGData
// If we used `BlockIterator` 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 currentBlockGHOSTDAGData.BlueScore >= requiredBlueScore { for currentBlockGHOSTDAGData.BlueScore() >= requiredBlueScore {
if currentBlockGHOSTDAGData.SelectedParent == nil { // genesis if currentBlockGHOSTDAGData.SelectedParent() == nil { // genesis
return currentBlockHash, nil return currentBlockHash, nil
} }
currentBlockHash = currentBlockGHOSTDAGData.SelectedParent currentBlockHash = currentBlockGHOSTDAGData.SelectedParent()
currentBlockGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockHash) currentBlockGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockHash)
if err != nil { if err != nil {
return nil, err return nil, err
@ -104,15 +104,15 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash
currentBlockGHOSTDAGData := highBlockGHOSTDAGData currentBlockGHOSTDAGData := highBlockGHOSTDAGData
iterator := dtm.SelectedParentIterator(highHash) iterator := dtm.SelectedParentIterator(highHash)
for iterator.Next() { for iterator.Next() {
selectedParentBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockGHOSTDAGData.SelectedParent) selectedParentBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockGHOSTDAGData.SelectedParent())
if err != nil { if err != nil {
return nil, err return nil, err
} }
if selectedParentBlockGHOSTDAGData.BlueScore < blueScore { if selectedParentBlockGHOSTDAGData.BlueScore() < blueScore {
break break
} }
currentHash = selectedParentBlockGHOSTDAGData.SelectedParent currentHash = selectedParentBlockGHOSTDAGData.SelectedParent()
currentBlockGHOSTDAGData = selectedParentBlockGHOSTDAGData currentBlockGHOSTDAGData = selectedParentBlockGHOSTDAGData
} }

View File

@ -15,15 +15,15 @@ func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash
return nil, err return nil, err
} }
for uint64(len(window)) < windowSize && currentGHOSTDAGData.SelectedParent != nil { for uint64(len(window)) < windowSize && currentGHOSTDAGData.SelectedParent() != nil {
for _, blue := range currentGHOSTDAGData.MergeSetBlues { for _, blue := range currentGHOSTDAGData.MergeSetBlues() {
window = append(window, blue) window = append(window, blue)
if uint64(len(window)) == windowSize { if uint64(len(window)) == windowSize {
break break
} }
} }
currentHash = currentGHOSTDAGData.SelectedParent currentHash = currentGHOSTDAGData.SelectedParent()
currentGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash) currentGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,12 +1,13 @@
package difficultymanager package difficultymanager
import ( import (
"math/big"
"time"
"github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/bigintpool" "github.com/kaspanet/kaspad/util/bigintpool"
"math/big"
"time"
) )
// DifficultyManager provides a method to resolve the // DifficultyManager provides a method to resolve the
@ -94,7 +95,7 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas
} }
// Not enough blocks for building a difficulty window. // Not enough blocks for building a difficulty window.
if bluestGhostDAG.BlueScore < dm.difficultyAdjustmentWindowSize+1 { if bluestGhostDAG.BlueScore() < dm.difficultyAdjustmentWindowSize+1 {
return dm.genesisBits() return dm.genesisBits()
} }

View File

@ -0,0 +1,203 @@
package difficultymanager_test
import (
"testing"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
"github.com/kaspanet/kaspad/domain/dagconfig"
"github.com/kaspanet/kaspad/util"
)
func TestDifficulty(t *testing.T) {
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
params.K = 1
params.DifficultyAdjustmentWindowSize = 264
factory := consensus.NewFactory()
tc, teardown, err := factory.NewTestConsensus(params, "TestDifficulty")
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
addBlock := func(blockTime int64, parents ...*externalapi.DomainHash) (*externalapi.DomainBlock, *externalapi.DomainHash) {
bluestParent, err := tc.GHOSTDAGManager().ChooseSelectedParent(parents...)
if err != nil {
t.Fatalf("ChooseSelectedParent: %+v", err)
}
if blockTime == 0 {
header, err := tc.BlockHeaderStore().BlockHeader(tc.DatabaseContext(), bluestParent)
if err != nil {
t.Fatalf("BlockHeader: %+v", err)
}
blockTime = header.TimeInMilliseconds + params.TargetTimePerBlock.Milliseconds()
}
block, _, err := tc.BuildBlockWithParents(parents, nil, nil)
if err != nil {
t.Fatalf("BuildBlockWithParents: %+v", err)
}
block.Header.TimeInMilliseconds = blockTime
err = tc.ValidateAndInsertBlock(block)
if err != nil {
t.Fatalf("ValidateAndInsertBlock: %+v", err)
}
return block, consensushashing.BlockHash(block)
}
minimumTime := func(parents ...*externalapi.DomainHash) int64 {
var tempHash externalapi.DomainHash
tc.BlockRelationStore().StageBlockRelation(&tempHash, &model.BlockRelations{
Parents: parents,
Children: nil,
})
defer tc.BlockRelationStore().Discard()
err = tc.GHOSTDAGManager().GHOSTDAG(&tempHash)
if err != nil {
t.Fatalf("GHOSTDAG: %+v", err)
}
defer tc.GHOSTDAGDataStore().Discard()
pastMedianTime, err := tc.PastMedianTimeManager().PastMedianTime(&tempHash)
if err != nil {
t.Fatalf("PastMedianTime: %+v", err)
}
return pastMedianTime + 1
}
addBlockWithMinimumTime := func(parents ...*externalapi.DomainHash) (*externalapi.DomainBlock, *externalapi.DomainHash) {
minTime := minimumTime(parents...)
return addBlock(minTime, parents...)
}
tipHash := params.GenesisHash
tip := params.GenesisBlock
for i := uint64(0); i < params.DifficultyAdjustmentWindowSize; i++ {
tip, tipHash = addBlock(0, tipHash)
if tip.Header.Bits != params.GenesisBlock.Header.Bits {
t.Fatalf("As long as the bluest parent's blue score is less then the difficulty adjustment " +
"window size, the difficulty should be the same as genesis'")
}
}
for i := uint64(0); i < params.DifficultyAdjustmentWindowSize+100; i++ {
tip, tipHash = addBlock(0, tipHash)
if tip.Header.Bits != params.GenesisBlock.Header.Bits {
t.Fatalf("As long as the block rate remains the same, the difficulty shouldn't change")
}
}
blockInThePast, tipHash := addBlockWithMinimumTime(tipHash)
if blockInThePast.Header.Bits != tip.Header.Bits {
t.Fatalf("The difficulty should only change when blockInThePast is in the past of a block bluest parent")
}
tip = blockInThePast
tip, tipHash = addBlock(0, tipHash)
if tip.Header.Bits != blockInThePast.Header.Bits {
t.Fatalf("The difficulty should only change when blockInThePast is in the past of a block bluest parent")
}
tip, tipHash = addBlock(0, tipHash)
if compareBits(tip.Header.Bits, blockInThePast.Header.Bits) >= 0 {
t.Fatalf("tip.bits should be smaller than blockInThePast.bits because blockInThePast increased the " +
"block rate, so the difficulty should increase as well")
}
var expectedBits uint32
switch params.Name {
case "kaspa-testnet", "kaspa-devnet":
expectedBits = uint32(0x1e7f83df)
case "kaspa-mainnet", "kaspa-simnet":
expectedBits = uint32(0x207f83df)
}
if tip.Header.Bits != expectedBits {
t.Errorf("tip.bits was expected to be %x but got %x", expectedBits, tip.Header.Bits)
}
// Increase block rate to increase difficulty
for i := uint64(0); i < params.DifficultyAdjustmentWindowSize; i++ {
tip, tipHash = addBlockWithMinimumTime(tipHash)
tipGHOSTDAGData, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), tipHash)
if err != nil {
t.Fatalf("GHOSTDAGDataStore: %+v", err)
}
selectedParentHeader, err := tc.BlockHeaderStore().BlockHeader(tc.DatabaseContext(),
tipGHOSTDAGData.SelectedParent())
if err != nil {
t.Fatalf("BlockHeader: %+v", err)
}
if compareBits(tip.Header.Bits, selectedParentHeader.Bits) > 0 {
t.Fatalf("Because we're increasing the block rate, the difficulty can't decrease")
}
}
// Add blocks until difficulty stabilizes
lastBits := tip.Header.Bits
sameBitsCount := uint64(0)
for sameBitsCount < params.DifficultyAdjustmentWindowSize+1 {
tip, tipHash = addBlock(0, tipHash)
if tip.Header.Bits == lastBits {
sameBitsCount++
} else {
lastBits = tip.Header.Bits
sameBitsCount = 0
}
}
slowBlockTime := tip.Header.TimeInMilliseconds + params.TargetTimePerBlock.Milliseconds() + 1000
slowBlock, tipHash := addBlock(slowBlockTime, tipHash)
if slowBlock.Header.Bits != tip.Header.Bits {
t.Fatalf("The difficulty should only change when slowBlock is in the past of a block bluest parent")
}
tip = slowBlock
tip, tipHash = addBlock(0, tipHash)
if tip.Header.Bits != slowBlock.Header.Bits {
t.Fatalf("The difficulty should only change when slowBlock is in the past of a block bluest parent")
}
tip, tipHash = addBlock(0, tipHash)
if compareBits(tip.Header.Bits, slowBlock.Header.Bits) <= 0 {
t.Fatalf("tip.bits should be smaller than slowBlock.bits because slowBlock decreased the block" +
" rate, so the difficulty should decrease as well")
}
_, tipHash = addBlock(0, tipHash)
splitBlockHash := tipHash
for i := 0; i < 100; i++ {
_, tipHash = addBlock(0, tipHash)
}
blueTipHash := tipHash
redChainTipHash := splitBlockHash
for i := 0; i < 10; i++ {
_, redChainTipHash = addBlockWithMinimumTime(redChainTipHash)
}
tipWithRedPast, _ := addBlock(0, redChainTipHash, blueTipHash)
tipWithoutRedPast, _ := addBlock(0, blueTipHash)
if tipWithoutRedPast.Header.Bits != tipWithRedPast.Header.Bits {
t.Fatalf("tipWithoutRedPast.bits should be the same as tipWithRedPast.bits because red blocks" +
" shouldn't affect the difficulty")
}
})
}
func compareBits(a uint32, b uint32) int {
aTarget := util.CompactToBig(a)
bTarget := util.CompactToBig(b)
return aTarget.Cmp(bTarget)
}

View File

@ -1,9 +1,12 @@
package ghostdag2 package ghostdag2
import ( import (
"sort"
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
"github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"sort"
) )
type ghostdagHelper struct { type ghostdagHelper struct {
@ -44,7 +47,7 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error
if err != nil { if err != nil {
return err return err
} }
blockScore := blockData.BlueScore blockScore := blockData.BlueScore()
if blockScore > maxNum { if blockScore > maxNum {
selectedParent = parent selectedParent = parent
maxNum = blockScore maxNum = blockScore
@ -91,13 +94,8 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error
} }
myScore += uint64(len(mergeSetBlues)) myScore += uint64(len(mergeSetBlues))
e := model.BlockGHOSTDAGData{ e := ghostdagmanager.NewBlockGHOSTDAGData(myScore, selectedParent, mergeSetBlues, mergeSetReds, nil)
BlueScore: myScore, gh.dataStore.Stage(blockCandidate, e)
SelectedParent: selectedParent,
MergeSetBlues: mergeSetBlues,
MergeSetReds: mergeSetReds,
}
gh.dataStore.Stage(blockCandidate, &e)
return nil return nil
} }
@ -220,7 +218,7 @@ func (gh *ghostdagHelper) validateKCluster(chain *externalapi.DomainHash, checke
if err != nil { if err != nil {
return false, err return false, err
} }
if mergeSetReds := dataStore.MergeSetReds; contains(checkedBlock, mergeSetReds) { if mergeSetReds := dataStore.MergeSetReds(); contains(checkedBlock, mergeSetReds) {
return false, nil return false, nil
} }
} else { } else {
@ -326,14 +324,14 @@ func (gh *ghostdagHelper) findBlueSet(blueSet *[]*externalapi.DomainHash, select
if err != nil { if err != nil {
return err return err
} }
mergeSetBlue := blockData.MergeSetBlues mergeSetBlue := blockData.MergeSetBlues()
for _, blue := range mergeSetBlue { for _, blue := range mergeSetBlue {
if contains(blue, *blueSet) { if contains(blue, *blueSet) {
continue continue
} }
*blueSet = append(*blueSet, blue) *blueSet = append(*blueSet, blue)
} }
selectedParent = blockData.SelectedParent selectedParent = blockData.SelectedParent()
} }
return nil return nil
} }
@ -356,10 +354,10 @@ func (gh *ghostdagHelper) sortByBlueScore(arr []*externalapi.DomainHash) error {
return false return false
} }
if blockLeft.BlueScore < blockRight.BlueScore { if blockLeft.BlueScore() < blockRight.BlueScore() {
return true return true
} }
if blockLeft.BlueScore == blockRight.BlueScore { if blockLeft.BlueScore() == blockRight.BlueScore() {
return ismoreHash(arr[j], arr[i]) return ismoreHash(arr[j], arr[i])
} }
return false return false
@ -369,13 +367,13 @@ func (gh *ghostdagHelper) sortByBlueScore(arr []*externalapi.DomainHash) error {
/* --------------------------------------------- */ /* --------------------------------------------- */
func (gh *ghostdagHelper) BlockData(blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { func (gh *ghostdagHelper) BlockData(blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) {
return gh.dataStore.Get(gh.dbAccess, blockHash) return gh.dataStore.Get(gh.dbAccess, blockHash)
} }
func (gh *ghostdagHelper) ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) { func (gh *ghostdagHelper) ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) {
panic("implement me") panic("implement me")
} }
func (gh *ghostdagHelper) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool { func (gh *ghostdagHelper) Less(blockHashA *externalapi.DomainHash, ghostdagDataA model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB model.BlockGHOSTDAGData) bool {
panic("implement me") panic("implement me")
} }

View File

@ -53,11 +53,11 @@ func (gm *ghostdagManager) ChooseSelectedParent(blockHashes ...*externalapi.Doma
return selectedParent, nil return selectedParent, nil
} }
func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData, func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA model.BlockGHOSTDAGData,
blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool { blockHashB *externalapi.DomainHash, ghostdagDataB model.BlockGHOSTDAGData) bool {
blockBlueScoreA := ghostdagDataA.BlueScore blockBlueScoreA := ghostdagDataA.BlueScore()
blockBlueScoreB := ghostdagDataB.BlueScore blockBlueScoreB := ghostdagDataB.BlueScore()
if blockBlueScoreA == blockBlueScoreB { if blockBlueScoreA == blockBlueScoreB {
return hashes.Less(blockHashA, blockHashB) return hashes.Less(blockHashA, blockHashB)
} }

View File

@ -25,10 +25,10 @@ import (
// //
// For further details see the article https://eprint.iacr.org/2018/104.pdf // For further details see the article https://eprint.iacr.org/2018/104.pdf
func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
newBlockData := &model.BlockGHOSTDAGData{ newBlockData := &blockGHOSTDAGData{
MergeSetBlues: make([]*externalapi.DomainHash, 0), mergeSetBlues: make([]*externalapi.DomainHash, 0),
MergeSetReds: make([]*externalapi.DomainHash, 0), mergeSetReds: make([]*externalapi.DomainHash, 0),
BluesAnticoneSizes: make(map[externalapi.DomainHash]model.KType), bluesAnticoneSizes: make(map[externalapi.DomainHash]model.KType),
} }
blockParents, err := gm.dagTopologyManager.Parents(blockHash) blockParents, err := gm.dagTopologyManager.Parents(blockHash)
@ -43,12 +43,12 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
return err return err
} }
newBlockData.SelectedParent = selectedParent newBlockData.selectedParent = selectedParent
newBlockData.MergeSetBlues = append(newBlockData.MergeSetBlues, selectedParent) newBlockData.mergeSetBlues = append(newBlockData.mergeSetBlues, selectedParent)
newBlockData.BluesAnticoneSizes[*selectedParent] = 0 newBlockData.bluesAnticoneSizes[*selectedParent] = 0
} }
mergeSetWithoutSelectedParent, err := gm.mergeSetWithoutSelectedParent(newBlockData.SelectedParent, blockParents) mergeSetWithoutSelectedParent, err := gm.mergeSetWithoutSelectedParent(newBlockData.selectedParent, blockParents)
if err != nil { if err != nil {
return err return err
} }
@ -61,25 +61,25 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
if isBlue { if isBlue {
// No k-cluster violation found, we can now set the candidate block as blue // No k-cluster violation found, we can now set the candidate block as blue
newBlockData.MergeSetBlues = append(newBlockData.MergeSetBlues, blueCandidate) newBlockData.mergeSetBlues = append(newBlockData.mergeSetBlues, blueCandidate)
newBlockData.BluesAnticoneSizes[*blueCandidate] = candidateAnticoneSize newBlockData.bluesAnticoneSizes[*blueCandidate] = candidateAnticoneSize
for blue, blueAnticoneSize := range candidateBluesAnticoneSizes { for blue, blueAnticoneSize := range candidateBluesAnticoneSizes {
newBlockData.BluesAnticoneSizes[blue] = blueAnticoneSize + 1 newBlockData.bluesAnticoneSizes[blue] = blueAnticoneSize + 1
} }
} else { } else {
newBlockData.MergeSetReds = append(newBlockData.MergeSetReds, blueCandidate) newBlockData.mergeSetReds = append(newBlockData.mergeSetReds, blueCandidate)
} }
} }
if !isGenesis { if !isGenesis {
selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, newBlockData.SelectedParent) selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, newBlockData.selectedParent)
if err != nil { if err != nil {
return err return err
} }
newBlockData.BlueScore = selectedParentGHOSTDAGData.BlueScore + uint64(len(newBlockData.MergeSetBlues)) newBlockData.blueScore = selectedParentGHOSTDAGData.BlueScore() + uint64(len(newBlockData.mergeSetBlues))
} else { } else {
// Genesis's blue score is defined to be 0. // Genesis's blue score is defined to be 0.
newBlockData.BlueScore = 0 newBlockData.blueScore = 0
} }
gm.ghostdagDataStore.Stage(blockHash, newBlockData) gm.ghostdagDataStore.Stage(blockHash, newBlockData)
@ -89,15 +89,15 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
type chainBlockData struct { type chainBlockData struct {
hash *externalapi.DomainHash hash *externalapi.DomainHash
blockData *model.BlockGHOSTDAGData blockData model.BlockGHOSTDAGData
} }
func (gm *ghostdagManager) checkBlueCandidate(newBlockData *model.BlockGHOSTDAGData, blueCandidate *externalapi.DomainHash) ( func (gm *ghostdagManager) checkBlueCandidate(newBlockData *blockGHOSTDAGData, blueCandidate *externalapi.DomainHash) (
isBlue bool, candidateAnticoneSize model.KType, candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType, err error) { isBlue bool, candidateAnticoneSize model.KType, candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType, err error) {
// The maximum length of node.blues can be K+1 because // The maximum length of node.blues can be K+1 because
// it contains the selected parent. // it contains the selected parent.
if model.KType(len(newBlockData.MergeSetBlues)) == gm.k+1 { if model.KType(len(newBlockData.mergeSetBlues)) == gm.k+1 {
return false, 0, nil, nil return false, 0, nil, nil
} }
@ -126,12 +126,12 @@ func (gm *ghostdagManager) checkBlueCandidate(newBlockData *model.BlockGHOSTDAGD
return false, 0, nil, nil return false, 0, nil, nil
} }
selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, chainBlock.blockData.SelectedParent) selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, chainBlock.blockData.SelectedParent())
if err != nil { if err != nil {
return false, 0, nil, err return false, 0, nil, err
} }
chainBlock = chainBlockData{hash: chainBlock.blockData.SelectedParent, chainBlock = chainBlockData{hash: chainBlock.blockData.SelectedParent(),
blockData: selectedParentGHOSTDAGData, blockData: selectedParentGHOSTDAGData,
} }
} }
@ -139,7 +139,7 @@ func (gm *ghostdagManager) checkBlueCandidate(newBlockData *model.BlockGHOSTDAGD
return true, candidateAnticoneSize, candidateBluesAnticoneSizes, nil return true, candidateAnticoneSize, candidateBluesAnticoneSizes, nil
} }
func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData *model.BlockGHOSTDAGData, func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData model.BlockGHOSTDAGData,
chainBlock chainBlockData, blueCandidate *externalapi.DomainHash, chainBlock chainBlockData, blueCandidate *externalapi.DomainHash,
candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType, candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType,
candidateAnticoneSize *model.KType) (isBlue, isRed bool, err error) { candidateAnticoneSize *model.KType) (isBlue, isRed bool, err error) {
@ -164,7 +164,7 @@ func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData *model.
} }
} }
for _, block := range chainBlock.blockData.MergeSetBlues { for _, block := range chainBlock.blockData.MergeSetBlues() {
// Skip blocks that exist in the past of blueCandidate. // Skip blocks that exist in the past of blueCandidate.
isAncestorOfBlueCandidate, err := gm.dagTopologyManager.IsAncestorOf(block, blueCandidate) isAncestorOfBlueCandidate, err := gm.dagTopologyManager.IsAncestorOf(block, blueCandidate)
if err != nil { if err != nil {
@ -204,16 +204,16 @@ func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData *model.
// blueAnticoneSize returns the blue anticone size of 'block' from the worldview of 'context'. // blueAnticoneSize returns the blue anticone size of 'block' from the worldview of 'context'.
// Expects 'block' to be in the blue set of 'context' // Expects 'block' to be in the blue set of 'context'
func (gm *ghostdagManager) blueAnticoneSize(block *externalapi.DomainHash, context *model.BlockGHOSTDAGData) (model.KType, error) { func (gm *ghostdagManager) blueAnticoneSize(block *externalapi.DomainHash, context model.BlockGHOSTDAGData) (model.KType, error) {
for current := context; current != nil; { for current := context; current != nil; {
if blueAnticoneSize, ok := current.BluesAnticoneSizes[*block]; ok { if blueAnticoneSize, ok := current.BluesAnticoneSizes()[*block]; ok {
return blueAnticoneSize, nil return blueAnticoneSize, nil
} }
if current.SelectedParent == nil { if current.SelectedParent() == nil {
break break
} }
var err error var err error
current, err = gm.ghostdagDataStore.Get(gm.databaseContext, current.SelectedParent) current, err = gm.ghostdagDataStore.Get(gm.databaseContext, current.SelectedParent())
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@ -0,0 +1,51 @@
package ghostdagmanager
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
type blockGHOSTDAGData struct {
blueScore uint64
selectedParent *externalapi.DomainHash
mergeSetBlues []*externalapi.DomainHash
mergeSetReds []*externalapi.DomainHash
bluesAnticoneSizes map[externalapi.DomainHash]model.KType
}
// NewBlockGHOSTDAGData creates a new instance of model.BlockGHOSTDAGData
func NewBlockGHOSTDAGData(
blueScore uint64,
selectedParent *externalapi.DomainHash,
mergeSetBlues []*externalapi.DomainHash,
mergeSetReds []*externalapi.DomainHash,
bluesAnticoneSizes map[externalapi.DomainHash]model.KType) model.BlockGHOSTDAGData {
return &blockGHOSTDAGData{
blueScore: blueScore,
selectedParent: selectedParent,
mergeSetBlues: mergeSetBlues,
mergeSetReds: mergeSetReds,
bluesAnticoneSizes: bluesAnticoneSizes,
}
}
func (bgd *blockGHOSTDAGData) BlueScore() uint64 {
return bgd.blueScore
}
func (bgd *blockGHOSTDAGData) SelectedParent() *externalapi.DomainHash {
return bgd.selectedParent
}
func (bgd *blockGHOSTDAGData) MergeSetBlues() []*externalapi.DomainHash {
return bgd.mergeSetBlues
}
func (bgd *blockGHOSTDAGData) MergeSetReds() []*externalapi.DomainHash {
return bgd.mergeSetReds
}
func (bgd *blockGHOSTDAGData) BluesAnticoneSizes() map[externalapi.DomainHash]model.KType {
return bgd.bluesAnticoneSizes
}

View File

@ -1,14 +1,17 @@
package ghostdagmanager package ghostdagmanager_test
import ( import (
"encoding/json" "encoding/json"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdag2"
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"testing" "testing"
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdag2"
) )
// TestGHOSTDAG iterates over several dag simulations, and checks // TestGHOSTDAG iterates over several dag simulations, and checks
@ -47,15 +50,9 @@ func TestGHOSTDAG(t *testing.T) {
} }
ghostdagDataStore := &GHOSTDAGDataStoreImpl{ ghostdagDataStore := &GHOSTDAGDataStoreImpl{
dagMap: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData), dagMap: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData),
}
var blockGHOSTDAGDataGenesis = &model.BlockGHOSTDAGData{
BlueScore: 0,
SelectedParent: nil,
MergeSetBlues: nil,
MergeSetReds: nil,
BluesAnticoneSizes: nil,
} }
blockGHOSTDAGDataGenesis := ghostdagmanager.NewBlockGHOSTDAGData(0, nil, nil, nil, nil)
var testsCounter int var testsCounter int
err := filepath.Walk("../../testdata/dags", func(path string, info os.FileInfo, err error) error { err := filepath.Walk("../../testdata/dags", func(path string, info os.FileInfo, err error) error {
@ -87,7 +84,7 @@ func TestGHOSTDAG(t *testing.T) {
//NOTE: FOR ADDING/REMOVING AN IMPLEMENTATION CHANGE BELOW: //NOTE: FOR ADDING/REMOVING AN IMPLEMENTATION CHANGE BELOW:
implementationFactories := []implManager{ implementationFactories := []implManager{
{New, "Original"}, {ghostdagmanager.New, "Original"},
{ghostdag2.New, "Tal's impl"}, {ghostdag2.New, "Tal's impl"},
} }
@ -110,30 +107,30 @@ func TestGHOSTDAG(t *testing.T) {
factory.implName, info.Name(), testBlockData.ID, err) factory.implName, info.Name(), testBlockData.ID, err)
} }
if testBlockData.Score != (ghostdagData.BlueScore) { if testBlockData.Score != (ghostdagData.BlueScore()) {
t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected blue score %d but got %d.", t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected blue score %d but got %d.",
factory.implName, info.Name(), testBlockData.ID, testBlockData.Score, ghostdagData.BlueScore) factory.implName, info.Name(), testBlockData.ID, testBlockData.Score, ghostdagData.BlueScore())
} }
if *StringToByte(testBlockData.SelectedParent) != *ghostdagData.SelectedParent { if *StringToByte(testBlockData.SelectedParent) != *ghostdagData.SelectedParent() {
t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected selected parent %v but got %v.", t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected selected parent %v but got %v.",
factory.implName, info.Name(), testBlockData.ID, testBlockData.SelectedParent, string(ghostdagData.SelectedParent[:])) factory.implName, info.Name(), testBlockData.ID, testBlockData.SelectedParent, ghostdagData.SelectedParent())
} }
if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetBlues), ghostdagData.MergeSetBlues) { if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetBlues), ghostdagData.MergeSetBlues()) {
t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set blues %v but got %v.", t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set blues %v but got %v.",
factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetBlues, hashesToStrings(ghostdagData.MergeSetBlues)) factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetBlues, hashesToStrings(ghostdagData.MergeSetBlues()))
} }
if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetReds), ghostdagData.MergeSetReds) { if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetReds), ghostdagData.MergeSetReds()) {
t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set reds %v but got %v.", t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set reds %v but got %v.",
factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetReds, hashesToStrings(ghostdagData.MergeSetReds)) factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetReds, hashesToStrings(ghostdagData.MergeSetReds()))
} }
} }
dagTopology.parentsMap = make(map[externalapi.DomainHash][]*externalapi.DomainHash) dagTopology.parentsMap = make(map[externalapi.DomainHash][]*externalapi.DomainHash)
dagTopology.parentsMap[genesisHash] = nil dagTopology.parentsMap[genesisHash] = nil
ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData) ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData)
ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis
} }
@ -172,10 +169,10 @@ func StringToByteArray(stringIDArr []string) []*externalapi.DomainHash {
/* ---------------------- */ /* ---------------------- */
type GHOSTDAGDataStoreImpl struct { type GHOSTDAGDataStoreImpl struct {
dagMap map[externalapi.DomainHash]*model.BlockGHOSTDAGData dagMap map[externalapi.DomainHash]model.BlockGHOSTDAGData
} }
func (ds *GHOSTDAGDataStoreImpl) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) { func (ds *GHOSTDAGDataStoreImpl) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData model.BlockGHOSTDAGData) {
ds.dagMap[*blockHash] = blockGHOSTDAGData ds.dagMap[*blockHash] = blockGHOSTDAGData
} }
@ -191,7 +188,7 @@ func (ds *GHOSTDAGDataStoreImpl) Commit(dbTx model.DBTransaction) error {
panic("implement me") panic("implement me")
} }
func (ds *GHOSTDAGDataStoreImpl) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { func (ds *GHOSTDAGDataStoreImpl) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) {
v, ok := ds.dagMap[*blockHash] v, ok := ds.dagMap[*blockHash]
if ok { if ok {
return v, nil return v, nil

View File

@ -46,7 +46,7 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma
} }
// Return nil on genesis // Return nil on genesis
if ghostdagData.SelectedParent == nil { if ghostdagData.SelectedParent() == nil {
return nil return nil
} }
@ -55,7 +55,7 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma
return err return err
} }
for _, red := range ghostdagData.MergeSetReds { for _, red := range ghostdagData.MergeSetReds() {
doesRedHaveFinalityPointInPast, err := mdm.dagTopologyManager.IsAncestorOf(finalityPoint, red) doesRedHaveFinalityPointInPast, err := mdm.dagTopologyManager.IsAncestorOf(finalityPoint, red)
if err != nil { if err != nil {
return err return err
@ -85,9 +85,9 @@ func (mdm mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *exter
return nil, err return nil, err
} }
nonBoundedMergeDepthViolatingBlues := make([]*externalapi.DomainHash, 0, len(ghostdagData.MergeSetBlues)) nonBoundedMergeDepthViolatingBlues := make([]*externalapi.DomainHash, 0, len(ghostdagData.MergeSetBlues()))
for _, blue := range ghostdagData.MergeSetBlues { for _, blue := range ghostdagData.MergeSetBlues() {
notViolatingFinality, err := mdm.hasFinalityPointInOthersSelectedChain(blockHash, blue) notViolatingFinality, err := mdm.hasFinalityPointInOthersSelectedChain(blockHash, blue)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,10 +1,11 @@
package pastmediantimemanager package pastmediantimemanager
import ( import (
"sort"
"github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/pkg/errors" "github.com/pkg/errors"
"sort"
) )
// pastMedianTimeManager provides a method to resolve the // pastMedianTimeManager provides a method to resolve the
@ -44,7 +45,7 @@ func (pmtm *pastMedianTimeManager) PastMedianTime(blockHash *externalapi.DomainH
if err != nil { if err != nil {
return 0, err return 0, err
} }
selectedParentHash := blockGHOSTDAGData.SelectedParent selectedParentHash := blockGHOSTDAGData.SelectedParent()
// Genesis block // Genesis block
if selectedParentHash == nil { if selectedParentHash == nil {

View File

@ -99,14 +99,14 @@ func (pm *pruningManager) FindNextPruningPoint() error {
if err != nil { if err != nil {
return err return err
} }
currentPBlueScore := currentPGhost.BlueScore currentPBlueScore := currentPGhost.BlueScore()
// Because the pruning point changes only once per finality, then there's no need to even check for that if a finality interval hasn't passed. // Because the pruning point changes only once per finality, then there's no need to even check for that if a finality interval hasn't passed.
if virtual.BlueScore <= currentPBlueScore+pm.finalityInterval { if virtual.BlueScore() <= currentPBlueScore+pm.finalityInterval {
return nil return nil
} }
// This means the pruning point is still genesis. // This means the pruning point is still genesis.
if virtual.BlueScore <= pm.pruningDepth+pm.finalityInterval { if virtual.BlueScore() <= pm.pruningDepth+pm.finalityInterval {
return nil return nil
} }
@ -121,7 +121,7 @@ func (pm *pruningManager) FindNextPruningPoint() error {
} }
// Actually check if the pruning point changed // Actually check if the pruning point changed
if (currentPBlueScore / pm.finalityInterval) < (candidatePGhost.BlueScore / pm.finalityInterval) { if (currentPBlueScore / pm.finalityInterval) < (candidatePGhost.BlueScore() / pm.finalityInterval) {
err = pm.savePruningPoint(candidatePHash) err = pm.savePruningPoint(candidatePHash)
if err != nil { if err != nil {
return err return err

View File

@ -45,7 +45,7 @@ func (rt *reachabilityManager) AddBlock(blockHash *externalapi.DomainHash) error
} }
// If this is the genesis node, simply initialize it and return // If this is the genesis node, simply initialize it and return
if ghostdagData.SelectedParent == nil { if ghostdagData.SelectedParent() == nil {
rt.stageReindexRoot(blockHash) rt.stageReindexRoot(blockHash)
return nil return nil
} }
@ -56,16 +56,16 @@ func (rt *reachabilityManager) AddBlock(blockHash *externalapi.DomainHash) error
} }
// Insert the node into the selected parent's reachability tree // Insert the node into the selected parent's reachability tree
err = rt.addChild(ghostdagData.SelectedParent, blockHash, reindexRoot) err = rt.addChild(ghostdagData.SelectedParent(), blockHash, reindexRoot)
if err != nil { if err != nil {
return err return err
} }
// Add the block to the futureCoveringSets of all the blocks // Add the block to the futureCoveringSets of all the blocks
// in the merget set // in the merget set
mergeSet := make([]*externalapi.DomainHash, len(ghostdagData.MergeSetBlues)+len(ghostdagData.MergeSetReds)) mergeSet := make([]*externalapi.DomainHash, len(ghostdagData.MergeSetBlues())+len(ghostdagData.MergeSetReds()))
copy(mergeSet, ghostdagData.MergeSetBlues) copy(mergeSet, ghostdagData.MergeSetBlues())
copy(mergeSet[len(ghostdagData.MergeSetBlues):], ghostdagData.MergeSetReds) copy(mergeSet[len(ghostdagData.MergeSetBlues()):], ghostdagData.MergeSetReds())
for _, current := range mergeSet { for _, current := range mergeSet {
err = rt.insertToFutureCoveringSet(current, blockHash) err = rt.insertToFutureCoveringSet(current, blockHash)

View File

@ -814,7 +814,7 @@ func (rt *reachabilityManager) maybeMoveReindexRoot(reindexRoot, newTreeNode *ex
return nil, false, err return nil, false, err
} }
if newTreeNodeGHOSTDAGData.BlueScore-reindexRootChosenChildGHOSTDAGData.BlueScore < rt.reindexWindow { if newTreeNodeGHOSTDAGData.BlueScore()-reindexRootChosenChildGHOSTDAGData.BlueScore() < rt.reindexWindow {
return nil, false, nil return nil, false, nil
} }

View File

@ -16,12 +16,12 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
if err != nil { if err != nil {
return nil, err return nil, err
} }
lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore()
highBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, highHash) highBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, highHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
highBlockBlueScore := highBlockGHOSTDAGData.BlueScore highBlockBlueScore := highBlockGHOSTDAGData.BlueScore()
if lowBlockBlueScore >= highBlockBlueScore { if lowBlockBlueScore >= highBlockBlueScore {
return nil, errors.Errorf("low hash blueScore >= high hash blueScore (%d >= %d)", return nil, errors.Errorf("low hash blueScore >= high hash blueScore (%d >= %d)",
lowBlockBlueScore, highBlockBlueScore) lowBlockBlueScore, highBlockBlueScore)
@ -37,7 +37,7 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
// fairly accurate because we presume that most DAG blocks are // fairly accurate because we presume that most DAG blocks are
// blue. // blue.
for highBlockBlueScore-lowBlockBlueScore+1 > maxHashesInAntiPastHashesBetween { for highBlockBlueScore-lowBlockBlueScore+1 > maxHashesInAntiPastHashesBetween {
highHash = highBlockGHOSTDAGData.SelectedParent highHash = highBlockGHOSTDAGData.SelectedParent()
} }
// Collect every node in highHash's past (including itself) but // Collect every node in highHash's past (including itself) but

View File

@ -14,13 +14,13 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH
if err != nil { if err != nil {
return nil, err return nil, err
} }
highHash = highBlockGHOSTDAGData.SelectedParent highHash = highBlockGHOSTDAGData.SelectedParent()
lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash) lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore()
currentHash := highHash currentHash := highHash
step := uint64(1) step := uint64(1)
@ -32,7 +32,7 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH
if err != nil { if err != nil {
return nil, err return nil, err
} }
currentBlockBlueScore := currentBlockGHOSTDAGData.BlueScore currentBlockBlueScore := currentBlockGHOSTDAGData.BlueScore()
// Nothing more to add once the low node has been added. // Nothing more to add once the low node has been added.
if currentBlockBlueScore <= lowBlockBlueScore { if currentBlockBlueScore <= lowBlockBlueScore {
@ -47,7 +47,7 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH
// final node is lowNode. // final node is lowNode.
nextBlueScore := currentBlockBlueScore - step nextBlueScore := currentBlockBlueScore - step
if currentBlockBlueScore < step { if currentBlockBlueScore < step {
nextBlueScore = lowBlockGHOSTDAGData.BlueScore nextBlueScore = lowBlockGHOSTDAGData.BlueScore()
} }
// Walk down currentHash's selected parent chain to the appropriate ancestor // Walk down currentHash's selected parent chain to the appropriate ancestor

View File

@ -91,7 +91,7 @@ func (sm *syncManager) virtualSelectedParentHash() (*externalapi.DomainHash, err
if err != nil { if err != nil {
return nil, err return nil, err
} }
return virtualGHOSTDAGData.SelectedParent, nil return virtualGHOSTDAGData.SelectedParent(), nil
} }
func (sm *syncManager) headerVirtualSelectedParentHash() (*externalapi.DomainHash, error) { func (sm *syncManager) headerVirtualSelectedParentHash() (*externalapi.DomainHash, error) {

View File

@ -59,7 +59,7 @@ func (v *transactionValidator) checkTransactionCoinbaseMaturity(
return err return err
} }
txBlueScore := ghostdagData.BlueScore txBlueScore := ghostdagData.BlueScore()
var missingOutpoints []*externalapi.DomainOutpoint var missingOutpoints []*externalapi.DomainOutpoint
for _, input := range tx.Inputs { for _, input := range tx.Inputs {
utxoEntry := input.UTXOEntry utxoEntry := input.UTXOEntry
@ -166,7 +166,7 @@ func (v *transactionValidator) checkTransactionSequenceLock(povBlockHash *extern
return err return err
} }
if !v.sequenceLockActive(sequenceLock, ghostdagData.BlueScore, medianTime) { if !v.sequenceLockActive(sequenceLock, ghostdagData.BlueScore(), medianTime) {
return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains "+ return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains "+
"transaction whose input sequence "+ "transaction whose input sequence "+
"locks are not met") "locks are not met")
@ -270,16 +270,16 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries(
for { for {
selectedParentGHOSTDAGData, err := v.ghostdagDataStore.Get(v.databaseContext, selectedParentGHOSTDAGData, err := v.ghostdagDataStore.Get(v.databaseContext,
baseGHOSTDAGData.SelectedParent) baseGHOSTDAGData.SelectedParent())
if err != nil { if err != nil {
return nil, err return nil, err
} }
if selectedParentGHOSTDAGData.BlueScore <= inputBlueScore { if selectedParentGHOSTDAGData.BlueScore() <= inputBlueScore {
break break
} }
baseHash = baseGHOSTDAGData.SelectedParent baseHash = baseGHOSTDAGData.SelectedParent()
baseGHOSTDAGData = selectedParentGHOSTDAGData baseGHOSTDAGData = selectedParentGHOSTDAGData
} }