Repository: kaspanet/kaspad
Pull request #1178 (2020-12-03 13:14:23)

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

ci-dag: Rebuild after update in master
ci-dag: Rebuild after update in master
ci-dag: Rebuild after update in master
svarogg: Rebuild after update in master

Patch:
diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go
index a5bcfed9..6db33d9d 100644
--- a/domain/consensus/consensus.go
+++ b/domain/consensus/consensus.go
@@ -134,7 +134,7 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap
 		return nil, err
 	}
 
-	blockInfo.BlueScore = ghostdagData.BlueScore
+	blockInfo.BlueScore = ghostdagData.BlueScore()
 
 	isBlockInHeaderPruningPointFuture, err := s.syncManager.IsBlockInHeaderPruningPointFuture(blockHash)
 	if err != nil {
@@ -196,7 +196,7 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error)
 	if err != nil {
 		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) {
diff --git a/domain/consensus/database/serialization/block_ghostdag_data.go b/domain/consensus/database/serialization/block_ghostdag_data.go
index 1765104b..2b4a2544 100644
--- a/domain/consensus/database/serialization/block_ghostdag_data.go
+++ b/domain/consensus/database/serialization/block_ghostdag_data.go
@@ -3,26 +3,27 @@ package serialization
 import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
+	"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
 )
 
 // BlockGHOSTDAGDataToDBBlockGHOSTDAGData converts BlockGHOSTDAGData to DbBlockGhostdagData
-func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData *model.BlockGHOSTDAGData) *DbBlockGhostdagData {
+func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDAGData) *DbBlockGhostdagData {
 	var selectedParent *DbHash
-	if blockGHOSTDAGData.SelectedParent != nil {
-		selectedParent = DomainHashToDbHash(blockGHOSTDAGData.SelectedParent)
+	if blockGHOSTDAGData.SelectedParent() != nil {
+		selectedParent = DomainHashToDbHash(blockGHOSTDAGData.SelectedParent())
 	}
 
 	return &DbBlockGhostdagData{
-		BlueScore:          blockGHOSTDAGData.BlueScore,
+		BlueScore:          blockGHOSTDAGData.BlueScore(),
 		SelectedParent:     selectedParent,
-		MergeSetBlues:      DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetBlues),
-		MergeSetReds:       DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetReds),
-		BluesAnticoneSizes: bluesAnticoneSizesToDBBluesAnticoneSizes(blockGHOSTDAGData.BluesAnticoneSizes),
+		MergeSetBlues:      DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetBlues()),
+		MergeSetReds:       DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetReds()),
+		BluesAnticoneSizes: bluesAnticoneSizesToDBBluesAnticoneSizes(blockGHOSTDAGData.BluesAnticoneSizes()),
 	}
 }
 
 // DBBlockGHOSTDAGDataToBlockGHOSTDAGData converts DbBlockGhostdagData to BlockGHOSTDAGData
-func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (*model.BlockGHOSTDAGData, error) {
+func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (model.BlockGHOSTDAGData, error) {
 	var selectedParent *externalapi.DomainHash
 	if dbBlockGHOSTDAGData.SelectedParent != nil {
 		var err error
@@ -47,11 +48,11 @@ func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdag
 		return nil, err
 	}
 
-	return &model.BlockGHOSTDAGData{
-		BlueScore:          dbBlockGHOSTDAGData.BlueScore,
-		SelectedParent:     selectedParent,
-		MergeSetBlues:      mergetSetBlues,
-		MergeSetReds:       mergetSetReds,
-		BluesAnticoneSizes: bluesAnticoneSizes,
-	}, nil
+	return ghostdagmanager.NewBlockGHOSTDAGData(
+		dbBlockGHOSTDAGData.BlueScore,
+		selectedParent,
+		mergetSetBlues,
+		mergetSetReds,
+		bluesAnticoneSizes,
+	), nil
 }
diff --git a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go
index aaa096a1..c42a0140 100644
--- a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go
+++ b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go
@@ -13,21 +13,21 @@ var bucket = dbkeys.MakeBucket([]byte("block-ghostdag-data"))
 
 // ghostdagDataStore represents a store of BlockGHOSTDAGData
 type ghostdagDataStore struct {
-	staging map[externalapi.DomainHash]*model.BlockGHOSTDAGData
+	staging map[externalapi.DomainHash]model.BlockGHOSTDAGData
 	cache   *lrucache.LRUCache
 }
 
 // New instantiates a new GHOSTDAGDataStore
 func New(cacheSize int) model.GHOSTDAGDataStore {
 	return &ghostdagDataStore{
-		staging: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData),
+		staging: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData),
 		cache:   lrucache.New(cacheSize),
 	}
 }
 
 // Stage stages the given blockGHOSTDAGData for the given blockHash
-func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) {
-	gds.staging[*blockHash] = blockGHOSTDAGData.Clone()
+func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData model.BlockGHOSTDAGData) {
+	gds.staging[*blockHash] = blockGHOSTDAGData
 }
 
 func (gds *ghostdagDataStore) IsStaged() bool {
@@ -35,7 +35,7 @@ func (gds *ghostdagDataStore) IsStaged() bool {
 }
 
 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 {
@@ -56,13 +56,13 @@ func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error {
 }
 
 // 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 {
-		return blockGHOSTDAGData.Clone(), nil
+		return blockGHOSTDAGData, nil
 	}
 
 	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))
@@ -75,18 +75,18 @@ func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externala
 		return nil, err
 	}
 	gds.cache.Add(blockHash, blockGHOSTDAGData)
-	return blockGHOSTDAGData.Clone(), nil
+	return blockGHOSTDAGData, nil
 }
 
 func (gds *ghostdagDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey {
 	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))
 }
 
