Repository: kaspanet/kaspad
Pull request #1131 (2020-11-22 10:35:27)

[RES-65] Add a test for BoundedMergeDepth - new
* Add a test for BoundedMergeDepth
* Fix a bug in GetBlockInfo
* Add a test for reproducing and checking that bug

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

Patch:
diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go
index ca92e2db..b5361a26 100644
--- a/app/protocol/flowcontext/blocks.go
+++ b/app/protocol/flowcontext/blocks.go
@@ -26,7 +26,7 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error {
 	for _, newBlock := range newBlocks {
 		blocklogger.LogBlock(block)
 
-		f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions)
+		_ = f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions)
 
 		if f.onBlockAddedToDAGHandler != nil {
 			err := f.onBlockAddedToDAGHandler(newBlock)
diff --git a/app/protocol/flows/handshake/handshake.go b/app/protocol/flows/handshake/handshake.go
index 515ff5b5..8f305d85 100644
--- a/app/protocol/flows/handshake/handshake.go
+++ b/app/protocol/flows/handshake/handshake.go
@@ -1,7 +1,6 @@
 package handshake
 
 import (
-	"sync"
 	"sync/atomic"
 
 	"github.com/kaspanet/kaspad/domain"
@@ -16,7 +15,6 @@ import (
 	"github.com/kaspanet/kaspad/app/appmessage"
 	peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
 	routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
-	"github.com/kaspanet/kaspad/util/locks"
 	"github.com/pkg/errors"
 )
 
@@ -38,10 +36,12 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N
 ) (*peerpkg.Peer, error) {
 
 	// For HandleHandshake to finish, we need to get from the other node
-	// a version and verack messages, so we increase the wait group by 2
-	// and block HandleHandshake with wg.Wait().
-	wg := sync.WaitGroup{}
-	wg.Add(2)
+	// a version and verack messages, so we set doneCount to 2, decrease it
+	// when sending and receiving the version, and close the doneChan when
+	// it's 0. Then we wait for on select for a tick from doneChan or from
+	// errChan.
+	doneCount := int32(2)
+	doneChan := make(chan struct{})
 
 	isStopping := uint32(0)
 	errChan := make(chan error)
@@ -56,7 +56,9 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N
 			return
 		}
 		peerAddress = address
-		wg.Done()
+		if atomic.AddInt32(&doneCount, -1) == 0 {
+			close(doneChan)
+		}
 	})
 
 	spawn("HandleHandshake-SendVersion", func() {
@@ -65,7 +67,9 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N
 			handleError(err, "SendVersion", &isStopping, errChan)
 			return
 		}
-		wg.Done()
+		if atomic.AddInt32(&doneCount, -1) == 0 {
+			close(doneChan)
+		}
 	})
 
 	select {
@@ -74,7 +78,7 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N
 			return nil, err
 		}
 		return nil, nil
-	case <-locks.ReceiveFromChanWhenDone(func() { wg.Wait() }):
+	case <-doneChan:
 	}
 
 	err := context.AddToPeers(peer)
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 7ef305f8..11a1098c 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -26,7 +26,7 @@ RUN golint -set_exit_status ./...
 # RUN aligncheck ./...
 # RUN structcheck -e ./...
 # RUN varcheck -e ./...
-RUN staticcheck -checks SA4006 ./...
+RUN staticcheck -checks "SA4006,SA4008,SA4009,SA4010,SA5003,SA1004,SA1014,SA1021,SA1023,SA1024,SA1025,SA1026,SA1027,SA1028,SA2000,SA2001,SA2003,SA4000,SA4001,SA4003,SA4004,SA4011,SA4012,SA4013,SA4014,SA4015,SA4016,SA4017,SA4018,SA4019,SA4020,SA4021,SA4022,SA4023,SA5000,SA5002,SA5004,SA5005,SA5007,SA5008,SA5009,SA5010,SA5011,SA5012,SA6001,SA6002,SA9001,SA9002,SA9003,SA9004,SA9005,SA9006,ST1019" ./...
 RUN GOOS=linux go build -a -installsuffix cgo -o kaspad .
 
 # Remove the line below and uncomment the line after it for testing with coverage
diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go
index 3a8903ee..fa07ae48 100644
--- a/domain/consensus/consensus.go
+++ b/domain/consensus/consensus.go
@@ -124,6 +124,11 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap
 	}
 	blockInfo.BlockStatus = blockStatus
 
