mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
Rewrite difficulty adjustment algorithm. Based on Digibyte's Digishield V3
This commit is contained in:
parent
a542816c86
commit
f5f7b50afd
2 changed files with 106 additions and 71 deletions
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/core/state"
|
"github.com/ubiq/go-ubiq/core/state"
|
||||||
"github.com/ubiq/go-ubiq/core/types"
|
"github.com/ubiq/go-ubiq/core/types"
|
||||||
|
"github.com/ubiq/go-ubiq/logger"
|
||||||
"github.com/ubiq/go-ubiq/logger/glog"
|
"github.com/ubiq/go-ubiq/logger/glog"
|
||||||
"github.com/ubiq/go-ubiq/params"
|
"github.com/ubiq/go-ubiq/params"
|
||||||
"github.com/ubiq/go-ubiq/pow"
|
"github.com/ubiq/go-ubiq/pow"
|
||||||
|
|
@ -31,11 +32,41 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ExpDiffPeriod = big.NewInt(100000)
|
ExpDiffPeriod = big.NewInt(100000)
|
||||||
big10 = big.NewInt(10)
|
big88 = big.NewInt(88)
|
||||||
bigMinus99 = big.NewInt(-99)
|
bigMinus99 = big.NewInt(-99)
|
||||||
|
nPowAveragingWindow = big.NewInt(21)
|
||||||
|
nPowMaxAdjustDown = big.NewInt(16) // 16% adjustment down
|
||||||
|
nPowMaxAdjustUp = big.NewInt(8) // 8% adjustment up
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func AveragingWindowTimespan() *big.Int {
|
||||||
|
x := new(big.Int)
|
||||||
|
return x.Mul(nPowAveragingWindow, big88)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MinActualTimespan() *big.Int {
|
||||||
|
// (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100
|
||||||
|
x := new(big.Int)
|
||||||
|
y := new(big.Int)
|
||||||
|
z := new(big.Int)
|
||||||
|
x.Sub(big.NewInt(100), nPowMaxAdjustUp)
|
||||||
|
y.Mul(AveragingWindowTimespan(), x)
|
||||||
|
z.Div(y, big.NewInt(100))
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
func MaxActualTimespan() *big.Int {
|
||||||
|
// (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100
|
||||||
|
x := new(big.Int)
|
||||||
|
y := new(big.Int)
|
||||||
|
z := new(big.Int)
|
||||||
|
x.Add(big.NewInt(100), nPowMaxAdjustDown)
|
||||||
|
y.Mul(AveragingWindowTimespan(), x)
|
||||||
|
z.Div(y, big.NewInt(100))
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
// BlockValidator is responsible for validating block headers, uncles and
|
// BlockValidator is responsible for validating block headers, uncles and
|
||||||
// processed state.
|
// processed state.
|
||||||
//
|
//
|
||||||
|
|
@ -310,87 +341,100 @@ func ValidateHeaderHeaderChain(config *params.ChainConfig, pow pow.PoW, header *
|
||||||
// CalcDifficulty is the difficulty adjustment algorithm. It returns
|
// CalcDifficulty is the difficulty adjustment algorithm. It returns
|
||||||
// the difficulty that a new block should have when created at time
|
// the difficulty that a new block should have when created at time
|
||||||
// given the parent block's time and difficulty.
|
// given the parent block's time and difficulty.
|
||||||
|
// Rewritten to be based on Digibyte's Digishield v3 retargeting
|
||||||
func CalcDifficulty(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int, bc *BlockChain) *big.Int {
|
func CalcDifficulty(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int, bc *BlockChain) *big.Int {
|
||||||
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki
|
|
||||||
// algorithm:
|
|
||||||
// diff = (parent_diff +
|
|
||||||
// (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
|
|
||||||
// ) + 2^(periodCount - 2)
|
|
||||||
|
|
||||||
bigTime := new(big.Int).SetUint64(time)
|
|
||||||
bigParentTime := new(big.Int).SetUint64(parentTime)
|
|
||||||
|
|
||||||
// holds intermediate values to make the algo easier to read & audit
|
// holds intermediate values to make the algo easier to read & audit
|
||||||
x := new(big.Int)
|
x := new(big.Int)
|
||||||
y := new(big.Int)
|
nFirstBlock := new(big.Int)
|
||||||
|
nFirstBlock.Sub(parentNumber, nPowAveragingWindow)
|
||||||
|
|
||||||
// 1 - (block_timestamp -parent_timestamp) // 10
|
glog.V(logger.Debug).Infof("CalcDifficulty parentNumber: %v parentDiff: %v\n", parentNumber, parentDiff)
|
||||||
x.Sub(bigTime, bigParentTime)
|
|
||||||
x.Div(x, big10)
|
|
||||||
x.Sub(common.Big1, x)
|
|
||||||
|
|
||||||
// max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
|
// Check we have enough blocks
|
||||||
if x.Cmp(bigMinus99) < 0 {
|
if parentNumber.Cmp(nPowAveragingWindow) < 1 {
|
||||||
x.Set(bigMinus99)
|
glog.V(logger.Debug).Infof("CalcDifficulty: parentNumber(%+x) < nPowAveragingWindow(%+x)\n", parentNumber, nPowAveragingWindow)
|
||||||
|
x.Set(parentDiff)
|
||||||
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
|
// Limit adjustment step
|
||||||
y.Div(parentDiff, params.DifficultyBoundDivisor)
|
// Use medians to prevent time-warp attacks
|
||||||
x.Mul(y, x)
|
// nActualTimespan := nLastBlockTime - nFirstBlockTime
|
||||||
x.Add(parentDiff, x)
|
nLastBlockTime := bc.CalcPastMedianTime(parentNumber.Uint64())
|
||||||
|
nFirstBlockTime := bc.CalcPastMedianTime(nFirstBlock.Uint64())
|
||||||
|
nActualTimespan := new(big.Int)
|
||||||
|
nActualTimespan.Sub(nLastBlockTime, nFirstBlockTime)
|
||||||
|
glog.V(logger.Debug).Infof("CalcDifficulty nActualTimespan = %v before dampening\n", nActualTimespan)
|
||||||
|
|
||||||
|
// nActualTimespan = AveragingWindowTimespan() + (nActualTimespan-AveragingWindowTimespan())/4
|
||||||
|
y := new(big.Int)
|
||||||
|
y.Sub(nActualTimespan, AveragingWindowTimespan())
|
||||||
|
y.Div(y, big.NewInt(4))
|
||||||
|
nActualTimespan.Add(y, AveragingWindowTimespan())
|
||||||
|
glog.V(logger.Debug).Infof("CalcDifficulty nActualTimespan = %v before bounds\n", nActualTimespan)
|
||||||
|
|
||||||
|
if nActualTimespan.Cmp(MinActualTimespan()) < 0 {
|
||||||
|
nActualTimespan.Set(MinActualTimespan())
|
||||||
|
glog.V(logger.Debug).Infoln("CalcDifficulty Minimum Timespan set")
|
||||||
|
} else if nActualTimespan.Cmp(MaxActualTimespan()) > 0 {
|
||||||
|
nActualTimespan.Set(MaxActualTimespan())
|
||||||
|
glog.V(logger.Debug).Infoln("CalcDifficulty Maximum Timespan set")
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.V(logger.Debug).Infof("CalcDifficulty nActualTimespan = %v final\n", nActualTimespan)
|
||||||
|
|
||||||
|
// Retarget
|
||||||
|
x.Mul(parentDiff, AveragingWindowTimespan())
|
||||||
|
glog.V(logger.Debug).Infoln("CalcDifficulty parentDiff * AveragingWindowTimespan:", x)
|
||||||
|
|
||||||
|
x.Div(x, nActualTimespan)
|
||||||
|
glog.V(logger.Debug).Infoln("CalcDifficulty x / nActualTimespan:", x)
|
||||||
|
|
||||||
// minimum difficulty can ever be (before exponential factor)
|
// minimum difficulty can ever be (before exponential factor)
|
||||||
if x.Cmp(params.MinimumDifficulty) < 0 {
|
if x.Cmp(params.MinimumDifficulty) < 0 {
|
||||||
x.Set(params.MinimumDifficulty)
|
x.Set(params.MinimumDifficulty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// for the exponential factor
|
|
||||||
periodCount := new(big.Int).Add(parentNumber, common.Big1)
|
|
||||||
periodCount.Div(periodCount, ExpDiffPeriod)
|
|
||||||
|
|
||||||
// the exponential factor, commonly referred to as "the bomb"
|
|
||||||
// diff = diff + 2^(periodCount - 2)
|
|
||||||
if periodCount.Cmp(common.Big1) > 0 {
|
|
||||||
y.Sub(periodCount, common.Big2)
|
|
||||||
y.Exp(common.Big2, y, nil)
|
|
||||||
x.Add(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
func CalcDifficultyHeaderChain(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int, hc *HeaderChain) *big.Int {
|
func CalcDifficultyHeaderChain(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int, hc *HeaderChain) *big.Int {
|
||||||
bigTime := new(big.Int).SetUint64(time)
|
// holds intermediate values to make the algo easier to read & audit
|
||||||
bigParentTime := new(big.Int).SetUint64(parentTime)
|
|
||||||
|
|
||||||
x := new(big.Int)
|
x := new(big.Int)
|
||||||
y := new(big.Int)
|
nFirstBlock := new(big.Int)
|
||||||
|
nFirstBlock.Sub(parentNumber, nPowAveragingWindow)
|
||||||
|
|
||||||
x.Sub(bigTime, bigParentTime)
|
// Check we have enough blocks
|
||||||
x.Div(x, big10)
|
if parentNumber.Cmp(nPowAveragingWindow) < 1 {
|
||||||
x.Sub(common.Big1, x)
|
x.Set(parentDiff)
|
||||||
|
return x
|
||||||
if x.Cmp(bigMinus99) < 0 {
|
|
||||||
x.Set(bigMinus99)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
y.Div(parentDiff, params.DifficultyBoundDivisor)
|
nLastBlockTime := hc.CalcPastMedianTime(parentNumber.Uint64())
|
||||||
x.Mul(y, x)
|
nFirstBlockTime := hc.CalcPastMedianTime(nFirstBlock.Uint64())
|
||||||
x.Add(parentDiff, x)
|
nActualTimespan := new(big.Int)
|
||||||
|
nActualTimespan.Sub(nLastBlockTime, nFirstBlockTime)
|
||||||
|
|
||||||
|
y := new(big.Int)
|
||||||
|
y.Sub(nActualTimespan, AveragingWindowTimespan())
|
||||||
|
y.Div(y, big.NewInt(4))
|
||||||
|
nActualTimespan.Add(y, AveragingWindowTimespan())
|
||||||
|
|
||||||
|
if nActualTimespan.Cmp(MinActualTimespan()) < 0 {
|
||||||
|
nActualTimespan.Set(MinActualTimespan())
|
||||||
|
} else if nActualTimespan.Cmp(MaxActualTimespan()) > 0 {
|
||||||
|
nActualTimespan.Set(MaxActualTimespan())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retarget
|
||||||
|
x.Mul(parentDiff, AveragingWindowTimespan())
|
||||||
|
x.Div(x, nActualTimespan)
|
||||||
|
|
||||||
|
// minimum difficulty can ever be (before exponential factor)
|
||||||
if x.Cmp(params.MinimumDifficulty) < 0 {
|
if x.Cmp(params.MinimumDifficulty) < 0 {
|
||||||
x.Set(params.MinimumDifficulty)
|
x.Set(params.MinimumDifficulty)
|
||||||
}
|
}
|
||||||
|
|
||||||
periodCount := new(big.Int).Add(parentNumber, common.Big1)
|
|
||||||
periodCount.Div(periodCount, ExpDiffPeriod)
|
|
||||||
|
|
||||||
if periodCount.Cmp(common.Big1) > 0 {
|
|
||||||
y.Sub(periodCount, common.Big2)
|
|
||||||
y.Exp(common.Big2, y, nil)
|
|
||||||
x.Add(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -402,7 +446,7 @@ func CalcDifficultyLegacy(config *params.ChainConfig, time, parentTime uint64, p
|
||||||
y := new(big.Int)
|
y := new(big.Int)
|
||||||
|
|
||||||
x.Sub(bigTime, bigParentTime)
|
x.Sub(bigTime, bigParentTime)
|
||||||
x.Div(x, big10)
|
x.Div(x, big88)
|
||||||
x.Sub(common.Big1, x)
|
x.Sub(common.Big1, x)
|
||||||
|
|
||||||
if x.Cmp(bigMinus99) < 0 {
|
if x.Cmp(bigMinus99) < 0 {
|
||||||
|
|
@ -417,15 +461,6 @@ func CalcDifficultyLegacy(config *params.ChainConfig, time, parentTime uint64, p
|
||||||
x.Set(params.MinimumDifficulty)
|
x.Set(params.MinimumDifficulty)
|
||||||
}
|
}
|
||||||
|
|
||||||
periodCount := new(big.Int).Add(parentNumber, common.Big1)
|
|
||||||
periodCount.Div(periodCount, ExpDiffPeriod)
|
|
||||||
|
|
||||||
if periodCount.Cmp(common.Big1) > 0 {
|
|
||||||
y.Sub(periodCount, common.Big2)
|
|
||||||
y.Exp(common.Big2, y, nil)
|
|
||||||
x.Add(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -359,7 +359,7 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co
|
||||||
|
|
||||||
func (hc *HeaderChain) GetBlockHeadersFromHash(hash common.Hash, max uint64) []*types.Header {
|
func (hc *HeaderChain) GetBlockHeadersFromHash(hash common.Hash, max uint64) []*types.Header {
|
||||||
// Get the origin header from which to fetch
|
// Get the origin header from which to fetch
|
||||||
header := hc.GetHeader(hash)
|
header := hc.GetHeaderByHash(hash)
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -367,10 +367,10 @@ func (hc *HeaderChain) GetBlockHeadersFromHash(hash common.Hash, max uint64) []*
|
||||||
chain := make([]*types.Header, 0, max)
|
chain := make([]*types.Header, 0, max)
|
||||||
for i := uint64(0); i < max; i++ {
|
for i := uint64(0); i < max; i++ {
|
||||||
next := header.ParentHash
|
next := header.ParentHash
|
||||||
if header = hc.GetHeader(next); header == nil {
|
if header = hc.GetHeaderByHash(next); header == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
chain = append(chain, hc.GetHeader(next))
|
chain = append(chain, hc.GetHeaderByHash(next))
|
||||||
if header.Number.Cmp(common.Big0) == 0 {
|
if header.Number.Cmp(common.Big0) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue