[lbry] blockchain: change the difficulty adjustment algorithm.

adjusted := target + (actual - target) / 8

  max := target + (target / 2)
  min := target - (target / 8)

  if adjusted > max {
    adjusted = max
  } else if adj < min {
    adjusted = min
  }

  diffculty := lastDifficulty * adjusted / target
This commit is contained in:
Roy Lee 2018-06-12 17:27:22 -07:00
parent 4bfd69e23d
commit e63ede0311
2 changed files with 28 additions and 33 deletions

View file

@ -1736,7 +1736,6 @@ func New(config *Config) (*BlockChain, error) {
params := config.ChainParams params := config.ChainParams
targetTimespan := int64(params.TargetTimespan / time.Second) targetTimespan := int64(params.TargetTimespan / time.Second)
targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second) targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second)
adjustmentFactor := params.RetargetAdjustmentFactor
b := BlockChain{ b := BlockChain{
checkpoints: config.Checkpoints, checkpoints: config.Checkpoints,
checkpointsByHeight: checkpointsByHeight, checkpointsByHeight: checkpointsByHeight,
@ -1745,8 +1744,8 @@ func New(config *Config) (*BlockChain, error) {
timeSource: config.TimeSource, timeSource: config.TimeSource,
sigCache: config.SigCache, sigCache: config.SigCache,
indexManager: config.IndexManager, indexManager: config.IndexManager,
minRetargetTimespan: targetTimespan / adjustmentFactor, minRetargetTimespan: targetTimespan - (targetTimespan / 8),
maxRetargetTimespan: targetTimespan * adjustmentFactor, maxRetargetTimespan: targetTimespan + (targetTimespan / 2),
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock), blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
index: newBlockIndex(config.DB, params), index: newBlockIndex(config.DB, params),
hashCache: config.HashCache, hashCache: config.HashCache,

View file

@ -159,7 +159,6 @@ func CalcWork(bits uint32) *big.Int {
func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 { func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
// Convert types used in the calculations below. // Convert types used in the calculations below.
durationVal := int64(duration / time.Second) durationVal := int64(duration / time.Second)
adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor)
// The test network rules allow minimum difficulty blocks after more // The test network rules allow minimum difficulty blocks after more
// than twice the desired amount of time needed to generate a block has // than twice the desired amount of time needed to generate a block has
@ -178,7 +177,8 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration)
// multiplied by the max adjustment factor. // multiplied by the max adjustment factor.
newTarget := CompactToBig(bits) newTarget := CompactToBig(bits)
for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 { for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 {
newTarget.Mul(newTarget, adjustmentFactor) adj := new(big.Int).Div(newTarget, big.NewInt(2))
newTarget.Add(newTarget, adj)
durationVal -= b.maxRetargetTimespan durationVal -= b.maxRetargetTimespan
} }
@ -224,47 +224,44 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
return b.chainParams.PowLimitBits, nil return b.chainParams.PowLimitBits, nil
} }
// Return the previous block's difficulty requirements if this block // For networks that support it, allow special reduction of the
// is not at a difficulty retarget interval. // required difficulty once too much time has elapsed without
if (lastNode.height+1)%b.blocksPerRetarget != 0 { // mining a block.
// For networks that support it, allow special reduction of the if b.chainParams.ReduceMinDifficulty {
// required difficulty once too much time has elapsed without // Return minimum difficulty when more than the desired
// mining a block. // amount of time has elapsed without mining a block.
if b.chainParams.ReduceMinDifficulty { reductionTime := int64(b.chainParams.MinDiffReductionTime /
// Return minimum difficulty when more than the desired time.Second)
// amount of time has elapsed without mining a block. allowMinTime := lastNode.timestamp + reductionTime
reductionTime := int64(b.chainParams.MinDiffReductionTime / if newBlockTime.Unix() > allowMinTime {
time.Second) return b.chainParams.PowLimitBits, nil
allowMinTime := lastNode.timestamp + reductionTime
if newBlockTime.Unix() > allowMinTime {
return b.chainParams.PowLimitBits, nil
}
// The block was mined within the desired timeframe, so
// return the difficulty for the last block which did
// not have the special minimum difficulty rule applied.
return b.findPrevTestNetDifficulty(lastNode), nil
} }
// For the main network (or any unrecognized networks), simply // The block was mined within the desired timeframe, so
// return the previous block's difficulty requirements. // return the difficulty for the last block which did
return lastNode.bits, nil // not have the special minimum difficulty rule applied.
return b.findPrevTestNetDifficulty(lastNode), nil
} }
// Get the block node at the previous retarget (targetTimespan days // Get the block node at the previous retarget (targetTimespan days
// worth of blocks). // worth of blocks).
firstNode := lastNode.RelativeAncestor(b.blocksPerRetarget - 1) firstNode := lastNode.RelativeAncestor(b.blocksPerRetarget)
if lastNode.height == 0 {
firstNode = lastNode
}
if firstNode == nil { if firstNode == nil {
return 0, AssertError("unable to obtain previous retarget block") return 0, AssertError("unable to obtain previous retarget block")
} }
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
// Limit the amount of adjustment that can occur to the previous // Limit the amount of adjustment that can occur to the previous
// difficulty. // difficulty.
actualTimespan := lastNode.timestamp - firstNode.timestamp actualTimespan := lastNode.timestamp - firstNode.timestamp
adjustedTimespan := actualTimespan adjustedTimespan := targetTimeSpan + (actualTimespan-targetTimeSpan)/8
if actualTimespan < b.minRetargetTimespan { if adjustedTimespan < b.minRetargetTimespan {
adjustedTimespan = b.minRetargetTimespan adjustedTimespan = b.minRetargetTimespan
} else if actualTimespan > b.maxRetargetTimespan { } else if adjustedTimespan > b.maxRetargetTimespan {
adjustedTimespan = b.maxRetargetTimespan adjustedTimespan = b.maxRetargetTimespan
} }
@ -275,7 +272,6 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
// result. // result.
oldTarget := CompactToBig(lastNode.bits) oldTarget := CompactToBig(lastNode.bits)
newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan)) newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan))
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
newTarget.Div(newTarget, big.NewInt(targetTimeSpan)) newTarget.Div(newTarget, big.NewInt(targetTimeSpan))
// Limit new value to the proof of work limit. // Limit new value to the proof of work limit.