From 4cccf98786bd87492fa95346e0d9c778480816b8 Mon Sep 17 00:00:00 2001 From: Roy Lee Date: Tue, 12 Jun 2018 17:27:22 -0700 Subject: [PATCH] [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 --- blockchain/chain.go | 5 ++-- blockchain/difficulty.go | 56 +++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/blockchain/chain.go b/blockchain/chain.go index 1a95a00b..b4a871b9 100644 --- a/blockchain/chain.go +++ b/blockchain/chain.go @@ -1736,7 +1736,6 @@ func New(config *Config) (*BlockChain, error) { params := config.ChainParams targetTimespan := int64(params.TargetTimespan / time.Second) targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second) - adjustmentFactor := params.RetargetAdjustmentFactor b := BlockChain{ checkpoints: config.Checkpoints, checkpointsByHeight: checkpointsByHeight, @@ -1745,8 +1744,8 @@ func New(config *Config) (*BlockChain, error) { timeSource: config.TimeSource, sigCache: config.SigCache, indexManager: config.IndexManager, - minRetargetTimespan: targetTimespan / adjustmentFactor, - maxRetargetTimespan: targetTimespan * adjustmentFactor, + minRetargetTimespan: targetTimespan - (targetTimespan / 8), + maxRetargetTimespan: targetTimespan + (targetTimespan / 2), blocksPerRetarget: int32(targetTimespan / targetTimePerBlock), index: newBlockIndex(config.DB, params), hashCache: config.HashCache, diff --git a/blockchain/difficulty.go b/blockchain/difficulty.go index 05f78a3e..3eae3844 100644 --- a/blockchain/difficulty.go +++ b/blockchain/difficulty.go @@ -159,7 +159,6 @@ func CalcWork(bits uint32) *big.Int { func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 { // Convert types used in the calculations below. durationVal := int64(duration / time.Second) - adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor) // The test network rules allow minimum difficulty blocks after more // 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. newTarget := CompactToBig(bits) 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 } @@ -224,47 +224,44 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim return b.chainParams.PowLimitBits, nil } - // Return the previous block's difficulty requirements if this block - // is not at a difficulty retarget interval. - if (lastNode.height+1)%b.blocksPerRetarget != 0 { - // For networks that support it, allow special reduction of the - // required difficulty once too much time has elapsed without - // mining a block. - if b.chainParams.ReduceMinDifficulty { - // Return minimum difficulty when more than the desired - // amount of time has elapsed without mining a block. - reductionTime := int64(b.chainParams.MinDiffReductionTime / - time.Second) - 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 networks that support it, allow special reduction of the + // required difficulty once too much time has elapsed without + // mining a block. + if b.chainParams.ReduceMinDifficulty { + // Return minimum difficulty when more than the desired + // amount of time has elapsed without mining a block. + reductionTime := int64(b.chainParams.MinDiffReductionTime / + time.Second) + allowMinTime := lastNode.timestamp + reductionTime + if newBlockTime.Unix() > allowMinTime { + return b.chainParams.PowLimitBits, nil } - // For the main network (or any unrecognized networks), simply - // return the previous block's difficulty requirements. - return lastNode.bits, 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 } // Get the block node at the previous retarget (targetTimespan days // worth of blocks). - firstNode := lastNode.RelativeAncestor(b.blocksPerRetarget - 1) + firstNode := lastNode.RelativeAncestor(b.blocksPerRetarget) + if lastNode.height == 0 { + firstNode = lastNode + } if firstNode == nil { 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 // difficulty. actualTimespan := lastNode.timestamp - firstNode.timestamp - adjustedTimespan := actualTimespan - if actualTimespan < b.minRetargetTimespan { + adjustedTimespan := targetTimeSpan + (actualTimespan-targetTimeSpan)/8 + if adjustedTimespan < b.minRetargetTimespan { adjustedTimespan = b.minRetargetTimespan - } else if actualTimespan > b.maxRetargetTimespan { + } else if adjustedTimespan > b.maxRetargetTimespan { adjustedTimespan = b.maxRetargetTimespan } @@ -275,7 +272,6 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim // result. oldTarget := CompactToBig(lastNode.bits) newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan)) - targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second) newTarget.Div(newTarget, big.NewInt(targetTimeSpan)) // Limit new value to the proof of work limit.