diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index e277d421..5ac953dd 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -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); } diff --git a/lib/protocol/networks.js b/lib/protocol/networks.js index 1cc67b19..fe731dfe 100644 --- a/lib/protocol/networks.js +++ b/lib/protocol/networks.js @@ -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 };