-func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes []byte) (*model.BlockGHOSTDAGData, error) {
+func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes []byte) (model.BlockGHOSTDAGData, error) {
 	dbBlockGHOSTDAGData := &serialization.DbBlockGhostdagData{}
 	err := proto.Unmarshal(blockGHOSTDAGDataBytes, dbBlockGHOSTDAGData)
 	if err != nil {
diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go
index 1e1aacdd..ca0db772 100644
--- a/domain/consensus/factory.go
+++ b/domain/consensus/factory.go
@@ -63,24 +63,23 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
 	dbManager := consensusdatabase.New(db)
 
 	// Data Structures
-	storeCacheSize := 200
-	acceptanceDataStore := acceptancedatastore.New(storeCacheSize)
-	blockStore, err := blockstore.New(dbManager, storeCacheSize)
+	acceptanceDataStore := acceptancedatastore.New(200)
+	blockStore, err := blockstore.New(dbManager, 200)
 	if err != nil {
 		return nil, err
 	}
-	blockHeaderStore, err := blockheaderstore.New(dbManager, storeCacheSize)
+	blockHeaderStore, err := blockheaderstore.New(dbManager, 10_000)
 	if err != nil {
 		return nil, err
 	}
-	blockRelationStore := blockrelationstore.New(storeCacheSize)
-	blockStatusStore := blockstatusstore.New(storeCacheSize)
-	multisetStore := multisetstore.New(storeCacheSize)
+	blockRelationStore := blockrelationstore.New(200)
+	blockStatusStore := blockstatusstore.New(200)
+	multisetStore := multisetstore.New(200)
 	pruningStore := pruningstore.New()
-	reachabilityDataStore := reachabilitydatastore.New(storeCacheSize)
-	utxoDiffStore := utxodiffstore.New(storeCacheSize)
+	reachabilityDataStore := reachabilitydatastore.New(200)
+	utxoDiffStore := utxodiffstore.New(200)
 	consensusStateStore := consensusstatestore.New()
-	ghostdagDataStore := ghostdagdatastore.New(storeCacheSize)
+	ghostdagDataStore := ghostdagdatastore.New(10_000)
 	headerTipsStore := headertipsstore.New()
 
 	// Processes
diff --git a/domain/consensus/model/ghostdag.go b/domain/consensus/model/ghostdag.go
index d649c34a..2f1b4370 100644
--- a/domain/consensus/model/ghostdag.go
+++ b/domain/consensus/model/ghostdag.go
@@ -3,32 +3,12 @@ package model
 import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 
 // BlockGHOSTDAGData represents GHOSTDAG data for some block
-type BlockGHOSTDAGData struct {
-	BlueScore          uint64
-	SelectedParent     *externalapi.DomainHash
-	MergeSetBlues      []*externalapi.DomainHash
-	MergeSetReds       []*externalapi.DomainHash
-	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,
-	}
+type BlockGHOSTDAGData interface {
+	BlueScore() uint64
+	SelectedParent() *externalapi.DomainHash
+	MergeSetBlues() []*externalapi.DomainHash
+	MergeSetReds() []*externalapi.DomainHash
+	BluesAnticoneSizes() map[externalapi.DomainHash]KType
 }
 
 // KType defines the size of GHOSTDAG consensus algorithm K parameter.
diff --git a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go
index 13522feb..4e20e340 100644
--- a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go
+++ b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go
@@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 // GHOSTDAGDataStore represents a store of BlockGHOSTDAGData
 type GHOSTDAGDataStore interface {
 	Store
-	Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *BlockGHOSTDAGData)
+	Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData BlockGHOSTDAGData)
 	IsStaged() bool
-	Get(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockGHOSTDAGData, error)
+	Get(dbContext DBReader, blockHash *externalapi.DomainHash) (BlockGHOSTDAGData, error)
 }
diff --git a/domain/consensus/model/interface_processes_ghostdagmanager.go b/domain/consensus/model/interface_processes_ghostdagmanager.go
index f7cbab39..1222d556 100644
--- a/domain/consensus/model/interface_processes_ghostdagmanager.go
+++ b/domain/consensus/model/interface_processes_ghostdagmanager.go
@@ -6,6 +6,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 type GHOSTDAGManager interface {
 	GHOSTDAG(blockHash *externalapi.DomainHash) error
 	ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error)
-	Less(blockHashA *externalapi.DomainHash, ghostdagDataA *BlockGHOSTDAGData,
-		blockHashB *externalapi.DomainHash, ghostdagDataB *BlockGHOSTDAGData) bool
+	Less(blockHashA *externalapi.DomainHash, ghostdagDataA BlockGHOSTDAGData,
+		blockHashB *externalapi.DomainHash, ghostdagDataB BlockGHOSTDAGData) bool
 }
diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go
index c5b2de29..b8d8603e 100644
--- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go
+++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go
@@ -170,7 +170,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
 			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",