+	// If the status is invalid, then we don't have the necessary reachability data to check if it's in PruningPoint.Future.
+	if blockStatus == externalapi.StatusInvalid {
+		return blockInfo, nil
+	}
+
 	isBlockInHeaderPruningPointFuture, err := s.syncManager.IsBlockInHeaderPruningPointFuture(blockHash)
 	if err != nil {
 		return nil, err
diff --git a/domain/consensus/database/transaction.go b/domain/consensus/database/transaction.go
index 807150bb..9f17bc54 100644
--- a/domain/consensus/database/transaction.go
+++ b/domain/consensus/database/transaction.go
@@ -26,7 +26,7 @@ func (d *dbTransaction) Commit() error {
 }
 
 func (d *dbTransaction) RollbackUnlessClosed() error {
-	return d.RollbackUnlessClosed()
+	return d.transaction.RollbackUnlessClosed()
 }
 
 func newDBTransaction(transaction database.Transaction) model.DBTransaction {
diff --git a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go
index b74cec54..f19a4402 100644
--- a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go
+++ b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go
@@ -5,6 +5,7 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
 	"google.golang.org/protobuf/proto"
 )
 
@@ -14,25 +15,21 @@ var bucket = dbkeys.MakeBucket([]byte("acceptance-data"))
 type acceptanceDataStore struct {
 	staging  map[externalapi.DomainHash]model.AcceptanceData
 	toDelete map[externalapi.DomainHash]struct{}
+	cache    *lrucache.LRUCache
 }
 
 // New instantiates a new AcceptanceDataStore
-func New() model.AcceptanceDataStore {
+func New(cacheSize int) model.AcceptanceDataStore {
 	return &acceptanceDataStore{
 		staging:  make(map[externalapi.DomainHash]model.AcceptanceData),
 		toDelete: make(map[externalapi.DomainHash]struct{}),
+		cache:    lrucache.New(cacheSize),
 	}
 }
 
 // Stage stages the given acceptanceData for the given blockHash
-func (ads *acceptanceDataStore) Stage(blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) error {
-	clone, err := ads.cloneAcceptanceData(acceptanceData)
-	if err != nil {
-		return err
-	}
-
-	ads.staging[*blockHash] = clone
-	return nil
+func (ads *acceptanceDataStore) Stage(blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) {
+	ads.staging[*blockHash] = acceptanceData.Clone()
 }
 
 func (ads *acceptanceDataStore) IsStaged() bool {
@@ -54,6 +51,7 @@ func (ads *acceptanceDataStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		ads.cache.Add(&hash, acceptanceData)
 	}
 
 	for hash := range ads.toDelete {
@@ -61,6 +59,7 @@ func (ads *acceptanceDataStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		ads.cache.Remove(&hash)
 	}
 
 	ads.Discard()
@@ -70,7 +69,11 @@ func (ads *acceptanceDataStore) Commit(dbTx model.DBTransaction) error {
 // Get gets the acceptanceData associated with the given blockHash
 func (ads *acceptanceDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.AcceptanceData, error) {
 	if acceptanceData, ok := ads.staging[*blockHash]; ok {
-		return acceptanceData, nil
+		return acceptanceData.Clone(), nil
+	}
+
+	if acceptanceData, ok := ads.cache.Get(blockHash); ok {
+		return acceptanceData.(model.AcceptanceData).Clone(), nil
 	}
 
 	acceptanceDataBytes, err := dbContext.Get(ads.hashAsKey(blockHash))
@@ -78,7 +81,12 @@ func (ads *acceptanceDataStore) Get(dbContext model.DBReader, blockHash *externa
 		return nil, err
 	}
 
-	return ads.deserializeAcceptanceData(acceptanceDataBytes)
+	acceptanceData, err := ads.deserializeAcceptanceData(acceptanceDataBytes)
+	if err != nil {
+		return nil, err
+	}
+	ads.cache.Add(blockHash, acceptanceData)
+	return acceptanceData.Clone(), nil
 }
 
 // Delete deletes the acceptanceData associated with the given blockHash
@@ -107,12 +115,3 @@ func (ads *acceptanceDataStore) deserializeAcceptanceData(acceptanceDataBytes []
 func (ads *acceptanceDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey {
 	return bucket.Key(hash[:])
 }
-
-func (ads *acceptanceDataStore) cloneAcceptanceData(acceptanceData model.AcceptanceData) (model.AcceptanceData, error) {
-	serialized, err := ads.serializeAcceptanceData(acceptanceData)
-	if err != nil {
-		return nil, err
-	}
-
-	return ads.deserializeAcceptanceData(serialized)
-}
diff --git a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go
index 27e08451..81934893 100644
--- a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go
+++ b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go
@@ -6,6 +6,7 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
 )
 
 var bucket = dbkeys.MakeBucket([]byte("block-headers"))
@@ -15,14 +16,16 @@ var countKey = dbkeys.MakeBucket().Key([]byte("block-headers-count"))
 type blockHeaderStore struct {
 	staging  map[externalapi.DomainHash]*externalapi.DomainBlockHeader
 	toDelete map[externalapi.DomainHash]struct{}
+	cache    *lrucache.LRUCache
 	count    uint64
 }
 
 // New instantiates a new BlockHeaderStore
-func New(dbContext model.DBReader) (model.BlockHeaderStore, error) {
+func New(dbContext model.DBReader, cacheSize int) (model.BlockHeaderStore, error) {
 	blockHeaderStore := &blockHeaderStore{
 		staging:  make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader),
 		toDelete: make(map[externalapi.DomainHash]struct{}),
+		cache:    lrucache.New(cacheSize),
 	}
 
 	err := blockHeaderStore.initializeCount(dbContext)
@@ -54,14 +57,8 @@ func (bhs *blockHeaderStore) initializeCount(dbContext model.DBReader) error {
 }
 
 // Stage stages the given block header for the given blockHash
-func (bhs *blockHeaderStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) error {
-	clone, err := bhs.cloneHeader(blockHeader)
-	if err != nil {
-		return err
-	}
-
-	bhs.staging[*blockHash] = clone
-	return nil
+func (bhs *blockHeaderStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) {
+	bhs.staging[*blockHash] = blockHeader.Clone()
 }
 
 func (bhs *blockHeaderStore) IsStaged() bool {
@@ -83,6 +80,7 @@ func (bhs *blockHeaderStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		bhs.cache.Add(&hash, header)
 	}
 
 	for hash := range bhs.toDelete {
@@ -90,6 +88,7 @@ func (bhs *blockHeaderStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		bhs.cache.Remove(&hash)
 	}
 
 	err := bhs.commitCount(dbTx)
@@ -104,7 +103,11 @@ func (bhs *blockHeaderStore) Commit(dbTx model.DBTransaction) error {
 // BlockHeader gets the block header associated with the given blockHash
 func (bhs *blockHeaderStore) BlockHeader(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) {
 	if header, ok := bhs.staging[*blockHash]; ok {
-		return header, nil
+		return header.Clone(), nil
+	}
+
+	if header, ok := bhs.cache.Get(blockHash); ok {
+		return header.(*externalapi.DomainBlockHeader).Clone(), nil
 	}
 
 	headerBytes, err := dbContext.Get(bhs.hashAsKey(blockHash))
@@ -112,7 +115,12 @@ func (bhs *blockHeaderStore) BlockHeader(dbContext model.DBReader, blockHash *ex
 		return nil, err
 	}
 
-	return bhs.deserializeHeader(headerBytes)
+	header, err := bhs.deserializeHeader(headerBytes)
+	if err != nil {
+		return nil, err
+	}
+	bhs.cache.Add(blockHash, header)
+	return header.Clone(), nil
 }
 
 // HasBlock returns whether a block header with a given hash exists in the store.
@@ -121,6 +129,10 @@ func (bhs *blockHeaderStore) HasBlockHeader(dbContext model.DBReader, blockHash
 		return true, nil
 	}
 
+	if bhs.cache.Has(blockHash) {
+		return true, nil
+	}
+
 	exists, err := dbContext.Has(bhs.hashAsKey(blockHash))
 	if err != nil {
 		return false, err
@@ -169,15 +181,6 @@ func (bhs *blockHeaderStore) deserializeHeader(headerBytes []byte) (*externalapi
 	return serialization.DbBlockHeaderToDomainBlockHeader(dbBlockHeader)
 }
 
-func (bhs *blockHeaderStore) cloneHeader(header *externalapi.DomainBlockHeader) (*externalapi.DomainBlockHeader, error) {
-	serialized, err := bhs.serializeHeader(header)
-	if err != nil {
-		return nil, err
-	}
-
-	return bhs.deserializeHeader(serialized)
-}
-
 func (bhs *blockHeaderStore) Count() uint64 {
 	return bhs.count + uint64(len(bhs.staging)) - uint64(len(bhs.toDelete))
 }
diff --git a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go
index 284b3216..64b69e5c 100644
--- a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go
+++ b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go
@@ -6,6 +6,7 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
 )
 
 var bucket = dbkeys.MakeBucket([]byte("block-relations"))
@@ -13,23 +14,19 @@ var bucket = dbkeys.MakeBucket([]byte("block-relations"))
 // blockRelationStore represents a store of BlockRelations
 type blockRelationStore struct {
 	staging map[externalapi.DomainHash]*model.BlockRelations
+	cache   *lrucache.LRUCache
 }
 
 // New instantiates a new BlockRelationStore
-func New() model.BlockRelationStore {
+func New(cacheSize int) model.BlockRelationStore {
 	return &blockRelationStore{
 		staging: make(map[externalapi.DomainHash]*model.BlockRelations),
+		cache:   lrucache.New(cacheSize),
 	}
 }
 
-func (brs *blockRelationStore) StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *model.BlockRelations) error {
-	clone, err := brs.clone(blockRelations)
-	if err != nil {
-		return err
-	}
-
-	brs.staging[*blockHash] = clone
-	return nil
+func (brs *blockRelationStore) StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *model.BlockRelations) {
+	brs.staging[*blockHash] = blockRelations.Clone()
 }
 
 func (brs *blockRelationStore) IsStaged() bool {
@@ -50,6 +47,7 @@ func (brs *blockRelationStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		brs.cache.Add(&hash, blockRelations)
 	}
 
 	brs.Discard()
@@ -58,7 +56,11 @@ func (brs *blockRelationStore) Commit(dbTx model.DBTransaction) error {
 
 func (brs *blockRelationStore) BlockRelation(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockRelations, error) {
 	if blockRelations, ok := brs.staging[*blockHash]; ok {
-		return blockRelations, nil
+		return blockRelations.Clone(), nil
+	}
+
+	if blockRelations, ok := brs.cache.Get(blockHash); ok {
+		return blockRelations.(*model.BlockRelations).Clone(), nil
 	}
 
 	blockRelationsBytes, err := dbContext.Get(brs.hashAsKey(blockHash))
@@ -66,7 +68,12 @@ func (brs *blockRelationStore) BlockRelation(dbContext model.DBReader, blockHash
 		return nil, err
 	}
 
-	return brs.deserializeBlockRelations(blockRelationsBytes)
+	blockRelations, err := brs.deserializeBlockRelations(blockRelationsBytes)
+	if err != nil {
+		return nil, err
+	}
+	brs.cache.Add(blockHash, blockRelations)
+	return blockRelations.Clone(), nil
 }
 
 func (brs *blockRelationStore) Has(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) {
@@ -74,6 +81,10 @@ func (brs *blockRelationStore) Has(dbContext model.DBReader, blockHash *external
 		return true, nil
 	}
 
+	if brs.cache.Has(blockHash) {
+		return true, nil
+	}
+
 	return dbContext.Has(brs.hashAsKey(blockHash))
 }
 
@@ -94,12 +105,3 @@ func (brs *blockRelationStore) deserializeBlockRelations(blockRelationsBytes []b
 	}
 	return serialization.DbBlockRelationsToDomainBlockRelations(dbBlockRelations)
 }
-
-func (brs *blockRelationStore) clone(blockRelations *model.BlockRelations) (*model.BlockRelations, error) {
-	serialized, err := brs.serializeBlockRelations(blockRelations)
-	if err != nil {
-		return nil, err
-	}
-
-	return brs.deserializeBlockRelations(serialized)
-}
diff --git a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go
index 4b62be44..943d3ad5 100644
--- a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go
+++ b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go
@@ -6,6 +6,7 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
 )
 
 var bucket = dbkeys.MakeBucket([]byte("block-statuses"))
@@ -13,18 +14,20 @@ var bucket = dbkeys.MakeBucket([]byte("block-statuses"))
 // blockStatusStore represents a store of BlockStatuses
 type blockStatusStore struct {
 	staging map[externalapi.DomainHash]externalapi.BlockStatus
+	cache   *lrucache.LRUCache
 }
 
 // New instantiates a new BlockStatusStore
-func New() model.BlockStatusStore {
+func New(cacheSize int) model.BlockStatusStore {
 	return &blockStatusStore{
 		staging: make(map[externalapi.DomainHash]externalapi.BlockStatus),
+		cache:   lrucache.New(cacheSize),
 	}
 }
 
 // Stage stages the given blockStatus for the given blockHash
 func (bss *blockStatusStore) Stage(blockHash *externalapi.DomainHash, blockStatus externalapi.BlockStatus) {
-	bss.staging[*blockHash] = blockStatus
+	bss.staging[*blockHash] = blockStatus.Clone()
 }
 
 func (bss *blockStatusStore) IsStaged() bool {
@@ -45,6 +48,7 @@ func (bss *blockStatusStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		bss.cache.Add(&hash, status)
 	}
 
 	bss.Discard()
@@ -57,12 +61,21 @@ func (bss *blockStatusStore) Get(dbContext model.DBReader, blockHash *externalap
 		return status, nil
 	}
 
+	if status, ok := bss.cache.Get(blockHash); ok {
+		return status.(externalapi.BlockStatus), nil
+	}
+
 	statusBytes, err := dbContext.Get(bss.hashAsKey(blockHash))
 	if err != nil {
 		return 0, err
 	}
 
-	return bss.deserializeBlockStatus(statusBytes)
+	status, err := bss.deserializeBlockStatus(statusBytes)
+	if err != nil {
+		return 0, err
+	}
+	bss.cache.Add(blockHash, status)
+	return status, nil
 }
 
 // Exists returns true if the blockStatus for the given blockHash exists
@@ -71,6 +84,10 @@ func (bss *blockStatusStore) Exists(dbContext model.DBReader, blockHash *externa
 		return true, nil
 	}
 
+	if bss.cache.Has(blockHash) {
+		return true, nil
+	}
+
 	exists, err := dbContext.Has(bss.hashAsKey(blockHash))
 	if err != nil {
 		return false, err
diff --git a/domain/consensus/datastructures/blockstore/blockstore.go b/domain/consensus/datastructures/blockstore/blockstore.go
index 6824e11d..20c51efb 100644
--- a/domain/consensus/datastructures/blockstore/blockstore.go
+++ b/domain/consensus/datastructures/blockstore/blockstore.go
@@ -6,6 +6,7 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
 )
 
 var bucket = dbkeys.MakeBucket([]byte("blocks"))
@@ -15,14 +16,16 @@ var countKey = dbkeys.MakeBucket().Key([]byte("blocks-count"))
 type blockStore struct {
 	staging  map[externalapi.DomainHash]*externalapi.DomainBlock
 	toDelete map[externalapi.DomainHash]struct{}
+	cache    *lrucache.LRUCache
 	count    uint64
 }
 
 // New instantiates a new BlockStore
-func New(dbContext model.DBReader) (model.BlockStore, error) {
+func New(dbContext model.DBReader, cacheSize int) (model.BlockStore, error) {
 	blockStore := &blockStore{
 		staging:  make(map[externalapi.DomainHash]*externalapi.DomainBlock),
 		toDelete: make(map[externalapi.DomainHash]struct{}),
+		cache:    lrucache.New(cacheSize),
 	}
 
 	err := blockStore.initializeCount(dbContext)
@@ -54,14 +57,8 @@ func (bs *blockStore) initializeCount(dbContext model.DBReader) error {
 }
 
 // Stage stages the given block for the given blockHash
-func (bs *blockStore) Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) error {
-	clone, err := bs.clone(block)
-	if err != nil {
-		return err
-	}
-
-	bs.staging[*blockHash] = clone
-	return nil
+func (bs *blockStore) Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) {
+	bs.staging[*blockHash] = block.Clone()
 }
 
 func (bs *blockStore) IsStaged() bool {
@@ -83,6 +80,7 @@ func (bs *blockStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		bs.cache.Add(&hash, block)
 	}
 
 	for hash := range bs.toDelete {
@@ -90,6 +88,7 @@ func (bs *blockStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		bs.cache.Remove(&hash)
 	}
 
 	err := bs.commitCount(dbTx)
@@ -104,7 +103,11 @@ func (bs *blockStore) Commit(dbTx model.DBTransaction) error {
 // Block gets the block associated with the given blockHash
 func (bs *blockStore) Block(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) {
 	if block, ok := bs.staging[*blockHash]; ok {
-		return block, nil
+		return block.Clone(), nil
+	}
+
+	if block, ok := bs.cache.Get(blockHash); ok {
+		return block.(*externalapi.DomainBlock).Clone(), nil
 	}
 
 	blockBytes, err := dbContext.Get(bs.hashAsKey(blockHash))
@@ -112,7 +115,12 @@ func (bs *blockStore) Block(dbContext model.DBReader, blockHash *externalapi.Dom
 		return nil, err
 	}
 
-	return bs.deserializeBlock(blockBytes)
+	block, err := bs.deserializeBlock(blockBytes)
+	if err != nil {
+		return nil, err
+	}
+	bs.cache.Add(blockHash, block)
+	return block.Clone(), nil
 }
 
 // HasBlock returns whether a block with a given hash exists in the store.
@@ -121,6 +129,10 @@ func (bs *blockStore) HasBlock(dbContext model.DBReader, blockHash *externalapi.
 		return true, nil
 	}
 
+	if bs.cache.Has(blockHash) {
+		return true, nil
+	}
+
 	exists, err := dbContext.Has(bs.hashAsKey(blockHash))
 	if err != nil {
 		return false, err
@@ -169,15 +181,6 @@ func (bs *blockStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey {
 	return bucket.Key(hash[:])
 }
 
-func (bs *blockStore) clone(block *externalapi.DomainBlock) (*externalapi.DomainBlock, error) {
-	serialized, err := bs.serializeBlock(block)
-	if err != nil {
-		return nil, err
-	}
-
-	return bs.deserializeBlock(serialized)
-}
-
 func (bs *blockStore) Count() uint64 {
 	return bs.count + uint64(len(bs.staging)) - uint64(len(bs.toDelete))
 }
diff --git a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go
index b84f213c..aaa096a1 100644
--- a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go
+++ b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go
@@ -6,6 +6,7 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
 )
 
 var bucket = dbkeys.MakeBucket([]byte("block-ghostdag-data"))
@@ -13,24 +14,20 @@ var bucket = dbkeys.MakeBucket([]byte("block-ghostdag-data"))
 // ghostdagDataStore represents a store of BlockGHOSTDAGData
 type ghostdagDataStore struct {
 	staging map[externalapi.DomainHash]*model.BlockGHOSTDAGData
+	cache   *lrucache.LRUCache
 }
 
 // New instantiates a new GHOSTDAGDataStore
-func New() model.GHOSTDAGDataStore {
+func New(cacheSize int) model.GHOSTDAGDataStore {
 	return &ghostdagDataStore{
 		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) error {
-	clone, err := gds.clone(blockGHOSTDAGData)
-	if err != nil {
-		return err
-	}
-
-	gds.staging[*blockHash] = clone
-	return nil
+func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) {
+	gds.staging[*blockHash] = blockGHOSTDAGData.Clone()
 }
 
 func (gds *ghostdagDataStore) IsStaged() bool {
@@ -47,11 +44,11 @@ func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
-
 		err = dbTx.Put(gds.hashAsKey(&hash), blockGhostdagDataBytes)
 		if err != nil {
 			return err
 		}
+		gds.cache.Add(&hash, blockGHOSTDAGData)
 	}
 
 	gds.Discard()
@@ -61,7 +58,11 @@ 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) {
 	if blockGHOSTDAGData, ok := gds.staging[*blockHash]; ok {
-		return blockGHOSTDAGData, nil
+		return blockGHOSTDAGData.Clone(), nil
+	}
+
+	if blockGHOSTDAGData, ok := gds.cache.Get(blockHash); ok {
+		return blockGHOSTDAGData.(*model.BlockGHOSTDAGData).Clone(), nil
 	}
 
 	blockGHOSTDAGDataBytes, err := dbContext.Get(gds.hashAsKey(blockHash))
@@ -69,7 +70,12 @@ func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externala
 		return nil, err
 	}
 
-	return gds.deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes)
+	blockGHOSTDAGData, err := gds.deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes)
+	if err != nil {
+		return nil, err
+	}
+	gds.cache.Add(blockHash, blockGHOSTDAGData)
+	return blockGHOSTDAGData.Clone(), nil
 }
 
 func (gds *ghostdagDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey {
@@ -89,12 +95,3 @@ func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataByte
 
 	return serialization.DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData)
 }
-
-func (gds *ghostdagDataStore) clone(blockGHOSTDAGData *model.BlockGHOSTDAGData) (*model.BlockGHOSTDAGData, error) {
-	serialized, err := gds.serializeBlockGHOSTDAGData(blockGHOSTDAGData)
-	if err != nil {
-		return nil, err
-	}
-
-	return gds.deserializeBlockGHOSTDAGData(serialized)
-}
diff --git a/domain/consensus/datastructures/headertipsstore/headertipsstore.go b/domain/consensus/datastructures/headertipsstore/headertipsstore.go
index c404a431..cb36b6ee 100644
--- a/domain/consensus/datastructures/headertipsstore/headertipsstore.go
+++ b/domain/consensus/datastructures/headertipsstore/headertipsstore.go
@@ -12,56 +12,64 @@ var headerTipsKey = dbkeys.MakeBucket().Key([]byte("header-tips"))
 
 type headerTipsStore struct {
 	staging []*externalapi.DomainHash
+	cache   []*externalapi.DomainHash
 }
 
-func (h *headerTipsStore) HasTips(dbContext model.DBReader) (bool, error) {
-	if h.staging != nil {
-		return len(h.staging) > 0, nil
+// New instantiates a new HeaderTipsStore
+func New() model.HeaderTipsStore {
+	return &headerTipsStore{}
+}
+
+func (hts *headerTipsStore) HasTips(dbContext model.DBReader) (bool, error) {
+	if len(hts.staging) > 0 {
+		return true, nil
+	}
+
+	if len(hts.cache) > 0 {
+		return true, nil
 	}
 
 	return dbContext.Has(headerTipsKey)
 }
 
-func (h *headerTipsStore) Discard() {
-	h.staging = nil
+func (hts *headerTipsStore) Discard() {
+	hts.staging = nil
 }
 
-func (h *headerTipsStore) Commit(dbTx model.DBTransaction) error {
-	if h.staging == nil {
+func (hts *headerTipsStore) Commit(dbTx model.DBTransaction) error {
+	if hts.staging == nil {
 		return nil
 	}
 
-	tipsBytes, err := h.serializeTips(h.staging)
+	tipsBytes, err := hts.serializeTips(hts.staging)
 	if err != nil {
 		return err
 	}
-
 	err = dbTx.Put(headerTipsKey, tipsBytes)
 	if err != nil {
 		return err
 	}
+	hts.cache = hts.staging
 
-	h.Discard()
+	hts.Discard()
 	return nil
 }
 
-func (h *headerTipsStore) Stage(tips []*externalapi.DomainHash) error {
-	clone, err := h.clone(tips)
-	if err != nil {
-		return err
-	}
-
-	h.staging = clone
-	return nil
+func (hts *headerTipsStore) Stage(tips []*externalapi.DomainHash) {
+	hts.staging = externalapi.CloneHashes(tips)
 }
 
-func (h *headerTipsStore) IsStaged() bool {
-	return h.staging != nil
+func (hts *headerTipsStore) IsStaged() bool {
+	return hts.staging != nil
 }
 
-func (h *headerTipsStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) {
-	if h.staging != nil {
-		return h.staging, nil
+func (hts *headerTipsStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) {
+	if hts.staging != nil {
+		return externalapi.CloneHashes(hts.staging), nil
+	}
+
+	if hts.cache != nil {
+		return externalapi.CloneHashes(hts.cache), nil
 	}
 
 	tipsBytes, err := dbContext.Get(headerTipsKey)
@@ -69,15 +77,20 @@ func (h *headerTipsStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainH
 		return nil, err
 	}
 
-	return h.deserializeTips(tipsBytes)
+	tips, err := hts.deserializeTips(tipsBytes)
+	if err != nil {
+		return nil, err
+	}
+	hts.cache = tips
+	return externalapi.CloneHashes(tips), nil
 }
 
-func (h *headerTipsStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) {
+func (hts *headerTipsStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) {
 	dbTips := serialization.HeaderTipsToDBHeaderTips(tips)
 	return proto.Marshal(dbTips)
 }
 
-func (h *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, error) {
+func (hts *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, error) {
 	dbTips := &serialization.DbHeaderTips{}
 	err := proto.Unmarshal(tipsBytes, dbTips)
 	if err != nil {
@@ -86,19 +99,3 @@ func (h *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.Doma
 
 	return serialization.DBHeaderTipsToHeaderTips(dbTips)
 }
-
-func (h *headerTipsStore) clone(tips []*externalapi.DomainHash,
-) ([]*externalapi.DomainHash, error) {
-
-	serialized, err := h.serializeTips(tips)
-	if err != nil {
-		return nil, err
-	}
-
-	return h.deserializeTips(serialized)
-}
-
-// New instantiates a new HeaderTipsStore
-func New() model.HeaderTipsStore {
-	return &headerTipsStore{}
-}
diff --git a/domain/consensus/datastructures/multisetstore/multisetstore.go b/domain/consensus/datastructures/multisetstore/multisetstore.go
index 176a1bfe..17aa680c 100644
--- a/domain/consensus/datastructures/multisetstore/multisetstore.go
+++ b/domain/consensus/datastructures/multisetstore/multisetstore.go
@@ -6,6 +6,7 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
 )
 
 var bucket = dbkeys.MakeBucket([]byte("multisets"))
@@ -14,19 +15,21 @@ var bucket = dbkeys.MakeBucket([]byte("multisets"))
 type multisetStore struct {
 	staging  map[externalapi.DomainHash]model.Multiset
 	toDelete map[externalapi.DomainHash]struct{}
+	cache    *lrucache.LRUCache
 }
 
 // New instantiates a new MultisetStore
-func New() model.MultisetStore {
+func New(cacheSize int) model.MultisetStore {
 	return &multisetStore{
 		staging:  make(map[externalapi.DomainHash]model.Multiset),
 		toDelete: make(map[externalapi.DomainHash]struct{}),
+		cache:    lrucache.New(cacheSize),
 	}
 }
 
 // Stage stages the given multiset for the given blockHash
 func (ms *multisetStore) Stage(blockHash *externalapi.DomainHash, multiset model.Multiset) {
-	ms.staging[*blockHash] = multiset
+	ms.staging[*blockHash] = multiset.Clone()
 }
 
 func (ms *multisetStore) IsStaged() bool {
@@ -44,11 +47,11 @@ func (ms *multisetStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
-
 		err = dbTx.Put(ms.hashAsKey(&hash), multisetBytes)
 		if err != nil {
 			return err
 		}
+		ms.cache.Add(&hash, multiset)
 	}
 
 	for hash := range ms.toDelete {
@@ -56,6 +59,7 @@ func (ms *multisetStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		ms.cache.Remove(&hash)
 	}
 
 	ms.Discard()
@@ -65,7 +69,11 @@ func (ms *multisetStore) Commit(dbTx model.DBTransaction) error {
 // Get gets the multiset associated with the given blockHash
 func (ms *multisetStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.Multiset, error) {
 	if multiset, ok := ms.staging[*blockHash]; ok {
-		return multiset.Clone()
+		return multiset.Clone(), nil
+	}
+
+	if multiset, ok := ms.cache.Get(blockHash); ok {
+		return multiset.(model.Multiset).Clone(), nil
 	}
 
 	multisetBytes, err := dbContext.Get(ms.hashAsKey(blockHash))
@@ -73,7 +81,12 @@ func (ms *multisetStore) Get(dbContext model.DBReader, blockHash *externalapi.Do
 		return nil, err
 	}
 
-	return ms.deserializeMultiset(multisetBytes)
+	multiset, err := ms.deserializeMultiset(multisetBytes)
+	if err != nil {
+		return nil, err
+	}
+	ms.cache.Add(blockHash, multiset)
+	return multiset.Clone(), nil
 }
 
 // Delete deletes the multiset associated with the given blockHash
diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go
index e72f531a..646f6bba 100644
--- a/domain/consensus/datastructures/pruningstore/pruningstore.go
+++ b/domain/consensus/datastructures/pruningstore/pruningstore.go
@@ -15,19 +15,17 @@ var pruningSerializedUTXOSetkey = dbkeys.MakeBucket().Key([]byte("pruning-utxo-s
 type pruningStore struct {
 	pruningPointStaging      *externalapi.DomainHash
 	serializedUTXOSetStaging []byte
+	pruningPointCache        *externalapi.DomainHash
 }
 
 // New instantiates a new PruningStore
 func New() model.PruningStore {
-	return &pruningStore{
-		pruningPointStaging:      nil,
-		serializedUTXOSetStaging: nil,
-	}
+	return &pruningStore{}
 }
 
 // Stage stages the pruning state
 func (ps *pruningStore) Stage(pruningPointBlockHash *externalapi.DomainHash, pruningPointUTXOSetBytes []byte) {
-	ps.pruningPointStaging = &(*pruningPointBlockHash)
+	ps.pruningPointStaging = pruningPointBlockHash.Clone()
 	ps.serializedUTXOSetStaging = pruningPointUTXOSetBytes
 }
 
@@ -50,6 +48,7 @@ func (ps *pruningStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		ps.pruningPointCache = ps.pruningPointStaging
 	}
 
 	if ps.serializedUTXOSetStaging != nil {
@@ -57,7 +56,6 @@ func (ps *pruningStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
-
 		err = dbTx.Put(pruningSerializedUTXOSetkey, utxoSetBytes)
 		if err != nil {
 			return err
@@ -74,16 +72,21 @@ func (ps *pruningStore) PruningPoint(dbContext model.DBReader) (*externalapi.Dom
 		return ps.pruningPointStaging, nil
 	}
 
-	blockHashBytes, err := dbContext.Get(pruningBlockHashKey)
+	if ps.pruningPointCache != nil {
+		return ps.pruningPointCache, nil
+	}
+
+	pruningPointBytes, err := dbContext.Get(pruningBlockHashKey)
 	if err != nil {
 		return nil, err
 	}
 
-	blockHash, err := ps.deserializePruningPoint(blockHashBytes)
+	pruningPoint, err := ps.deserializePruningPoint(pruningPointBytes)
 	if err != nil {
 		return nil, err
 	}
-	return blockHash, nil
+	ps.pruningPointCache = pruningPoint
+	return pruningPoint, nil
 }
 
 // PruningPointSerializedUTXOSet returns the serialized UTXO set of the current pruning point
@@ -97,7 +100,11 @@ func (ps *pruningStore) PruningPointSerializedUTXOSet(dbContext model.DBReader)
 		return nil, err
 	}
 
-	return ps.deserializeUTXOSetBytes(dbPruningPointUTXOSetBytes)
+	pruningPointUTXOSet, err := ps.deserializeUTXOSetBytes(dbPruningPointUTXOSetBytes)
+	if err != nil {
+		return nil, err
+	}
+	return pruningPointUTXOSet, nil
 }
 
 func (ps *pruningStore) serializePruningPoint(pruningPoint *externalapi.DomainHash) ([]byte, error) {
@@ -133,5 +140,9 @@ func (ps *pruningStore) HasPruningPoint(dbContext model.DBReader) (bool, error)
 		return true, nil
 	}
 
+	if ps.pruningPointCache != nil {
+		return true, nil
+	}
+
 	return dbContext.Has(pruningBlockHashKey)
 }
diff --git a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go
index e7f996cf..f466e9d9 100644
--- a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go
+++ b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go
@@ -6,6 +6,7 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
 )
 
 var reachabilityDataBucket = dbkeys.MakeBucket([]byte("reachability-data"))
@@ -15,26 +16,22 @@ var reachabilityReindexRootKey = dbkeys.MakeBucket().Key([]byte("reachability-re
 type reachabilityDataStore struct {
 	reachabilityDataStaging        map[externalapi.DomainHash]*model.ReachabilityData
 	reachabilityReindexRootStaging *externalapi.DomainHash
+	reachabilityDataCache          *lrucache.LRUCache
+	reachabilityReindexRootCache   *externalapi.DomainHash
 }
 
 // New instantiates a new ReachabilityDataStore
-func New() model.ReachabilityDataStore {
+func New(cacheSize int) model.ReachabilityDataStore {
 	return &reachabilityDataStore{
-		reachabilityDataStaging:        make(map[externalapi.DomainHash]*model.ReachabilityData),
-		reachabilityReindexRootStaging: nil,
+		reachabilityDataStaging: make(map[externalapi.DomainHash]*model.ReachabilityData),
+		reachabilityDataCache:   lrucache.New(cacheSize),
 	}
 }
 
 // StageReachabilityData stages the given reachabilityData for the given blockHash
 func (rds *reachabilityDataStore) StageReachabilityData(blockHash *externalapi.DomainHash,
-	reachabilityData *model.ReachabilityData) error {
-	clone, err := rds.cloneReachabilityData(reachabilityData)
-	if err != nil {
-		return err
-	}
-
-	rds.reachabilityDataStaging[*blockHash] = clone
-	return nil
+	reachabilityData *model.ReachabilityData) {
+	rds.reachabilityDataStaging[*blockHash] = reachabilityData.Clone()
 }
 
 // StageReachabilityReindexRoot stages the given reachabilityReindexRoot
@@ -57,22 +54,22 @@ func (rds *reachabilityDataStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
-
 		err = dbTx.Put(reachabilityReindexRootKey, reachabilityReindexRootBytes)
 		if err != nil {
 			return err
 		}
+		rds.reachabilityReindexRootCache = rds.reachabilityReindexRootStaging
 	}
 	for hash, reachabilityData := range rds.reachabilityDataStaging {
 		reachabilityDataBytes, err := rds.serializeReachabilityData(reachabilityData)
 		if err != nil {
 			return err
 		}
-
 		err = dbTx.Put(rds.reachabilityDataBlockHashAsKey(&hash), reachabilityDataBytes)
 		if err != nil {
 			return err
 		}
+		rds.reachabilityDataCache.Add(&hash, reachabilityData)
 	}
 
 	rds.Discard()
@@ -84,7 +81,11 @@ func (rds *reachabilityDataStore) ReachabilityData(dbContext model.DBReader,
 	blockHash *externalapi.DomainHash) (*model.ReachabilityData, error) {
 
 	if reachabilityData, ok := rds.reachabilityDataStaging[*blockHash]; ok {
-		return reachabilityData, nil
+		return reachabilityData.Clone(), nil
+	}
+
+	if reachabilityData, ok := rds.reachabilityDataCache.Get(blockHash); ok {
+		return reachabilityData.(*model.ReachabilityData).Clone(), nil
 	}
 
 	reachabilityDataBytes, err := dbContext.Get(rds.reachabilityDataBlockHashAsKey(blockHash))
@@ -92,7 +93,12 @@ func (rds *reachabilityDataStore) ReachabilityData(dbContext model.DBReader,
 		return nil, err
 	}
 
-	return rds.deserializeReachabilityData(reachabilityDataBytes)
+	reachabilityData, err := rds.deserializeReachabilityData(reachabilityDataBytes)
+	if err != nil {
+		return nil, err
+	}
+	rds.reachabilityDataCache.Add(blockHash, reachabilityData)
+	return reachabilityData.Clone(), nil
 }
 
 func (rds *reachabilityDataStore) HasReachabilityData(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) {
@@ -100,6 +106,10 @@ func (rds *reachabilityDataStore) HasReachabilityData(dbContext model.DBReader,
 		return true, nil
 	}
 
+	if rds.reachabilityDataCache.Has(blockHash) {
+		return true, nil
+	}
+
 	return dbContext.Has(rds.reachabilityDataBlockHashAsKey(blockHash))
 }
 
@@ -108,6 +118,11 @@ func (rds *reachabilityDataStore) ReachabilityReindexRoot(dbContext model.DBRead
 	if rds.reachabilityReindexRootStaging != nil {
 		return rds.reachabilityReindexRootStaging, nil
 	}
+
+	if rds.reachabilityReindexRootCache != nil {
+		return rds.reachabilityReindexRootCache, nil
+	}
+
 	reachabilityReindexRootBytes, err := dbContext.Get(reachabilityReindexRootKey)
 	if err != nil {
 		return nil, err
@@ -117,6 +132,7 @@ func (rds *reachabilityDataStore) ReachabilityReindexRoot(dbContext model.DBRead
 	if err != nil {
 		return nil, err
 	}
+	rds.reachabilityReindexRootCache = reachabilityReindexRoot
 	return reachabilityReindexRoot, nil
 }
 
@@ -151,12 +167,3 @@ func (rds *reachabilityDataStore) deserializeReachabilityReindexRoot(reachabilit
 
 	return serialization.DbHashToDomainHash(dbHash)
 }
-
-func (rds *reachabilityDataStore) cloneReachabilityData(reachabilityData *model.ReachabilityData) (*model.ReachabilityData, error) {
-	serialized, err := rds.serializeReachabilityData(reachabilityData)
-	if err != nil {
-		return nil, err
-	}
-
-	return rds.deserializeReachabilityData(serialized)
-}
diff --git a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go
index 58442400..ea0b14dc 100644
--- a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go
+++ b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go
@@ -6,6 +6,7 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
 	"github.com/pkg/errors"
 )
 
@@ -17,30 +18,28 @@ type utxoDiffStore struct {
 	utxoDiffStaging      map[externalapi.DomainHash]*model.UTXODiff
 	utxoDiffChildStaging map[externalapi.DomainHash]*externalapi.DomainHash
 	toDelete             map[externalapi.DomainHash]struct{}
+	utxoDiffCache        *lrucache.LRUCache
+	utxoDiffChildCache   *lrucache.LRUCache
 }
 
 // New instantiates a new UTXODiffStore
-func New() model.UTXODiffStore {
+func New(cacheSize int) model.UTXODiffStore {
 	return &utxoDiffStore{
 		utxoDiffStaging:      make(map[externalapi.DomainHash]*model.UTXODiff),
 		utxoDiffChildStaging: make(map[externalapi.DomainHash]*externalapi.DomainHash),
 		toDelete:             make(map[externalapi.DomainHash]struct{}),
+		utxoDiffCache:        lrucache.New(cacheSize),
+		utxoDiffChildCache:   lrucache.New(cacheSize),
 	}
 }
 
 // Stage stages the given utxoDiff for the given blockHash
-func (uds *utxoDiffStore) Stage(blockHash *externalapi.DomainHash, utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) error {
-	utxoDiffClone, err := uds.cloneUTXODiff(utxoDiff)
-	if err != nil {
-		return err
-	}
-	uds.utxoDiffStaging[*blockHash] = utxoDiffClone
+func (uds *utxoDiffStore) Stage(blockHash *externalapi.DomainHash, utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) {
+	uds.utxoDiffStaging[*blockHash] = utxoDiff.Clone()
 
 	if utxoDiffChild != nil {
-		utxoDiffChildClone := uds.cloneUTXODiffChild(utxoDiffChild)
-		uds.utxoDiffChildStaging[*blockHash] = utxoDiffChildClone
+		uds.utxoDiffChildStaging[*blockHash] = utxoDiffChild.Clone()
 	}
-	return nil
 }
 
 func (uds *utxoDiffStore) IsStaged() bool {
@@ -67,11 +66,11 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
-
 		err = dbTx.Put(uds.utxoDiffHashAsKey(&hash), utxoDiffBytes)
 		if err != nil {
 			return err
 		}
+		uds.utxoDiffCache.Add(&hash, utxoDiff)
 	}
 	for hash, utxoDiffChild := range uds.utxoDiffChildStaging {
 		if utxoDiffChild == nil {
@@ -86,6 +85,7 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		uds.utxoDiffChildCache.Add(&hash, utxoDiffChild)
 	}
 
 	for hash := range uds.toDelete {
@@ -93,11 +93,13 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error {
 		if err != nil {
 			return err
 		}
+		uds.utxoDiffCache.Remove(&hash)
 
 		err = dbTx.Delete(uds.utxoDiffChildHashAsKey(&hash))
 		if err != nil {
 			return err
 		}
+		uds.utxoDiffChildCache.Remove(&hash)
 	}
 
 	uds.Discard()
@@ -107,7 +109,11 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error {
 // UTXODiff gets the utxoDiff associated with the given blockHash
 func (uds *utxoDiffStore) UTXODiff(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.UTXODiff, error) {
 	if utxoDiff, ok := uds.utxoDiffStaging[*blockHash]; ok {
-		return utxoDiff, nil
+		return utxoDiff.Clone(), nil
+	}
+
+	if utxoDiff, ok := uds.utxoDiffCache.Get(blockHash); ok {
+		return utxoDiff.(*model.UTXODiff).Clone(), nil
 	}
 
 	utxoDiffBytes, err := dbContext.Get(uds.utxoDiffHashAsKey(blockHash))
@@ -115,13 +121,22 @@ func (uds *utxoDiffStore) UTXODiff(dbContext model.DBReader, blockHash *external
 		return nil, err
 	}
 
-	return uds.deserializeUTXODiff(utxoDiffBytes)
+	utxoDiff, err := uds.deserializeUTXODiff(utxoDiffBytes)
+	if err != nil {
+		return nil, err
+	}
+	uds.utxoDiffCache.Add(blockHash, utxoDiff)
+	return utxoDiff.Clone(), nil
 }
 
 // UTXODiffChild gets the utxoDiff child associated with the given blockHash
 func (uds *utxoDiffStore) UTXODiffChild(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) {
 	if utxoDiffChild, ok := uds.utxoDiffChildStaging[*blockHash]; ok {
-		return utxoDiffChild, nil
+		return utxoDiffChild.Clone(), nil
+	}
+
+	if utxoDiffChild, ok := uds.utxoDiffChildCache.Get(blockHash); ok {
+		return utxoDiffChild.(*externalapi.DomainHash).Clone(), nil
 	}
 
 	utxoDiffChildBytes, err := dbContext.Get(uds.utxoDiffChildHashAsKey(blockHash))
@@ -133,7 +148,8 @@ func (uds *utxoDiffStore) UTXODiffChild(dbContext model.DBReader, blockHash *ext
 	if err != nil {
 		return nil, err
 	}
-	return utxoDiffChild, nil
+	uds.utxoDiffChildCache.Add(blockHash, utxoDiffChild)
+	return utxoDiffChild.Clone(), nil
 }
 
 // HasUTXODiffChild returns true if the given blockHash has a UTXODiffChild
@@ -142,6 +158,10 @@ func (uds *utxoDiffStore) HasUTXODiffChild(dbContext model.DBReader, blockHash *
 		return true, nil
 	}
 
+	if uds.utxoDiffChildCache.Has(blockHash) {
+		return true, nil
+	}
+
 	return dbContext.Has(uds.utxoDiffChildHashAsKey(blockHash))
 }
 
@@ -203,16 +223,3 @@ func (uds *utxoDiffStore) deserializeUTXODiffChild(utxoDiffChildBytes []byte) (*
 
 	return serialization.DbHashToDomainHash(dbHash)
 }
-
-func (uds *utxoDiffStore) cloneUTXODiff(diff *model.UTXODiff) (*model.UTXODiff, error) {
-	serialized, err := uds.serializeUTXODiff(diff)
-	if err != nil {
-		return nil, err
-	}
-
-	return uds.deserializeUTXODiff(serialized)
-}
-
-func (uds *utxoDiffStore) cloneUTXODiffChild(diffChild *externalapi.DomainHash) *externalapi.DomainHash {
-	return diffChild.Clone()
-}
diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go
index 5ea856d7..5d68536d 100644
--- a/domain/consensus/factory.go
+++ b/domain/consensus/factory.go
@@ -62,23 +62,24 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
 	dbManager := consensusdatabase.New(db)
 
 	// Data Structures
-	acceptanceDataStore := acceptancedatastore.New()
-	blockStore, err := blockstore.New(dbManager)
+	storeCacheSize := int(dagParams.FinalityDepth())
+	acceptanceDataStore := acceptancedatastore.New(storeCacheSize)
+	blockStore, err := blockstore.New(dbManager, storeCacheSize)
 	if err != nil {
 		return nil, err
 	}
-	blockHeaderStore, err := blockheaderstore.New(dbManager)
+	blockHeaderStore, err := blockheaderstore.New(dbManager, storeCacheSize)
 	if err != nil {
 		return nil, err
 	}
-	blockRelationStore := blockrelationstore.New()
-	blockStatusStore := blockstatusstore.New()
-	multisetStore := multisetstore.New()
+	blockRelationStore := blockrelationstore.New(storeCacheSize)
+	blockStatusStore := blockstatusstore.New(storeCacheSize)
+	multisetStore := multisetstore.New(storeCacheSize)
 	pruningStore := pruningstore.New()
-	reachabilityDataStore := reachabilitydatastore.New()
-	utxoDiffStore := utxodiffstore.New()
+	reachabilityDataStore := reachabilitydatastore.New(storeCacheSize)
+	utxoDiffStore := utxodiffstore.New(storeCacheSize)
 	consensusStateStore := consensusstatestore.New()
-	ghostdagDataStore := ghostdagdatastore.New()
+	ghostdagDataStore := ghostdagdatastore.New(storeCacheSize)
 	headerTipsStore := headertipsstore.New()
 
 	// Processes
diff --git a/domain/consensus/model/acceptancedata.go b/domain/consensus/model/acceptancedata.go
index 923e715c..27f79c32 100644
--- a/domain/consensus/model/acceptancedata.go
+++ b/domain/consensus/model/acceptancedata.go
@@ -6,12 +6,39 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 // It's ordered in the same way as the block merge set blues.
 type AcceptanceData []*BlockAcceptanceData
 
+// Clone clones the AcceptanceData
+func (ad AcceptanceData) Clone() AcceptanceData {
+	if ad == nil {
+		return nil
+	}
+	clone := make(AcceptanceData, len(ad))
+	for i, blockAcceptanceData := range ad {
+		clone[i] = blockAcceptanceData.Clone()
+	}
+
+	return clone
+}
+
 // BlockAcceptanceData stores all transactions in a block with an indication
 // if they were accepted or not by some other block
 type BlockAcceptanceData struct {
 	TransactionAcceptanceData []*TransactionAcceptanceData
 }
 
+// Clone returns a clone of BlockAcceptanceData
+func (bad *BlockAcceptanceData) Clone() *BlockAcceptanceData {
+	if bad == nil {
+		return nil
+	}
+
+	clone := &BlockAcceptanceData{TransactionAcceptanceData: make([]*TransactionAcceptanceData, len(bad.TransactionAcceptanceData))}
+	for i, acceptanceData := range bad.TransactionAcceptanceData {
+		clone.TransactionAcceptanceData[i] = acceptanceData.Clone()
+	}
+
+	return clone
+}
+
 // TransactionAcceptanceData stores a transaction together with an indication
 // if it was accepted or not by some block
 type TransactionAcceptanceData struct {
@@ -19,3 +46,16 @@ type TransactionAcceptanceData struct {
 	Fee         uint64
 	IsAccepted  bool
 }
+
+// Clone returns a clone of TransactionAcceptanceData
+func (tad *TransactionAcceptanceData) Clone() *TransactionAcceptanceData {
+	if tad == nil {
+		return nil
+	}
+
+	return &TransactionAcceptanceData{
+		Transaction: tad.Transaction.Clone(),
+		Fee:         tad.Fee,
+		IsAccepted:  tad.IsAccepted,
+	}
+}
diff --git a/domain/consensus/model/blockrelations.go b/domain/consensus/model/blockrelations.go
index 5f326ef8..2ed402d4 100644
--- a/domain/consensus/model/blockrelations.go
+++ b/domain/consensus/model/blockrelations.go
@@ -7,3 +7,15 @@ type BlockRelations struct {
 	Parents  []*externalapi.DomainHash
 	Children []*externalapi.DomainHash
 }
+
+// Clone returns a clone of BlockRelations
+func (br *BlockRelations) Clone() *BlockRelations {
+	if br == nil {
+		return nil
+	}
+
+	return &BlockRelations{
+		Parents:  externalapi.CloneHashes(br.Parents),
+		Children: externalapi.CloneHashes(br.Children),
+	}
+}
diff --git a/domain/consensus/model/externalapi/block.go b/domain/consensus/model/externalapi/block.go
index 522465c4..da499062 100644
--- a/domain/consensus/model/externalapi/block.go
+++ b/domain/consensus/model/externalapi/block.go
@@ -6,6 +6,23 @@ type DomainBlock struct {
 	Transactions []*DomainTransaction
 }
 
+// Clone returns a clone of DomainBlock
+func (block *DomainBlock) Clone() *DomainBlock {
+	if block == nil {
+		return nil
+	}
+
+	transactionClone := make([]*DomainTransaction, len(block.Transactions))
+	for i, tx := range block.Transactions {
+		transactionClone[i] = tx.Clone()
+	}
+
+	return &DomainBlock{
+		Header:       block.Header.Clone(),
+		Transactions: transactionClone,
+	}
+}
+
 // DomainBlockHeader represents the header part of a Kaspa block
 type DomainBlockHeader struct {
 	Version              int32
@@ -17,3 +34,21 @@ type DomainBlockHeader struct {
 	Bits                 uint32
 	Nonce                uint64
 }
+
+// Clone returns a clone of DomainBlockHeader
+func (header *DomainBlockHeader) Clone() *DomainBlockHeader {
+	if header == nil {
+		return nil
+	}
+
+	return &DomainBlockHeader{
+		Version:              header.Version,
+		ParentHashes:         CloneHashes(header.ParentHashes),
+		HashMerkleRoot:       *header.HashMerkleRoot.Clone(),
+		AcceptedIDMerkleRoot: *header.AcceptedIDMerkleRoot.Clone(),
+		UTXOCommitment:       *header.UTXOCommitment.Clone(),
+		TimeInMilliseconds:   header.TimeInMilliseconds,
+		Bits:                 header.Bits,
+		Nonce:                header.Nonce,
+	}
+}
diff --git a/domain/consensus/model/externalapi/blockstatus.go b/domain/consensus/model/externalapi/blockstatus.go
index 50a9b848..8fc15cf3 100644
--- a/domain/consensus/model/externalapi/blockstatus.go
+++ b/domain/consensus/model/externalapi/blockstatus.go
@@ -3,6 +3,11 @@ package externalapi
 // BlockStatus represents the validation state of the block.
 type BlockStatus byte
 
+// Clone returns a clone of BlockStatus
+func (bs BlockStatus) Clone() BlockStatus {
+	return bs
+}
+
 const (
 	// StatusInvalid indicates that the block is invalid.
 	StatusInvalid BlockStatus = iota
diff --git a/domain/consensus/model/externalapi/hash.go b/domain/consensus/model/externalapi/hash.go
index eb19869b..40446d6d 100644
--- a/domain/consensus/model/externalapi/hash.go
+++ b/domain/consensus/model/externalapi/hash.go
@@ -22,7 +22,18 @@ func (hash *DomainHash) Clone() *DomainHash {
 	if hash == nil {
 		return nil
 	}
-	return &*hash
+
+	hashClone := *hash
+	return &hashClone
+}
+
+// CloneHashes returns a clone of the given hashes slice
+func CloneHashes(hashes []*DomainHash) []*DomainHash {
+	clone := make([]*DomainHash, len(hashes))
+	for i, hash := range hashes {
+		clone[i] = hash.Clone()
+	}
+	return clone
 }
 
 // DomainHashesToStrings returns a slice of strings representing the hashes in the given slice of hashes
diff --git a/domain/consensus/model/externalapi/subnetworkid.go b/domain/consensus/model/externalapi/subnetworkid.go
index 51f58084..8a948dff 100644
--- a/domain/consensus/model/externalapi/subnetworkid.go
+++ b/domain/consensus/model/externalapi/subnetworkid.go
@@ -15,3 +15,13 @@ func (id DomainSubnetworkID) String() string {
 	}
 	return hex.EncodeToString(id[:])
 }
+
+// Clone returns a clone of DomainSubnetworkID
+func (id *DomainSubnetworkID) Clone() *DomainSubnetworkID {
+	if id == nil {
+		return nil
+	}
+
+	idClone := *id
+	return &idClone
+}
diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go
index 63e4a10c..32959ec6 100644
--- a/domain/consensus/model/externalapi/transaction.go
+++ b/domain/consensus/model/externalapi/transaction.go
@@ -19,6 +19,39 @@ type DomainTransaction struct {
 	Mass uint64
 }
 
+// Clone returns a clone of DomainTransaction
+func (tx *DomainTransaction) Clone() *DomainTransaction {
+	if tx == nil {
+		return nil
+	}
+
+	payloadClone := make([]byte, len(tx.Payload))
+	copy(payloadClone, tx.Payload)
+
+	inputsClone := make([]*DomainTransactionInput, len(tx.Inputs))
+	for i, input := range tx.Inputs {
+		inputsClone[i] = input.Clone()
+	}
+
+	outputsClone := make([]*DomainTransactionOutput, len(tx.Outputs))
+	for i, output := range tx.Outputs {
+		outputsClone[i] = output.Clone()
+	}
+
+	return &DomainTransaction{
+		Version:      tx.Version,
+		Inputs:       inputsClone,
+		Outputs:      outputsClone,
+		LockTime:     tx.LockTime,
+		SubnetworkID: *tx.SubnetworkID.Clone(),
+		Gas:          tx.Gas,
+		PayloadHash:  *tx.PayloadHash.Clone(),
+		Payload:      payloadClone,
+		Fee:          tx.Fee,
+		Mass:         tx.Mass,
+	}
+}
+
 // DomainTransactionInput represents a Kaspa transaction input
 type DomainTransactionInput struct {
 	PreviousOutpoint DomainOutpoint
@@ -28,12 +61,41 @@ type DomainTransactionInput struct {
 	UTXOEntry *UTXOEntry
 }
 
+// Clone returns a clone of DomainTransactionInput
+func (input *DomainTransactionInput) Clone() *DomainTransactionInput {
+	if input == nil {
+		return nil
+	}
+
+	signatureScriptClone := make([]byte, len(input.SignatureScript))
+	copy(signatureScriptClone, input.SignatureScript)
+
+	return &DomainTransactionInput{
+		PreviousOutpoint: *input.PreviousOutpoint.Clone(),
+		SignatureScript:  signatureScriptClone,
+		Sequence:         input.Sequence,
+		UTXOEntry:        input.UTXOEntry.Clone(),
+	}
+}
+
 // DomainOutpoint represents a Kaspa transaction outpoint
 type DomainOutpoint struct {
 	TransactionID DomainTransactionID
 	Index         uint32
 }
 
+// Clone returns a clone of DomainOutpoint
+func (op *DomainOutpoint) Clone() *DomainOutpoint {
+	if op == nil {
+		return nil
+	}
+
+	return &DomainOutpoint{
+		TransactionID: *op.TransactionID.Clone(),
+		Index:         op.Index,
+	}
+}
+
 // String stringifies an outpoint.
 func (op DomainOutpoint) String() string {
 	return fmt.Sprintf("(%s: %d)", op.TransactionID, op.Index)
@@ -53,6 +115,21 @@ type DomainTransactionOutput struct {
 	ScriptPublicKey []byte
 }
 
+// Clone returns a clone of DomainTransactionOutput
+func (output *DomainTransactionOutput) Clone() *DomainTransactionOutput {
+	if output == nil {
+		return nil
+	}
+
+	scriptPublicKeyClone := make([]byte, len(output.ScriptPublicKey))
+	copy(scriptPublicKeyClone, output.ScriptPublicKey)
+
+	return &DomainTransactionOutput{
+		Value:           output.Value,
+		ScriptPublicKey: scriptPublicKeyClone,
+	}
+}
+
 // DomainTransactionID represents the ID of a Kaspa transaction
 type DomainTransactionID DomainHash
 
@@ -60,3 +137,13 @@ type DomainTransactionID DomainHash
 func (id DomainTransactionID) String() string {
 	return DomainHash(id).String()
 }
+
+// Clone returns a clone of DomainTransactionID
+func (id *DomainTransactionID) Clone() *DomainTransactionID {
+	if id == nil {
+		return nil
+	}
+
+	idClone := *id
+	return &idClone
+}
diff --git a/domain/consensus/model/externalapi/utxoentry.go b/domain/consensus/model/externalapi/utxoentry.go
index 9aa98c31..69f5a475 100644
--- a/domain/consensus/model/externalapi/utxoentry.go
+++ b/domain/consensus/model/externalapi/utxoentry.go
@@ -11,6 +11,23 @@ type UTXOEntry struct {
 	IsCoinbase      bool
 }
 
+// Clone returns a clone of UTXOEntry
+func (entry *UTXOEntry) Clone() *UTXOEntry {
+	if entry == nil {
+		return nil
+	}
+
+	scriptPublicKeyClone := make([]byte, len(entry.ScriptPublicKey))
+	copy(scriptPublicKeyClone, entry.ScriptPublicKey)
+
+	return &UTXOEntry{
+		Amount:          entry.Amount,
+		ScriptPublicKey: scriptPublicKeyClone,
+		BlockBlueScore:  entry.BlockBlueScore,
+		IsCoinbase:      entry.IsCoinbase,
+	}
+}
+
 // NewUTXOEntry creates a new utxoEntry representing the given txOut
 func NewUTXOEntry(amount uint64, scriptPubKey []byte, isCoinbase bool, blockBlueScore uint64) *UTXOEntry {
 	return &UTXOEntry{
diff --git a/domain/consensus/model/ghostdag.go b/domain/consensus/model/ghostdag.go
index 335d634a..d649c34a 100644
--- a/domain/consensus/model/ghostdag.go
+++ b/domain/consensus/model/ghostdag.go
@@ -11,5 +11,25 @@ type BlockGHOSTDAGData struct {
 	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.
 type KType byte
diff --git a/domain/consensus/model/interface_datastructures_acceptancedatastore.go b/domain/consensus/model/interface_datastructures_acceptancedatastore.go
index db656cd4..4d75e122 100644
--- a/domain/consensus/model/interface_datastructures_acceptancedatastore.go
+++ b/domain/consensus/model/interface_datastructures_acceptancedatastore.go
@@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 // AcceptanceDataStore represents a store of AcceptanceData
 type AcceptanceDataStore interface {
 	Store
-	Stage(blockHash *externalapi.DomainHash, acceptanceData AcceptanceData) error
+	Stage(blockHash *externalapi.DomainHash, acceptanceData AcceptanceData)
 	IsStaged() bool
 	Get(dbContext DBReader, blockHash *externalapi.DomainHash) (AcceptanceData, error)
 	Delete(blockHash *externalapi.DomainHash)
diff --git a/domain/consensus/model/interface_datastructures_blockheaderstore.go b/domain/consensus/model/interface_datastructures_blockheaderstore.go
index e6d5be9b..20edf9c0 100644
--- a/domain/consensus/model/interface_datastructures_blockheaderstore.go
+++ b/domain/consensus/model/interface_datastructures_blockheaderstore.go
@@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 // BlockHeaderStore represents a store of block headers
 type BlockHeaderStore interface {
 	Store
-	Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) error
+	Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader)
 	IsStaged() bool
 	BlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error)
 	HasBlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error)
diff --git a/domain/consensus/model/interface_datastructures_blockrelationstore.go b/domain/consensus/model/interface_datastructures_blockrelationstore.go
index e34cca75..b4274c68 100644
--- a/domain/consensus/model/interface_datastructures_blockrelationstore.go
+++ b/domain/consensus/model/interface_datastructures_blockrelationstore.go
@@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 // BlockRelationStore represents a store of BlockRelations
 type BlockRelationStore interface {
 	Store
-	StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *BlockRelations) error
+	StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *BlockRelations)
 	IsStaged() bool
 	BlockRelation(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockRelations, error)
 	Has(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error)
diff --git a/domain/consensus/model/interface_datastructures_blockstore.go b/domain/consensus/model/interface_datastructures_blockstore.go
index 0ebc8dc6..f2aadb56 100644
--- a/domain/consensus/model/interface_datastructures_blockstore.go
+++ b/domain/consensus/model/interface_datastructures_blockstore.go
@@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 // BlockStore represents a store of blocks
 type BlockStore interface {
 	Store
-	Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) error
+	Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock)
 	IsStaged() bool
 	Block(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error)
 	HasBlock(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error)
diff --git a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go
index 7d8f4c04..13522feb 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) error
+	Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *BlockGHOSTDAGData)
 	IsStaged() bool
 	Get(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockGHOSTDAGData, error)
 }
diff --git a/domain/consensus/model/interface_datastructures_headertipsstore.go b/domain/consensus/model/interface_datastructures_headertipsstore.go
index b285599b..df3bc6dc 100644
--- a/domain/consensus/model/interface_datastructures_headertipsstore.go
+++ b/domain/consensus/model/interface_datastructures_headertipsstore.go
@@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 // HeaderTipsStore represents a store of the header tips
 type HeaderTipsStore interface {
 	Store
-	Stage(tips []*externalapi.DomainHash) error
+	Stage(tips []*externalapi.DomainHash)
 	IsStaged() bool
 	Tips(dbContext DBReader) ([]*externalapi.DomainHash, error)
 	HasTips(dbContext DBReader) (bool, error)
diff --git a/domain/consensus/model/interface_datastructures_reachabilitydatastore.go b/domain/consensus/model/interface_datastructures_reachabilitydatastore.go
index 5d82c138..e1225b19 100644
--- a/domain/consensus/model/interface_datastructures_reachabilitydatastore.go
+++ b/domain/consensus/model/interface_datastructures_reachabilitydatastore.go
@@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 // ReachabilityDataStore represents a store of ReachabilityData
 type ReachabilityDataStore interface {
 	Store
-	StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *ReachabilityData) error
+	StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *ReachabilityData)
 	StageReachabilityReindexRoot(reachabilityReindexRoot *externalapi.DomainHash)
 	IsAnythingStaged() bool
 	ReachabilityData(dbContext DBReader, blockHash *externalapi.DomainHash) (*ReachabilityData, error)
diff --git a/domain/consensus/model/interface_datastructures_utxodiffstore.go b/domain/consensus/model/interface_datastructures_utxodiffstore.go
index 4388d4b3..4d7ab310 100644
--- a/domain/consensus/model/interface_datastructures_utxodiffstore.go
+++ b/domain/consensus/model/interface_datastructures_utxodiffstore.go
@@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 // UTXODiffStore represents a store of UTXODiffs
 type UTXODiffStore interface {
 	Store
-	Stage(blockHash *externalapi.DomainHash, utxoDiff *UTXODiff, utxoDiffChild *externalapi.DomainHash) error
+	Stage(blockHash *externalapi.DomainHash, utxoDiff *UTXODiff, utxoDiffChild *externalapi.DomainHash)
 	IsStaged() bool
 	UTXODiff(dbContext DBReader, blockHash *externalapi.DomainHash) (*UTXODiff, error)
 	UTXODiffChild(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error)
diff --git a/domain/consensus/model/multiset.go b/domain/consensus/model/multiset.go
index bf176d0b..086c42e0 100644
--- a/domain/consensus/model/multiset.go
+++ b/domain/consensus/model/multiset.go
@@ -8,5 +8,5 @@ type Multiset interface {
 	Remove(data []byte)
 	Hash() *externalapi.DomainHash
 	Serialize() []byte
-	Clone() (Multiset, error)
+	Clone() Multiset
 }
diff --git a/domain/consensus/model/reachabilitydata.go b/domain/consensus/model/reachabilitydata.go
index 0efb7b62..93ffd3b2 100644
--- a/domain/consensus/model/reachabilitydata.go
+++ b/domain/consensus/model/reachabilitydata.go
@@ -12,6 +12,18 @@ type ReachabilityData struct {
 	FutureCoveringSet FutureCoveringTreeNodeSet
 }
 
+// Clone returns a clone of ReachabilityData
+func (rd *ReachabilityData) Clone() *ReachabilityData {
+	if rd == nil {
+		return nil
+	}
+
+	return &ReachabilityData{
+		TreeNode:          rd.TreeNode.Clone(),
+		FutureCoveringSet: externalapi.CloneHashes(rd.FutureCoveringSet),
+	}
+}
+
 // ReachabilityTreeNode represents a node in the reachability tree
 // of some DAG block. It mainly provides the ability to query *tree*
 // reachability with O(1) query time. It does so by managing an
@@ -36,6 +48,19 @@ type ReachabilityTreeNode struct {
 	Interval *ReachabilityInterval
 }
 
+// Clone returns a clone of ReachabilityTreeNode
+func (rtn *ReachabilityTreeNode) Clone() *ReachabilityTreeNode {
+	if rtn == nil {
+		return nil
+	}
+
+	return &ReachabilityTreeNode{
+		Children: externalapi.CloneHashes(rtn.Children),
+		Parent:   rtn.Parent.Clone(),
+		Interval: rtn.Interval.Clone(),
+	}
+}
+
 // ReachabilityInterval represents an interval to be used within the
 // tree reachability algorithm. See ReachabilityTreeNode for further
 // details.
@@ -44,6 +69,18 @@ type ReachabilityInterval struct {
 	End   uint64
 }
 
+// Clone returns a clone of ReachabilityInterval
+func (ri *ReachabilityInterval) Clone() *ReachabilityInterval {
+	if ri == nil {
+		return nil
+	}
+
+	return &ReachabilityInterval{
+		Start: ri.Start,
+		End:   ri.End,
+	}
+}
+
 func (ri *ReachabilityInterval) String() string {
 	return fmt.Sprintf("[%d,%d]", ri.Start, ri.End)
 }
diff --git a/domain/consensus/model/utxodiff.go b/domain/consensus/model/utxodiff.go
index 00f61978..7448f1c0 100644
--- a/domain/consensus/model/utxodiff.go
+++ b/domain/consensus/model/utxodiff.go
@@ -11,18 +11,18 @@ import (
 // UTXOCollection represents a set of UTXOs indexed by their outpoints
 type UTXOCollection map[externalapi.DomainOutpoint]*externalapi.UTXOEntry
 
-// UTXODiff represents a diff between two UTXO Sets.
-type UTXODiff struct {
-	ToAdd    UTXOCollection
-	ToRemove UTXOCollection
-}
+// Clone returns a clone of UTXOCollection
+func (uc UTXOCollection) Clone() UTXOCollection {
+	if uc == nil {
+		return nil
+	}
 
-// NewUTXODiff instantiates an empty UTXODiff
-func NewUTXODiff() *UTXODiff {
-	return &UTXODiff{
-		ToAdd:    UTXOCollection{},
-		ToRemove: UTXOCollection{},
+	clone := make(UTXOCollection, len(uc))
+	for outpoint, entry := range uc {
+		clone[outpoint] = entry.Clone()
 	}
+
+	return clone
 }
 
 func (uc UTXOCollection) String() string {
@@ -41,6 +41,32 @@ func (uc UTXOCollection) String() string {
 	return fmt.Sprintf("[ %s ]", strings.Join(utxoStrings, ", "))
 }
 
+// UTXODiff represents a diff between two UTXO Sets.
+type UTXODiff struct {
+	ToAdd    UTXOCollection
+	ToRemove UTXOCollection
+}
+
+// Clone returns a clone of UTXODiff
+func (d *UTXODiff) Clone() *UTXODiff {
+	if d == nil {
+		return nil
+	}
+
+	return &UTXODiff{
+		ToAdd:    d.ToAdd.Clone(),
+		ToRemove: d.ToRemove.Clone(),
+	}
+}
+
 func (d UTXODiff) String() string {
 	return fmt.Sprintf("ToAdd: %s; ToRemove: %s", d.ToAdd, d.ToRemove)
 }
+
+// NewUTXODiff instantiates an empty UTXODiff
+func NewUTXODiff() *UTXODiff {
+	return &UTXODiff{
+		ToAdd:    UTXOCollection{},
+		ToRemove: UTXOCollection{},
+	}
+}
diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go
index d7c4c5c0..911a06e0 100644
--- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go
+++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go
@@ -129,10 +129,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
 		if err != nil {
 			return err
 		}
-		err = bp.headerTipsStore.Stage(tips)
-		if err != nil {
-			return err
-		}
+		bp.headerTipsStore.Stage(tips)
 	}
 
 	if syncInfo.State != externalapi.SyncStateMissingGenesis {
@@ -216,10 +213,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex
 	}
 
 	if !hasHeader {
-		err = bp.blockHeaderStore.Stage(blockHash, block.Header)
-		if err != nil {
-			return err
-		}
+		bp.blockHeaderStore.Stage(blockHash, block.Header)
 	}
 
 	// If any validation until (included) proof-of-work fails, simply
@@ -276,12 +270,9 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock
 	blockHash := consensusserialization.BlockHash(block)
 
 	if mode.State != externalapi.SyncStateHeadersFirst {
-		err := bp.blockStore.Stage(blockHash, block)
-		if err != nil {
-			return err
-		}
+		bp.blockStore.Stage(blockHash, block)
 
-		err = bp.blockValidator.ValidateBodyInIsolation(blockHash)
+		err := bp.blockValidator.ValidateBodyInIsolation(blockHash)
 		if err != nil {
 			return err
 		}
diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go
index 6eca2566..1f60fed0 100644
--- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go
+++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go
@@ -101,10 +101,7 @@ func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (ne
 	}
 	log.Tracef("The new tips are: %s", newTips)
 
-	err = csm.consensusStateStore.StageTips(newTips)
-	if err != nil {
-		return nil, err
-	}
+	csm.consensusStateStore.StageTips(newTips)
 	log.Tracef("Staged the new tips %s", newTips)
 
 	return newTips, nil
diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go
index c2e2ffdb..1b33df78 100644
--- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go
+++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go
@@ -127,7 +127,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH
 	log.Tracef("The past median time for block %s is: %d", blockHash, selectedParentMedianTime)
 
 	multiblockAcceptanceData := make(model.AcceptanceData, len(blueBlocks))
-	accumulatedUTXODiff := utxoalgebra.DiffClone(selectedParentPastUTXODiff)
+	accumulatedUTXODiff := selectedParentPastUTXODiff.Clone()
 	accumulatedMass := uint64(0)
 
 	for i, blueBlock := range blueBlocks {
diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go
index 57c45e4e..eb6998f2 100644
--- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go
+++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go
@@ -132,10 +132,7 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap
 	}
 
 	log.Tracef("Staging the calculated acceptance data of block %s", blockHash)
-	err = csm.acceptanceDataStore.Stage(blockHash, acceptanceData)
-	if err != nil {
-		return 0, err
-	}
+	csm.acceptanceDataStore.Stage(blockHash, acceptanceData)
 
 	block, err := csm.blockStore.Block(csm.databaseContext, blockHash)
 	if err != nil {
diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go
index 9f8f5891..83e37e6f 100644
--- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go
+++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go
@@ -67,10 +67,7 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
 	log.Tracef("Header tip pruning point multiset validation passed")
 
 	log.Tracef("Staging the parent hashes for the header tips pruning point as the DAG tips")
-	err = csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.ParentHashes)
-	if err != nil {
-		return err
-	}
+	csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.ParentHashes)
 
 	log.Tracef("Setting the parent hashes for the header tips pruning point as the virtual parents")
 	err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, headerTipsPruningPointHeader.ParentHashes)
@@ -159,12 +156,10 @@ func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainH
 	log.Tracef("The current header tips are: %s", headerTips)
 
 	log.Tracef("Temporarily staging the parents of the virtual header to be the header tips: %s", headerTips)
-	err = csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{
+	csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{
 		Parents: headerTips,
 	})
-	if err != nil {
-		return nil, err
-	}
+
 	defer csm.blockRelationStore.Discard()
 
 	err = csm.ghostdagManager.GHOSTDAG(virtualHeaderHash)
diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go
index 3a5a3638..001b675c 100644
--- a/domain/consensus/processes/consensusstatemanager/update_virtual.go
+++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go
@@ -35,10 +35,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain
 	}
 
 	log.Tracef("Staging new acceptance data for the virtual block")
-	err = csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData)
-	if err != nil {
-		return err
-	}
+	csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData)
 
 	log.Tracef("Staging new multiset for the virtual block")
 	csm.multisetStore.Stage(model.VirtualBlockHash, virtualMultiset)
diff --git a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go
index 385f577a..1f55fb33 100644
--- a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go
+++ b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go
@@ -13,10 +13,7 @@ func (csm *consensusStateManager) stageDiff(blockHash *externalapi.DomainHash,
 	defer log.Tracef("stageDiff end for block %s", blockHash)
 
 	log.Tracef("Staging block %s as the diff child of %s", utxoDiffChild, blockHash)
-	err := csm.utxoDiffStore.Stage(blockHash, utxoDiff, utxoDiffChild)
-	if err != nil {
-		return err
-	}
+	csm.utxoDiffStore.Stage(blockHash, utxoDiff, utxoDiffChild)
 
 	if utxoDiffChild == nil {
 		log.Tracef("Adding block %s to the virtual diff parents", blockHash)
@@ -55,7 +52,8 @@ func (csm *consensusStateManager) addToVirtualDiffParents(blockHash *externalapi
 
 	newVirtualDiffParents := append([]*externalapi.DomainHash{blockHash}, oldVirtualDiffParents...)
 	log.Tracef("Staging virtual diff parents after adding %s to it", blockHash)
-	return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents)
+	csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents)
+	return nil
 }
 
 func (csm *consensusStateManager) removeFromVirtualDiffParents(blockHash *externalapi.DomainHash) error {
@@ -80,5 +78,6 @@ func (csm *consensusStateManager) removeFromVirtualDiffParents(blockHash *extern
 	}
 
 	log.Tracef("Staging virtual diff parents after removing %s from it", blockHash)
-	return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents)
+	csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents)
+	return nil
 }
diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go b/domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go
index 78624d3b..148ea926 100644
--- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go
+++ b/domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go
@@ -48,13 +48,3 @@ func collectionContainsWithBlueScore(collection model.UTXOCollection, outpoint *
 	entry, ok := CollectionGet(collection, outpoint)
 	return ok && entry.BlockBlueScore == blueScore
 }
-
-// clone returns a clone of this collection
-func collectionClone(collection model.UTXOCollection) model.UTXOCollection {
-	clone := make(model.UTXOCollection, len(collection))
-	for outpoint, entry := range collection {
-		collectionAdd(clone, &outpoint, entry)
-	}
-
-	return clone
-}
diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go
index 58bb13f8..9bcaf3f0 100644
--- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go
+++ b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go
@@ -242,7 +242,7 @@ func WithDiffInPlace(this *model.UTXODiff, diff *model.UTXODiff) error {
 // WithDiff applies provided diff to this diff, creating a new utxoDiff, that would be the result if
 // first d, and than diff were applied to some base
 func WithDiff(this *model.UTXODiff, diff *model.UTXODiff) (*model.UTXODiff, error) {
-	clone := DiffClone(this)
+	clone := this.Clone()
 
 	err := WithDiffInPlace(clone, diff)
 	if err != nil {
diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go
index fc7b5bd0..2eb45829 100644
--- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go
+++ b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go
@@ -12,15 +12,6 @@ import (
 	"github.com/pkg/errors"
 )
 
-// DiffClone returns a new UTXODiff which is identical to the given diff
-func DiffClone(diff *model.UTXODiff) *model.UTXODiff {
-	clone := &model.UTXODiff{
-		ToAdd:    collectionClone(diff.ToAdd),
-		ToRemove: collectionClone(diff.ToRemove),
-	}
-	return clone
-}
-
 // DiffAddTransaction modifies the provided utxoDiff with provided transaction.
 func DiffAddTransaction(utxoDiff *model.UTXODiff, transaction *externalapi.DomainTransaction, blockBlueScore uint64) error {
 	for _, input := range transaction.Inputs {
diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go
index 0b696620..c38c32ce 100644
--- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go
+++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go
@@ -48,7 +48,7 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo
 	log.Tracef("Coinbase transaction validation passed for block %s", blockHash)
 
 	log.Tracef("Validating transactions against past UTXO for block %s", blockHash)
-	err = csm.validateBlockTransactionsAgainstPastUTXO(block, blockHash, pastUTXODiff, err)
+	err = csm.validateBlockTransactionsAgainstPastUTXO(block, blockHash, pastUTXODiff)
 	if err != nil {
 		return err
 	}
@@ -58,7 +58,7 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo
 }
 
 func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block *externalapi.DomainBlock,
-	blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff, err error) error {
+	blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff) error {
 
 	log.Tracef("validateBlockTransactionsAgainstPastUTXO start for block %s", blockHash)
 	defer log.Tracef("validateBlockTransactionsAgainstPastUTXO end for block %s", blockHash)
diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go
index cc1a3051..1c430c8a 100644
--- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go
+++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go
@@ -127,10 +127,7 @@ func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, par
 			for i, parentChild := range parentRelations.Children {
 				if *parentChild == *blockHash {
 					parentRelations.Children = append(parentRelations.Children[:i], parentRelations.Children[i+1:]...)
-					err = dtm.blockRelationStore.StageBlockRelation(currentParent, parentRelations)
-					if err != nil {
-						return err
-					}
+					dtm.blockRelationStore.StageBlockRelation(currentParent, parentRelations)
 
 					break
 				}
@@ -153,21 +150,15 @@ func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, par
 		}
 		if !isBlockAlreadyInChildren {
 			parentRelations.Children = append(parentRelations.Children, blockHash)
-			err = dtm.blockRelationStore.StageBlockRelation(parent, parentRelations)
-			if err != nil {
-				return err
-			}
+			dtm.blockRelationStore.StageBlockRelation(parent, parentRelations)
 		}
 	}
 
 	// Finally - create the relations for the block itself
-	err = dtm.blockRelationStore.StageBlockRelation(blockHash, &model.BlockRelations{
+	dtm.blockRelationStore.StageBlockRelation(blockHash, &model.BlockRelations{
 		Parents:  parentHashes,
 		Children: []*externalapi.DomainHash{},
 	})
-	if err != nil {
-		return err
-	}
 
 	return nil
 }
diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag.go b/domain/consensus/processes/ghostdagmanager/ghostdag.go
index 23037776..c510959a 100644
--- a/domain/consensus/processes/ghostdagmanager/ghostdag.go
+++ b/domain/consensus/processes/ghostdagmanager/ghostdag.go
@@ -82,10 +82,7 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
 		newBlockData.BlueScore = 0
 	}
 
-	err = gm.ghostdagDataStore.Stage(blockHash, newBlockData)
-	if err != nil {
-		return err
-	}
+	gm.ghostdagDataStore.Stage(blockHash, newBlockData)
 
 	return nil
 }
diff --git a/domain/consensus/processes/headertipsmanager/headertipsmanager.go b/domain/consensus/processes/headertipsmanager/headertipsmanager.go
index 96ba6544..5ad81bdb 100644
--- a/domain/consensus/processes/headertipsmanager/headertipsmanager.go
+++ b/domain/consensus/processes/headertipsmanager/headertipsmanager.go
@@ -53,10 +53,7 @@ func (h headerTipsManager) AddHeaderTip(hash *externalapi.DomainHash) error {
 	}
 
 	newTips = append(newTips, hash)
-	err = h.headerTipsStore.Stage(newTips)
-	if err != nil {
-		return err
-	}
+	h.headerTipsStore.Stage(newTips)
 
 	return nil
 }
diff --git a/domain/consensus/processes/reachabilitymanager/stage.go b/domain/consensus/processes/reachabilitymanager/stage.go
index 563b42c5..0c38d61d 100644
--- a/domain/consensus/processes/reachabilitymanager/stage.go
+++ b/domain/consensus/processes/reachabilitymanager/stage.go
@@ -5,8 +5,8 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 )
 
-func (rt *reachabilityManager) stageData(blockHash *externalapi.DomainHash, data *model.ReachabilityData) error {
-	return rt.reachabilityDataStore.StageReachabilityData(blockHash, data)
+func (rt *reachabilityManager) stageData(blockHash *externalapi.DomainHash, data *model.ReachabilityData) {
+	rt.reachabilityDataStore.StageReachabilityData(blockHash, data)
 }
 
 func (rt *reachabilityManager) stageFutureCoveringSet(blockHash *externalapi.DomainHash, set model.FutureCoveringTreeNodeSet) error {
@@ -16,7 +16,8 @@ func (rt *reachabilityManager) stageFutureCoveringSet(blockHash *externalapi.Dom
 	}
 
 	data.FutureCoveringSet = set
-	return rt.reachabilityDataStore.StageReachabilityData(blockHash, data)
+	rt.reachabilityDataStore.StageReachabilityData(blockHash, data)
+	return nil
 }
 
 func (rt *reachabilityManager) stageTreeNode(blockHash *externalapi.DomainHash, node *model.ReachabilityTreeNode) error {
@@ -26,7 +27,8 @@ func (rt *reachabilityManager) stageTreeNode(blockHash *externalapi.DomainHash,
 	}
 
 	data.TreeNode = node
-	return rt.reachabilityDataStore.StageReachabilityData(blockHash, data)
+	rt.reachabilityDataStore.StageReachabilityData(blockHash, data)
+	return nil
 }
 
 func (rt *reachabilityManager) stageReindexRoot(blockHash *externalapi.DomainHash) {
diff --git a/domain/consensus/utils/lrucache/lrucache.go b/domain/consensus/utils/lrucache/lrucache.go
new file mode 100644
index 00000000..94b175a0
--- /dev/null
+++ b/domain/consensus/utils/lrucache/lrucache.go
@@ -0,0 +1,59 @@
+package lrucache
+
+import (
+	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
+)
+
+// LRUCache is a least-recently-used cache for any type
+// that's able to be indexed by DomainHash
+type LRUCache struct {
+	cache    map[externalapi.DomainHash]interface{}
+	capacity int
+}
+
+// New creates a new LRUCache
+func New(capacity int) *LRUCache {
+	return &LRUCache{
+		cache:    make(map[externalapi.DomainHash]interface{}, capacity+1),
+		capacity: capacity,
+	}
+}
+
+// Add adds an entry to the LRUCache
+func (c *LRUCache) Add(key *externalapi.DomainHash, value interface{}) {
+	c.cache[*key] = value
+
+	if len(c.cache) > c.capacity {
+		c.evictRandom()
+	}
+}
+
+// Get returns the entry for the given key, or (nil, false) otherwise
+func (c *LRUCache) Get(key *externalapi.DomainHash) (interface{}, bool) {
+	value, ok := c.cache[*key]
+	if !ok {
+		return nil, false
+	}
+	return value, true
+}
+
+// Has returns whether the LRUCache contains the given key
+func (c *LRUCache) Has(key *externalapi.DomainHash) bool {
+	_, ok := c.cache[*key]
+	return ok
+}
+
+// Remove removes the entry for the the given key. Does nothing if
+// the entry does not exist
+func (c *LRUCache) Remove(key *externalapi.DomainHash) {
+	delete(c.cache, *key)
+}
+
+func (c *LRUCache) evictRandom() {
+	var keyToEvict externalapi.DomainHash
+	for key := range c.cache {
+		keyToEvict = key
+		break
+	}
+	c.Remove(&keyToEvict)
+}
diff --git a/domain/consensus/utils/multiset/multiset.go b/domain/consensus/utils/multiset/multiset.go
index cea53eee..efda18f9 100644
--- a/domain/consensus/utils/multiset/multiset.go
+++ b/domain/consensus/utils/multiset/multiset.go
@@ -34,8 +34,9 @@ func (m multiset) Serialize() []byte {
 	return m.ms.Serialize()[:]
 }
 
-func (m multiset) Clone() (model.Multiset, error) {
-	return FromBytes(m.Serialize())
+func (m multiset) Clone() model.Multiset {
+	msClone := *m.ms
+	return &multiset{ms: &msClone}
 }
 
 // FromBytes deserializes the given bytes slice and returns a multiset.
diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go
index 99ebf0e1..908ffb5f 100644
--- a/domain/miningmanager/mempool/mempool.go
+++ b/domain/miningmanager/mempool/mempool.go
@@ -858,7 +858,7 @@ func (mp *mempool) Transactions() []*consensusexternalapi.DomainTransaction {
 // from the mempool and the orphan pool, and it also removes
 // from the mempool transactions that double spend a
 // transaction that is already in the DAG
-func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) {
+func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction {
 	// Protect concurrent access.
 	mp.mtx.Lock()
 	defer mp.mtx.Unlock()
@@ -886,6 +886,8 @@ func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.Domain
 			acceptedTxs = append(acceptedTxs, acceptedOrphan.DomainTransaction)
 		}
 	}
+
+	return acceptedTxs
 }
 
 func (mp *mempool) RemoveTransactions(txs []*consensusexternalapi.DomainTransaction) {
diff --git a/domain/miningmanager/miningmanager.go b/domain/miningmanager/miningmanager.go
index a9e166bf..82b66a1e 100644
--- a/domain/miningmanager/miningmanager.go
+++ b/domain/miningmanager/miningmanager.go
@@ -10,7 +10,7 @@ import (
 type MiningManager interface {
 	GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error)
 	GetTransaction(transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool)
-	HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction)
+	HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction
 	ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error
 }
 
@@ -25,8 +25,8 @@ func (mm *miningManager) GetBlockTemplate(coinbaseData *consensusexternalapi.Dom
 }
 
 // HandleNewBlock handles the transactions for a new block that was just added to the DAG
-func (mm *miningManager) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) {
-	mm.mempool.HandleNewBlockTransactions(txs)
+func (mm *miningManager) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction {
+	return mm.mempool.HandleNewBlockTransactions(txs)
 }
 
 // ValidateAndInsertTransaction validates the given transaction, and
diff --git a/domain/miningmanager/model/interface_mempool.go b/domain/miningmanager/model/interface_mempool.go
index ee010a3c..20bb8ff3 100644
--- a/domain/miningmanager/model/interface_mempool.go
+++ b/domain/miningmanager/model/interface_mempool.go
@@ -7,7 +7,7 @@ import (
 // Mempool maintains a set of known transactions that
 // are intended to be mined into new blocks
 type Mempool interface {
-	HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction)
+	HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction
 	Transactions() []*consensusexternalapi.DomainTransaction
 	ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error
 	RemoveTransactions(txs []*consensusexternalapi.DomainTransaction)
diff --git a/go.sum b/go.sum
index 0598d276..8bfb2dbe 100644
--- a/go.sum
+++ b/go.sum
@@ -39,8 +39,6 @@ github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
diff --git a/util/locks/receive_from_chan_when_done.go b/util/locks/receive_from_chan_when_done.go
deleted file mode 100644
index 759b6c65..00000000
--- a/util/locks/receive_from_chan_when_done.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package locks
-
-// ReceiveFromChanWhenDone takes a blocking function and returns a channel that sends an empty struct when the function is done.
-func ReceiveFromChanWhenDone(callback func()) <-chan struct{} {
-	ch := make(chan struct{})
-	spawn("ReceiveFromChanWhenDone", func() {
-		callback()
-		close(ch)
-	})
-	return ch
-}


Test patch:
diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go
new file mode 100644
index 00000000..af64f73e
--- /dev/null
+++ b/domain/consensus/consensus_test.go
@@ -0,0 +1,75 @@
+package consensus
+
+import (
+	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
+	"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
+	"github.com/kaspanet/kaspad/domain/dagconfig"
+	"github.com/pkg/errors"
+	"testing"
+)
+
+func TestConsensus_GetBlockInfo(t *testing.T) {
+	testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
+
+		factory := NewFactory()
+		consensus, teardown, err := factory.NewTestConsensus(params, "TestConsensus_GetBlockInfo")
+		if err != nil {
+			t.Fatalf("Error setting up consensus: %+v", err)
+		}
+		defer teardown()
+
+		invalidBlock, err := consensus.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		invalidBlock.Header.TimeInMilliseconds = 0
+		err = consensus.ValidateAndInsertBlock(invalidBlock)
+		if !errors.Is(err, ruleerrors.ErrTimeTooOld) {
+			t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrTimeTooOld, err)
+		}
+
+		info, err := consensus.GetBlockInfo(consensusserialization.BlockHash(invalidBlock))
+		if err != nil {
+			t.Fatalf("Failed to get block info: %v", err)
+		}
+
+		if !info.Exists {
+			t.Fatal("The block is missing")
+		}
+		if info.BlockStatus != externalapi.StatusInvalid {
+			t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusInvalid, info.BlockStatus)
+		}
+		if info.IsBlockInHeaderPruningPointFuture != false {
+			t.Fatalf("Expected IsBlockInHeaderPruningPointFuture=false, instead found: %t", info.IsBlockInHeaderPruningPointFuture)
+		}
+
+		emptyCoinbase := externalapi.DomainCoinbaseData{}
+		validBlock, err := consensus.BuildBlock(&emptyCoinbase, nil)
+		if err != nil {
+			t.Fatalf("consensus.BuildBlock with an empty coinbase shouldn't fail: %v", err)
+		}
+
+		err = consensus.ValidateAndInsertBlock(validBlock)
+		if err != nil {
+			t.Fatalf("consensus.ValidateAndInsertBlock with a block straight from consensus.BuildBlock should not fail: %v", err)
+		}
+
+		info, err = consensus.GetBlockInfo(consensusserialization.BlockHash(validBlock))
+		if err != nil {
+			t.Fatalf("Failed to get block info: %v", err)
+		}
+
+		if !info.Exists {
+			t.Fatal("The block is missing")
+		}
+		if info.BlockStatus != externalapi.StatusValid {
+			t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusValid, info.BlockStatus)
+		}
+		if info.IsBlockInHeaderPruningPointFuture != true {
+			t.Fatalf("Expected IsBlockInHeaderPruningPointFuture=true, instead found: %t", info.IsBlockInHeaderPruningPointFuture)
+		}
+
+	})
+}
diff --git a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go
index c2cf22ef..c0ea148e 100644
--- a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go
+++ b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go
@@ -7,10 +7,13 @@ import (
 
 // consensusStateStore represents a store for the current consensus state
 type consensusStateStore struct {
-	stagedTips               []*externalapi.DomainHash
-	stagedVirtualDiffParents []*externalapi.DomainHash
-	stagedVirtualUTXODiff    *model.UTXODiff
-	stagedVirtualUTXOSet     model.UTXOCollection
+	tipsStaging               []*externalapi.DomainHash
+	virtualDiffParentsStaging []*externalapi.DomainHash
+	virtualUTXODiffStaging    *model.UTXODiff
+	virtualUTXOSetStaging     model.UTXOCollection
+
+	tipsCache               []*externalapi.DomainHash
+	virtualDiffParentsCache []*externalapi.DomainHash
 }
 
 // New instantiates a new ConsensusStateStore
@@ -18,40 +21,40 @@ func New() model.ConsensusStateStore {
 	return &consensusStateStore{}
 }
 
-func (c *consensusStateStore) Discard() {
-	c.stagedTips = nil
-	c.stagedVirtualUTXODiff = nil
-	c.stagedVirtualDiffParents = nil
-	c.stagedVirtualUTXOSet = nil
+func (css *consensusStateStore) Discard() {
+	css.tipsStaging = nil
+	css.virtualUTXODiffStaging = nil
+	css.virtualDiffParentsStaging = nil
+	css.virtualUTXOSetStaging = nil
 }
 
-func (c *consensusStateStore) Commit(dbTx model.DBTransaction) error {
-	err := c.commitTips(dbTx)
+func (css *consensusStateStore) Commit(dbTx model.DBTransaction) error {
+	err := css.commitTips(dbTx)
 	if err != nil {
 		return err
 	}
-	err = c.commitVirtualDiffParents(dbTx)
+	err = css.commitVirtualDiffParents(dbTx)
 	if err != nil {
 		return err
 	}
 
-	err = c.commitVirtualUTXODiff(dbTx)
+	err = css.commitVirtualUTXODiff(dbTx)
 	if err != nil {
 		return err
 	}
 
-	err = c.commitVirtualUTXOSet(dbTx)
+	err = css.commitVirtualUTXOSet(dbTx)
 	if err != nil {
 		return err
 	}
 
-	c.Discard()
+	css.Discard()
 
 	return nil
 }
 
-func (c *consensusStateStore) IsStaged() bool {
-	return c.stagedTips != nil ||
-		c.stagedVirtualDiffParents != nil ||
-		c.stagedVirtualUTXODiff != nil
+func (css *consensusStateStore) IsStaged() bool {
+	return css.tipsStaging != nil ||
+		css.virtualDiffParentsStaging != nil ||
+		css.virtualUTXODiffStaging != nil
 }
diff --git a/domain/consensus/datastructures/consensusstatestore/tips.go b/domain/consensus/datastructures/consensusstatestore/tips.go
index 60fab19e..c9cb4400 100644
--- a/domain/consensus/datastructures/consensusstatestore/tips.go
+++ b/domain/consensus/datastructures/consensusstatestore/tips.go
@@ -10,9 +10,13 @@ import (
 
 var tipsKey = dbkeys.MakeBucket().Key([]byte("tips"))
 
-func (c *consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) {
-	if c.stagedTips != nil {
-		return c.stagedTips, nil
+func (css *consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) {
+	if css.tipsStaging != nil {
+		return externalapi.CloneHashes(css.tipsStaging), nil
+	}
+
+	if css.tipsCache != nil {
+		return externalapi.CloneHashes(css.tipsCache), nil
 	}
 
 	tipsBytes, err := dbContext.Get(tipsKey)
@@ -20,43 +24,44 @@ func (c *consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.Dom
 		return nil, err
 	}
 
-	return c.deserializeTips(tipsBytes)
-}
-
-func (c *consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) error {
-	clone, err := c.cloneTips(tipHashes)
+	tips, err := css.deserializeTips(tipsBytes)
 	if err != nil {
-		return err
+		return nil, err
 	}
+	css.tipsCache = tips
+	return externalapi.CloneHashes(tips), nil
+}
 
-	c.stagedTips = clone
-	return nil
+func (css *consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) {
+	css.tipsStaging = externalapi.CloneHashes(tipHashes)
 }
 
-func (c *consensusStateStore) commitTips(dbTx model.DBTransaction) error {
-	if c.stagedTips == nil {
+func (css *consensusStateStore) commitTips(dbTx model.DBTransaction) error {
+	if css.tipsStaging == nil {
 		return nil
 	}
 
-	tipsBytes, err := c.serializeTips(c.stagedTips)
+	tipsBytes, err := css.serializeTips(css.tipsStaging)
 	if err != nil {
 		return err
 	}
-
 	err = dbTx.Put(tipsKey, tipsBytes)
 	if err != nil {
 		return err
 	}
+	css.tipsCache = css.tipsStaging
 
+	// Note: we don't discard the staging here since that's
+	// being done at the end of Commit()
 	return nil
 }
 
-func (c *consensusStateStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) {
+func (css *consensusStateStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) {
 	dbTips := serialization.TipsToDBTips(tips)
 	return proto.Marshal(dbTips)
 }
 
-func (c *consensusStateStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash,
+func (css *consensusStateStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash,
 	error) {
 
 	dbTips := &serialization.DbTips{}
@@ -67,14 +72,3 @@ func (c *consensusStateStore) deserializeTips(tipsBytes []byte) ([]*externalapi.
 
 	return serialization.DBTipsToTips(dbTips)
 }
-
-func (c *consensusStateStore) cloneTips(tips []*externalapi.DomainHash,
-) ([]*externalapi.DomainHash, error) {
-
-	serialized, err := c.serializeTips(tips)
-	if err != nil {
-		return nil, err
-	}
-
-	return c.deserializeTips(serialized)
-}
diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go
index f51dc6b9..fe510a71 100644
--- a/domain/consensus/datastructures/consensusstatestore/utxo.go
+++ b/domain/consensus/datastructures/consensusstatestore/utxo.go
@@ -18,21 +18,21 @@ func utxoKey(outpoint *externalapi.DomainOutpoint) (model.DBKey, error) {
 	return utxoSetBucket.Key(serializedOutpoint), nil
 }
 
-func (c *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODiff) error {
-	if c.stagedVirtualUTXOSet != nil {
+func (css *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODiff) error {
+	if css.virtualUTXOSetStaging != nil {
 		return errors.New("cannot stage virtual UTXO diff while virtual UTXO set is staged")
 	}
 
-	c.stagedVirtualUTXODiff = c.cloneUTXODiff(virtualUTXODiff)
+	css.virtualUTXODiffStaging = virtualUTXODiff.Clone()
 	return nil
 }
 
-func (c *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) error {
-	if c.stagedVirtualUTXODiff == nil {
+func (css *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) error {
+	if css.virtualUTXODiffStaging == nil {
 		return nil
 	}
 
-	for toRemoveOutpoint := range c.stagedVirtualUTXODiff.ToRemove {
+	for toRemoveOutpoint := range css.virtualUTXODiffStaging.ToRemove {
 		dbKey, err := utxoKey(&toRemoveOutpoint)
 		if err != nil {
 			return err
@@ -43,7 +43,7 @@ func (c *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) er
 		}
 	}
 
-	for toAddOutpoint, toAddEntry := range c.stagedVirtualUTXODiff.ToAdd {
+	for toAddOutpoint, toAddEntry := range css.virtualUTXODiffStaging.ToAdd {
 		dbKey, err := utxoKey(&toAddOutpoint)
 		if err != nil {
 			return err
@@ -58,15 +58,17 @@ func (c *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) er
 		}
 	}
 
+	// Note: we don't discard the staging here since that's
+	// being done at the end of Commit()
 	return nil
 }
 
-func (c *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) error {
-	if c.stagedVirtualUTXOSet == nil {
+func (css *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) error {
+	if css.virtualUTXOSetStaging == nil {
 		return nil
 	}
 
-	for outpoint, utxoEntry := range c.stagedVirtualUTXOSet {
+	for outpoint, utxoEntry := range css.virtualUTXOSetStaging {
 		dbKey, err := utxoKey(&outpoint)
 		if err != nil {
 			return err
@@ -81,28 +83,30 @@ func (c *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) err
 		}
 	}
 
+	// Note: we don't discard the staging here since that's
+	// being done at the end of Commit()
 	return nil
 }
 
-func (c *consensusStateStore) UTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (
+func (css *consensusStateStore) UTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (
 	*externalapi.UTXOEntry, error) {
 
-	if c.stagedVirtualUTXOSet != nil {
-		return c.utxoByOutpointFromStagedVirtualUTXOSet(outpoint)
+	if css.virtualUTXOSetStaging != nil {
+		return css.utxoByOutpointFromStagedVirtualUTXOSet(outpoint)
 	}
 
-	return c.utxoByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint)
+	return css.utxoByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint)
 }
 
-func (c *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader,
+func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader,
 	outpoint *externalapi.DomainOutpoint) (
 	*externalapi.UTXOEntry, error) {
 
-	if c.stagedVirtualUTXODiff != nil {
-		if _, ok := c.stagedVirtualUTXODiff.ToRemove[*outpoint]; ok {
+	if css.virtualUTXODiffStaging != nil {
+		if _, ok := css.virtualUTXODiffStaging.ToRemove[*outpoint]; ok {
 			return nil, errors.Errorf("outpoint was not found")
 		}
-		if utxoEntry, ok := c.stagedVirtualUTXODiff.ToAdd[*outpoint]; ok {
+		if utxoEntry, ok := css.virtualUTXODiffStaging.ToAdd[*outpoint]; ok {
 			return utxoEntry, nil
 		}
 	}
@@ -120,31 +124,31 @@ func (c *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContext
 	return deserializeUTXOEntry(serializedUTXOEntry)
 }
 
-func (c *consensusStateStore) utxoByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) (
+func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) (
 	*externalapi.UTXOEntry, error) {
-	if utxoEntry, ok := c.stagedVirtualUTXOSet[*outpoint]; ok {
+	if utxoEntry, ok := css.virtualUTXOSetStaging[*outpoint]; ok {
 		return utxoEntry, nil
 	}
 
 	return nil, errors.Errorf("outpoint was not found")
 }
 
-func (c *consensusStateStore) HasUTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) {
-	if c.stagedVirtualUTXOSet != nil {
-		return c.hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint), nil
+func (css *consensusStateStore) HasUTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) {
+	if css.virtualUTXOSetStaging != nil {
+		return css.hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint), nil
 	}
 
-	return c.hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint)
+	return css.hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint)
 }
 
-func (c *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader,
+func (css *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader,
 	outpoint *externalapi.DomainOutpoint) (bool, error) {
 
-	if c.stagedVirtualUTXODiff != nil {
-		if _, ok := c.stagedVirtualUTXODiff.ToRemove[*outpoint]; ok {
+	if css.virtualUTXODiffStaging != nil {
+		if _, ok := css.virtualUTXODiffStaging.ToRemove[*outpoint]; ok {
 			return false, nil
 		}
-		if _, ok := c.stagedVirtualUTXODiff.ToAdd[*outpoint]; ok {
+		if _, ok := css.virtualUTXODiffStaging.ToAdd[*outpoint]; ok {
 			return true, nil
 		}
 	}
@@ -157,12 +161,12 @@ func (c *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbConte
 	return dbContext.Has(key)
 }
 
-func (c *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) bool {
-	_, ok := c.stagedVirtualUTXOSet[*outpoint]
+func (css *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) bool {
+	_, ok := css.virtualUTXOSetStaging[*outpoint]
 	return ok
 }
 
-func (c *consensusStateStore) VirtualUTXOSetIterator(dbContext model.DBReader) (model.ReadOnlyUTXOSetIterator, error) {
+func (css *consensusStateStore) VirtualUTXOSetIterator(dbContext model.DBReader) (model.ReadOnlyUTXOSetIterator, error) {
 	cursor, err := dbContext.Cursor(utxoSetBucket)
 	if err != nil {
 		return nil, err
@@ -207,55 +211,23 @@ func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry
 	return outpoint, utxoEntry, nil
 }
 
-func (c *consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.ReadOnlyUTXOSetIterator) error {
-	if c.stagedVirtualUTXODiff != nil {
+func (css *consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.ReadOnlyUTXOSetIterator) error {
+	if css.virtualUTXODiffStaging != nil {
 		return errors.New("cannot stage virtual UTXO set while virtual UTXO diff is staged")
 	}
 
-	c.stagedVirtualUTXOSet = make(model.UTXOCollection)
+	css.virtualUTXOSetStaging = make(model.UTXOCollection)
 	for virtualUTXOSetIterator.Next() {
 		outpoint, entry, err := virtualUTXOSetIterator.Get()
 		if err != nil {
 			return err
 		}
 
-		if _, exists := c.stagedVirtualUTXOSet[*outpoint]; exists {
+		if _, exists := css.virtualUTXOSetStaging[*outpoint]; exists {
 			return errors.Errorf("outpoint %s is found more than once in the given iterator", outpoint)
 		}
-		c.stagedVirtualUTXOSet[*outpoint] = entry
+		css.virtualUTXOSetStaging[*outpoint] = entry
 	}
 
 	return nil
 }
-
-func (c *consensusStateStore) cloneUTXODiff(diff *model.UTXODiff) *model.UTXODiff {
-	utxoDiffCopy := &model.UTXODiff{
-		ToAdd:    make(model.UTXOCollection, len(diff.ToAdd)),
-		ToRemove: make(model.UTXOCollection, len(diff.ToRemove)),
-	}
-
-	for outpoint, entry := range diff.ToAdd {
-		scriptPublicKeyCopy := make([]byte, len(entry.ScriptPublicKey))
-		copy(scriptPublicKeyCopy, entry.ScriptPublicKey)
-		utxoDiffCopy.ToAdd[outpoint] = cloneUTXOEntry(entry)
-	}
-
-	for outpoint, entry := range diff.ToRemove {
-		scriptPublicKeyCopy := make([]byte, len(entry.ScriptPublicKey))
-		copy(scriptPublicKeyCopy, entry.ScriptPublicKey)
-		utxoDiffCopy.ToRemove[outpoint] = cloneUTXOEntry(entry)
-	}
-
-	return diff
-}
-
-func cloneUTXOEntry(entry *externalapi.UTXOEntry) *externalapi.UTXOEntry {
-	scriptPublicKeyCopy := make([]byte, len(entry.ScriptPublicKey))
-	copy(scriptPublicKeyCopy, entry.ScriptPublicKey)
-	return &externalapi.UTXOEntry{
-		Amount:          entry.Amount,
-		ScriptPublicKey: scriptPublicKeyCopy,
-		BlockBlueScore:  entry.BlockBlueScore,
-		IsCoinbase:      entry.IsCoinbase,
-	}
-}
diff --git a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go
index 00635347..c834a191 100644
--- a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go
+++ b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go
@@ -10,9 +10,13 @@ import (
 
 var virtualDiffParentsKey = dbkeys.MakeBucket().Key([]byte("virtual-diff-parents"))
 
-func (c *consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*externalapi.DomainHash, error) {
-	if c.stagedVirtualDiffParents != nil {
-		return c.stagedVirtualDiffParents, nil
+func (css *consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*externalapi.DomainHash, error) {
+	if css.virtualDiffParentsStaging != nil {
+		return externalapi.CloneHashes(css.virtualDiffParentsStaging), nil
+	}
+
+	if css.virtualDiffParentsCache != nil {
+		return externalapi.CloneHashes(css.virtualDiffParentsCache), nil
 	}
 
 	virtualDiffParentsBytes, err := dbContext.Get(virtualDiffParentsKey)
@@ -20,43 +24,44 @@ func (c *consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*e
 		return nil, err
 	}
 
-	return c.deserializeVirtualDiffParents(virtualDiffParentsBytes)
-}
-
-func (c *consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.DomainHash) error {
-	clone, err := c.cloneVirtualDiffParents(tipHashes)
+	virtualDiffParents, err := css.deserializeVirtualDiffParents(virtualDiffParentsBytes)
 	if err != nil {
-		return err
+		return nil, err
 	}
+	css.virtualDiffParentsCache = virtualDiffParents
+	return externalapi.CloneHashes(virtualDiffParents), nil
+}
 
-	c.stagedVirtualDiffParents = clone
-	return nil
+func (css *consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.DomainHash) {
+	css.virtualDiffParentsStaging = externalapi.CloneHashes(tipHashes)
 }
 
-func (c *consensusStateStore) commitVirtualDiffParents(dbTx model.DBTransaction) error {
-	if c.stagedVirtualDiffParents == nil {
+func (css *consensusStateStore) commitVirtualDiffParents(dbTx model.DBTransaction) error {
+	if css.virtualDiffParentsStaging == nil {
 		return nil
 	}
 
-	virtualDiffParentsBytes, err := c.serializeVirtualDiffParents(c.stagedVirtualDiffParents)
+	virtualDiffParentsBytes, err := css.serializeVirtualDiffParents(css.virtualDiffParentsStaging)
 	if err != nil {
 		return err
 	}
-
 	err = dbTx.Put(virtualDiffParentsKey, virtualDiffParentsBytes)
 	if err != nil {
 		return err
 	}
+	css.virtualDiffParentsCache = css.virtualDiffParentsStaging
 
+	// Note: we don't discard the staging here since that's
+	// being done at the end of Commit()
 	return nil
 }
 
-func (c *consensusStateStore) serializeVirtualDiffParents(virtualDiffParentsBytes []*externalapi.DomainHash) ([]byte, error) {
+func (css *consensusStateStore) serializeVirtualDiffParents(virtualDiffParentsBytes []*externalapi.DomainHash) ([]byte, error) {
 	virtualDiffParents := serialization.VirtualDiffParentsToDBHeaderVirtualDiffParents(virtualDiffParentsBytes)
 	return proto.Marshal(virtualDiffParents)
 }
 
-func (c *consensusStateStore) deserializeVirtualDiffParents(virtualDiffParentsBytes []byte) ([]*externalapi.DomainHash,
+func (css *consensusStateStore) deserializeVirtualDiffParents(virtualDiffParentsBytes []byte) ([]*externalapi.DomainHash,
 	error) {
 
 	dbVirtualDiffParents := &serialization.DbVirtualDiffParents{}
@@ -67,14 +72,3 @@ func (c *consensusStateStore) deserializeVirtualDiffParents(virtualDiffParentsBy
 
 	return serialization.DBVirtualDiffParentsToVirtualDiffParents(dbVirtualDiffParents)
 }
-
-func (c *consensusStateStore) cloneVirtualDiffParents(virtualDiffParents []*externalapi.DomainHash,
-) ([]*externalapi.DomainHash, error) {
-
-	serialized, err := c.serializeVirtualDiffParents(virtualDiffParents)
-	if err != nil {
-		return nil, err
-	}
-
-	return c.deserializeVirtualDiffParents(serialized)
-}
diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go
index 24af2edb..5cf6532e 100644
--- a/domain/consensus/finality_test.go
+++ b/domain/consensus/finality_test.go
@@ -1,11 +1,16 @@
 package consensus
 
 import (
+	"github.com/kaspanet/kaspad/domain/consensus/model"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
+	"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
+	"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
 	"github.com/kaspanet/kaspad/domain/dagconfig"
+	"github.com/pkg/errors"
 
+	"fmt"
 	"testing"
 )
 
@@ -167,3 +172,249 @@ func TestFinality(t *testing.T) {
 		}
 	})
 }
+
+func TestBoundedMergeDepth(t *testing.T) {
+	testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
+		// Set finalityInterval to 50 blocks, so that test runs quickly
+		params.FinalityDuration = 50 * params.TargetTimePerBlock
+		finalityInterval := int(params.FinalityDepth())
+
+		if int(params.K) >= finalityInterval {
+			t.Fatal("K must be smaller than finality duration for this test to run")
+		}
+
+		checkViolatingMergeDepth := func(consensus testapi.TestConsensus, parents []*externalapi.DomainHash) (*externalapi.DomainBlock, bool) {
+			block, err := consensus.BuildBlockWithParents(parents, nil, nil)
+			if err != nil {
+				t.Fatalf("TestBoundedMergeDepth: BuildBlockWithParents failed: %v", err)
+				return nil, false // fo some reason go doesn't recognize that t.Fatalf never returns
+			}
+
+			err = consensus.ValidateAndInsertBlock(block)
+			if err == nil {
+				return block, false
+			} else if errors.Is(err, ruleerrors.ErrViolatingBoundedMergeDepth) {
+				return block, true
+			} else {
+				t.Fatalf("TestBoundedMergeDepth: expected err: %v, found err: %v", ruleerrors.ErrViolatingBoundedMergeDepth, err)
+				return nil, false // fo some reason go doesn't recognize that t.Fatalf never returns
+			}
+		}
+
+		processBlock := func(consensus testapi.TestConsensus, block *externalapi.DomainBlock, name string) {
+			err := consensus.ValidateAndInsertBlock(block)
+			if err != nil {
+				t.Fatalf("TestBoundedMergeDepth: %s got unexpected error from ProcessBlock: %+v", name, err)
+
+			}
+		}
+
+		buildAndInsertBlock := func(consensus testapi.TestConsensus, parentHashes []*externalapi.DomainHash) *externalapi.DomainBlock {
+			block, err := consensus.BuildBlockWithParents(parentHashes, nil, nil)
+			if err != nil {
+				t.Fatalf("TestBoundedMergeDepth: Failed building block: %v", err)
+			}
+			err = consensus.ValidateAndInsertBlock(block)
+			if err != nil {
+				t.Fatalf("TestBoundedMergeDepth: Failed Inserting block to consensus: %v", err)
+			}
+			return block
+		}
+
+		getStatus := func(consensus testapi.TestConsensus, block *externalapi.DomainBlock) externalapi.BlockStatus {
+			blockInfo, err := consensus.GetBlockInfo(consensusserialization.BlockHash(block))
+			if err != nil {
+				t.Fatalf("TestBoundedMergeDepth: Failed to get block info: %v", err)
+			} else if !blockInfo.Exists {
+				t.Fatalf("TestBoundedMergeDepth: Failed to get block info, block doesn't exists")
+			}
+			return blockInfo.BlockStatus
+		}
+
+		factory := NewFactory()
+		consensusBuild, teardownFunc1, err := factory.NewTestConsensus(params, "BoundedMergeTestBuild")
+		if err != nil {
+			t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err)
+		}
+
+		consensusReal, teardownFunc2, err := factory.NewTestConsensus(params, "BoundedMergeTestReal")
+		if err != nil {
+			t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err)
+		}
+		defer teardownFunc2()
+
+		// Create a block on top on genesis
+		block1 := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{params.GenesisHash})
+
+		// Create a chain
+		selectedChain := make([]*externalapi.DomainBlock, 0, finalityInterval+1)
+		parent := consensusserialization.BlockHash(block1)
+		// Make sure this is always bigger than `blocksChain2` so it will stay the selected chain
+		for i := 0; i < finalityInterval+2; i++ {
+			block := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{parent})
+			selectedChain = append(selectedChain, block)
+			parent = consensusserialization.BlockHash(block)
+		}
+
+		// Create another chain
+		blocksChain2 := make([]*externalapi.DomainBlock, 0, finalityInterval+1)
+		parent = consensusserialization.BlockHash(block1)
+		for i := 0; i < finalityInterval+1; i++ {
+			block := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{parent})
+			blocksChain2 = append(blocksChain2, block)
+			parent = consensusserialization.BlockHash(block)
+		}
+
+		// Teardown and assign nil to make sure we use the right DAG from here on.
+		teardownFunc1()
+		consensusBuild = nil
+
+		// Now test against the real DAG
+		// submit block1
+		processBlock(consensusReal, block1, "block1")
+
+		// submit chain1
+		for i, block := range selectedChain {
+			processBlock(consensusReal, block, fmt.Sprintf("selectedChain block No %d", i))
+		}
+
+		// submit chain2
+		for i, block := range blocksChain2 {
+			processBlock(consensusReal, block, fmt.Sprintf("blocksChain2 block No %d", i))
+		}
+
+		// submit a block pointing at tip(chain1) and on first block in chain2 directly
+		mergeDepthViolatingBlockBottom, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(blocksChain2[0]), consensusserialization.BlockHash(selectedChain[len(selectedChain)-1])})
+		if !isViolatingMergeDepth {
+			t.Fatalf("TestBoundedMergeDepth: Expected mergeDepthViolatingBlockBottom to violate merge depth")
+		}
+
+		// submit a block pointing at tip(chain1) and tip(chain2) should also obviously violate merge depth (this points at first block in chain2 indirectly)
+		mergeDepthViolatingTop, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(blocksChain2[len(blocksChain2)-1]), consensusserialization.BlockHash(selectedChain[len(selectedChain)-1])})
+		if !isViolatingMergeDepth {
+			t.Fatalf("TestBoundedMergeDepth: Expected mergeDepthViolatingTop to violate merge depth")
+		}
+
+		// the location of the parents in the slices need to be both `-X` so the `selectedChain` one will have higher blueScore (it's a chain longer by 1)
+		kosherizingBlock, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(blocksChain2[len(blocksChain2)-3]), consensusserialization.BlockHash(selectedChain[len(selectedChain)-3])})
+		kosherizingBlockHash := consensusserialization.BlockHash(kosherizingBlock)
+		if isViolatingMergeDepth {
+			t.Fatalf("TestBoundedMergeDepth: Expected blueKosherizingBlock to not violate merge depth")
+		}
+
+		virtualGhotDagData, err := consensusReal.GHOSTDAGDataStore().Get(consensusReal.DatabaseContext(), model.VirtualBlockHash)
+		if err != nil {
+			t.Fatalf("TestBoundedMergeDepth: Failed getting the ghostdag data of the virtual: %v", err)
+		}
+		// Make sure it's actually blue
+		found := false
+		for _, blue := range virtualGhotDagData.MergeSetBlues {
+			if *blue == *kosherizingBlockHash {
+				found = true
+				break
+			}
+		}
+		if !found {
+			t.Fatalf("TestBoundedMergeDepth: Expected kosherizingBlock to be blue by the virtual")
+		}
+
+		pointAtBlueKosherizing, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{kosherizingBlockHash, consensusserialization.BlockHash(selectedChain[len(selectedChain)-1])})
+		if isViolatingMergeDepth {
+
+			t.Fatalf("TestBoundedMergeDepth: Expected selectedTip to not violate merge depth")
+		}
+
+		virtualSelectedParent, err := consensusReal.GetVirtualSelectedParent()
+		if err != nil {
+			t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err)
+		}
+
+		if *consensusserialization.BlockHash(virtualSelectedParent) != *consensusserialization.BlockHash(pointAtBlueKosherizing) {
+			t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensusserialization.BlockHash(pointAtBlueKosherizing), consensusserialization.BlockHash(virtualSelectedParent))
+		}
+
+		// Now let's make the kosherizing block red and try to merge again
+		tip := consensusserialization.BlockHash(selectedChain[len(selectedChain)-1])
+		// we use k-1 because `kosherizingBlock` points at tip-2, so 2+k-1 = k+1 anticone.
+		for i := 0; i < int(params.K)-1; i++ {
+			block := buildAndInsertBlock(consensusReal, []*externalapi.DomainHash{tip})
+			tip = consensusserialization.BlockHash(block)
+		}
+
+		virtualSelectedParent, err = consensusReal.GetVirtualSelectedParent()
+		if err != nil {
+			t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err)
+		}
+
+		if *consensusserialization.BlockHash(virtualSelectedParent) != *tip {
+			t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", tip, consensusserialization.BlockHash(virtualSelectedParent))
+		}
+
+		virtualGhotDagData, err = consensusReal.GHOSTDAGDataStore().Get(consensusReal.DatabaseContext(), model.VirtualBlockHash)
+		if err != nil {
+			t.Fatalf("TestBoundedMergeDepth: Failed getting the ghostdag data of the virtual: %v", err)
+		}
+		// Make sure it's actually blue
+		found = false
+		for _, blue := range virtualGhotDagData.MergeSetBlues {
+			if *blue == *kosherizingBlockHash {
+				found = true
+				break
+			}
+		}
+		if found {
+			t.Fatalf("expected kosherizingBlock to be red by the virtual")
+		}
+
+		pointAtRedKosherizing, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{kosherizingBlockHash, tip})
+		if !isViolatingMergeDepth {
+			t.Fatalf("TestBoundedMergeDepth: Expected selectedTipRedKosherize to violate merge depth")
+		}
+
+		// Now `pointAtBlueKosherizing` itself is actually still blue, so we can still point at that even though we can't point at kosherizing directly anymore
+		transitiveBlueKosherizing, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(pointAtBlueKosherizing), tip})
+		if isViolatingMergeDepth {
+			t.Fatalf("TestBoundedMergeDepth: Expected transitiveBlueKosherizing to not violate merge depth")
+		}
+
+		virtualSelectedParent, err = consensusReal.GetVirtualSelectedParent()
+		if err != nil {
+			t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err)
+		}
+
+		if *consensusserialization.BlockHash(virtualSelectedParent) != *consensusserialization.BlockHash(transitiveBlueKosherizing) {
+			t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensusserialization.BlockHash(transitiveBlueKosherizing), consensusserialization.BlockHash(virtualSelectedParent))
+		}
+
+		// Lets validate the status of all the interesting blocks
+		if getStatus(consensusReal, pointAtBlueKosherizing) != externalapi.StatusValid {
+			t.Fatalf("TestBoundedMergeDepth: pointAtBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusValid, getStatus(consensusReal, pointAtBlueKosherizing))
+		}
+		if getStatus(consensusReal, pointAtRedKosherizing) != externalapi.StatusInvalid {
+			t.Fatalf("TestBoundedMergeDepth: pointAtRedKosherizing expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, pointAtRedKosherizing))
+		}
+		if getStatus(consensusReal, transitiveBlueKosherizing) != externalapi.StatusValid {
+			t.Fatalf("TestBoundedMergeDepth: transitiveBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusValid, getStatus(consensusReal, transitiveBlueKosherizing))
+		}
+		if getStatus(consensusReal, mergeDepthViolatingBlockBottom) != externalapi.StatusInvalid {
+			t.Fatalf("TestBoundedMergeDepth: mergeDepthViolatingBlockBottom expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, mergeDepthViolatingBlockBottom))
+		}
+		if getStatus(consensusReal, mergeDepthViolatingTop) != externalapi.StatusInvalid {
+			t.Fatalf("TestBoundedMergeDepth: mergeDepthViolatingTop expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, mergeDepthViolatingTop))
+		}
+		if getStatus(consensusReal, kosherizingBlock) != externalapi.StatusUTXOPendingVerification {
+			t.Fatalf("kosherizingBlock expected status '%s' but got '%s'", externalapi.StatusUTXOPendingVerification, getStatus(consensusReal, kosherizingBlock))
+		}
+
+		for i, b := range blocksChain2 {
+			if getStatus(consensusReal, b) != externalapi.StatusUTXOPendingVerification {
+				t.Fatalf("blocksChain2[%d] expected status '%s' but got '%s'", i, externalapi.StatusUTXOPendingVerification, getStatus(consensusReal, b))
+			}
+		}
+		for i, b := range selectedChain {
+			if getStatus(consensusReal, b) != externalapi.StatusValid {
+				t.Fatalf("selectedChain[%d] expected status '%s' but got '%s'", i, externalapi.StatusValid, getStatus(consensusReal, b))
+			}
+		}
+	})
+}
diff --git a/domain/consensus/model/interface_datastructures_consensusstatestore.go b/domain/consensus/model/interface_datastructures_consensusstatestore.go
index 9be74807..022f8c54 100644
--- a/domain/consensus/model/interface_datastructures_consensusstatestore.go
+++ b/domain/consensus/model/interface_datastructures_consensusstatestore.go
@@ -13,9 +13,9 @@ type ConsensusStateStore interface {
 	HasUTXOByOutpoint(dbContext DBReader, outpoint *externalapi.DomainOutpoint) (bool, error)
 	VirtualUTXOSetIterator(dbContext DBReader) (ReadOnlyUTXOSetIterator, error)
 
-	StageVirtualDiffParents(virtualDiffParents []*externalapi.DomainHash) error
+	StageVirtualDiffParents(virtualDiffParents []*externalapi.DomainHash)
 	VirtualDiffParents(dbContext DBReader) ([]*externalapi.DomainHash, error)
 
-	StageTips(tipHashes []*externalapi.DomainHash) error
+	StageTips(tipHashes []*externalapi.DomainHash)
 	Tips(dbContext DBReader) ([]*externalapi.DomainHash, error)
 }
diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go
index 1521a107..667dd23e 100644
--- a/domain/consensus/processes/blockbuilder/test_block_builder.go
+++ b/domain/consensus/processes/blockbuilder/test_block_builder.go
@@ -83,12 +83,9 @@ func (bb *testBlockBuilder) buildBlockWithParents(
 		}
 	}
 
-	err := bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes})
-	if err != nil {
-		return nil, err
-	}
+	bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes})
 
-	err = bb.ghostdagManager.GHOSTDAG(tempBlockHash)
+	err := bb.ghostdagManager.GHOSTDAG(tempBlockHash)
 	if err != nil {
 		return nil, err
 	}
@@ -111,10 +108,8 @@ func (bb *testBlockBuilder) buildBlockWithParents(
 	if err != nil {
 		return nil, err
 	}
-	err = bb.acceptanceDataStore.Stage(tempBlockHash, acceptanceData)
-	if err != nil {
-		return nil, err
-	}
+
+	bb.acceptanceDataStore.Stage(tempBlockHash, acceptanceData)
 
 	coinbase, err := bb.coinbaseManager.ExpectedCoinbaseTransaction(tempBlockHash, coinbaseData)
 	if err != nil {
diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go
index e7b1b95c..3fe1177a 100644
--- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go
+++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go
@@ -4,9 +4,12 @@ import (
 	"github.com/kaspanet/kaspad/domain/consensus"
 	"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
 	"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
+	"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
 	"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
 	"github.com/kaspanet/kaspad/domain/dagconfig"
 	"github.com/pkg/errors"
+	"math"
 	"testing"
 )
 
@@ -72,3 +75,928 @@ func TestChainedTransactions(t *testing.T) {
 		}
 	})
 }
+
+// TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works
+// as expected.
+func TestCheckBlockSanity(t *testing.T) {
+	testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
+		factory := consensus.NewFactory()
+		consensus, teardown, err := factory.NewTestConsensus(params, "TestCheckBlockSanity")
+		if err != nil {
+			t.Fatalf("Error setting up consensus: %+v", err)
+		}
+		defer teardown()
+		blockHash := consensusserialization.BlockHash(&exampleValidBlock)
+		if len(exampleValidBlock.Transactions) < 3 {
+			t.Fatalf("Too few transactions in block, expect at least 3, got %v", len(exampleValidBlock.Transactions))
+		}
+
+		consensus.BlockStore().Stage(blockHash, &exampleValidBlock)
+
+		err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash)
+		if err != nil {
+			t.Fatalf("Failed validating block in isolation: %v", err)
+		}
+
+		// Test with block with wrong transactions sorting order
+		blockHash = consensusserialization.BlockHash(&blockWithWrongTxOrder)
+		consensus.BlockStore().Stage(blockHash, &blockWithWrongTxOrder)
+		err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash)
+		if !errors.Is(err, ruleerrors.ErrTransactionsNotSorted) {
+			t.Errorf("CheckBlockSanity: Expected ErrTransactionsNotSorted error, instead got %v", err)
+		}
+
+		// Test a block with invalid parents order
+		// We no longer require blocks to have ordered parents
+		blockHash = consensusserialization.BlockHash(&unOrderedParentsBlock)
+		consensus.BlockStore().Stage(blockHash, &unOrderedParentsBlock)
+		err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash)
+		if err != nil {
+			t.Errorf("CheckBlockSanity: Expected block to be be body in isolation valid, got error instead: %v", err)
+		}
+	})
+}
+
+var unOrderedParentsBlock = externalapi.DomainBlock{
+	Header: &externalapi.DomainBlockHeader{
+		Version: 0x10000000,
+		ParentHashes: []*externalapi.DomainHash{
+			{
+				0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b,
+				0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87,
+				0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52,
+				0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00,
+			},
+			{
+				0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95,
+				0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3,
+				0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b,
+				0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00,
+			},
+		},
+		HashMerkleRoot: externalapi.DomainHash{
+			0xa2, 0x60, 0x5a, 0x45, 0xfe, 0x01, 0x41, 0xc9,
+			0xc2, 0x8d, 0xe2, 0xc3, 0x2d, 0x00, 0xa4, 0x29,
+			0xd4, 0x01, 0x57, 0x2d, 0x2f, 0xcd, 0x49, 0xd4,
+			0xff, 0x6f, 0xab, 0xd2, 0xd1, 0x96, 0x38, 0xb9,
+		},
+		AcceptedIDMerkleRoot: externalapi.DomainHash{
+			0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95,
+			0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06,
+			0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25,
+			0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2,
+		},
+		UTXOCommitment: externalapi.DomainHash{
+			0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95,
+			0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06,
+			0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25,
+			0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2,
+		},
+		TimeInMilliseconds: 0x5cd18053000,
+		Bits:               0x207fffff,
+		Nonce:              0x1,
+	},
+	Transactions: []*externalapi.DomainTransaction{
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID{},
+						Index:         0xffffffff,
+					},
+					SignatureScript: []byte{
+						0x02, 0x10, 0x27, 0x08, 0xac, 0x29, 0x2f, 0x2f,
+						0xcf, 0x70, 0xb0, 0x7e, 0x0b, 0x2f, 0x50, 0x32,
+						0x53, 0x48, 0x2f, 0x62, 0x74, 0x63, 0x64, 0x2f,
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0x12a05f200, // 5000000000
+					ScriptPublicKey: []byte{
+						0x51,
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDCoinbase,
+			Payload:      []byte{9, 0, 0, 0, 0, 0, 0, 0, 0},
+			PayloadHash: externalapi.DomainHash{
+				0x95, 0x7b, 0xde, 0x03, 0xa6, 0x26, 0x1f, 0xf0,
+				0x95, 0x5d, 0x2c, 0x92, 0x07, 0x4b, 0x5c, 0xdc,
+				0xd5, 0xbb, 0x9f, 0x7d, 0x8f, 0xeb, 0x61, 0x16,
+				0xe3, 0xe5, 0x77, 0x16, 0x5e, 0x98, 0x82, 0xa7,
+			},
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID([32]byte{
+							0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60,
+							0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac,
+							0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07,
+							0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87,
+						}), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03
+						Index: 0,
+					},
+					SignatureScript: []byte{
+						0x49, // OP_DATA_73
+						0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3,
+						0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6,
+						0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94,
+						0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58,
+						0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00,
+						0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62,
+						0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c,
+						0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60,
+						0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48,
+						0x01, // 73-byte signature
+						0x41, // OP_DATA_65
+						0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d,
+						0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38,
+						0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25,
+						0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e,
+						0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8,
+						0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd,
+						0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b,
+						0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3,
+						0xd3, // 65-byte pubkey
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0x2123e300, // 556000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60,
+						0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e,
+						0xf7, 0xf5, 0x8b, 0x32,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+				{
+					Value: 0x108e20f00, // 4444000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f,
+						0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b,
+						0x52, 0xde, 0x3d, 0x7c,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDNative,
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID([32]byte{
+							0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d,
+							0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27,
+							0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65,
+							0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf,
+						}), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3
+						Index: 1,
+					},
+					SignatureScript: []byte{
+						0x47, // OP_DATA_71
+						0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf,
+						0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5,
+						0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34,
+						0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31,
+						0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee,
+						0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f,
+						0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c,
+						0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e,
+						0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01,
+						0x41, // OP_DATA_65
+						0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78,
+						0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5,
+						0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39,
+						0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21,
+						0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee,
+						0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3,
+						0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95,
+						0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85,
+						0x0f, // 65-byte pubkey
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0xf4240, // 1000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04,
+						0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d,
+						0xad, 0xbe, 0x7e, 0x10,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+				{
+					Value: 0x11d260c0, // 299000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1,
+						0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab,
+						0xb3, 0x40, 0x9c, 0xd9,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDNative,
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID([32]byte{
+							0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73,
+							0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac,
+							0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90,
+							0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4,
+						}), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b
+						Index: 0,
+					},
+					SignatureScript: []byte{
+						0x49, // OP_DATA_73
+						0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2,
+						0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c,
+						0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd,
+						0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f,
+						0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00,
+						0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14,
+						0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb,
+						0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c,
+						0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3,
+						0x01, // 73-byte signature
+						0x41, // OP_DATA_65
+						0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97,
+						0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18,
+						0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17,
+						0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94,
+						0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65,
+						0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f,
+						0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce,
+						0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f,
+						0xbb, // 65-byte pubkey
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0xf4240, // 1000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7,
+						0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b,
+						0xf2, 0xeb, 0x9e, 0xe0,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDNative,
+		},
+	},
+}
+
+// exampleValidBlock defines a sample valid block
+var exampleValidBlock = externalapi.DomainBlock{
+	Header: &externalapi.DomainBlockHeader{
+		Version: 0x10000000,
+		ParentHashes: []*externalapi.DomainHash{
+			{
+				0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95,
+				0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3,
+				0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b,
+				0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00,
+			},
+			{
+				0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b,
+				0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87,
+				0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52,
+				0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00,
+			},
+		},
+		HashMerkleRoot: externalapi.DomainHash{
+			0xce, 0xea, 0x78, 0x53, 0x7e, 0x89, 0x67, 0xaf,
+			0xdc, 0x4a, 0xd1, 0x67, 0xb0, 0xc4, 0xfc, 0x6e,
+			0xe5, 0x4b, 0x87, 0xb0, 0x55, 0x8f, 0xf4, 0x6b,
+			0x05, 0x4d, 0x43, 0x0a, 0xb6, 0xbb, 0xe8, 0xdf,
+		},
+		AcceptedIDMerkleRoot: externalapi.DomainHash{
+			0x8a, 0xb7, 0xd6, 0x73, 0x1b, 0xe6, 0xc5, 0xd3,
+			0x5d, 0x4e, 0x2c, 0xc9, 0x57, 0x88, 0x30, 0x65,
+			0x81, 0xb8, 0xa0, 0x68, 0x77, 0xc4, 0x02, 0x1e,
+			0x3c, 0xb1, 0x16, 0x8f, 0x5f, 0x6b, 0x45, 0x87,
+		},
+		UTXOCommitment:     [32]byte{},
+		TimeInMilliseconds: 0x17305aa654a,
+		Bits:               0x207fffff,
+		Nonce:              1,
+	},
+	Transactions: []*externalapi.DomainTransaction{
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID{
+							0x9b, 0x22, 0x59, 0x44, 0x66, 0xf0, 0xbe, 0x50,
+							0x7c, 0x1c, 0x8a, 0xf6, 0x06, 0x27, 0xe6, 0x33,
+							0x38, 0x7e, 0xd1, 0xd5, 0x8c, 0x42, 0x59, 0x1a,
+							0x31, 0xac, 0x9a, 0xa6, 0x2e, 0xd5, 0x2b, 0x0f,
+						},
+						Index: 0xffffffff,
+					},
+					SignatureScript: nil,
+					Sequence:        math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0x12a05f200, // 5000000000
+					ScriptPublicKey: []byte{
+						0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49,
+						0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7,
+						0x7e, 0xba, 0x30, 0xcd, 0x5a, 0x4b, 0x87,
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDCoinbase,
+			Payload:      []byte{9, 0, 0, 0, 0, 0, 0, 0, 0},
+			PayloadHash: externalapi.DomainHash{
+				0x95, 0x7b, 0xde, 0x03, 0xa6, 0x26, 0x1f, 0xf0,
+				0x95, 0x5d, 0x2c, 0x92, 0x07, 0x4b, 0x5c, 0xdc,
+				0xd5, 0xbb, 0x9f, 0x7d, 0x8f, 0xeb, 0x61, 0x16,
+				0xe3, 0xe5, 0x77, 0x16, 0x5e, 0x98, 0x82, 0xa7,
+			},
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID{
+							0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95,
+							0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3,
+							0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b,
+							0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00,
+						},
+						Index: 0xffffffff,
+					},
+					Sequence: math.MaxUint64,
+				},
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID{
+							0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b,
+							0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87,
+							0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52,
+							0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00,
+						},
+						Index: 0xffffffff,
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			SubnetworkID: subnetworks.SubnetworkIDNative,
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID([32]byte{
+							0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60,
+							0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac,
+							0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07,
+							0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87,
+						}), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03
+						Index: 0,
+					},
+					SignatureScript: []byte{
+						0x49, // OP_DATA_73
+						0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3,
+						0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6,
+						0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94,
+						0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58,
+						0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00,
+						0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62,
+						0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c,
+						0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60,
+						0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48,
+						0x01, // 73-byte signature
+						0x41, // OP_DATA_65
+						0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d,
+						0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38,
+						0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25,
+						0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e,
+						0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8,
+						0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd,
+						0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b,
+						0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3,
+						0xd3, // 65-byte pubkey
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0x2123e300, // 556000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60,
+						0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e,
+						0xf7, 0xf5, 0x8b, 0x32,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+				{
+					Value: 0x108e20f00, // 4444000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f,
+						0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b,
+						0x52, 0xde, 0x3d, 0x7c,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDNative,
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID([32]byte{
+							0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d,
+							0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27,
+							0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65,
+							0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf,
+						}), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3
+						Index: 1,
+					},
+					SignatureScript: []byte{
+						0x47, // OP_DATA_71
+						0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf,
+						0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5,
+						0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34,
+						0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31,
+						0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee,
+						0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f,
+						0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c,
+						0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e,
+						0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01,
+						0x41, // OP_DATA_65
+						0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78,
+						0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5,
+						0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39,
+						0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21,
+						0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee,
+						0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3,
+						0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95,
+						0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85,
+						0x0f, // 65-byte pubkey
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0xf4240, // 1000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04,
+						0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d,
+						0xad, 0xbe, 0x7e, 0x10,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+				{
+					Value: 0x11d260c0, // 299000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1,
+						0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab,
+						0xb3, 0x40, 0x9c, 0xd9,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDNative,
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID{
+							0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73,
+							0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac,
+							0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90,
+							0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4,
+						}, // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b
+						Index: 0,
+					},
+					SignatureScript: []byte{
+						0x49, // OP_DATA_73
+						0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2,
+						0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c,
+						0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd,
+						0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f,
+						0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00,
+						0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14,
+						0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb,
+						0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c,
+						0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3,
+						0x01, // 73-byte signature
+						0x41, // OP_DATA_65
+						0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97,
+						0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18,
+						0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17,
+						0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94,
+						0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65,
+						0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f,
+						0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce,
+						0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f,
+						0xbb, // 65-byte pubkey
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0xf4240, // 1000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7,
+						0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b,
+						0xf2, 0xeb, 0x9e, 0xe0,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDNative,
+		},
+	},
+}
+
+// blockWithWrongTxOrder defines invalid block 100,000 of the block DAG.
+var blockWithWrongTxOrder = externalapi.DomainBlock{
+	Header: &externalapi.DomainBlockHeader{
+		Version: 1,
+		ParentHashes: []*externalapi.DomainHash{
+			{
+				0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95,
+				0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3,
+				0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b,
+				0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00,
+			},
+			{
+				0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b,
+				0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87,
+				0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52,
+				0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00,
+			},
+		},
+		HashMerkleRoot: externalapi.DomainHash{
+			0xac, 0xa4, 0x21, 0xe1, 0xa6, 0xc3, 0xbe, 0x5d,
+			0x52, 0x66, 0xf3, 0x0b, 0x21, 0x87, 0xbc, 0xf3,
+			0xf3, 0x2d, 0xd1, 0x05, 0x64, 0xb5, 0x16, 0x76,
+			0xe4, 0x66, 0x7d, 0x51, 0x53, 0x18, 0x6d, 0xb1,
+		},
+		AcceptedIDMerkleRoot: externalapi.DomainHash{
+			0xa0, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3,
+			0xcd, 0xc7, 0xc9, 0xaf, 0xfb, 0xd2, 0x1b, 0x85,
+			0x0b, 0x79, 0xf5, 0x29, 0x6d, 0x1c, 0xaa, 0x90,
+			0x2f, 0x01, 0xd4, 0x83, 0x9b, 0x2a, 0x04, 0x5e,
+		},
+		UTXOCommitment: externalapi.DomainHash{
+			0x00, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3,
+			0xcd, 0xc7, 0xc9, 0xaf, 0xfb, 0xd2, 0x1b, 0x85,
+			0x0b, 0x79, 0xf5, 0x29, 0x6d, 0x1c, 0xaa, 0x90,
+			0x2f, 0x01, 0xd4, 0x83, 0x9b, 0x2a, 0x04, 0x5e,
+		},
+		TimeInMilliseconds: 0x5cd16eaa000,
+		Bits:               0x207fffff,
+		Nonce:              1,
+	},
+	Transactions: []*externalapi.DomainTransaction{
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID{
+							0x9b, 0x22, 0x59, 0x44, 0x66, 0xf0, 0xbe, 0x50,
+							0x7c, 0x1c, 0x8a, 0xf6, 0x06, 0x27, 0xe6, 0x33,
+							0x38, 0x7e, 0xd1, 0xd5, 0x8c, 0x42, 0x59, 0x1a,
+							0x31, 0xac, 0x9a, 0xa6, 0x2e, 0xd5, 0x2b, 0x0f,
+						},
+						Index: 0xffffffff,
+					},
+					SignatureScript: nil,
+					Sequence:        math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0x12a05f200, // 5000000000
+					ScriptPublicKey: []byte{
+						0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49,
+						0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7,
+						0x7e, 0xba, 0x30, 0xcd, 0x5a, 0x4b, 0x87,
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDCoinbase,
+			Payload:      []byte{9, 0, 0, 0, 0, 0, 0, 0, 0},
+			PayloadHash: externalapi.DomainHash{
+				0x95, 0x7b, 0xde, 0x03, 0xa6, 0x26, 0x1f, 0xf0,
+				0x95, 0x5d, 0x2c, 0x92, 0x07, 0x4b, 0x5c, 0xdc,
+				0xd5, 0xbb, 0x9f, 0x7d, 0x8f, 0xeb, 0x61, 0x16,
+				0xe3, 0xe5, 0x77, 0x16, 0x5e, 0x98, 0x82, 0xa7,
+			},
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID{
+							0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95,
+							0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3,
+							0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b,
+							0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00,
+						},
+						Index: 0xffffffff,
+					},
+					Sequence: math.MaxUint64,
+				},
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID{
+							0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b,
+							0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87,
+							0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52,
+							0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00,
+						},
+						Index: 0xffffffff,
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			SubnetworkID: subnetworks.SubnetworkIDNative,
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID([32]byte{
+							0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60,
+							0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac,
+							0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07,
+							0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87,
+						}), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03
+						Index: 0,
+					},
+					SignatureScript: []byte{
+						0x49, // OP_DATA_73
+						0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3,
+						0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6,
+						0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94,
+						0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58,
+						0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00,
+						0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62,
+						0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c,
+						0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60,
+						0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48,
+						0x01, // 73-byte signature
+						0x41, // OP_DATA_65
+						0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d,
+						0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38,
+						0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25,
+						0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e,
+						0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8,
+						0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd,
+						0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b,
+						0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3,
+						0xd3, // 65-byte pubkey
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0x2123e300, // 556000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60,
+						0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e,
+						0xf7, 0xf5, 0x8b, 0x32,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+				{
+					Value: 0x108e20f00, // 4444000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f,
+						0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b,
+						0x52, 0xde, 0x3d, 0x7c,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: externalapi.DomainSubnetworkID{11},
+			Payload:      []byte{},
+			PayloadHash:  [32]byte{0xFF, 0xFF},
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID([32]byte{
+							0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d,
+							0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27,
+							0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65,
+							0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf,
+						}), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3
+						Index: 1,
+					},
+					SignatureScript: []byte{
+						0x47, // OP_DATA_71
+						0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf,
+						0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5,
+						0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34,
+						0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31,
+						0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee,
+						0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f,
+						0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c,
+						0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e,
+						0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01,
+						0x41, // OP_DATA_65
+						0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78,
+						0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5,
+						0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39,
+						0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21,
+						0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee,
+						0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3,
+						0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95,
+						0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85,
+						0x0f, // 65-byte pubkey
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0xf4240, // 1000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04,
+						0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d,
+						0xad, 0xbe, 0x7e, 0x10,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+				{
+					Value: 0x11d260c0, // 299000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1,
+						0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab,
+						0xb3, 0x40, 0x9c, 0xd9,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDNative,
+		},
+		{
+			Version: 1,
+			Inputs: []*externalapi.DomainTransactionInput{
+				{
+					PreviousOutpoint: externalapi.DomainOutpoint{
+						TransactionID: externalapi.DomainTransactionID([32]byte{
+							0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73,
+							0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac,
+							0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90,
+							0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4,
+						}), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b
+						Index: 0,
+					},
+					SignatureScript: []byte{
+						0x49, // OP_DATA_73
+						0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2,
+						0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c,
+						0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd,
+						0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f,
+						0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00,
+						0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14,
+						0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb,
+						0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c,
+						0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3,
+						0x01, // 73-byte signature
+						0x41, // OP_DATA_65
+						0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97,
+						0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18,
+						0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17,
+						0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94,
+						0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65,
+						0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f,
+						0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce,
+						0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f,
+						0xbb, // 65-byte pubkey
+					},
+					Sequence: math.MaxUint64,
+				},
+			},
+			Outputs: []*externalapi.DomainTransactionOutput{
+				{
+					Value: 0xf4240, // 1000000
+					ScriptPublicKey: []byte{
+						0x76, // OP_DUP
+						0xa9, // OP_HASH160
+						0x14, // OP_DATA_20
+						0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7,
+						0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b,
+						0xf2, 0xeb, 0x9e, 0xe0,
+						0x88, // OP_EQUALVERIFY
+						0xac, // OP_CHECKSIG
+					},
+				},
+			},
+			LockTime:     0,
+			SubnetworkID: subnetworks.SubnetworkIDNative,
+		},
+	},
+}
diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go
index 781a15e2..fab862ba 100644
--- a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go
+++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go
@@ -38,13 +38,10 @@ func TestValidateMedianTime(t *testing.T) {
 
 		pastMedianTime := func(parents ...*externalapi.DomainHash) int64 {
 			var tempHash externalapi.DomainHash
-			err := tc.BlockRelationStore().StageBlockRelation(&tempHash, &model.BlockRelations{
+			tc.BlockRelationStore().StageBlockRelation(&tempHash, &model.BlockRelations{
 				Parents:  parents,
 				Children: nil,
 			})
-			if err != nil {
-				t.Fatalf("StageBlockRelation: %+v", err)
-			}
 			defer tc.BlockRelationStore().Discard()
 
 			err = tc.GHOSTDAGManager().GHOSTDAG(&tempHash)
diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra_test.go b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra_test.go
index 43c1a954..e42e9514 100644
--- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra_test.go
+++ b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra_test.go
@@ -58,7 +58,7 @@ func TestUTXOCollection(t *testing.T) {
 		}
 
 		// Test model.UTXOCollection cloning
-		collectionClone := collectionClone(test.collection)
+		collectionClone := test.collection.Clone()
 		if reflect.ValueOf(collectionClone).Pointer() == reflect.ValueOf(test.collection).Pointer() {
 			t.Errorf("collection is reference-equal to its clone in test \"%s\". ", test.name)
 		}
@@ -95,7 +95,7 @@ func TestUTXODiff(t *testing.T) {
 	}
 
 	// Test utxoDiff cloning
-	clonedDiff := DiffClone(diff)
+	clonedDiff := diff.Clone()
 	if clonedDiff == diff {
 		t.Errorf("cloned diff is reference-equal to the original")
 	}
@@ -576,7 +576,7 @@ func TestUTXODiffRules(t *testing.T) {
 		}
 
 		// Repeat WithDiff check test.this time using withDiffInPlace
-		thisClone := DiffClone(test.this)
+		thisClone := test.this.Clone()
 		err = WithDiffInPlace(thisClone, test.other)
 
 		// Test whether withDiffInPlace returned an error
diff --git a/domain/consensus/processes/reachabilitymanager/reachability_test.go b/domain/consensus/processes/reachabilitymanager/reachability_test.go
index 6b473d10..448ebb03 100644
--- a/domain/consensus/processes/reachabilitymanager/reachability_test.go
+++ b/domain/consensus/processes/reachabilitymanager/reachability_test.go
@@ -23,10 +23,9 @@ func (r *reachabilityDataStoreMock) Commit(_ model.DBTransaction) error {
 	panic("implement me")
 }
 
-func (r *reachabilityDataStoreMock) StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *model.ReachabilityData) error {
+func (r *reachabilityDataStoreMock) StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *model.ReachabilityData) {
 	r.reachabilityDataStaging[*blockHash] = reachabilityData
 	r.recorder[*blockHash] = struct{}{}
-	return nil
 }
 
 func (r *reachabilityDataStoreMock) StageReachabilityReindexRoot(reachabilityReindexRoot *externalapi.DomainHash) {
diff --git a/testing/integration/64_incoming_connections_test.go b/testing/integration/64_incoming_connections_test.go
index edc3055c..3ac4a869 100644
--- a/testing/integration/64_incoming_connections_test.go
+++ b/testing/integration/64_incoming_connections_test.go
@@ -6,8 +6,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/kaspanet/kaspad/util/locks"
-
 	"github.com/kaspanet/kaspad/app/appmessage"
 )
 
@@ -56,6 +54,16 @@ func Test64IncomingConnections(t *testing.T) {
 	select {
 	case <-time.After(defaultTimeout):
 		t.Fatalf("Timeout waiting for block added notification from the bullies")
-	case <-locks.ReceiveFromChanWhenDone(func() { blockAddedWG.Wait() }):
+	case <-ReceiveFromChanWhenDone(func() { blockAddedWG.Wait() }):
 	}
 }
+
+// ReceiveFromChanWhenDone takes a blocking function and returns a channel that sends an empty struct when the function is done.
+func ReceiveFromChanWhenDone(callback func()) <-chan struct{} {
+	ch := make(chan struct{})
+	spawn("ReceiveFromChanWhenDone", func() {
+		callback()
+		close(ch)
+	})
+	return ch
+}
diff --git a/testing/integration/ibd_test.go b/testing/integration/ibd_test.go
index 1fb26ca6..78b39fc8 100644
--- a/testing/integration/ibd_test.go
+++ b/testing/integration/ibd_test.go
@@ -5,8 +5,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/kaspanet/kaspad/util/locks"
-
 	"github.com/kaspanet/kaspad/app/appmessage"
 )
 
@@ -33,7 +31,7 @@ func TestIBD(t *testing.T) {
 	select {
 	case <-time.After(defaultTimeout):
 		t.Fatalf("Timeout waiting for IBD to finish. Received %d blocks out of %d", receivedBlocks, numBlocks)
-	case <-locks.ReceiveFromChanWhenDone(func() { blockAddedWG.Wait() }):
+	case <-ReceiveFromChanWhenDone(func() { blockAddedWG.Wait() }):
 	}
 
 	tip1Hash, err := syncer.rpcClient.GetSelectedTipHash()