mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
Fix for rare consensus bug regarding daa window order (#1934)
* Fix for rare consensus bug: daa window min-time-block was not deterministic when timestamps are equal * Something is missing * Extract compare logic to a function with better performance * typo
This commit is contained in:
parent
598392d0cf
commit
dab1a881fe
@ -1,18 +1,18 @@
|
||||
package difficultymanager
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/util/difficulty"
|
||||
"math"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type difficultyBlock struct {
|
||||
timeInMilliseconds int64
|
||||
Bits uint32
|
||||
hash *externalapi.DomainHash
|
||||
blueWork *big.Int
|
||||
}
|
||||
|
||||
type blockWindow []difficultyBlock
|
||||
@ -27,6 +27,8 @@ func (dm *difficultyManager) getDifficultyBlock(
|
||||
return difficultyBlock{
|
||||
timeInMilliseconds: header.TimeInMilliseconds(),
|
||||
Bits: header.Bits(),
|
||||
hash: blockHash,
|
||||
blueWork: header.BlueWork(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -53,19 +55,32 @@ func (dm *difficultyManager) blockWindow(stagingArea *model.StagingArea, startin
|
||||
return window, windowHashes, nil
|
||||
}
|
||||
|
||||
func (window blockWindow) minMaxTimestamps() (min, max int64, minIndex, maxIndex int) {
|
||||
func ghostdagLess(blockA *difficultyBlock, blockB *difficultyBlock) bool {
|
||||
switch blockA.blueWork.Cmp(blockB.blueWork) {
|
||||
case -1:
|
||||
return true
|
||||
case 1:
|
||||
return false
|
||||
case 0:
|
||||
return blockA.hash.Less(blockB.hash)
|
||||
default:
|
||||
panic("big.Int.Cmp is defined to always return -1/1/0 and nothing else")
|
||||
}
|
||||
}
|
||||
|
||||
func (window blockWindow) minMaxTimestamps() (min, max int64, minIndex int) {
|
||||
min = math.MaxInt64
|
||||
minIndex = math.MaxInt64
|
||||
minIndex = 0
|
||||
max = 0
|
||||
maxIndex = 0
|
||||
for i, block := range window {
|
||||
if block.timeInMilliseconds < min {
|
||||
// If timestamps are equal we ghostdag compare in order to reach consensus on `minIndex`
|
||||
if block.timeInMilliseconds < min ||
|
||||
(block.timeInMilliseconds == min && ghostdagLess(&block, &window[minIndex])) {
|
||||
min = block.timeInMilliseconds
|
||||
minIndex = i
|
||||
}
|
||||
if block.timeInMilliseconds > max {
|
||||
max = block.timeInMilliseconds
|
||||
maxIndex = i
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -115,9 +115,10 @@ func (dm *difficultyManager) requiredDifficultyFromTargetsWindow(targetsWindow b
|
||||
if len(targetsWindow) < 2 || len(targetsWindow) < dm.difficultyAdjustmentWindowSize {
|
||||
return dm.genesisBits, nil
|
||||
}
|
||||
windowMinTimestamp, windowMaxTimeStamp, windowsMinIndex, _ := targetsWindow.minMaxTimestamps()
|
||||
|
||||
windowMinTimestamp, windowMaxTimeStamp, windowMinIndex := targetsWindow.minMaxTimestamps()
|
||||
// Remove the last block from the window so to calculate the average target of dag.difficultyAdjustmentWindowSize blocks
|
||||
targetsWindow.remove(windowsMinIndex)
|
||||
targetsWindow.remove(windowMinIndex)
|
||||
|
||||
// Calculate new target difficulty as:
|
||||
// averageWindowTarget * (windowMinTimestamp / (targetTimePerBlock * windowSize))
|
||||
|
@ -35,7 +35,7 @@ func (dm *difficultyManager) estimateNetworkHashesPerSecond(stagingArea *model.S
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
minWindowTimestamp, maxWindowTimestamp, _, _ := blockWindow.minMaxTimestamps()
|
||||
minWindowTimestamp, maxWindowTimestamp, _ := blockWindow.minMaxTimestamps()
|
||||
if minWindowTimestamp == maxWindowTimestamp {
|
||||
return 0, errors.Errorf("min window timestamp is equal to the max window timestamp")
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user