-			virtualGhostDAGData.BlueScore, syncInfo.State, syncInfo.BlockCount, syncInfo.HeaderCount)
+			virtualGhostDAGData.BlueScore(), syncInfo.State, syncInfo.BlockCount, syncInfo.HeaderCount)
 	}))
 	if logClosureErr != nil {
 		return logClosureErr
diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context.go b/domain/consensus/processes/blockvalidator/block_body_in_context.go
index b2897fee..6e577a6c 100644
--- a/domain/consensus/processes/blockvalidator/block_body_in_context.go
+++ b/domain/consensus/processes/blockvalidator/block_body_in_context.go
@@ -39,7 +39,7 @@ func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi.
 
 	// Ensure all transactions in the block are finalized.
 	for _, tx := range block.Transactions {
-		if !v.isFinalizedTransaction(tx, ghostdagData.BlueScore, blockTime) {
+		if !v.isFinalizedTransaction(tx, ghostdagData.BlueScore(), blockTime) {
 			txID := consensushashing.TransactionID(tx)
 			return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains unfinalized "+
 				"transaction %s", txID)
diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go
index 42f5403a..cc2aa156 100644
--- a/domain/consensus/processes/blockvalidator/block_header_in_context.go
+++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go
@@ -115,7 +115,7 @@ func (v *blockValidator) checkMergeSizeLimit(hash *externalapi.DomainHash) error
 		return err
 	}
 
-	mergeSetSize := len(ghostdagData.MergeSetReds) + len(ghostdagData.MergeSetBlues)
+	mergeSetSize := len(ghostdagData.MergeSetReds()) + len(ghostdagData.MergeSetBlues())
 
 	if uint64(mergeSetSize) > v.mergeSetSizeLimit {
 		return errors.Wrapf(ruleerrors.ErrViolatingMergeLimit,
diff --git a/domain/consensus/processes/coinbasemanager/coinbasemanager.go b/domain/consensus/processes/coinbasemanager/coinbasemanager.go
index 0799d91b..068b7fb4 100644
--- a/domain/consensus/processes/coinbasemanager/coinbasemanager.go
+++ b/domain/consensus/processes/coinbasemanager/coinbasemanager.go
@@ -31,8 +31,8 @@ func (c coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Doma
 		return nil, err
 	}
 
-	txOuts := make([]*externalapi.DomainTransactionOutput, 0, len(ghostdagData.MergeSetBlues))
-	for i, blue := range ghostdagData.MergeSetBlues {
+	txOuts := make([]*externalapi.DomainTransactionOutput, 0, len(ghostdagData.MergeSetBlues()))
+	for i, blue := range ghostdagData.MergeSetBlues() {
 		txOut, hasReward, err := c.coinbaseOutputForBlueBlock(blue, acceptanceData[i])
 		if err != nil {
 			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 {
 		return nil, err
 	}
@@ -120,7 +120,7 @@ func (c coinbaseManager) calcBlockSubsidy(blockHash *externalapi.DomainHash) (ui
 	}
 
 	// 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
diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go
index 1f60fed0..11b5d63c 100644
--- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go
+++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go
@@ -80,8 +80,8 @@ func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externa
 	}
 
 	log.Tracef("Selecting the next selected parent between "+
-		"the block %s the current selected parent %s", blockHash, virtualGhostdagData.SelectedParent)
-	nextVirtualSelectedParent, err := csm.ghostdagManager.ChooseSelectedParent(virtualGhostdagData.SelectedParent, blockHash)
+		"the block %s the current selected parent %s", blockHash, virtualGhostdagData.SelectedParent())
+	nextVirtualSelectedParent, err := csm.ghostdagManager.ChooseSelectedParent(virtualGhostdagData.SelectedParent(), blockHash)
 	if err != nil {
 		return false, err
 	}
diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go
index 4799fd5c..1e3dbb1c 100644
--- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go
+++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go
@@ -30,8 +30,8 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *
 	}
 
 	log.Tracef("Restoring the past UTXO of block %s with selectedParent %s",
-		blockHash, blockGHOSTDAGData.SelectedParent)
-	selectedParentPastUTXO, err := csm.restorePastUTXO(blockGHOSTDAGData.SelectedParent)
+		blockHash, blockGHOSTDAGData.SelectedParent())
+	selectedParentPastUTXO, err := csm.restorePastUTXO(blockGHOSTDAGData.SelectedParent())
 	if err != nil {
 		return nil, nil, nil, err
 	}
@@ -108,13 +108,13 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH
 }
 
 func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainHash,
-	selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData *model.BlockGHOSTDAGData) (
+	selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData model.BlockGHOSTDAGData) (
 	model.AcceptanceData, model.MutableUTXODiff, error) {
 
 	log.Tracef("applyBlueBlocks start 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 {
 		return nil, nil, err
 	}
@@ -146,7 +146,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH
 				transactionID, blueBlockHash)
 
 			isAccepted, accumulatedMass, err = csm.maybeAcceptTransaction(transaction, blockHash, isSelectedParent,
-				accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, ghostdagData.BlueScore)
+				accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, ghostdagData.BlueScore())
 			if err != nil {
 				return nil, nil, err
 			}
diff --git a/domain/consensus/processes/consensusstatemanager/multisets.go b/domain/consensus/processes/consensusstatemanager/multisets.go
index 7786b499..bb3f1a91 100644
--- a/domain/consensus/processes/consensusstatemanager/multisets.go
+++ b/domain/consensus/processes/consensusstatemanager/multisets.go
@@ -10,22 +10,22 @@ import (
 )
 
 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)
