From 5a26b7b71eaa368f7d95e57d9c2df89edffee9d0 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Fri, 1 Jan 2016 19:53:57 -0800 Subject: [PATCH] add pow retargeting to full chain. --- lib/bcoin/fullchain.js | 63 +++++++++++++++++++++++++++++++++++ lib/bcoin/protocol/network.js | 19 +++++++++++ 2 files changed, 82 insertions(+) diff --git a/lib/bcoin/fullchain.js b/lib/bcoin/fullchain.js index c4c3a18f..4b28211d 100644 --- a/lib/bcoin/fullchain.js +++ b/lib/bcoin/fullchain.js @@ -520,6 +520,69 @@ ChainBlock.prototype.getChainwork = function() { return (this.prev ? this.prev.chainwork : new bn(0)).add(this.proof); }; +Chain.prototype.target = function target(last) { + var proofOfWorkLimit = utils.toCompact(network.powLimit); + var adjustmentInterval = network.powTargetTimespan / network.powTargetSpacing; + var newBlockTs, heightFirst, first; + + adjustmentInterval |= 0; + + if (!last) + last = this.getTip(); + + // Do not retarget + if ((last.height + 1) % adjustmentInterval) { + if (network.powAllowMinDifficultyBlocks) { + // Special behavior for testnet: + newBlockTs = Date.now() / 1000 | 0; + if (newBlockTs > last.ts + network.powTargetSpacing * 2) + return proofOfWorkLimit; + + while (last.prev + && last.height % adjustmentInterval !== 0 + && last.bits !== proofOfWorkLimit) { + last = last.prev; + } + + return last.bits; + } + return last.bits; + } + + // Back 2 weeks + heightFirst = last.height - (adjustmentInterval - 1); + first = this.byHeight(heightFirst); + + if (!first) + return 0; + + return this.retarget(last, first.ts); +}; + +Chain.prototype.retarget = function retarget(last, firstTs) { + var powTargetTimespan = new bn(network.powTargetTimespan); + var actualTimespan, powLimit, target; + + if (network.powNoRetargeting) + return last.bits; + + actualTimespan = new bn(last.ts).subn(firstTs); + if (actualTimespan.cmp(powTargetTimespan.divn(4)) < 0) + actualTimespan = powTargetTimespan.divn(4); + + if (actualTimespan.cmp(powTargetTimespan.muln(4)) > 0) + actualTimespan = powTargetTimespan.muln(4); + + powLimit = network.powLimit; + target = utils.fromCompact(last.bits); + target.imul(actualTimespan); + target = target.div(powTargetTimespan); + if (target.cmp(powLimit) > 0) + target = powLimit.clone(); + + return utils.toCompact(target); +}; + ChainBlock.prototype.toJSON = function() { // return [ // this.hash, diff --git a/lib/bcoin/protocol/network.js b/lib/bcoin/protocol/network.js index 9d2d146b..b45c1532 100644 --- a/lib/bcoin/protocol/network.js +++ b/lib/bcoin/protocol/network.js @@ -5,6 +5,7 @@ */ var bcoin = require('../../bcoin'); +var bn = require('bn.js'); var utils = bcoin.utils; /** @@ -107,6 +108,15 @@ main.magic = 0xd9b4bef9; main.preload = require('./preload'); +main.powLimit = new bn( + '00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff', + 'hex' +); +main.powTargetTimespan = 14 * 24 * 60 * 60; // two weeks +main.powTargetSpacing = 10 * 60; +main.powAllowMinDifficultyBlocks = false; +main.powNoRetargeting = false; + /** * Testnet (v3) * https://en.bitcoin.it/wiki/Testnet @@ -187,3 +197,12 @@ testnet.preload = { 'ts': [testnet.genesis.ts], 'heights': [0] }; + +testnet.powLimit = new bn( + '00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff', + 'hex' +); +testnet.powTargetTimespan = 14 * 24 * 60 * 60; // two weeks +testnet.powTargetSpacing = 10 * 60; +testnet.powAllowMinDifficultyBlocks = true; +testnet.powNoRetargeting = false;