mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 10:56:47 +00:00
blockchain: Modify diff redux logic for testnet.
This modifies the logic which allows the reduction of difficulty on testnet to match the upstream code such that after a block has not been produced for a long period of time, as configured by the parameters, the difficulty drops to the minimum allowed by the configured proof-of-work limit for the network. It should be noted that this would be a hard fork if the test network had the code path enabled, however, since the code is disabled for testnet2, it does not technically change the consensus rules for it. The modified code will be active for testnet3.
This commit is contained in:
parent
96a1a8546d
commit
74c9622e22
@ -232,11 +232,6 @@ func (b *BlockChain) findPrevTestNetDifficulty(startNode *blockNode) uint32 {
|
||||
// the exported version uses the current best chain as the previous block node
|
||||
// while this function accepts any block node.
|
||||
func (b *BlockChain) calcNextRequiredDifficulty(curNode *blockNode, newBlockTime time.Time) (uint32, error) {
|
||||
// Genesis block.
|
||||
if curNode == nil {
|
||||
return b.chainParams.PowLimitBits, nil
|
||||
}
|
||||
|
||||
// Get the old difficulty; if we aren't at a block height where it changes,
|
||||
// just return this.
|
||||
oldDiff := curNode.bits
|
||||
@ -253,30 +248,8 @@ func (b *BlockChain) calcNextRequiredDifficulty(curNode *blockNode, newBlockTime
|
||||
reductionTime := int64(b.chainParams.MinDiffReductionTime /
|
||||
time.Second)
|
||||
allowMinTime := curNode.timestamp + reductionTime
|
||||
|
||||
// For every extra target timespan that passes, we halve the
|
||||
// difficulty.
|
||||
if newBlockTime.Unix() > allowMinTime {
|
||||
timePassed := newBlockTime.Unix() - curNode.timestamp
|
||||
timePassed -= reductionTime
|
||||
shifts := uint((timePassed / int64(b.chainParams.TargetTimePerBlock/
|
||||
time.Second)) + 1)
|
||||
|
||||
// Scale the difficulty with time passed.
|
||||
oldTarget := CompactToBig(curNode.bits)
|
||||
newTarget := new(big.Int)
|
||||
if shifts < maxShift {
|
||||
newTarget.Lsh(oldTarget, shifts)
|
||||
} else {
|
||||
newTarget.Set(oneLsh256)
|
||||
}
|
||||
|
||||
// Limit new value to the proof of work limit.
|
||||
if newTarget.Cmp(b.chainParams.PowLimit) > 0 {
|
||||
newTarget.Set(b.chainParams.PowLimit)
|
||||
}
|
||||
|
||||
return BigToCompact(newTarget), nil
|
||||
return b.chainParams.PowLimitBits, nil
|
||||
}
|
||||
|
||||
// The block was mined within the desired timeframe, so
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"math/big"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/decred/dcrd/chaincfg"
|
||||
"github.com/decred/dcrd/wire"
|
||||
@ -1050,3 +1051,162 @@ nextTest:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMinDifficultyReduction ensures the code which results in reducing the
|
||||
// minimum required difficulty, when the network params allow it, works as
|
||||
// expected.
|
||||
func TestMinDifficultyReduction(t *testing.T) {
|
||||
// Create chain params based on simnet params, but set the fields related to
|
||||
// proof-of-work difficulty to specific values expected by the tests.
|
||||
params := chaincfg.SimNetParams
|
||||
params.ReduceMinDifficulty = true
|
||||
params.TargetTimePerBlock = time.Minute * 2
|
||||
params.MinDiffReductionTime = time.Minute * 10 // ~99.3% chance to be mined
|
||||
params.WorkDiffAlpha = 1
|
||||
params.WorkDiffWindowSize = 144
|
||||
params.WorkDiffWindows = 20
|
||||
params.TargetTimespan = params.TargetTimePerBlock *
|
||||
time.Duration(params.WorkDiffWindowSize)
|
||||
params.RetargetAdjustmentFactor = 4
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
timeAdjustment func(i int) time.Duration
|
||||
numBlocks int64
|
||||
expectedDiff func(i int) uint32
|
||||
}{
|
||||
{
|
||||
name: "genesis block",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: 1,
|
||||
expectedDiff: func(i int) uint32 { return params.PowLimitBits },
|
||||
},
|
||||
{
|
||||
name: "create difficulty spike - part 1",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: params.WorkDiffWindowSize - 2,
|
||||
expectedDiff: func(i int) uint32 { return 545259519 },
|
||||
},
|
||||
{
|
||||
name: "create difficulty spike - part 2",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 545259519 },
|
||||
},
|
||||
{
|
||||
name: "create difficulty spike - part 3",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 541100164 },
|
||||
},
|
||||
{
|
||||
name: "create difficulty spike - part 4",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 537954654 },
|
||||
},
|
||||
{
|
||||
name: "create difficulty spike - part 5",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 537141847 },
|
||||
},
|
||||
{
|
||||
name: "create difficulty spike - part 6",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 536938645 },
|
||||
},
|
||||
{
|
||||
name: "create difficulty spike - part 7",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 524428608 },
|
||||
},
|
||||
{
|
||||
name: "create difficulty spike - part 8",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 521177424 },
|
||||
},
|
||||
{
|
||||
name: "create difficulty spike - part 9",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 520364628 },
|
||||
},
|
||||
{
|
||||
name: "create difficulty spike - part 10",
|
||||
timeAdjustment: func(i int) time.Duration { return time.Second },
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 520161429 },
|
||||
},
|
||||
{
|
||||
name: "alternate min diff blocks",
|
||||
timeAdjustment: func(i int) time.Duration {
|
||||
if i%2 == 0 {
|
||||
return params.MinDiffReductionTime + time.Second
|
||||
}
|
||||
return params.TargetTimePerBlock
|
||||
},
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 {
|
||||
if i%2 == 0 && i != 0 {
|
||||
return params.PowLimitBits
|
||||
}
|
||||
return 507651392
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "interval of blocks taking twice the target time - part 1",
|
||||
timeAdjustment: func(i int) time.Duration {
|
||||
return params.TargetTimePerBlock * 2
|
||||
},
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 509850141 },
|
||||
},
|
||||
{
|
||||
name: "interval of blocks taking twice the target time - part 2",
|
||||
timeAdjustment: func(i int) time.Duration {
|
||||
return params.TargetTimePerBlock * 2
|
||||
},
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 520138451 },
|
||||
},
|
||||
{
|
||||
name: "interval of blocks taking twice the target time - part 3",
|
||||
timeAdjustment: func(i int) time.Duration {
|
||||
return params.TargetTimePerBlock * 2
|
||||
},
|
||||
numBlocks: params.WorkDiffWindowSize,
|
||||
expectedDiff: func(i int) uint32 { return 520177692 },
|
||||
},
|
||||
}
|
||||
|
||||
bc := newFakeChain(¶ms)
|
||||
node := bc.bestChain.Tip()
|
||||
blockTime := time.Unix(node.timestamp, 0)
|
||||
for _, test := range tests {
|
||||
for i := 0; i < int(test.numBlocks); i++ {
|
||||
// Update the block time according to the test data and calculate
|
||||
// the difficulty for the next block.
|
||||
blockTime = blockTime.Add(test.timeAdjustment(i))
|
||||
diff, err := bc.calcNextRequiredDifficulty(node, blockTime)
|
||||
if err != nil {
|
||||
t.Fatalf("calcNextRequiredDifficulty: unexpected err: %v", err)
|
||||
}
|
||||
|
||||
// Ensure the calculated difficulty matches the expected value.
|
||||
expectedDiff := test.expectedDiff(i)
|
||||
if diff != expectedDiff {
|
||||
t.Fatalf("calcNextRequiredDifficulty (%s): did not get "+
|
||||
"expected difficulty -- got %d, want %d", test.name, diff,
|
||||
expectedDiff)
|
||||
}
|
||||
|
||||
node = newFakeNode(node, 1, 1, diff, blockTime)
|
||||
bc.index.AddNode(node)
|
||||
bc.bestChain.SetTip(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user