Fix Difficulty Retargeting

This commit is contained in:
Sky Young 2019-07-18 12:08:33 -06:00
parent 2bc297d93b
commit 2caeac559a
2 changed files with 167 additions and 130 deletions

View File

@ -14,6 +14,7 @@ const Logger = require('blgr');
const {Lock} = require('bmutex');
const LRU = require('blru');
const {BufferMap} = require('buffer-map');
const BN = require('bcrypto/lib/bn.js');
const Network = require('../protocol/network');
const ChainDB = require('./chaindb');
const common = require('./common');
@ -380,8 +381,7 @@ class Chain extends AsyncEmitter {
// Ensure the POW is what we expect.
const bits = await this.getTarget(block.time, prev);
// FLO Block 39511 on testnet fails this check for some reason, hardcode to allow until further research can be done.
if (block.bits !== bits && block.height >= 39512) {
if (block.bits !== bits) {
throw new VerifyError(block,
'invalid',
'bad-diffbits',
@ -2198,35 +2198,37 @@ class Chain extends AsyncEmitter {
return pow.bits;
}
let retargetInterval, targetSpacing, averagingInterval;
let retargetInterval, averagingInterval, targetTimespan;
if (prev.height < pow.blockHeight_version2){
let targetSpacing = pow.targetSpacing
retargetInterval = pow.retargetInterval_version1;
targetSpacing = pow.targetSpacing_version1;
averagingInterval = pow.averagingInterval_version1;
if ((prev.height + 1) < pow.blockHeight_Version2){
} else if (prev.height >= pow.blockHeight_version2 && prev.height < pow.blockHeight_version3){
retargetInterval = pow.retargetInterval_Version1;
averagingInterval = pow.averagingInterval_Version1;
targetTimespan = pow.targetTimespan_Version1;
} else if ((prev.height + 1) < pow.blockHeight_Version3){
retargetInterval = pow.retargetInterval_version2;
targetSpacing = pow.targetSpacing_version2;
averagingInterval = pow.averagingInterval_version2;
retargetInterval = pow.retargetInterval_Version2;
averagingInterval = pow.averagingInterval_Version2;
targetTimespan = pow.targetTimespan_Version2 * targetSpacing;
} else if (prev.height >= pow.blockHeight_version3) {
} else {
retargetInterval = pow.retargetInterval_version3;
targetSpacing = pow.targetSpacing_version3;
averagingInterval = pow.averagingInterval_version3;
retargetInterval = pow.retargetInterval_Version3;
averagingInterval = pow.averagingInterval_Version3;
targetTimespan = pow.targetTimespan_Version3 * targetSpacing;
}
// Do not retarget
if ((prev.height + 1) % retargetInterval !== 0) {
if (pow.targetReset) {
// Special behavior for testnet:
if (time > prev.time + targetSpacing * 2)
// Special behavior for testnet
if (time > prev.time + (targetTimespan * 2)) {
return pow.bits;
}
while (prev.height !== 0
&& prev.height % retargetInterval !== 0
&& prev.bits === pow.bits) {
@ -2243,21 +2245,19 @@ class Chain extends AsyncEmitter {
return prev.bits;
}
// Back 6 block
var back = averagingInterval - 1;
// Back 6 block
var back = averagingInterval - 1;
if (prev.height + 1 !== averagingInterval)
back = averagingInterval;
let first = prev;
for (let i = 0; i < back; i++){
if (first)
first = await this.getPrevious(first)
}
if (prev.height + 1 !== averagingInterval)
back = averagingInterval;
let first = prev;
for (let i = 0; i < back; i++){
if (first)
first = await this.getPrevious(first)
}
assert(first);
assert(first);
return this.retarget(prev, first);
}
@ -2273,75 +2273,69 @@ class Chain extends AsyncEmitter {
retarget(prev, first) {
const pow = this.network.pow;
let height = prev.height;
if (pow.noRetargeting)
return prev.bits;
let height = prev.height + 1;
let targetTimespan, averagingIntervalTimespan, targetSpacing, adjustUp, adjustDown;
if (height < pow.blockHeight_version2){
targetSpacing = pow.targetSpacing
targetTimespan = pow.targetTimespan_version1;
averagingIntervalTimespan = pow.averagingIntervalTimespan_version1;
targetSpacing = pow.targetSpacing_version1;
adjustUp = pow.adjustUp_version1;
adjustDown = pow.adjustDown_version1;
if (height < pow.blockHeight_Version2){
} else if (height >= pow.blockHeight_version2 && height < pow.blockHeight_version3){
targetTimespan = pow.targetTimespan_Version1;
averagingIntervalTimespan = pow.averagingIntervalTimespan_Version1;
adjustUp = pow.adjustUp_Version1;
adjustDown = pow.adjustDown_Version1;
targetTimespan = pow.targetTimespan_version2;
averagingIntervalTimespan = pow.averagingIntervalTimespan_version2;
targetSpacing = pow.targetSpacing_version2;
adjustUp = pow.adjustUp_version2;
adjustDown = pow.adjustDown_version2;
} else if (height < pow.blockHeight_Version3){
} else if (height >= pow.blockHeight_version3) {
targetTimespan = pow.targetTimespan_version3;
averagingIntervalTimespan = pow.averagingIntervalTimespan_version3;
targetSpacing = pow.targetSpacing_version3;
adjustUp = pow.adjustUp_version3;
adjustDown = pow.adjustDown_version3;
targetTimespan = pow.targetTimespan_Version2;
averagingIntervalTimespan = pow.averagingIntervalTimespan_Version2;
adjustUp = pow.adjustUp_Version2;
adjustDown = pow.adjustDown_Version2;
} else {
// Difficulty NOT handled?!?
targetTimespan = pow.targetTimespan_Version3;
averagingIntervalTimespan = pow.averagingIntervalTimespan_Version3;
adjustUp = pow.adjustUp_Version3;
adjustDown = pow.adjustDown_Version3;
}
if (pow.noRetargeting)
return prev.bits;
averagingIntervalTimespan = averagingIntervalTimespan * targetSpacing
let actualTimespan = prev.time - first.time;
// console.log("Actual Timespan: " + actualTimespan);
let minActualTimespan = Math.floor(averagingIntervalTimespan * (100 - adjustUp) / 100)
let maxActualTimespan = Math.floor(averagingIntervalTimespan * (100 + adjustDown) / 100)
// console.log("minActualTimespan: " + minActualTimespan);
// console.log("maxActualTimespan: " + maxActualTimespan);
if (actualTimespan < minActualTimespan)
actualTimespan = minActualTimespan;
// console.log("New Actual Timespan: " + actualTimespan)
if (actualTimespan > maxActualTimespan)
actualTimespan = maxActualTimespan;
// console.log("New Actual Timespan: " + actualTimespan)
// Retarget
let target = consensus.fromCompact(prev.bits);
// console.log("Target: " + target)
// FLO: intermediate uint256 can overflow by 1 bit
let fShift = (consensus.toCompact(target) > pow.bits - 1)
if (fShift)
target.ishl(new BN(1))
target.imuln(actualTimespan);
// console.log("imuln: " + target)
target.idivn(targetTimespan);
// console.log("idivn: " + target)
if (target.gt(pow.limit))
return pow.bits;
if (fShift)
target.ishr(new BN(1))
// console.log("gt: " + target)
if (consensus.toCompact(target) > pow.bits){
return pow.bits;
}
return consensus.toCompact(target);
}

View File

@ -222,14 +222,6 @@ main.pow = {
'hex'
),
/**
* Desired retarget period in seconds.
* @const {Number}
* @default
*/
targetTimespan: 6 * 40,
/**
* Average block time.
* @const {Number}
@ -238,13 +230,25 @@ main.pow = {
targetSpacing: 40,
/**
* Desired retarget period in seconds.
* @const {Number}
* @default
*/
targetTimespan_Version1: 60 * 60,
targetTimespan_Version2: 15 * 40,
targetTimespan_Version3: 6 * 40,
/**
* Retarget interval in blocks.
* @const {Number}
* @default
*/
retargetInterval: 1,
retargetInterval_Version1: (60 * 60) / 40,
retargetInterval_Version2: 15,
retargetInterval_Version3: 1,
/**
* Average retarget interval in blocks.
@ -252,7 +256,9 @@ main.pow = {
* @default
*/
averagingInterval: 6,
averagingInterval_Version1: (60 * 60) / 40,
averagingInterval_Version2: 15,
averagingInterval_Version3: 6,
/**
* Average retarget interval in blocks.
@ -260,7 +266,9 @@ main.pow = {
* @default
*/
averagingIntervalTimespan: 6 * 40,
averagingIntervalTimespan_Version1: (60 * 60) / 40,
averagingIntervalTimespan_Version2: 15,
averagingIntervalTimespan_Version3: 6,
/**
* Adjust Target Timespan Max.
@ -268,7 +276,9 @@ main.pow = {
* @default
*/
adjustUp: 2,
adjustUp_Version1: 75,
adjustUp_Version2: 75,
adjustUp_Version3: 2,
/**
* Adjust Target Timespan Min.
@ -276,31 +286,17 @@ main.pow = {
* @default
*/
adjustDown: 3,
adjustDown_Version1: 300,
adjustDown_Version2: 300,
adjustDown_Version3: 3,
targetTimespan_version1: 60 * 60,
targetSpacing_version1: 40,
retargetInterval_version1: (60 * 60) / 40,
averagingInterval_version1: (60 * 60) / 40,
averagingIntervalTimespan_version1: ((60 * 60) / 40) * 40,
adjustUp_version1: 75,
adjustDown_version1: 300,
blockHeight_version2: 208440,
targetTimespan_version2: 15 * 40,
targetSpacing_version2: 40,
retargetInterval_version2: 15,
averagingInterval_version2: 15,
averagingIntervalTimespan_version2: 15 * 40,
adjustUp_version2: 75,
adjustDown_version2: 300,
blockHeight_version3: 426000,
targetTimespan_version3: 6 * 40,
targetSpacing_version3: 40,
retargetInterval_version3: 1,
averagingInterval_version3: 6,
averagingIntervalTimespan_version3: 6 * 40,
adjustUp_version3: 2,
adjustDown_version3: 3,
/**
* Block Heights that each difficulty algorithm should be used
* @const {Number}
* @default
*/
blockHeight_Version2: 208440,
blockHeight_Version3: 426000,
/**
* Whether to reset target if a block
@ -622,32 +618,79 @@ testnet.pow = {
),
bits: 504365055,
chainwork: new BN(
'000000000000000000000000000000000000000000000000000000083540886d',
'0000000000000000000000000000000000000000000000000000003dd47d3172',
'hex'
),
targetTimespan_version1: 60 * 60,
targetSpacing_version1: 40,
retargetInterval_version1: (60 * 60) / 40,
averagingInterval_version1: (60 * 60) / 40,
averagingIntervalTimespan_version1: ((60 * 60) / 40) * 40,
adjustUp_version1: 75,
adjustDown_version1: 300,
blockHeight_version2: 50000,
targetTimespan_version2: 15 * 40,
targetSpacing_version2: 40,
retargetInterval_version2: 15,
averagingInterval_version2: 15,
averagingIntervalTimespan_version2: 15 * 40,
adjustUp_version2: 75,
adjustDown_version2: 300,
blockHeight_version3: 60000,
targetTimespan_version3: 6 * 40,
targetSpacing_version3: 40,
retargetInterval_version3: 1,
averagingInterval_version3: 6,
averagingIntervalTimespan_version3: 6 * 40,
adjustUp_version3: 2,
adjustDown_version3: 3,
targetSpacing: 40,
/**
* Desired retarget period in seconds.
* @const {Number}
* @default
*/
targetTimespan_Version1: 60 * 60,
targetTimespan_Version2: 15 * 40,
targetTimespan_Version3: 6 * 40,
/**
* Retarget interval in blocks.
* @const {Number}
* @default
*/
retargetInterval_Version1: (60 * 60) / 40,
retargetInterval_Version2: 15,
retargetInterval_Version3: 1,
/**
* Average retarget interval in blocks.
* @const {Number}
* @default
*/
averagingInterval_Version1: (60 * 60) / 40,
averagingInterval_Version2: 15,
averagingInterval_Version3: 6,
/**
* Average retarget interval in blocks.
* @const {Number}
* @default
*/
averagingIntervalTimespan_Version1: (60 * 60) / 40,
averagingIntervalTimespan_Version2: 15,
averagingIntervalTimespan_Version3: 6,
/**
* Adjust Target Timespan Max.
* @const {Number}
* @default
*/
adjustUp_Version1: 75,
adjustUp_Version2: 75,
adjustUp_Version3: 2,
/**
* Adjust Target Timespan Min.
* @const {Number}
* @default
*/
adjustDown_Version1: 300,
adjustDown_Version2: 300,
adjustDown_Version3: 3,
/**
* Block Heights that each difficulty algorithm should be used
* @const {Number}
* @default
*/
blockHeight_Version2: 50000,
blockHeight_Version3: 60000,
targetReset: true,
noRetargeting: false
};