Skip to content

Commit

Permalink
Merge pull request #103 from tuxcanfly/bcash-deployments
Browse files Browse the repository at this point in the history
chain: refactor deployments, pow target
  • Loading branch information
tuxcanfly authored Nov 14, 2018
2 parents 8a1af6b + 0f3b085 commit 720f353
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 56 deletions.
129 changes: 81 additions & 48 deletions lib/blockchain/chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -521,12 +521,21 @@ class Chain extends AsyncEmitter {
if (height >= this.network.block.bip65height)
state.flags |= Script.flags.VERIFY_CHECKLOCKTIMEVERIFY;

// CHECKSEQUENCEVERIFY and median time
// past locktimes are now usable (bip9 & bip113).
if (await this.isActive(prev, deployments.csv)) {
state.flags |= Script.flags.VERIFY_CHECKSEQUENCEVERIFY;
state.lockFlags |= common.lockFlags.VERIFY_SEQUENCE;
state.lockFlags |= common.lockFlags.MEDIAN_TIME_PAST;
}

// UAHF is now enabled.
if (height > this.network.block.uahfHeight) {
state.flags |= Script.flags.VERIFY_STRICTENC;
state.flags |= Script.flags.VERIFY_SIGHASH_FORKID;
}

// DAA is now enabled.
if (height > this.network.block.daaHeight) {
state.daa = true;
state.flags |= Script.flags.VERIFY_LOW_S;
Expand All @@ -543,14 +552,6 @@ class Chain extends AsyncEmitter {
state.flags |= Script.flags.VERIFY_CLEANSTACK;
}

// CHECKSEQUENCEVERIFY and median time
// past locktimes are now usable (bip9 & bip113).
if (await this.isActive(prev, deployments.csv)) {
state.flags |= Script.flags.VERIFY_CHECKSEQUENCEVERIFY;
state.lockFlags |= common.lockFlags.VERIFY_SEQUENCE;
state.lockFlags |= common.lockFlags.MEDIAN_TIME_PAST;
}

return state;
}

Expand Down Expand Up @@ -2265,52 +2266,16 @@ class Chain extends AsyncEmitter {
}

/**
* Calculate the next target.
* Calculate the next target using legacy bitcoin difficulty adjustment +
* emergency difficulty adjustment (EDA).
* @param {Number} time - Next block timestamp.
* @param {ChainEntry} prev - Previous entry.
* @returns {Promise} - returns Number
* (target is in compact/mantissa form).
*/

async getTarget(time, prev) {
async getEDATarget(time, prev) {
const pow = this.network.pow;

// Genesis
if (!prev) {
assert(time === this.network.genesis.time);
return pow.bits;
}

if (pow.noRetargeting)
return prev.bits;

// DAA is now enabled.
if (this.tip.height >= this.network.block.daaHeight) {
// Do not retarget
if (pow.targetReset) {
// Special behavior for (simnet and testnet):
// If blocks have not been mined for 2 * 10 mins
// allow mining min difficulty.
if (time > prev.time + (pow.targetSpacing * 2))
return pow.bits;
}

// special behaviour for simnet
if (prev.height < pow.retargetInterval)
return prev.bits;

// Get the last suitable block of the difficulty interval.
const last = await this.getSuitableBlock(prev);

// Get the first suitable block of the difficulty interval.
const height = prev.height - 144;
const first = await this.getSuitableBlock(
await this.getAncestor(prev, height));

// Compute the target based on time and work done during the interval.
return this.computeTarget(first, last);
}

if ((prev.height + 1) % pow.retargetInterval === 0) {
// Back 2 weeks
const height = prev.height - (pow.retargetInterval - 1);
Expand Down Expand Up @@ -2361,7 +2326,75 @@ class Chain extends AsyncEmitter {
return pow.bits;

return consensus.toCompact(target);
};
}

/**
* Calculate the next target using a weighted average of the estimaated
* hashrate per block.
* @param {Number} time - Next block timestamp.
* @param {ChainEntry} prev - Previous entry.
* @returns {Promise} - returns Number
* (target is in compact/mantissa form).
*/
async getCashTarget(time, prev) {
const pow = this.network.pow;

// Cannot handle genesis block
assert(prev);

// Special behavior for (simnet and testnet):
// If blocks have not been mined for 2 * 10 mins
// allow mining min difficulty.
if (pow.targetReset) {
if (time > prev.time + (pow.targetSpacing * 2))
return pow.bits;
}

// Special behaviour for simnet
if (prev.height < pow.retargetInterval)
return prev.bits;

// Get the last suitable block of the difficulty interval.
const last = await this.getSuitableBlock(prev);

// Get the first suitable block of the difficulty interval.
const height = prev.height - 144;
const first = await this.getSuitableBlock(
await this.getAncestor(prev, height));

// Compute the target based on time and work done during the interval.
return this.computeTarget(first, last);
}

/**
* Calculate the next target.
* @param {Number} time - Next block timestamp.
* @param {ChainEntry} prev - Previous entry.
* @returns {Promise} - returns Number
* (target is in compact/mantissa form).
*/

async getTarget(time, prev) {
const pow = this.network.pow;

// Genesis
if (!prev) {
assert(time === this.network.genesis.time);
return pow.bits;
}

// Special rule for regtest; we never retarget
if (pow.noRetargeting)
return prev.bits;

// Deployment state is not set at this time, so cannot use state.daa just
// yet. Rely on height instead.
if (prev.height >= this.network.block.daaHeight) {
return this.getCashTarget(time, prev);
}

return this.getEDATarget(time, prev);
};

/**
* Compute a target based on the work between 2 blocks and the time
Expand Down
14 changes: 6 additions & 8 deletions test/pow-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,6 @@ describe('Difficulty', function() {
const target = network.pow.limit.ushrn(4);
let bits = consensus.toCompact(target);

// Enable DAA Deployment
chain.network.block.daaHeight = 0;
const blocks = {};

blocks[0] = new ChainEntry();
Expand Down Expand Up @@ -229,7 +227,7 @@ describe('Difficulty', function() {
for (let j = 0; j < 10; i++, j++) {
blocks[i] = getEntry(blocks[i-1], 550, bits);
const nextBits =
await chain.getTarget(blocks[0].time, blocks[i]);
await chain.getCashTarget(blocks[0].time, blocks[i]);

const currentTarget = consensus.fromCompact(bits);
const nextTarget = consensus.fromCompact(nextBits);
Expand All @@ -248,7 +246,7 @@ describe('Difficulty', function() {
for (let j = 0; j < 20; i++, j++) {
blocks[i] = getEntry(blocks[i-1], 10, bits);
const nextBits =
await chain.getTarget(blocks[0].time, blocks[i]);
await chain.getCashTarget(blocks[0].time, blocks[i]);

const currentTarget = consensus.fromCompact(bits);
const nextTarget = consensus.fromCompact(nextBits);
Expand All @@ -266,7 +264,7 @@ describe('Difficulty', function() {
// We start to emit blocks significantly slower. The first block has no
// impact.
blocks[i] = getEntry(blocks[i-1], 6000, bits);
bits = await chain.getTarget(blocks[0].time, blocks[i++]);
bits = await chain.getCashTarget(blocks[0].time, blocks[i++]);

// Check the actual value.
assert.strictEqual(bits, 0x1c0d9222);
Expand All @@ -275,7 +273,7 @@ describe('Difficulty', function() {
for (let j = 0; j < 93; i++, j++) {
blocks[i] = getEntry(blocks[i-1], 6000, bits);
const nextBits =
await chain.getTarget(blocks[0].time, blocks[i]);
await chain.getCashTarget(blocks[0].time, blocks[i]);

const currentTarget = consensus.fromCompact(bits);
const nextTarget = consensus.fromCompact(nextBits);
Expand All @@ -294,15 +292,15 @@ describe('Difficulty', function() {
// Due to the window of time being bounded, next block's difficulty actually
// gets harder.
blocks[i] = getEntry(blocks[i-1], 6000, bits);
bits = await chain.getTarget(blocks[0].time, blocks[i++]);
bits = await chain.getCashTarget(blocks[0].time, blocks[i++]);
assert.strictEqual(bits, 0x1c2ee9bf);

// And goes down again. It takes a while due to the window being bounded and
// the skewed block causes 2 blocks to get out of the window.
for (let j = 0; j < 192; i++, j++) {
blocks[i] = getEntry(blocks[i-1], 6000, bits);
const nextBits =
await chain.getTarget(blocks[0].time, blocks[i]);
await chain.getCashTarget(blocks[0].time, blocks[i]);

const currentTarget = consensus.fromCompact(bits);
const nextTarget = consensus.fromCompact(nextBits);
Expand Down

0 comments on commit 720f353

Please sign in to comment.