-	defer log.Tracef("calculateMultiset end 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())
 
-	if blockGHOSTDAGData.SelectedParent == nil {
+	if blockGHOSTDAGData.SelectedParent() == nil {
 		log.Tracef("Selected parent is nil, which could only happen for the genesis. " +
 			"The genesis, by definition, has an empty multiset")
 		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 {
 		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 i, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData {
@@ -40,7 +40,7 @@ func (csm *consensusStateManager) calculateMultiset(
 			log.Tracef("Is transaction %s a coinbase transaction: %t", transactionID, isCoinbase)
 
 			var err error
-			err = addTransactionToMultiset(ms, transaction, blockGHOSTDAGData.BlueScore, isCoinbase)
+			err = addTransactionToMultiset(ms, transaction, blockGHOSTDAGData.BlueScore(), isCoinbase)
 			if err != nil {
 				return nil, err
 			}
diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go
index bce7a8f6..84af3bf6 100644
--- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go
+++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go
@@ -214,7 +214,7 @@ func (csm *consensusStateManager) boundedMergeBreakingParents(
 	if err != nil {
 		return nil, err
 	}
-	for _, redBlock := range virtualGHOSTDAGData.MergeSetReds {
+	for _, redBlock := range virtualGHOSTDAGData.MergeSetReds() {
 		log.Tracef("Check whether red block %s is kosherized", redBlock)
 		isFinalityPointInPast, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, redBlock)
 		if err != nil {
diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go
index 3a2447aa..2aa6156b 100644
--- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go
+++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go
@@ -79,7 +79,7 @@ func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*e
 	if err != nil {
 		return 0, err
 	}
-	return csm.blockStatusStore.Get(csm.databaseContext, lastUnverifiedBlockGHOSTDAGData.SelectedParent)
+	return csm.blockStatusStore.Get(csm.databaseContext, lastUnverifiedBlockGHOSTDAGData.SelectedParent())
 }
 
 func (csm *consensusStateManager) getUnverifiedChainBlocks(
@@ -110,13 +110,13 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks(
 			return nil, err
 		}
 
-		if currentBlockGHOSTDAGData.SelectedParent == nil {
+		if currentBlockGHOSTDAGData.SelectedParent() == nil {
 			log.Tracef("Genesis block reached. Returning all the "+
 				"unverified blocks prior to it: %s", unverifiedBlocks)
 			return unverifiedBlocks, nil
 		}
 
-		currentHash = currentBlockGHOSTDAGData.SelectedParent
+		currentHash = currentBlockGHOSTDAGData.SelectedParent()
 	}
 }
 
diff --git a/domain/consensus/processes/dagtraversalmanager/block_heap.go b/domain/consensus/processes/dagtraversalmanager/block_heap.go
index 6a1caaad..40a0849e 100644
--- a/domain/consensus/processes/dagtraversalmanager/block_heap.go
+++ b/domain/consensus/processes/dagtraversalmanager/block_heap.go
@@ -9,7 +9,7 @@ import (
 
 type blockHeapNode struct {
 	hash         *externalapi.DomainHash
-	ghostdagData *model.BlockGHOSTDAGData
+	ghostdagData model.BlockGHOSTDAGData
 }
 
 // baseHeap  is an implementation for heap.Interface that sorts blocks by their height
diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go
index bc157f78..5a0329fe 100644
--- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go
+++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go
@@ -32,7 +32,7 @@ func (spi *selectedParentIterator) Next() bool {
 	if err != nil {
 		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
 }
 
@@ -75,17 +75,17 @@ func (dtm *dagTraversalManager) BlockAtDepth(highHash *externalapi.DomainHash, d
 	}
 
 	requiredBlueScore := uint64(0)
-	if highBlockGHOSTDAGData.BlueScore > depth {
-		requiredBlueScore = highBlockGHOSTDAGData.BlueScore - depth
+	if highBlockGHOSTDAGData.BlueScore() > depth {
+		requiredBlueScore = highBlockGHOSTDAGData.BlueScore() - depth
 	}
 
 	currentBlockGHOSTDAGData := highBlockGHOSTDAGData
 	// If we used `BlockIterator` we'd need to do more calls to `ghostdagDataStore` so we can get the blueScore
-	for currentBlockGHOSTDAGData.BlueScore >= requiredBlueScore {
-		if currentBlockGHOSTDAGData.SelectedParent == nil { // genesis
+	for currentBlockGHOSTDAGData.BlueScore() >= requiredBlueScore {
+		if currentBlockGHOSTDAGData.SelectedParent() == nil { // genesis
 			return currentBlockHash, nil
 		}
-		currentBlockHash = currentBlockGHOSTDAGData.SelectedParent
+		currentBlockHash = currentBlockGHOSTDAGData.SelectedParent()
 		currentBlockGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockHash)
 		if err != nil {
 			return nil, err
@@ -104,15 +104,15 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash
 	currentBlockGHOSTDAGData := highBlockGHOSTDAGData
 	iterator := dtm.SelectedParentIterator(highHash)
 	for iterator.Next() {
-		selectedParentBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockGHOSTDAGData.SelectedParent)
+		selectedParentBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockGHOSTDAGData.SelectedParent())
 		if err != nil {
 			return nil, err
 		}
 
-		if selectedParentBlockGHOSTDAGData.BlueScore < blueScore {
+		if selectedParentBlockGHOSTDAGData.BlueScore() < blueScore {
 			break
 		}
-		currentHash = selectedParentBlockGHOSTDAGData.SelectedParent
+		currentHash = selectedParentBlockGHOSTDAGData.SelectedParent()
 		currentBlockGHOSTDAGData = selectedParentBlockGHOSTDAGData
 	}
 
diff --git a/domain/consensus/processes/dagtraversalmanager/window.go b/domain/consensus/processes/dagtraversalmanager/window.go
index 8f480598..25b8a321 100644
--- a/domain/consensus/processes/dagtraversalmanager/window.go
+++ b/domain/consensus/processes/dagtraversalmanager/window.go
@@ -15,15 +15,15 @@ func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash
 		return nil, err
 	}
 
-	for uint64(len(window)) < windowSize && currentGHOSTDAGData.SelectedParent != nil {
-		for _, blue := range currentGHOSTDAGData.MergeSetBlues {
+	for uint64(len(window)) < windowSize && currentGHOSTDAGData.SelectedParent() != nil {
+		for _, blue := range currentGHOSTDAGData.MergeSetBlues() {
 			window = append(window, blue)
 			if uint64(len(window)) == windowSize {
 				break
 			}
 		}
 
-		currentHash = currentGHOSTDAGData.SelectedParent
+		currentHash = currentGHOSTDAGData.SelectedParent()
 		currentGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash)
 		if err != nil {
 			return nil, err
diff --git a/domain/consensus/processes/difficultymanager/difficultymanager.go b/domain/consensus/processes/difficultymanager/difficultymanager.go
index 45bbadd1..7a18faad 100644
--- a/domain/consensus/processes/difficultymanager/difficultymanager.go
+++ b/domain/consensus/processes/difficultymanager/difficultymanager.go
@@ -1,12 +1,13 @@
 package difficultymanager
 
 import (
+	"math/big"
+	"time"
+
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/util"
 	"github.com/kaspanet/kaspad/util/bigintpool"
-	"math/big"
-	"time"
 )
 
 // 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.
-	if bluestGhostDAG.BlueScore < dm.difficultyAdjustmentWindowSize+1 {
+	if bluestGhostDAG.BlueScore() < dm.difficultyAdjustmentWindowSize+1 {
 		return dm.genesisBits()
 	}
 
diff --git a/domain/consensus/processes/ghostdag2/ghostdagimpl.go b/domain/consensus/processes/ghostdag2/ghostdagimpl.go
index 867f52a8..abaaf183 100644
--- a/domain/consensus/processes/ghostdag2/ghostdagimpl.go
+++ b/domain/consensus/processes/ghostdag2/ghostdagimpl.go
@@ -1,9 +1,12 @@
 package ghostdag2
 
 import (
+	"sort"
+
+	"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
+
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
-	"sort"
 )
 
 type ghostdagHelper struct {
@@ -44,7 +47,7 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error
 		if err != nil {
 			return err
 		}
-		blockScore := blockData.BlueScore
+		blockScore := blockData.BlueScore()
 		if blockScore > maxNum {
 			selectedParent = parent
 			maxNum = blockScore
@@ -91,13 +94,8 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error
 	}
 	myScore += uint64(len(mergeSetBlues))
 
-	e := model.BlockGHOSTDAGData{
-		BlueScore:      myScore,
-		SelectedParent: selectedParent,
-		MergeSetBlues:  mergeSetBlues,
-		MergeSetReds:   mergeSetReds,
-	}
-	gh.dataStore.Stage(blockCandidate, &e)
+	e := ghostdagmanager.NewBlockGHOSTDAGData(myScore, selectedParent, mergeSetBlues, mergeSetReds, nil)
+	gh.dataStore.Stage(blockCandidate, e)
 	return nil
 }
 
@@ -220,7 +218,7 @@ func (gh *ghostdagHelper) validateKCluster(chain *externalapi.DomainHash, checke
 		if err != nil {
 			return false, err
 		}
-		if mergeSetReds := dataStore.MergeSetReds; contains(checkedBlock, mergeSetReds) {
+		if mergeSetReds := dataStore.MergeSetReds(); contains(checkedBlock, mergeSetReds) {
 			return false, nil
 		}
 	} else {
@@ -326,14 +324,14 @@ func (gh *ghostdagHelper) findBlueSet(blueSet *[]*externalapi.DomainHash, select
 		if err != nil {
 			return err
 		}
-		mergeSetBlue := blockData.MergeSetBlues
+		mergeSetBlue := blockData.MergeSetBlues()
 		for _, blue := range mergeSetBlue {
 			if contains(blue, *blueSet) {
 				continue
 			}
 			*blueSet = append(*blueSet, blue)
 		}
-		selectedParent = blockData.SelectedParent
+		selectedParent = blockData.SelectedParent()
 	}
 	return nil
 }
@@ -356,10 +354,10 @@ func (gh *ghostdagHelper) sortByBlueScore(arr []*externalapi.DomainHash) error {
 			return false
 		}
 
-		if blockLeft.BlueScore < blockRight.BlueScore {
+		if blockLeft.BlueScore() < blockRight.BlueScore() {
 			return true
 		}
-		if blockLeft.BlueScore == blockRight.BlueScore {
+		if blockLeft.BlueScore() == blockRight.BlueScore() {
 			return ismoreHash(arr[j], arr[i])
 		}
 		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)
 }
 func (gh *ghostdagHelper) ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) {
 	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")
 }
diff --git a/domain/consensus/processes/ghostdagmanager/compare.go b/domain/consensus/processes/ghostdagmanager/compare.go
index b5c16f27..76ad1844 100644
--- a/domain/consensus/processes/ghostdagmanager/compare.go
+++ b/domain/consensus/processes/ghostdagmanager/compare.go
@@ -53,11 +53,11 @@ func (gm *ghostdagManager) ChooseSelectedParent(blockHashes ...*externalapi.Doma
 	return selectedParent, nil
 }
 
-func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData,
-	blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool {
+func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA model.BlockGHOSTDAGData,
+	blockHashB *externalapi.DomainHash, ghostdagDataB model.BlockGHOSTDAGData) bool {
 
-	blockBlueScoreA := ghostdagDataA.BlueScore
-	blockBlueScoreB := ghostdagDataB.BlueScore
+	blockBlueScoreA := ghostdagDataA.BlueScore()
+	blockBlueScoreB := ghostdagDataB.BlueScore()
 	if blockBlueScoreA == blockBlueScoreB {
 		return hashes.Less(blockHashA, blockHashB)
 	}
diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag.go b/domain/consensus/processes/ghostdagmanager/ghostdag.go
index c510959a..8e24ea4c 100644
--- a/domain/consensus/processes/ghostdagmanager/ghostdag.go
+++ b/domain/consensus/processes/ghostdagmanager/ghostdag.go
@@ -25,10 +25,10 @@ import (
 //
 // For further details see the article https://eprint.iacr.org/2018/104.pdf
 func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
-	newBlockData := &model.BlockGHOSTDAGData{
-		MergeSetBlues:      make([]*externalapi.DomainHash, 0),
-		MergeSetReds:       make([]*externalapi.DomainHash, 0),
-		BluesAnticoneSizes: make(map[externalapi.DomainHash]model.KType),
+	newBlockData := &blockGHOSTDAGData{
+		mergeSetBlues:      make([]*externalapi.DomainHash, 0),
+		mergeSetReds:       make([]*externalapi.DomainHash, 0),
+		bluesAnticoneSizes: make(map[externalapi.DomainHash]model.KType),
 	}
 
 	blockParents, err := gm.dagTopologyManager.Parents(blockHash)
@@ -43,12 +43,12 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
 			return err
 		}
 
-		newBlockData.SelectedParent = selectedParent
-		newBlockData.MergeSetBlues = append(newBlockData.MergeSetBlues, selectedParent)
-		newBlockData.BluesAnticoneSizes[*selectedParent] = 0
+		newBlockData.selectedParent = selectedParent
+		newBlockData.mergeSetBlues = append(newBlockData.mergeSetBlues, selectedParent)
+		newBlockData.bluesAnticoneSizes[*selectedParent] = 0
 	}
 
-	mergeSetWithoutSelectedParent, err := gm.mergeSetWithoutSelectedParent(newBlockData.SelectedParent, blockParents)
+	mergeSetWithoutSelectedParent, err := gm.mergeSetWithoutSelectedParent(newBlockData.selectedParent, blockParents)
 	if err != nil {
 		return err
 	}
@@ -61,25 +61,25 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
 
 		if isBlue {
 			// No k-cluster violation found, we can now set the candidate block as blue
-			newBlockData.MergeSetBlues = append(newBlockData.MergeSetBlues, blueCandidate)
-			newBlockData.BluesAnticoneSizes[*blueCandidate] = candidateAnticoneSize
+			newBlockData.mergeSetBlues = append(newBlockData.mergeSetBlues, blueCandidate)
+			newBlockData.bluesAnticoneSizes[*blueCandidate] = candidateAnticoneSize
 			for blue, blueAnticoneSize := range candidateBluesAnticoneSizes {
-				newBlockData.BluesAnticoneSizes[blue] = blueAnticoneSize + 1
+				newBlockData.bluesAnticoneSizes[blue] = blueAnticoneSize + 1
 			}
 		} else {
-			newBlockData.MergeSetReds = append(newBlockData.MergeSetReds, blueCandidate)
+			newBlockData.mergeSetReds = append(newBlockData.mergeSetReds, blueCandidate)
 		}
 	}
 
 	if !isGenesis {
-		selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, newBlockData.SelectedParent)
+		selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, newBlockData.selectedParent)
 		if err != nil {
 			return err
 		}
-		newBlockData.BlueScore = selectedParentGHOSTDAGData.BlueScore + uint64(len(newBlockData.MergeSetBlues))
+		newBlockData.blueScore = selectedParentGHOSTDAGData.BlueScore() + uint64(len(newBlockData.mergeSetBlues))
 	} else {
 		// Genesis's blue score is defined to be 0.
-		newBlockData.BlueScore = 0
+		newBlockData.blueScore = 0
 	}
 
 	gm.ghostdagDataStore.Stage(blockHash, newBlockData)
@@ -89,15 +89,15 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
 
 type chainBlockData struct {
 	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) {
 
 	// The maximum length of node.blues can be K+1 because
 	// 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
 	}
 
@@ -126,12 +126,12 @@ func (gm *ghostdagManager) checkBlueCandidate(newBlockData *model.BlockGHOSTDAGD
 			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 {
 			return false, 0, nil, err
 		}
 
-		chainBlock = chainBlockData{hash: chainBlock.blockData.SelectedParent,
+		chainBlock = chainBlockData{hash: chainBlock.blockData.SelectedParent(),
 			blockData: selectedParentGHOSTDAGData,
 		}
 	}
@@ -139,7 +139,7 @@ func (gm *ghostdagManager) checkBlueCandidate(newBlockData *model.BlockGHOSTDAGD
 	return true, candidateAnticoneSize, candidateBluesAnticoneSizes, nil
 }
 
-func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData *model.BlockGHOSTDAGData,
+func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData model.BlockGHOSTDAGData,
 	chainBlock chainBlockData, blueCandidate *externalapi.DomainHash,
 	candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType,
 	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.
 		isAncestorOfBlueCandidate, err := gm.dagTopologyManager.IsAncestorOf(block, blueCandidate)
 		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'.
 // 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; {
-		if blueAnticoneSize, ok := current.BluesAnticoneSizes[*block]; ok {
+		if blueAnticoneSize, ok := current.BluesAnticoneSizes()[*block]; ok {
 			return blueAnticoneSize, nil
 		}
-		if current.SelectedParent == nil {
+		if current.SelectedParent() == nil {
 			break
 		}
 		var err error
-		current, err = gm.ghostdagDataStore.Get(gm.databaseContext, current.SelectedParent)
+		current, err = gm.ghostdagDataStore.Get(gm.databaseContext, current.SelectedParent())
 		if err != nil {
 			return 0, err
 		}
diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_data.go b/domain/consensus/processes/ghostdagmanager/ghostdag_data.go
new file mode 100644
index 00000000..b708241b
--- /dev/null
+++ b/domain/consensus/processes/ghostdagmanager/ghostdag_data.go
@@ -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
+}
diff --git a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go
index cbf29f33..155dcd73 100644
--- a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go
+++ b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go
@@ -46,7 +46,7 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma
 	}
 
 	// Return nil on genesis
-	if ghostdagData.SelectedParent == nil {
+	if ghostdagData.SelectedParent() == nil {
 		return nil
 	}
 
@@ -55,7 +55,7 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma
 		return err
 	}
 
-	for _, red := range ghostdagData.MergeSetReds {
+	for _, red := range ghostdagData.MergeSetReds() {
 		doesRedHaveFinalityPointInPast, err := mdm.dagTopologyManager.IsAncestorOf(finalityPoint, red)
 		if err != nil {
 			return err
@@ -85,9 +85,9 @@ func (mdm mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *exter
 		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)
 		if err != nil {
 			return nil, err
diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go
index a2d92dbb..5d29206c 100644
--- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go
+++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go
@@ -1,10 +1,11 @@
 package pastmediantimemanager
 
 import (
+	"sort"
+
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/pkg/errors"
-	"sort"
 )
 
 // pastMedianTimeManager provides a method to resolve the
@@ -44,7 +45,7 @@ func (pmtm *pastMedianTimeManager) PastMedianTime(blockHash *externalapi.DomainH
 	if err != nil {
 		return 0, err
 	}
-	selectedParentHash := blockGHOSTDAGData.SelectedParent
+	selectedParentHash := blockGHOSTDAGData.SelectedParent()
 
 	// Genesis block
 	if selectedParentHash == nil {
diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go
index 9dda97c9..57ca1dd1 100644
--- a/domain/consensus/processes/pruningmanager/pruningmanager.go
+++ b/domain/consensus/processes/pruningmanager/pruningmanager.go
@@ -99,14 +99,14 @@ func (pm *pruningManager) FindNextPruningPoint() error {
 	if err != nil {
 		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.
-	if virtual.BlueScore <= currentPBlueScore+pm.finalityInterval {
+	if virtual.BlueScore() <= currentPBlueScore+pm.finalityInterval {
 		return nil
 	}
 
 	// This means the pruning point is still genesis.
-	if virtual.BlueScore <= pm.pruningDepth+pm.finalityInterval {
+	if virtual.BlueScore() <= pm.pruningDepth+pm.finalityInterval {
 		return nil
 	}
 
@@ -121,7 +121,7 @@ func (pm *pruningManager) FindNextPruningPoint() error {
 	}
 
 	// 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)
 		if err != nil {
 			return err
diff --git a/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go b/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go
index 9bafb96c..57723957 100644
--- a/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go
+++ b/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go
@@ -45,7 +45,7 @@ func (rt *reachabilityManager) AddBlock(blockHash *externalapi.DomainHash) error
 	}
 
 	// If this is the genesis node, simply initialize it and return
-	if ghostdagData.SelectedParent == nil {
+	if ghostdagData.SelectedParent() == nil {
 		rt.stageReindexRoot(blockHash)
 		return nil
 	}
@@ -56,16 +56,16 @@ func (rt *reachabilityManager) AddBlock(blockHash *externalapi.DomainHash) error
 	}
 
 	// 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 {
 		return err
 	}
 
 	// Add the block to the futureCoveringSets of all the blocks
 	// in the merget set
-	mergeSet := make([]*externalapi.DomainHash, len(ghostdagData.MergeSetBlues)+len(ghostdagData.MergeSetReds))
-	copy(mergeSet, ghostdagData.MergeSetBlues)
-	copy(mergeSet[len(ghostdagData.MergeSetBlues):], ghostdagData.MergeSetReds)
+	mergeSet := make([]*externalapi.DomainHash, len(ghostdagData.MergeSetBlues())+len(ghostdagData.MergeSetReds()))
+	copy(mergeSet, ghostdagData.MergeSetBlues())
+	copy(mergeSet[len(ghostdagData.MergeSetBlues()):], ghostdagData.MergeSetReds())
 
 	for _, current := range mergeSet {
 		err = rt.insertToFutureCoveringSet(current, blockHash)
diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go
index 8ea71193..1dea962e 100644
--- a/domain/consensus/processes/reachabilitymanager/tree.go
+++ b/domain/consensus/processes/reachabilitymanager/tree.go
@@ -814,7 +814,7 @@ func (rt *reachabilityManager) maybeMoveReindexRoot(reindexRoot, newTreeNode *ex
 		return nil, false, err
 	}
 
-	if newTreeNodeGHOSTDAGData.BlueScore-reindexRootChosenChildGHOSTDAGData.BlueScore < rt.reindexWindow {
+	if newTreeNodeGHOSTDAGData.BlueScore()-reindexRootChosenChildGHOSTDAGData.BlueScore() < rt.reindexWindow {
 		return nil, false, nil
 	}
 
diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go
index 973b9efb..7cdf339c 100644
--- a/domain/consensus/processes/syncmanager/antipast.go
+++ b/domain/consensus/processes/syncmanager/antipast.go
@@ -16,12 +16,12 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
 	if err != nil {
 		return nil, err
 	}
-	lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore
+	lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore()
 	highBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, highHash)
 	if err != nil {
 		return nil, err
 	}
-	highBlockBlueScore := highBlockGHOSTDAGData.BlueScore
+	highBlockBlueScore := highBlockGHOSTDAGData.BlueScore()
 	if lowBlockBlueScore >= highBlockBlueScore {
 		return nil, errors.Errorf("low hash blueScore >= high hash blueScore (%d >= %d)",
 			lowBlockBlueScore, highBlockBlueScore)
@@ -37,7 +37,7 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
 	// fairly accurate because we presume that most DAG blocks are
 	// blue.
 	for highBlockBlueScore-lowBlockBlueScore+1 > maxHashesInAntiPastHashesBetween {
-		highHash = highBlockGHOSTDAGData.SelectedParent
+		highHash = highBlockGHOSTDAGData.SelectedParent()
 	}
 
 	// Collect every node in highHash's past (including itself) but
diff --git a/domain/consensus/processes/syncmanager/blocklocator.go b/domain/consensus/processes/syncmanager/blocklocator.go
index a808e10a..770b22ee 100644
--- a/domain/consensus/processes/syncmanager/blocklocator.go
+++ b/domain/consensus/processes/syncmanager/blocklocator.go
@@ -14,13 +14,13 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH
 	if err != nil {
 		return nil, err
 	}
-	highHash = highBlockGHOSTDAGData.SelectedParent
+	highHash = highBlockGHOSTDAGData.SelectedParent()
 
 	lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash)
 	if err != nil {
 		return nil, err
 	}
-	lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore
+	lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore()
 
 	currentHash := highHash
 	step := uint64(1)
@@ -32,7 +32,7 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH
 		if err != nil {
 			return nil, err
 		}
-		currentBlockBlueScore := currentBlockGHOSTDAGData.BlueScore
+		currentBlockBlueScore := currentBlockGHOSTDAGData.BlueScore()
 
 		// Nothing more to add once the low node has been added.
 		if currentBlockBlueScore <= lowBlockBlueScore {
@@ -47,7 +47,7 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH
 		// final node is lowNode.
 		nextBlueScore := currentBlockBlueScore - step
 		if currentBlockBlueScore < step {
-			nextBlueScore = lowBlockGHOSTDAGData.BlueScore
+			nextBlueScore = lowBlockGHOSTDAGData.BlueScore()
 		}
 
 		// Walk down currentHash's selected parent chain to the appropriate ancestor
diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go
index 5d502b11..62a3f2a7 100644
--- a/domain/consensus/processes/syncmanager/syncinfo.go
+++ b/domain/consensus/processes/syncmanager/syncinfo.go
@@ -91,7 +91,7 @@ func (sm *syncManager) virtualSelectedParentHash() (*externalapi.DomainHash, err
 	if err != nil {
 		return nil, err
 	}
-	return virtualGHOSTDAGData.SelectedParent, nil
+	return virtualGHOSTDAGData.SelectedParent(), nil
 }
 
 func (sm *syncManager) headerVirtualSelectedParentHash() (*externalapi.DomainHash, error) {
diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_context.go b/domain/consensus/processes/transactionvalidator/transaction_in_context.go
index 9f40f999..57395bf4 100644
--- a/domain/consensus/processes/transactionvalidator/transaction_in_context.go
+++ b/domain/consensus/processes/transactionvalidator/transaction_in_context.go
@@ -59,7 +59,7 @@ func (v *transactionValidator) checkTransactionCoinbaseMaturity(
 		return err
 	}
 
-	txBlueScore := ghostdagData.BlueScore
+	txBlueScore := ghostdagData.BlueScore()
 	var missingOutpoints []*externalapi.DomainOutpoint
 	for _, input := range tx.Inputs {
 		utxoEntry := input.UTXOEntry
@@ -166,7 +166,7 @@ func (v *transactionValidator) checkTransactionSequenceLock(povBlockHash *extern
 		return err
 	}
 
-	if !v.sequenceLockActive(sequenceLock, ghostdagData.BlueScore, medianTime) {
+	if !v.sequenceLockActive(sequenceLock, ghostdagData.BlueScore(), medianTime) {
 		return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains "+
 			"transaction whose input sequence "+
 			"locks are not met")
@@ -270,16 +270,16 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries(
 
 			for {
 				selectedParentGHOSTDAGData, err := v.ghostdagDataStore.Get(v.databaseContext,
-					baseGHOSTDAGData.SelectedParent)
+					baseGHOSTDAGData.SelectedParent())
 				if err != nil {
 					return nil, err
 				}
 
-				if selectedParentGHOSTDAGData.BlueScore <= inputBlueScore {
+				if selectedParentGHOSTDAGData.BlueScore() <= inputBlueScore {
 					break
 				}
 
-				baseHash = baseGHOSTDAGData.SelectedParent
+				baseHash = baseGHOSTDAGData.SelectedParent()
 				baseGHOSTDAGData = selectedParentGHOSTDAGData
 			}
 


Test patch:
diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go
index 3beff0f4..61b0c3c1 100644
--- a/domain/consensus/finality_test.go
+++ b/domain/consensus/finality_test.go
@@ -155,7 +155,7 @@ func TestFinality(t *testing.T) {
 			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")
 		}
 
@@ -308,7 +308,7 @@ func TestBoundedMergeDepth(t *testing.T) {
 		}
 		// Make sure it's actually blue
 		found := false
-		for _, blue := range virtualGhotDagData.MergeSetBlues {
+		for _, blue := range virtualGhotDagData.MergeSetBlues() {
 			if *blue == *kosherizingBlockHash {
 				found = true
 				break
@@ -356,7 +356,7 @@ func TestBoundedMergeDepth(t *testing.T) {
 		}
 		// Make sure it's actually blue
 		found = false
-		for _, blue := range virtualGhotDagData.MergeSetBlues {
+		for _, blue := range virtualGhotDagData.MergeSetBlues() {
 			if *blue == *kosherizingBlockHash {
 				found = true
 				break
diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go
index 967a1e4d..78e5a56c 100644
--- a/domain/consensus/processes/blockbuilder/test_block_builder.go
+++ b/domain/consensus/processes/blockbuilder/test_block_builder.go
@@ -96,13 +96,13 @@ func (bb *testBlockBuilder) buildBlockWithParents(parentHashes []*externalapi.Do
 		return nil, nil, err
 	}
 
-	selectedParentStatus, err := bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent)
+	selectedParentStatus, err := bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent())
 	if err != nil {
 		return nil, nil, err
 	}
 	if selectedParentStatus == externalapi.StatusDisqualifiedFromChain {
 		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)
diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go
new file mode 100644
index 00000000..8b8de6df
--- /dev/null
+++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go
@@ -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)
+}
diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go
index bd01b100..6afcf609 100644
--- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go
+++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go
@@ -1,14 +1,17 @@
-package ghostdagmanager
+package ghostdagmanager_test
 
 import (
 	"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"
 	"path/filepath"
 	"reflect"
 	"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
@@ -47,15 +50,9 @@ func TestGHOSTDAG(t *testing.T) {
 	}
 
 	ghostdagDataStore := &GHOSTDAGDataStoreImpl{
-		dagMap: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData),
-	}
-	var blockGHOSTDAGDataGenesis = &model.BlockGHOSTDAGData{
-		BlueScore:          0,
-		SelectedParent:     nil,
-		MergeSetBlues:      nil,
-		MergeSetReds:       nil,
-		BluesAnticoneSizes: nil,
+		dagMap: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData),
 	}
+	blockGHOSTDAGDataGenesis := ghostdagmanager.NewBlockGHOSTDAGData(0, nil, nil, nil, nil)
 
 	var testsCounter int
 	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:
 		implementationFactories := []implManager{
-			{New, "Original"},
+			{ghostdagmanager.New, "Original"},
 			{ghostdag2.New, "Tal's impl"},
 		}
 
@@ -110,30 +107,30 @@ func TestGHOSTDAG(t *testing.T) {
 						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.",
-						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.",
-						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.",
-						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.",
-						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[genesisHash] = nil
-			ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData)
+			ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData)
 			ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis
 		}
 
@@ -172,10 +169,10 @@ func StringToByteArray(stringIDArr []string) []*externalapi.DomainHash {
 
 /* ---------------------- */
 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
 }
 
@@ -191,7 +188,7 @@ func (ds *GHOSTDAGDataStoreImpl) Commit(dbTx model.DBTransaction) error {
 	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]
 	if ok {
 		return v, nil