Smal performance improvements to BlueWindow (#1343)

* Convert BlockGHOSTDAGData from an interface to a public struct with getters

* Move hashes.Less to externalapi so it can access the hashes directly without copying

* Reduce calls to ghostdagstore.Get in blueWindow

* Simplify the logic in RequiredDifficulty and reuse big.Int

* Remove bigintpool as its no longer used

* Use ChooseSelectedParent in RequiredDifficulty instead of looping over the parents

* Remove comment
This commit is contained in:
Elichai Turkel
2021-01-05 12:13:02 +02:00
committed by GitHub
parent 0fb97a4f37
commit e509cb1597
20 changed files with 170 additions and 232 deletions

View File

@@ -3,12 +3,11 @@ package serialization
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
"math/big"
)
// BlockGHOSTDAGDataToDBBlockGHOSTDAGData converts BlockGHOSTDAGData to DbBlockGhostdagData
func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDAGData) *DbBlockGhostdagData {
func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData *model.BlockGHOSTDAGData) *DbBlockGhostdagData {
var selectedParent *DbHash
if blockGHOSTDAGData.SelectedParent() != nil {
selectedParent = DomainHashToDbHash(blockGHOSTDAGData.SelectedParent())
@@ -25,7 +24,7 @@ func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDA
}
// DBBlockGHOSTDAGDataToBlockGHOSTDAGData converts DbBlockGhostdagData to BlockGHOSTDAGData
func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (model.BlockGHOSTDAGData, error) {
func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (*model.BlockGHOSTDAGData, error) {
var selectedParent *externalapi.DomainHash
if dbBlockGHOSTDAGData.SelectedParent != nil {
var err error
@@ -50,7 +49,7 @@ func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdag
return nil, err
}
return ghostdagmanager.NewBlockGHOSTDAGData(
return model.NewBlockGHOSTDAGData(
dbBlockGHOSTDAGData.BlueScore,
new(big.Int).SetBytes(dbBlockGHOSTDAGData.BlueWork),
selectedParent,

View File

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

View File

@@ -105,3 +105,21 @@ func HashesEqual(a, b []*DomainHash) bool {
}
return true
}
func cmp(a, b *DomainHash) int {
// We compare the hashes backwards because Hash is stored as a little endian byte array.
for i := DomainHashSize - 1; i >= 0; i-- {
switch {
case a.hashArray[i] < b.hashArray[i]:
return -1
case a.hashArray[i] > b.hashArray[i]:
return 1
}
}
return 0
}
// Less returns true iff hash a is less than hash b
func Less(a, b *DomainHash) bool {
return cmp(a, b) < 0
}

View File

@@ -6,16 +6,74 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
// BlockGHOSTDAGData represents GHOSTDAG data for some block
type BlockGHOSTDAGData interface {
BlueScore() uint64
BlueWork() *big.Int
SelectedParent() *externalapi.DomainHash
MergeSetBlues() []*externalapi.DomainHash
MergeSetReds() []*externalapi.DomainHash
MergeSet() []*externalapi.DomainHash
BluesAnticoneSizes() map[externalapi.DomainHash]KType
}
// KType defines the size of GHOSTDAG consensus algorithm K parameter.
type KType byte
// BlockGHOSTDAGData represents GHOSTDAG data for some block
type BlockGHOSTDAGData struct {
blueScore uint64
blueWork *big.Int
selectedParent *externalapi.DomainHash
mergeSetBlues []*externalapi.DomainHash
mergeSetReds []*externalapi.DomainHash
bluesAnticoneSizes map[externalapi.DomainHash]KType
}
// NewBlockGHOSTDAGData creates a new instance of BlockGHOSTDAGData
func NewBlockGHOSTDAGData(
blueScore uint64,
blueWork *big.Int,
selectedParent *externalapi.DomainHash,
mergeSetBlues []*externalapi.DomainHash,
mergeSetReds []*externalapi.DomainHash,
bluesAnticoneSizes map[externalapi.DomainHash]KType) *BlockGHOSTDAGData {
return &BlockGHOSTDAGData{
blueScore: blueScore,
blueWork: blueWork,
selectedParent: selectedParent,
mergeSetBlues: mergeSetBlues,
mergeSetReds: mergeSetReds,
bluesAnticoneSizes: bluesAnticoneSizes,
}
}
// BlueScore returns the BlueScore of the block
func (bgd *BlockGHOSTDAGData) BlueScore() uint64 {
return bgd.blueScore
}
// BlueWork returns the BlueWork of the block
func (bgd *BlockGHOSTDAGData) BlueWork() *big.Int {
return bgd.blueWork
}
// SelectedParent returns the SelectedParent of the block
func (bgd *BlockGHOSTDAGData) SelectedParent() *externalapi.DomainHash {
return bgd.selectedParent
}
// MergeSetBlues returns the MergeSetBlues of the block (not a copy)
func (bgd *BlockGHOSTDAGData) MergeSetBlues() []*externalapi.DomainHash {
return bgd.mergeSetBlues
}
// MergeSetReds returns the MergeSetReds of the block (not a copy)
func (bgd *BlockGHOSTDAGData) MergeSetReds() []*externalapi.DomainHash {
return bgd.mergeSetReds
}
// BluesAnticoneSizes returns a map between the blocks in its MergeSetBlues and the size of their anticone
func (bgd *BlockGHOSTDAGData) BluesAnticoneSizes() map[externalapi.DomainHash]KType {
return bgd.bluesAnticoneSizes
}
// MergeSet returns the whole MergeSet of the block (equivalent to MergeSetBlues+MergeSetReds)
func (bgd *BlockGHOSTDAGData) MergeSet() []*externalapi.DomainHash {
mergeSet := make([]*externalapi.DomainHash, len(bgd.mergeSetBlues)+len(bgd.mergeSetReds))
copy(mergeSet, bgd.mergeSetBlues)
if len(bgd.mergeSetReds) > 0 {
copy(mergeSet[len(bgd.mergeSetBlues):], bgd.mergeSetReds)
}
return mergeSet
}

View File

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

View File

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

View File

@@ -109,7 +109,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH
}
func (csm *consensusStateManager) applyMergeSetBlocks(blockHash *externalapi.DomainHash,
selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData model.BlockGHOSTDAGData) (
selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData *model.BlockGHOSTDAGData) (
externalapi.AcceptanceData, model.MutableUTXODiff, error) {
log.Debugf("applyMergeSetBlocks start for block %s", blockHash)

View File

@@ -10,7 +10,7 @@ import (
)
func (csm *consensusStateManager) calculateMultiset(
acceptanceData externalapi.AcceptanceData, blockGHOSTDAGData model.BlockGHOSTDAGData) (model.Multiset, error) {
acceptanceData externalapi.AcceptanceData, blockGHOSTDAGData *model.BlockGHOSTDAGData) (model.Multiset, error) {
log.Debugf("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent())
defer log.Debugf("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent())

View File

@@ -9,7 +9,7 @@ import (
type blockHeapNode struct {
hash *externalapi.DomainHash
ghostdagData model.BlockGHOSTDAGData
ghostdagData *model.BlockGHOSTDAGData
}
func (left *blockHeapNode) less(right *blockHeapNode, gm model.GHOSTDAGManager) bool {
@@ -152,12 +152,8 @@ func (sbh *sizedUpBlockHeap) pop() *externalapi.DomainHash {
return heap.Pop(&sbh.impl).(*blockHeapNode).hash
}
// tryPush tries to push the block onto the heap, if the heap is full and it's less than the minimum it rejects it
func (sbh *sizedUpBlockHeap) tryPush(blockHash *externalapi.DomainHash) (bool, error) {
ghostdagData, err := sbh.ghostdagStore.Get(sbh.dbContext, blockHash)
if err != nil {
return false, err
}
// tryPushWithGHOSTDAGData is just like tryPush but the caller provides the ghostdagData of the block.
func (sbh *sizedUpBlockHeap) tryPushWithGHOSTDAGData(blockHash *externalapi.DomainHash, ghostdagData *model.BlockGHOSTDAGData) (bool, error) {
node := &blockHeapNode{
hash: blockHash,
ghostdagData: ghostdagData,
@@ -173,3 +169,12 @@ func (sbh *sizedUpBlockHeap) tryPush(blockHash *externalapi.DomainHash) (bool, e
heap.Push(&sbh.impl, node)
return true, nil
}
// tryPush tries to push the block onto the heap, if the heap is full and it's less than the minimum it rejects it
func (sbh *sizedUpBlockHeap) tryPush(blockHash *externalapi.DomainHash) (bool, error) {
ghostdagData, err := sbh.ghostdagStore.Get(sbh.dbContext, blockHash)
if err != nil {
return false, err
}
return sbh.tryPushWithGHOSTDAGData(blockHash, ghostdagData)
}

View File

@@ -18,7 +18,11 @@ func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash
windowHeap := dtm.newSizedUpHeap(windowSize)
for windowHeap.len() <= windowSize && currentGHOSTDAGData.SelectedParent() != nil {
added, err := windowHeap.tryPush(currentGHOSTDAGData.SelectedParent())
selectedParentGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentGHOSTDAGData.SelectedParent())
if err != nil {
return nil, err
}
added, err := windowHeap.tryPushWithGHOSTDAGData(currentGHOSTDAGData.SelectedParent(), selectedParentGHOSTDAGData)
if err != nil {
return nil, err
}
@@ -55,10 +59,7 @@ func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash
}
}
currentHash = currentGHOSTDAGData.SelectedParent()
currentGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash)
if err != nil {
return nil, err
}
currentGHOSTDAGData = selectedParentGHOSTDAGData
}
window := make([]*externalapi.DomainHash, 0, windowSize)

View File

@@ -3,7 +3,6 @@ package difficultymanager
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/bigintpool"
"github.com/pkg/errors"
"math"
"math/big"
@@ -72,19 +71,14 @@ func (window *blockWindow) remove(n int) {
*window = (*window)[:len(*window)-1]
}
func (window blockWindow) averageTarget(averageTarget *big.Int) {
averageTarget.SetInt64(0)
target := bigintpool.Acquire(0)
defer bigintpool.Release(target)
func (window blockWindow) averageTarget() *big.Int {
averageTarget := new(big.Int)
targetTmp := new(big.Int)
for _, block := range window {
util.CompactToBigWithDestination(block.Bits, target)
averageTarget.Add(averageTarget, target)
util.CompactToBigWithDestination(block.Bits, targetTmp)
averageTarget.Add(averageTarget, targetTmp)
}
windowLen := bigintpool.Acquire(int64(len(window)))
defer bigintpool.Release(windowLen)
averageTarget.Div(averageTarget, windowLen)
return averageTarget.Div(averageTarget, big.NewInt(int64(len(window))))
}
func (window blockWindow) medianTimestamp() (int64, error) {

View File

@@ -7,7 +7,6 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/bigintpool"
)
// DifficultyManager provides a method to resolve the
@@ -74,24 +73,13 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas
}
// find bluestParent
bluestParent := parents[0]
bluestGhostDAG, err := dm.ghostdagStore.Get(dm.databaseContext, bluestParent)
bluestParent, err := dm.ghostdagManager.ChooseSelectedParent(parents...)
if err != nil {
return 0, err
}
for i := 1; i < len(parents); i++ {
parentGhostDAG, err := dm.ghostdagStore.Get(dm.databaseContext, parents[i])
if err != nil {
return 0, err
}
newBluest, err := dm.ghostdagManager.ChooseSelectedParent(bluestParent, parents[i])
if err != nil {
return 0, err
}
if bluestParent != newBluest {
bluestParent = newBluest
bluestGhostDAG = parentGhostDAG
}
bluestGhostDAG, err := dm.ghostdagStore.Get(dm.databaseContext, bluestParent)
if err != nil {
return 0, err
}
// Not enough blocks for building a difficulty window.
@@ -113,20 +101,12 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas
// averageWindowTarget * (windowMinTimestamp / (targetTimePerBlock * windowSize))
// The result uses integer division which means it will be slightly
// rounded down.
newTarget := bigintpool.Acquire(0)
defer bigintpool.Release(newTarget)
windowTimeStampDifference := bigintpool.Acquire(windowMaxTimeStamp - windowMinTimestamp)
defer bigintpool.Release(windowTimeStampDifference)
targetTimePerBlock := bigintpool.Acquire(dm.targetTimePerBlock.Milliseconds())
defer bigintpool.Release(targetTimePerBlock)
difficultyAdjustmentWindowSize := bigintpool.Acquire(int64(dm.difficultyAdjustmentWindowSize))
defer bigintpool.Release(difficultyAdjustmentWindowSize)
targetsWindow.averageTarget(newTarget)
div := new(big.Int)
newTarget := targetsWindow.averageTarget()
newTarget.
Mul(newTarget, windowTimeStampDifference).
Div(newTarget, targetTimePerBlock).
Div(newTarget, difficultyAdjustmentWindowSize)
Mul(newTarget, div.SetInt64(windowMaxTimeStamp-windowMinTimestamp)).
Div(newTarget, div.SetInt64(dm.targetTimePerBlock.Milliseconds())).
Div(newTarget, div.SetUint64(uint64(dm.difficultyAdjustmentWindowSize)))
if newTarget.Cmp(dm.powMax) > 0 {
return util.BigToCompact(dm.powMax), nil
}

View File

@@ -3,8 +3,6 @@ package ghostdag2
import (
"sort"
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
"math/big"
"github.com/kaspanet/kaspad/domain/consensus/model"
@@ -116,7 +114,7 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error
myWork.Add(myWork, util.CalcWork(header.Bits()))
}
e := ghostdagmanager.NewBlockGHOSTDAGData(myScore, myWork, selectedParent, mergeSetBlues, mergeSetReds, nil)
e := model.NewBlockGHOSTDAGData(myScore, myWork, selectedParent, mergeSetBlues, mergeSetReds, nil)
gh.dataStore.Stage(blockCandidate, e)
return nil
}
@@ -391,13 +389,13 @@ func (gh *ghostdagHelper) sortByBlueWork(arr []*externalapi.DomainHash) error {
/* --------------------------------------------- */
func (gh *ghostdagHelper) BlockData(blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) {
func (gh *ghostdagHelper) BlockData(blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) {
return gh.dataStore.Get(gh.dbAccess, blockHash)
}
func (gh *ghostdagHelper) ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) {
panic("implement me")
}
func (gh *ghostdagHelper) Less(blockHashA *externalapi.DomainHash, ghostdagDataA model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB model.BlockGHOSTDAGData) bool {
func (gh *ghostdagHelper) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool {
panic("implement me")
}

View File

@@ -3,7 +3,6 @@ package ghostdagmanager
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
)
func (gm *ghostdagManager) findSelectedParent(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, error) {
@@ -53,16 +52,15 @@ func (gm *ghostdagManager) ChooseSelectedParent(blockHashes ...*externalapi.Doma
return selectedParent, nil
}
func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA model.BlockGHOSTDAGData,
blockHashB *externalapi.DomainHash, ghostdagDataB model.BlockGHOSTDAGData) bool {
func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData,
blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool {
switch ghostdagDataA.BlueWork().Cmp(ghostdagDataB.BlueWork()) {
case -1:
return true
case 1:
return false
case 0:
return hashes.Less(blockHashA, blockHashB)
return externalapi.Less(blockHashA, blockHashB)
default:
panic("big.Int.Cmp is defined to always return -1/1/0 and nothing else")
}

View File

@@ -8,6 +8,19 @@ import (
"math/big"
)
type blockGHOSTDAGData struct {
blueScore uint64
blueWork *big.Int
selectedParent *externalapi.DomainHash
mergeSetBlues []*externalapi.DomainHash
mergeSetReds []*externalapi.DomainHash
bluesAnticoneSizes map[externalapi.DomainHash]model.KType
}
func (bg *blockGHOSTDAGData) toModel() *model.BlockGHOSTDAGData {
return model.NewBlockGHOSTDAGData(bg.blueScore, bg.blueWork, bg.selectedParent, bg.mergeSetBlues, bg.mergeSetReds, bg.bluesAnticoneSizes)
}
// GHOSTDAG runs the GHOSTDAG protocol and calculates the block BlockGHOSTDAGData by the given parents.
// The function calculates MergeSetBlues by iterating over the blocks in
// the anticone of the new block selected parent (which is the parent with the
@@ -57,7 +70,7 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
}
for _, blueCandidate := range mergeSetWithoutSelectedParent {
isBlue, candidateAnticoneSize, candidateBluesAnticoneSizes, err := gm.checkBlueCandidate(newBlockData, blueCandidate)
isBlue, candidateAnticoneSize, candidateBluesAnticoneSizes, err := gm.checkBlueCandidate(newBlockData.toModel(), blueCandidate)
if err != nil {
return err
}
@@ -96,22 +109,22 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error {
newBlockData.blueWork.SetUint64(0)
}
gm.ghostdagDataStore.Stage(blockHash, newBlockData)
gm.ghostdagDataStore.Stage(blockHash, newBlockData.toModel())
return nil
}
type chainBlockData struct {
hash *externalapi.DomainHash
blockData model.BlockGHOSTDAGData
blockData *model.BlockGHOSTDAGData
}
func (gm *ghostdagManager) checkBlueCandidate(newBlockData *blockGHOSTDAGData, blueCandidate *externalapi.DomainHash) (
func (gm *ghostdagManager) checkBlueCandidate(newBlockData *model.BlockGHOSTDAGData, blueCandidate *externalapi.DomainHash) (
isBlue bool, candidateAnticoneSize model.KType, candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType, err error) {
// The maximum length of node.blues can be K+1 because
// it contains the selected parent.
if model.KType(len(newBlockData.mergeSetBlues)) == gm.k+1 {
if model.KType(len(newBlockData.MergeSetBlues())) == gm.k+1 {
return false, 0, nil, nil
}
@@ -153,7 +166,7 @@ func (gm *ghostdagManager) checkBlueCandidate(newBlockData *blockGHOSTDAGData, b
return true, candidateAnticoneSize, candidateBluesAnticoneSizes, nil
}
func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData model.BlockGHOSTDAGData,
func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData *model.BlockGHOSTDAGData,
chainBlock chainBlockData, blueCandidate *externalapi.DomainHash,
candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType,
candidateAnticoneSize *model.KType) (isBlue, isRed bool, err error) {
@@ -218,7 +231,7 @@ func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData model.B
// blueAnticoneSize returns the blue anticone size of 'block' from the worldview of 'context'.
// Expects 'block' to be in the blue set of 'context'
func (gm *ghostdagManager) blueAnticoneSize(block *externalapi.DomainHash, context model.BlockGHOSTDAGData) (model.KType, error) {
func (gm *ghostdagManager) blueAnticoneSize(block *externalapi.DomainHash, context *model.BlockGHOSTDAGData) (model.KType, error) {
for current := context; current != nil; {
if blueAnticoneSize, ok := current.BluesAnticoneSizes()[*block]; ok {
return blueAnticoneSize, nil

View File

@@ -1,69 +0,0 @@
package ghostdagmanager
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"math/big"
)
type blockGHOSTDAGData struct {
blueScore uint64
blueWork *big.Int
selectedParent *externalapi.DomainHash
mergeSetBlues []*externalapi.DomainHash
mergeSetReds []*externalapi.DomainHash
bluesAnticoneSizes map[externalapi.DomainHash]model.KType
}
// NewBlockGHOSTDAGData creates a new instance of model.BlockGHOSTDAGData
func NewBlockGHOSTDAGData(
blueScore uint64,
blueWork *big.Int,
selectedParent *externalapi.DomainHash,
mergeSetBlues []*externalapi.DomainHash,
mergeSetReds []*externalapi.DomainHash,
bluesAnticoneSizes map[externalapi.DomainHash]model.KType) model.BlockGHOSTDAGData {
return &blockGHOSTDAGData{
blueScore: blueScore,
blueWork: blueWork,
selectedParent: selectedParent,
mergeSetBlues: mergeSetBlues,
mergeSetReds: mergeSetReds,
bluesAnticoneSizes: bluesAnticoneSizes,
}
}
func (bgd *blockGHOSTDAGData) BlueScore() uint64 {
return bgd.blueScore
}
func (bgd *blockGHOSTDAGData) BlueWork() *big.Int {
return bgd.blueWork
}
func (bgd *blockGHOSTDAGData) SelectedParent() *externalapi.DomainHash {
return bgd.selectedParent
}
func (bgd *blockGHOSTDAGData) MergeSetBlues() []*externalapi.DomainHash {
return bgd.mergeSetBlues
}
func (bgd *blockGHOSTDAGData) MergeSetReds() []*externalapi.DomainHash {
return bgd.mergeSetReds
}
func (bgd *blockGHOSTDAGData) BluesAnticoneSizes() map[externalapi.DomainHash]model.KType {
return bgd.bluesAnticoneSizes
}
func (bgd *blockGHOSTDAGData) MergeSet() []*externalapi.DomainHash {
mergeSet := make([]*externalapi.DomainHash, len(bgd.mergeSetBlues)+len(bgd.mergeSetReds))
copy(mergeSet, bgd.mergeSetBlues)
if len(bgd.mergeSetReds) > 0 {
copy(mergeSet[len(bgd.mergeSetBlues):], bgd.mergeSetReds)
}
return mergeSet
}

View File

@@ -63,14 +63,14 @@ func TestGHOSTDAG(t *testing.T) {
}
ghostdagDataStore := &GHOSTDAGDataStoreImpl{
dagMap: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData),
dagMap: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData),
}
blockHeadersStore := &blockHeadersStore{
dagMap: make(map[externalapi.DomainHash]externalapi.BlockHeader),
}
blockGHOSTDAGDataGenesis := ghostdagmanager.NewBlockGHOSTDAGData(0, new(big.Int), nil, nil, nil, nil)
blockGHOSTDAGDataGenesis := model.NewBlockGHOSTDAGData(0, new(big.Int), nil, nil, nil, nil)
genesisHeader := params.GenesisBlock.Header
genesisWork := util.CalcWork(genesisHeader.Bits())
@@ -160,7 +160,7 @@ func TestGHOSTDAG(t *testing.T) {
}
dagTopology.parentsMap = make(map[externalapi.DomainHash][]*externalapi.DomainHash)
dagTopology.parentsMap[genesisHash] = nil
ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData)
ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData)
ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis
blockHeadersStore.dagMap = make(map[externalapi.DomainHash]externalapi.BlockHeader)
blockHeadersStore.dagMap[genesisHash] = genesisHeader
@@ -202,10 +202,10 @@ func StringToDomainHashSlice(stringIDArr []string) []*externalapi.DomainHash {
/* ---------------------- */
type GHOSTDAGDataStoreImpl struct {
dagMap map[externalapi.DomainHash]model.BlockGHOSTDAGData
dagMap map[externalapi.DomainHash]*model.BlockGHOSTDAGData
}
func (ds *GHOSTDAGDataStoreImpl) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData model.BlockGHOSTDAGData) {
func (ds *GHOSTDAGDataStoreImpl) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) {
ds.dagMap[*blockHash] = blockGHOSTDAGData
}
@@ -221,7 +221,7 @@ func (ds *GHOSTDAGDataStoreImpl) Commit(dbTx model.DBTransaction) error {
panic("implement me")
}
func (ds *GHOSTDAGDataStoreImpl) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) {
func (ds *GHOSTDAGDataStoreImpl) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) {
v, ok := ds.dagMap[*blockHash]
if ok {
return v, nil

View File

@@ -1,31 +0,0 @@
package hashes
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
// cmp compares two hashes and returns:
//
// -1 if a < b
// 0 if a == b
// +1 if a > b
//
func cmp(a, b *externalapi.DomainHash) int {
aBytes := a.ByteArray()
bBytes := b.ByteArray()
// We compare the hashes backwards because Hash is stored as a little endian byte array.
for i := externalapi.DomainHashSize - 1; i >= 0; i-- {
switch {
case aBytes[i] < bBytes[i]:
return -1
case aBytes[i] > bBytes[i]:
return 1
}
}
return 0
}
// Less returns true iff hash a is less than hash b
func Less(a, b *externalapi.DomainHash) bool {
return cmp(a, b) < 0
}

View File

@@ -2,10 +2,9 @@ package transactionid
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
)
// Less returns true iff transaction ID a is less than hash b
func Less(a, b *externalapi.DomainTransactionID) bool {
return hashes.Less((*externalapi.DomainHash)(a), (*externalapi.DomainHash)(b))
return externalapi.Less((*externalapi.DomainHash)(a), (*externalapi.DomainHash)(b))
}

View File

@@ -1,25 +0,0 @@
package bigintpool
import (
"math/big"
"sync"
)
var bigIntPool = sync.Pool{
New: func() interface{} {
return big.NewInt(0)
},
}
// Acquire acquires a big.Int from the pool and
// initializes it to x.
func Acquire(x int64) *big.Int {
bigInt := bigIntPool.Get().(*big.Int)
bigInt.SetInt64(x)
return bigInt
}
// Release returns the given big.Int to the pool.
func Release(toRelease *big.Int) {
bigIntPool.Put(toRelease)
}