chain: implement bip91 and bip148.
This commit is contained in:
parent
9219e23d8c
commit
3a0c9b60e2
@ -23,6 +23,7 @@ const CoinView = require('../coins/coinview');
|
|||||||
const Script = require('../script/script');
|
const Script = require('../script/script');
|
||||||
const {VerifyError} = require('../protocol/errors');
|
const {VerifyError} = require('../protocol/errors');
|
||||||
const co = require('../utils/co');
|
const co = require('../utils/co');
|
||||||
|
const thresholdStates = common.thresholdStates;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a blockchain.
|
* Represents a blockchain.
|
||||||
@ -106,6 +107,12 @@ Chain.prototype._open = async function open() {
|
|||||||
if (this.options.coinCache)
|
if (this.options.coinCache)
|
||||||
this.logger.info('Coin cache is enabled.');
|
this.logger.info('Coin cache is enabled.');
|
||||||
|
|
||||||
|
if (this.options.bip91)
|
||||||
|
this.logger.warning('BIP91 enabled. Segsignal will be enforced.');
|
||||||
|
|
||||||
|
if (this.options.bip148)
|
||||||
|
this.logger.warning('BIP148 enabled. UASF will be enforced.');
|
||||||
|
|
||||||
await this.db.open();
|
await this.db.open();
|
||||||
|
|
||||||
tip = await this.db.getTip();
|
tip = await this.db.getTip();
|
||||||
@ -219,6 +226,7 @@ Chain.prototype.isGenesis = function isGenesis(block) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Chain.prototype.verify = async function verify(block, prev, flags) {
|
Chain.prototype.verify = async function verify(block, prev, flags) {
|
||||||
|
let deployments = this.network.deployments;
|
||||||
let hash = block.hash('hex');
|
let hash = block.hash('hex');
|
||||||
let now = this.network.now();
|
let now = this.network.now();
|
||||||
let height = prev.height + 1;
|
let height = prev.height + 1;
|
||||||
@ -315,6 +323,12 @@ Chain.prototype.verify = async function verify(block, prev, flags) {
|
|||||||
// Get the new deployment state.
|
// Get the new deployment state.
|
||||||
state = await this.getDeployments(block.ts, prev);
|
state = await this.getDeployments(block.ts, prev);
|
||||||
|
|
||||||
|
// Enforce BIP91/BIP148.
|
||||||
|
if (state.hasBIP91() || state.hasBIP148()) {
|
||||||
|
if (!consensus.hasBit(block.version, deployments.segwit.bit))
|
||||||
|
throw new VerifyError(block, 'invalid', 'bad-no-segwit', 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Get timestamp for tx.isFinal().
|
// Get timestamp for tx.isFinal().
|
||||||
ts = state.hasMTP() ? mtp : block.ts;
|
ts = state.hasMTP() ? mtp : block.ts;
|
||||||
|
|
||||||
@ -404,7 +418,7 @@ Chain.prototype.getDeployments = async function getDeployments(ts, prev) {
|
|||||||
let deployments = this.network.deployments;
|
let deployments = this.network.deployments;
|
||||||
let height = prev.height + 1;
|
let height = prev.height + 1;
|
||||||
let state = new DeploymentState();
|
let state = new DeploymentState();
|
||||||
let active;
|
let witness;
|
||||||
|
|
||||||
// For some reason bitcoind has p2sh in the
|
// For some reason bitcoind has p2sh in the
|
||||||
// mandatory flags by default, when in reality
|
// mandatory flags by default, when in reality
|
||||||
@ -431,21 +445,47 @@ Chain.prototype.getDeployments = async function getDeployments(ts, prev) {
|
|||||||
|
|
||||||
// CHECKSEQUENCEVERIFY and median time
|
// CHECKSEQUENCEVERIFY and median time
|
||||||
// past locktimes are now usable (bip9 & bip113).
|
// past locktimes are now usable (bip9 & bip113).
|
||||||
active = await this.isActive(prev, deployments.csv);
|
if (await this.isActive(prev, deployments.csv)) {
|
||||||
if (active) {
|
|
||||||
state.flags |= Script.flags.VERIFY_CHECKSEQUENCEVERIFY;
|
state.flags |= Script.flags.VERIFY_CHECKSEQUENCEVERIFY;
|
||||||
state.lockFlags |= common.lockFlags.VERIFY_SEQUENCE;
|
state.lockFlags |= common.lockFlags.VERIFY_SEQUENCE;
|
||||||
state.lockFlags |= common.lockFlags.MEDIAN_TIME_PAST;
|
state.lockFlags |= common.lockFlags.MEDIAN_TIME_PAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Segregrated witness is now usable (bip141).
|
// Check the state of the segwit deployment.
|
||||||
active = await this.isActive(prev, deployments.segwit);
|
witness = await this.getState(prev, deployments.segwit);
|
||||||
if (active) {
|
|
||||||
|
// Segregrated witness (bip141) is now usable
|
||||||
|
// along with SCRIPT_VERIFY_NULLDUMMY (bip147).
|
||||||
|
if (witness === thresholdStates.ACTIVE) {
|
||||||
state.flags |= Script.flags.VERIFY_WITNESS;
|
state.flags |= Script.flags.VERIFY_WITNESS;
|
||||||
// BIP147
|
|
||||||
state.flags |= Script.flags.VERIFY_NULLDUMMY;
|
state.flags |= Script.flags.VERIFY_NULLDUMMY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Segsignal is now enforced (bip91).
|
||||||
|
if (this.options.bip91) {
|
||||||
|
if (witness === thresholdStates.STARTED) {
|
||||||
|
if (await this.isActive(prev, deployments.segsignal))
|
||||||
|
state.bip91 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UASF is now enforced (bip148) (mainnet-only).
|
||||||
|
if (this.options.bip148 && this.network === Network.main) {
|
||||||
|
if (witness !== thresholdStates.LOCKED_IN
|
||||||
|
&& witness !== thresholdStates.ACTIVE) {
|
||||||
|
// The BIP148 MTP check is nonsensical in
|
||||||
|
// that it includes the _current_ entry's
|
||||||
|
// timestamp. This requires some hackery,
|
||||||
|
// since bcoin only operates on the sane
|
||||||
|
// assumption that deployment checks should
|
||||||
|
// only ever examine the values of the
|
||||||
|
// previous block (necessary for mining).
|
||||||
|
let mtp = await prev.getMedianTime(ts);
|
||||||
|
if (mtp >= 1501545600 && mtp <= 1510704000)
|
||||||
|
state.bip148 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -473,6 +513,12 @@ Chain.prototype.setDeploymentState = function setDeploymentState(state) {
|
|||||||
if (!this.state.hasWitness() && state.hasWitness())
|
if (!this.state.hasWitness() && state.hasWitness())
|
||||||
this.logger.warning('Segwit has been activated.');
|
this.logger.warning('Segwit has been activated.');
|
||||||
|
|
||||||
|
if (!this.state.hasBIP91() && state.hasBIP91())
|
||||||
|
this.logger.warning('BIP91 has been activated.');
|
||||||
|
|
||||||
|
if (!this.state.hasBIP148() && state.hasBIP148())
|
||||||
|
this.logger.warning('BIP148 has been activated.');
|
||||||
|
|
||||||
this.state = state;
|
this.state = state;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2056,7 +2102,7 @@ Chain.prototype.findLocator = async function findLocator(locator) {
|
|||||||
|
|
||||||
Chain.prototype.isActive = async function isActive(prev, deployment) {
|
Chain.prototype.isActive = async function isActive(prev, deployment) {
|
||||||
let state = await this.getState(prev, deployment);
|
let state = await this.getState(prev, deployment);
|
||||||
return state === common.thresholdStates.ACTIVE;
|
return state === thresholdStates.ACTIVE;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2071,22 +2117,27 @@ Chain.prototype.isActive = async function isActive(prev, deployment) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Chain.prototype.getState = async function getState(prev, deployment) {
|
Chain.prototype.getState = async function getState(prev, deployment) {
|
||||||
let period = this.network.minerWindow;
|
let window = this.network.minerWindow;
|
||||||
let threshold = this.network.activationThreshold;
|
let threshold = this.network.activationThreshold;
|
||||||
let thresholdStates = common.thresholdStates;
|
|
||||||
let bit = deployment.bit;
|
let bit = deployment.bit;
|
||||||
let compute = [];
|
let compute = [];
|
||||||
let entry, state;
|
let entry, state;
|
||||||
|
|
||||||
if (((prev.height + 1) % period) !== 0) {
|
if (deployment.threshold !== -1)
|
||||||
let height = prev.height - ((prev.height + 1) % period);
|
threshold = deployment.threshold;
|
||||||
|
|
||||||
|
if (deployment.window !== -1)
|
||||||
|
window = deployment.window;
|
||||||
|
|
||||||
|
if (((prev.height + 1) % window) !== 0) {
|
||||||
|
let height = prev.height - ((prev.height + 1) % window);
|
||||||
prev = await prev.getAncestor(height);
|
prev = await prev.getAncestor(height);
|
||||||
|
|
||||||
if (!prev)
|
if (!prev)
|
||||||
return thresholdStates.DEFINED;
|
return thresholdStates.DEFINED;
|
||||||
|
|
||||||
assert(prev.height === height);
|
assert(prev.height === height);
|
||||||
assert(((prev.height + 1) % period) === 0);
|
assert(((prev.height + 1) % window) === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = prev;
|
entry = prev;
|
||||||
@ -2111,7 +2162,7 @@ Chain.prototype.getState = async function getState(prev, deployment) {
|
|||||||
|
|
||||||
compute.push(entry);
|
compute.push(entry);
|
||||||
|
|
||||||
height = entry.height - period;
|
height = entry.height - window;
|
||||||
entry = await entry.getAncestor(height);
|
entry = await entry.getAncestor(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2144,7 +2195,7 @@ Chain.prototype.getState = async function getState(prev, deployment) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < period; i++) {
|
for (let i = 0; i < window; i++) {
|
||||||
if (block.hasBit(bit))
|
if (block.hasBit(bit))
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
@ -2193,8 +2244,8 @@ Chain.prototype.computeBlockVersion = async function computeBlockVersion(prev) {
|
|||||||
for (let deployment of this.network.deploys) {
|
for (let deployment of this.network.deploys) {
|
||||||
let state = await this.getState(prev, deployment);
|
let state = await this.getState(prev, deployment);
|
||||||
|
|
||||||
if (state === common.thresholdStates.LOCKED_IN
|
if (state === thresholdStates.LOCKED_IN
|
||||||
|| state === common.thresholdStates.STARTED) {
|
|| state === thresholdStates.STARTED) {
|
||||||
version |= 1 << deployment.bit;
|
version |= 1 << deployment.bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2356,11 +2407,12 @@ function ChainOptions(options) {
|
|||||||
this.bufferKeys = ChainDB.layout.binary;
|
this.bufferKeys = ChainDB.layout.binary;
|
||||||
|
|
||||||
this.spv = false;
|
this.spv = false;
|
||||||
|
this.bip91 = false;
|
||||||
|
this.bip148 = false;
|
||||||
this.prune = false;
|
this.prune = false;
|
||||||
this.indexTX = false;
|
this.indexTX = false;
|
||||||
this.indexAddress = false;
|
this.indexAddress = false;
|
||||||
this.forceWitness = false;
|
this.forceFlags = false;
|
||||||
this.forcePrune = false;
|
|
||||||
|
|
||||||
this.coinCache = 0;
|
this.coinCache = 0;
|
||||||
this.entryCache = 5000;
|
this.entryCache = 5000;
|
||||||
@ -2445,16 +2497,19 @@ ChainOptions.prototype.fromOptions = function fromOptions(options) {
|
|||||||
this.indexAddress = options.indexAddress;
|
this.indexAddress = options.indexAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.forceWitness != null) {
|
if (options.forceFlags != null) {
|
||||||
assert(typeof options.forceWitness === 'boolean');
|
assert(typeof options.forceFlags === 'boolean');
|
||||||
this.forceWitness = options.forceWitness;
|
this.forceFlags = options.forceFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.forcePrune != null) {
|
if (options.bip91 != null) {
|
||||||
assert(typeof options.forcePrune === 'boolean');
|
assert(typeof options.bip91 === 'boolean');
|
||||||
this.forcePrune = options.forcePrune;
|
this.bip91 = options.bip91;
|
||||||
if (options.forcePrune)
|
}
|
||||||
this.prune = true;
|
|
||||||
|
if (options.bip148 != null) {
|
||||||
|
assert(typeof options.bip148 === 'boolean');
|
||||||
|
this.bip148 = options.bip148;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.coinCache != null) {
|
if (options.coinCache != null) {
|
||||||
@ -2507,6 +2562,8 @@ function DeploymentState() {
|
|||||||
this.flags &= ~Script.flags.VERIFY_P2SH;
|
this.flags &= ~Script.flags.VERIFY_P2SH;
|
||||||
this.lockFlags = common.lockFlags.MANDATORY_LOCKTIME_FLAGS;
|
this.lockFlags = common.lockFlags.MANDATORY_LOCKTIME_FLAGS;
|
||||||
this.bip34 = false;
|
this.bip34 = false;
|
||||||
|
this.bip91 = false;
|
||||||
|
this.bip148 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2572,6 +2629,24 @@ DeploymentState.prototype.hasWitness = function hasWitness() {
|
|||||||
return (this.flags & Script.flags.VERIFY_WITNESS) !== 0;
|
return (this.flags & Script.flags.VERIFY_WITNESS) !== 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether bip91 is active.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
DeploymentState.prototype.hasBIP91 = function hasBIP91() {
|
||||||
|
return this.bip91;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether bip148 is active.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
DeploymentState.prototype.hasBIP148 = function hasBIP148() {
|
||||||
|
return this.bip148;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Orphan
|
* Orphan
|
||||||
* @constructor
|
* @constructor
|
||||||
|
|||||||
@ -495,7 +495,7 @@ ChainDB.prototype.getFlags = async function getFlags() {
|
|||||||
ChainDB.prototype.verifyFlags = async function verifyFlags(state) {
|
ChainDB.prototype.verifyFlags = async function verifyFlags(state) {
|
||||||
let options = this.options;
|
let options = this.options;
|
||||||
let flags = await this.getFlags();
|
let flags = await this.getFlags();
|
||||||
let needsWitness = false;
|
let needsSave = false;
|
||||||
let needsPrune = false;
|
let needsPrune = false;
|
||||||
|
|
||||||
if (!flags)
|
if (!flags)
|
||||||
@ -511,13 +511,25 @@ ChainDB.prototype.verifyFlags = async function verifyFlags(state) {
|
|||||||
throw new Error('Cannot retroactively disable SPV.');
|
throw new Error('Cannot retroactively disable SPV.');
|
||||||
|
|
||||||
if (!flags.witness) {
|
if (!flags.witness) {
|
||||||
if (!options.forceWitness)
|
if (!options.forceFlags)
|
||||||
throw new Error('Cannot retroactively enable witness.');
|
throw new Error('Cannot retroactively enable witness.');
|
||||||
needsWitness = true;
|
needsSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.bip91 !== flags.bip91) {
|
||||||
|
if (!options.forceFlags)
|
||||||
|
throw new Error('Cannot retroactively alter BIP91 flag.');
|
||||||
|
needsSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.bip148 !== flags.bip148) {
|
||||||
|
if (!options.forceFlags)
|
||||||
|
throw new Error('Cannot retroactively alter BIP148 flag.');
|
||||||
|
needsSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.prune && !flags.prune) {
|
if (options.prune && !flags.prune) {
|
||||||
if (!options.forcePrune)
|
if (!options.forceFlags)
|
||||||
throw new Error('Cannot retroactively prune.');
|
throw new Error('Cannot retroactively prune.');
|
||||||
needsPrune = true;
|
needsPrune = true;
|
||||||
}
|
}
|
||||||
@ -537,8 +549,8 @@ ChainDB.prototype.verifyFlags = async function verifyFlags(state) {
|
|||||||
if (!options.indexAddress && flags.indexAddress)
|
if (!options.indexAddress && flags.indexAddress)
|
||||||
throw new Error('Cannot retroactively disable address indexing.');
|
throw new Error('Cannot retroactively disable address indexing.');
|
||||||
|
|
||||||
if (needsWitness) {
|
if (needsSave) {
|
||||||
await this.logger.info('Writing witness bit to chain flags.');
|
await this.logger.info('Rewriting chain flags.');
|
||||||
await this.saveFlags();
|
await this.saveFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,7 +601,7 @@ ChainDB.prototype.saveDeployments = function saveDeployments() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ChainDB.prototype.writeDeployments = function writeDeployments(batch) {
|
ChainDB.prototype.writeDeployments = function writeDeployments(batch) {
|
||||||
let bw = new StaticWriter(1 + 9 * this.network.deploys.length);
|
let bw = new StaticWriter(1 + 17 * this.network.deploys.length);
|
||||||
|
|
||||||
bw.writeU8(this.network.deploys.length);
|
bw.writeU8(this.network.deploys.length);
|
||||||
|
|
||||||
@ -597,6 +609,8 @@ ChainDB.prototype.writeDeployments = function writeDeployments(batch) {
|
|||||||
bw.writeU8(deployment.bit);
|
bw.writeU8(deployment.bit);
|
||||||
bw.writeU32(deployment.startTime);
|
bw.writeU32(deployment.startTime);
|
||||||
bw.writeU32(deployment.timeout);
|
bw.writeU32(deployment.timeout);
|
||||||
|
bw.write32(deployment.threshold);
|
||||||
|
bw.write32(deployment.window);
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.put(layout.V, bw.render());
|
batch.put(layout.V, bw.render());
|
||||||
@ -623,11 +637,15 @@ ChainDB.prototype.checkDeployments = async function checkDeployments() {
|
|||||||
let bit = br.readU8();
|
let bit = br.readU8();
|
||||||
let start = br.readU32();
|
let start = br.readU32();
|
||||||
let timeout = br.readU32();
|
let timeout = br.readU32();
|
||||||
|
let threshold = br.read32();
|
||||||
|
let window = br.read32();
|
||||||
let deployment = this.network.byBit(bit);
|
let deployment = this.network.byBit(bit);
|
||||||
|
|
||||||
if (deployment
|
if (deployment
|
||||||
&& start === deployment.startTime
|
&& start === deployment.startTime
|
||||||
&& timeout === deployment.timeout) {
|
&& timeout === deployment.timeout
|
||||||
|
&& threshold === deployment.threshold
|
||||||
|
&& window === deployment.window) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,8 +662,17 @@ ChainDB.prototype.checkDeployments = async function checkDeployments() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ChainDB.prototype.verifyDeployments = async function verifyDeployments() {
|
ChainDB.prototype.verifyDeployments = async function verifyDeployments() {
|
||||||
let invalid = await this.checkDeployments();
|
let invalid, batch;
|
||||||
let batch;
|
|
||||||
|
try {
|
||||||
|
invalid = await this.checkDeployments();
|
||||||
|
} catch (e) {
|
||||||
|
if (e.type !== 'EncodingError')
|
||||||
|
throw e;
|
||||||
|
invalid = [];
|
||||||
|
for (let {bit} of this.network.deploys)
|
||||||
|
invalid.push(bit);
|
||||||
|
}
|
||||||
|
|
||||||
if (invalid.length === 0)
|
if (invalid.length === 0)
|
||||||
return true;
|
return true;
|
||||||
@ -1946,6 +1973,8 @@ function ChainFlags(options) {
|
|||||||
this.network = Network.primary;
|
this.network = Network.primary;
|
||||||
this.spv = false;
|
this.spv = false;
|
||||||
this.witness = true;
|
this.witness = true;
|
||||||
|
this.bip91 = false;
|
||||||
|
this.bip148 = false;
|
||||||
this.prune = false;
|
this.prune = false;
|
||||||
this.indexTX = false;
|
this.indexTX = false;
|
||||||
this.indexAddress = false;
|
this.indexAddress = false;
|
||||||
@ -1962,6 +1991,16 @@ ChainFlags.prototype.fromOptions = function fromOptions(options) {
|
|||||||
this.spv = options.spv;
|
this.spv = options.spv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.bip91 != null) {
|
||||||
|
assert(typeof options.bip91 === 'boolean');
|
||||||
|
this.bip91 = options.bip91;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.bip148 != null) {
|
||||||
|
assert(typeof options.bip148 === 'boolean');
|
||||||
|
this.bip148 = options.bip148;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.prune != null) {
|
if (options.prune != null) {
|
||||||
assert(typeof options.prune === 'boolean');
|
assert(typeof options.prune === 'boolean');
|
||||||
this.prune = options.prune;
|
this.prune = options.prune;
|
||||||
@ -2003,6 +2042,12 @@ ChainFlags.prototype.toRaw = function toRaw() {
|
|||||||
if (this.indexAddress)
|
if (this.indexAddress)
|
||||||
flags |= 1 << 4;
|
flags |= 1 << 4;
|
||||||
|
|
||||||
|
if (this.bip91)
|
||||||
|
flags |= 1 << 5;
|
||||||
|
|
||||||
|
if (this.bip148)
|
||||||
|
flags |= 1 << 6;
|
||||||
|
|
||||||
bw.writeU32(this.network.magic);
|
bw.writeU32(this.network.magic);
|
||||||
bw.writeU32(flags);
|
bw.writeU32(flags);
|
||||||
bw.writeU32(0);
|
bw.writeU32(0);
|
||||||
@ -2023,6 +2068,8 @@ ChainFlags.prototype.fromRaw = function fromRaw(data) {
|
|||||||
this.prune = (flags & 4) !== 0;
|
this.prune = (flags & 4) !== 0;
|
||||||
this.indexTX = (flags & 8) !== 0;
|
this.indexTX = (flags & 8) !== 0;
|
||||||
this.indexAddress = (flags & 16) !== 0;
|
this.indexAddress = (flags & 16) !== 0;
|
||||||
|
this.bip91 = (flags & 32) !== 0;
|
||||||
|
this.bip148 = (flags & 64) !== 0;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -267,14 +267,23 @@ ChainEntry.prototype.getNextEntry = async function getNextEntry() {
|
|||||||
/**
|
/**
|
||||||
* Calculate median time past.
|
* Calculate median time past.
|
||||||
* @method
|
* @method
|
||||||
|
* @param {Number?} ts
|
||||||
* @returns {Promise} - Returns Number.
|
* @returns {Promise} - Returns Number.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ChainEntry.prototype.getMedianTime = async function getMedianTime() {
|
ChainEntry.prototype.getMedianTime = async function getMedianTime(ts) {
|
||||||
let timespan = ChainEntry.MEDIAN_TIMESPAN;
|
let timespan = ChainEntry.MEDIAN_TIMESPAN;
|
||||||
let entry = this;
|
let entry = this;
|
||||||
let median = [];
|
let median = [];
|
||||||
|
|
||||||
|
// In case we ever want to check
|
||||||
|
// the MTP of the _current_ block
|
||||||
|
// (necessary for BIP148).
|
||||||
|
if (ts != null) {
|
||||||
|
median.push(ts);
|
||||||
|
timespan -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < timespan && entry; i++) {
|
for (let i = 0; i < timespan && entry; i++) {
|
||||||
let cache;
|
let cache;
|
||||||
|
|
||||||
@ -331,10 +340,7 @@ ChainEntry.prototype.hasUnknown = function hasUnknown() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ChainEntry.prototype.hasBit = function hasBit(bit) {
|
ChainEntry.prototype.hasBit = function hasBit(bit) {
|
||||||
let bits = this.version & consensus.VERSION_TOP_MASK;
|
return consensus.hasBit(this.version, bit);
|
||||||
let topBits = consensus.VERSION_TOP_BITS;
|
|
||||||
let mask = 1 << bit;
|
|
||||||
return (bits >>> 0) === topBits && (this.version & mask) !== 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1247,6 +1247,9 @@ RPC.prototype.getBlockTemplate = async function getBlockTemplate(args, help) {
|
|||||||
if (lpid)
|
if (lpid)
|
||||||
await this.handleLongpoll(lpid);
|
await this.handleLongpoll(lpid);
|
||||||
|
|
||||||
|
if (!rules)
|
||||||
|
rules = [];
|
||||||
|
|
||||||
return await this.createTemplate(maxVersion, coinbase, rules);
|
return await this.createTemplate(maxVersion, coinbase, rules);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1322,6 +1325,14 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.chain.options.bip91) {
|
||||||
|
rules.push('segwit');
|
||||||
|
rules.push('segsignal');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.chain.options.bip148)
|
||||||
|
rules.push('segwit');
|
||||||
|
|
||||||
// Calculate version based on given rules.
|
// Calculate version based on given rules.
|
||||||
for (let deploy of this.network.deploys) {
|
for (let deploy of this.network.deploys) {
|
||||||
let state = await this.chain.getState(this.chain.tip, deploy);
|
let state = await this.chain.getState(this.chain.tip, deploy);
|
||||||
@ -1335,15 +1346,16 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb
|
|||||||
version |= 1 << deploy.bit;
|
version |= 1 << deploy.bit;
|
||||||
case common.thresholdStates.STARTED:
|
case common.thresholdStates.STARTED:
|
||||||
if (!deploy.force) {
|
if (!deploy.force) {
|
||||||
if (!rules || rules.indexOf(name) === -1)
|
if (rules.indexOf(name) === -1)
|
||||||
version &= ~(1 << deploy.bit);
|
version &= ~(1 << deploy.bit);
|
||||||
name = '!' + name;
|
if (deploy.required)
|
||||||
|
name = '!' + name;
|
||||||
}
|
}
|
||||||
vbavailable[name] = deploy.bit;
|
vbavailable[name] = deploy.bit;
|
||||||
break;
|
break;
|
||||||
case common.thresholdStates.ACTIVE:
|
case common.thresholdStates.ACTIVE:
|
||||||
if (!deploy.force) {
|
if (!deploy.force && deploy.required) {
|
||||||
if (!rules || rules.indexOf(name) === -1) {
|
if (rules.indexOf(name) === -1) {
|
||||||
throw new RPCError(errs.INVALID_PARAMETER,
|
throw new RPCError(errs.INVALID_PARAMETER,
|
||||||
`Client must support ${name}.`);
|
`Client must support ${name}.`);
|
||||||
}
|
}
|
||||||
@ -1431,7 +1443,7 @@ RPC.prototype._createTemplate = async function _createTemplate(maxVersion, coinb
|
|||||||
json.coinbasevalue = attempt.getReward();
|
json.coinbasevalue = attempt.getReward();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rules && rules.indexOf('segwit') !== -1)
|
if (rules.indexOf('segwit') !== -1)
|
||||||
json.default_witness_commitment = attempt.getWitnessScript().toJSON();
|
json.default_witness_commitment = attempt.getWitnessScript().toJSON();
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
|
|||||||
@ -56,8 +56,9 @@ function FullNode(options) {
|
|||||||
prefix: this.config.prefix,
|
prefix: this.config.prefix,
|
||||||
maxFiles: this.config.num('max-files'),
|
maxFiles: this.config.num('max-files'),
|
||||||
cacheSize: this.config.mb('cache-size'),
|
cacheSize: this.config.mb('cache-size'),
|
||||||
forceWitness: this.config.bool('force-witness'),
|
forceFlags: this.config.bool('force-flags'),
|
||||||
forcePrune: this.config.bool('force-prune'),
|
bip91: this.config.bool('bip91'),
|
||||||
|
bip148: this.config.bool('bip148'),
|
||||||
prune: this.config.bool('prune'),
|
prune: this.config.bool('prune'),
|
||||||
checkpoints: this.config.bool('checkpoints'),
|
checkpoints: this.config.bool('checkpoints'),
|
||||||
coinCache: this.config.mb('coin-cache'),
|
coinCache: this.config.mb('coin-cache'),
|
||||||
|
|||||||
@ -52,8 +52,10 @@ function SPVNode(options) {
|
|||||||
maxFiles: this.config.num('max-files'),
|
maxFiles: this.config.num('max-files'),
|
||||||
cacheSize: this.config.mb('cache-size'),
|
cacheSize: this.config.mb('cache-size'),
|
||||||
entryCache: this.config.num('entry-cache'),
|
entryCache: this.config.num('entry-cache'),
|
||||||
forceWitness: this.config.bool('force-witness'),
|
forceFlags: this.config.bool('force-flags'),
|
||||||
checkpoints: this.config.bool('checkpoints'),
|
checkpoints: this.config.bool('checkpoints'),
|
||||||
|
bip91: this.config.bool('bip91'),
|
||||||
|
bip148: this.config.bool('bip148'),
|
||||||
spv: true
|
spv: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -332,3 +332,17 @@ exports.getReward = function getReward(height, interval) {
|
|||||||
|
|
||||||
return exports.HALF_REWARD >>> (halvings - 1);
|
return exports.HALF_REWARD >>> (halvings - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test version bit.
|
||||||
|
* @param {Number} version
|
||||||
|
* @param {Number} bit
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.hasBit = function hasBit(version, bit) {
|
||||||
|
let bits = version & exports.VERSION_TOP_MASK;
|
||||||
|
let topBits = exports.VERSION_TOP_BITS;
|
||||||
|
let mask = 1 << bit;
|
||||||
|
return (bits >>> 0) === topBits && (version & mask) !== 0;
|
||||||
|
};
|
||||||
|
|||||||
@ -335,18 +335,14 @@ main.minerWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
main.deployments = {
|
main.deployments = {
|
||||||
testdummy: {
|
|
||||||
name: 'testdummy',
|
|
||||||
bit: 28,
|
|
||||||
startTime: 1199145601, // January 1, 2008
|
|
||||||
timeout: 1230767999, // December 31, 2008
|
|
||||||
force: true
|
|
||||||
},
|
|
||||||
csv: {
|
csv: {
|
||||||
name: 'csv',
|
name: 'csv',
|
||||||
bit: 0,
|
bit: 0,
|
||||||
startTime: 1462060800, // May 1st, 2016
|
startTime: 1462060800, // May 1st, 2016
|
||||||
timeout: 1493596800, // May 1st, 2017
|
timeout: 1493596800, // May 1st, 2017
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: false,
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
segwit: {
|
segwit: {
|
||||||
@ -354,7 +350,30 @@ main.deployments = {
|
|||||||
bit: 1,
|
bit: 1,
|
||||||
startTime: 1479168000, // November 15th, 2016.
|
startTime: 1479168000, // November 15th, 2016.
|
||||||
timeout: 1510704000, // November 15th, 2017.
|
timeout: 1510704000, // November 15th, 2017.
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: true,
|
||||||
force: false
|
force: false
|
||||||
|
},
|
||||||
|
segsignal: {
|
||||||
|
name: 'segsignal',
|
||||||
|
bit: 4,
|
||||||
|
startTime: 1496275200, // June 1st, 2017.
|
||||||
|
timeout: 1510704000, // November 15th, 2017.
|
||||||
|
threshold: 269, // 80%
|
||||||
|
window: 336, // ~2.33 days
|
||||||
|
required: false,
|
||||||
|
force: false
|
||||||
|
},
|
||||||
|
testdummy: {
|
||||||
|
name: 'testdummy',
|
||||||
|
bit: 28,
|
||||||
|
startTime: 1199145601, // January 1, 2008
|
||||||
|
timeout: 1230767999, // December 31, 2008
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: false,
|
||||||
|
force: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -367,6 +386,7 @@ main.deployments = {
|
|||||||
main.deploys = [
|
main.deploys = [
|
||||||
main.deployments.csv,
|
main.deployments.csv,
|
||||||
main.deployments.segwit,
|
main.deployments.segwit,
|
||||||
|
main.deployments.segsignal,
|
||||||
main.deployments.testdummy
|
main.deployments.testdummy
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -555,18 +575,14 @@ testnet.activationThreshold = 1512; // 75% for testchains
|
|||||||
testnet.minerWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
|
testnet.minerWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
|
||||||
|
|
||||||
testnet.deployments = {
|
testnet.deployments = {
|
||||||
testdummy: {
|
|
||||||
name: 'testdummy',
|
|
||||||
bit: 28,
|
|
||||||
startTime: 1199145601, // January 1, 2008
|
|
||||||
timeout: 1230767999, // December 31, 2008
|
|
||||||
force: true
|
|
||||||
},
|
|
||||||
csv: {
|
csv: {
|
||||||
name: 'csv',
|
name: 'csv',
|
||||||
bit: 0,
|
bit: 0,
|
||||||
startTime: 1456790400, // March 1st, 2016
|
startTime: 1456790400, // March 1st, 2016
|
||||||
timeout: 1493596800, // May 1st, 2017
|
timeout: 1493596800, // May 1st, 2017
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: false,
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
segwit: {
|
segwit: {
|
||||||
@ -574,13 +590,37 @@ testnet.deployments = {
|
|||||||
bit: 1,
|
bit: 1,
|
||||||
startTime: 1462060800, // May 1st 2016
|
startTime: 1462060800, // May 1st 2016
|
||||||
timeout: 1493596800, // May 1st 2017
|
timeout: 1493596800, // May 1st 2017
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: true,
|
||||||
force: false
|
force: false
|
||||||
|
},
|
||||||
|
segsignal: {
|
||||||
|
name: 'segsignal',
|
||||||
|
bit: 4,
|
||||||
|
startTime: 0xffffffff,
|
||||||
|
timeout: 0xffffffff,
|
||||||
|
threshold: 269,
|
||||||
|
window: 336,
|
||||||
|
required: false,
|
||||||
|
force: false
|
||||||
|
},
|
||||||
|
testdummy: {
|
||||||
|
name: 'testdummy',
|
||||||
|
bit: 28,
|
||||||
|
startTime: 1199145601, // January 1, 2008
|
||||||
|
timeout: 1230767999, // December 31, 2008
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: false,
|
||||||
|
force: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
testnet.deploys = [
|
testnet.deploys = [
|
||||||
testnet.deployments.csv,
|
testnet.deployments.csv,
|
||||||
testnet.deployments.segwit,
|
testnet.deployments.segwit,
|
||||||
|
testnet.deployments.segsignal,
|
||||||
testnet.deployments.testdummy
|
testnet.deployments.testdummy
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -695,18 +735,14 @@ regtest.activationThreshold = 108; // 75% for testchains
|
|||||||
regtest.minerWindow = 144; // Faster than normal for regtest (144 instead of 2016)
|
regtest.minerWindow = 144; // Faster than normal for regtest (144 instead of 2016)
|
||||||
|
|
||||||
regtest.deployments = {
|
regtest.deployments = {
|
||||||
testdummy: {
|
|
||||||
name: 'testdummy',
|
|
||||||
bit: 28,
|
|
||||||
startTime: 0,
|
|
||||||
timeout: 0xffffffff,
|
|
||||||
force: true
|
|
||||||
},
|
|
||||||
csv: {
|
csv: {
|
||||||
name: 'csv',
|
name: 'csv',
|
||||||
bit: 0,
|
bit: 0,
|
||||||
startTime: 0,
|
startTime: 0,
|
||||||
timeout: 0xffffffff,
|
timeout: 0xffffffff,
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: false,
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
segwit: {
|
segwit: {
|
||||||
@ -714,13 +750,37 @@ regtest.deployments = {
|
|||||||
bit: 1,
|
bit: 1,
|
||||||
startTime: 0,
|
startTime: 0,
|
||||||
timeout: 0xffffffff,
|
timeout: 0xffffffff,
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: true,
|
||||||
force: false
|
force: false
|
||||||
|
},
|
||||||
|
segsignal: {
|
||||||
|
name: 'segsignal',
|
||||||
|
bit: 4,
|
||||||
|
startTime: 0xffffffff,
|
||||||
|
timeout: 0xffffffff,
|
||||||
|
threshold: 269,
|
||||||
|
window: 336,
|
||||||
|
required: false,
|
||||||
|
force: false
|
||||||
|
},
|
||||||
|
testdummy: {
|
||||||
|
name: 'testdummy',
|
||||||
|
bit: 28,
|
||||||
|
startTime: 0,
|
||||||
|
timeout: 0xffffffff,
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: false,
|
||||||
|
force: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
regtest.deploys = [
|
regtest.deploys = [
|
||||||
regtest.deployments.csv,
|
regtest.deployments.csv,
|
||||||
regtest.deployments.segwit,
|
regtest.deployments.segwit,
|
||||||
|
regtest.deployments.segsignal,
|
||||||
regtest.deployments.testdummy
|
regtest.deployments.testdummy
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -837,18 +897,14 @@ segnet4.activationThreshold = 108;
|
|||||||
segnet4.minerWindow = 144;
|
segnet4.minerWindow = 144;
|
||||||
|
|
||||||
segnet4.deployments = {
|
segnet4.deployments = {
|
||||||
testdummy: {
|
|
||||||
name: 'testdummy',
|
|
||||||
bit: 28,
|
|
||||||
startTime: 1199145601, // January 1, 2008
|
|
||||||
timeout: 1230767999, // December 31, 2008
|
|
||||||
force: true
|
|
||||||
},
|
|
||||||
csv: {
|
csv: {
|
||||||
name: 'csv',
|
name: 'csv',
|
||||||
bit: 0,
|
bit: 0,
|
||||||
startTime: 1456790400, // March 1st, 2016
|
startTime: 1456790400, // March 1st, 2016
|
||||||
timeout: 1493596800, // May 1st, 2017
|
timeout: 1493596800, // May 1st, 2017
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: false,
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
segwit: {
|
segwit: {
|
||||||
@ -856,13 +912,37 @@ segnet4.deployments = {
|
|||||||
bit: 1,
|
bit: 1,
|
||||||
startTime: 0,
|
startTime: 0,
|
||||||
timeout: 0xffffffff,
|
timeout: 0xffffffff,
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: true,
|
||||||
force: false
|
force: false
|
||||||
|
},
|
||||||
|
segsignal: {
|
||||||
|
name: 'segsignal',
|
||||||
|
bit: 4,
|
||||||
|
startTime: 0xffffffff,
|
||||||
|
timeout: 0xffffffff,
|
||||||
|
threshold: 269,
|
||||||
|
window: 336,
|
||||||
|
required: false,
|
||||||
|
force: false
|
||||||
|
},
|
||||||
|
testdummy: {
|
||||||
|
name: 'testdummy',
|
||||||
|
bit: 28,
|
||||||
|
startTime: 1199145601, // January 1, 2008
|
||||||
|
timeout: 1230767999, // December 31, 2008
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: false,
|
||||||
|
force: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
segnet4.deploys = [
|
segnet4.deploys = [
|
||||||
segnet4.deployments.csv,
|
segnet4.deployments.csv,
|
||||||
segnet4.deployments.segwit,
|
segnet4.deployments.segwit,
|
||||||
|
segnet4.deployments.segsignal,
|
||||||
segnet4.deployments.testdummy
|
segnet4.deployments.testdummy
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -979,18 +1059,14 @@ simnet.activationThreshold = 75; // 75% for testchains
|
|||||||
simnet.minerWindow = 100; // nPowTargetTimespan / nPowTargetSpacing
|
simnet.minerWindow = 100; // nPowTargetTimespan / nPowTargetSpacing
|
||||||
|
|
||||||
simnet.deployments = {
|
simnet.deployments = {
|
||||||
testdummy: {
|
|
||||||
name: 'testdummy',
|
|
||||||
bit: 28,
|
|
||||||
startTime: 1199145601, // January 1, 2008
|
|
||||||
timeout: 1230767999, // December 31, 2008
|
|
||||||
force: true
|
|
||||||
},
|
|
||||||
csv: {
|
csv: {
|
||||||
name: 'csv',
|
name: 'csv',
|
||||||
bit: 0,
|
bit: 0,
|
||||||
startTime: 0, // March 1st, 2016
|
startTime: 0, // March 1st, 2016
|
||||||
timeout: 0xffffffff, // May 1st, 2017
|
timeout: 0xffffffff, // May 1st, 2017
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: false,
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
segwit: {
|
segwit: {
|
||||||
@ -998,13 +1074,37 @@ simnet.deployments = {
|
|||||||
bit: 1,
|
bit: 1,
|
||||||
startTime: 0, // May 1st 2016
|
startTime: 0, // May 1st 2016
|
||||||
timeout: 0xffffffff, // May 1st 2017
|
timeout: 0xffffffff, // May 1st 2017
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: true,
|
||||||
force: false
|
force: false
|
||||||
|
},
|
||||||
|
segsignal: {
|
||||||
|
name: 'segsignal',
|
||||||
|
bit: 4,
|
||||||
|
startTime: 0xffffffff,
|
||||||
|
timeout: 0xffffffff,
|
||||||
|
threshold: 269,
|
||||||
|
window: 336,
|
||||||
|
required: false,
|
||||||
|
force: false
|
||||||
|
},
|
||||||
|
testdummy: {
|
||||||
|
name: 'testdummy',
|
||||||
|
bit: 28,
|
||||||
|
startTime: 1199145601, // January 1, 2008
|
||||||
|
timeout: 1230767999, // December 31, 2008
|
||||||
|
threshold: -1,
|
||||||
|
window: -1,
|
||||||
|
required: false,
|
||||||
|
force: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
simnet.deploys = [
|
simnet.deploys = [
|
||||||
simnet.deployments.csv,
|
simnet.deployments.csv,
|
||||||
simnet.deployments.segwit,
|
simnet.deployments.segwit,
|
||||||
|
simnet.deployments.segsignal,
|
||||||
simnet.deployments.testdummy
|
simnet.deployments.testdummy
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user