chain: versionbits refactor.
This commit is contained in:
parent
390f7d8ddb
commit
1f22013ce0
@ -436,6 +436,7 @@ Chain.prototype.verify = co(function* verify(block, prev) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Chain.prototype.getDeployments = co(function* getDeployments(block, prev) {
|
Chain.prototype.getDeployments = co(function* getDeployments(block, prev) {
|
||||||
|
var deployments = this.network.deployments;
|
||||||
var height = prev.height + 1;
|
var height = prev.height + 1;
|
||||||
var state = new DeploymentState();
|
var state = new DeploymentState();
|
||||||
var active;
|
var active;
|
||||||
@ -496,7 +497,7 @@ Chain.prototype.getDeployments = co(function* getDeployments(block, prev) {
|
|||||||
|
|
||||||
// CHECKSEQUENCEVERIFY and median time
|
// CHECKSEQUENCEVERIFY and median time
|
||||||
// past locktimes are now usable (bip9 & bip113).
|
// past locktimes are now usable (bip9 & bip113).
|
||||||
active = yield this.isActive(prev, 'csv');
|
active = yield this.isActive(prev, deployments.csv);
|
||||||
if (active) {
|
if (active) {
|
||||||
state.flags |= constants.flags.VERIFY_CHECKSEQUENCEVERIFY;
|
state.flags |= constants.flags.VERIFY_CHECKSEQUENCEVERIFY;
|
||||||
state.lockFlags |= constants.flags.VERIFY_SEQUENCE;
|
state.lockFlags |= constants.flags.VERIFY_SEQUENCE;
|
||||||
@ -504,7 +505,7 @@ Chain.prototype.getDeployments = co(function* getDeployments(block, prev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Segregrated witness is now usable (bip141 - segnet4)
|
// Segregrated witness is now usable (bip141 - segnet4)
|
||||||
active = yield this.isActive(prev, 'witness');
|
active = yield this.isActive(prev, deployments.witness);
|
||||||
if (active) {
|
if (active) {
|
||||||
if (this.options.witness)
|
if (this.options.witness)
|
||||||
state.flags |= constants.flags.VERIFY_WITNESS;
|
state.flags |= constants.flags.VERIFY_WITNESS;
|
||||||
@ -645,7 +646,7 @@ Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify sequence locks.
|
// Verify sequence locks.
|
||||||
valid = yield this.checkLocks(prev, tx, state.lockFlags);
|
valid = yield this.verifyLocks(prev, tx, state.lockFlags);
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new VerifyError(block,
|
throw new VerifyError(block,
|
||||||
@ -936,6 +937,13 @@ Chain.prototype.setBestChain = co(function* setBestChain(entry, block, prev) {
|
|||||||
yield this.reorganize(entry, block);
|
yield this.reorganize(entry, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Warn of unknown versionbits.
|
||||||
|
if (entry.hasUnknown()) {
|
||||||
|
this.logger.warning(
|
||||||
|
'Unknown version bits in block %d: %d.',
|
||||||
|
entry.height, entry.version);
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, everything is in order.
|
// Otherwise, everything is in order.
|
||||||
// Do "contextual" verification on our block
|
// Do "contextual" verification on our block
|
||||||
// now that we're certain its previous
|
// now that we're certain its previous
|
||||||
@ -995,6 +1003,13 @@ Chain.prototype.saveAlternate = co(function* saveAlternate(entry, block, prev) {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Warn of unknown versionbits.
|
||||||
|
if (entry.hasUnknown()) {
|
||||||
|
this.logger.warning(
|
||||||
|
'Unknown version bits in block %d: %d.',
|
||||||
|
entry.height, entry.version);
|
||||||
|
}
|
||||||
|
|
||||||
yield this.db.save(entry, block);
|
yield this.db.save(entry, block);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1912,7 +1927,7 @@ Chain.prototype.findLocator = co(function* findLocator(locator) {
|
|||||||
* @returns {Promise} - Returns Number.
|
* @returns {Promise} - Returns Number.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Chain.prototype.isActive = co(function* isActive(prev, id) {
|
Chain.prototype.isActive = co(function* isActive(prev, deployment) {
|
||||||
var state;
|
var state;
|
||||||
|
|
||||||
if (!this.options.witness) {
|
if (!this.options.witness) {
|
||||||
@ -1920,7 +1935,7 @@ Chain.prototype.isActive = co(function* isActive(prev, id) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = yield this.getState(prev, id);
|
state = yield this.getState(prev, deployment);
|
||||||
|
|
||||||
return state === constants.thresholdStates.ACTIVE;
|
return state === constants.thresholdStates.ACTIVE;
|
||||||
});
|
});
|
||||||
@ -1935,20 +1950,14 @@ Chain.prototype.isActive = co(function* isActive(prev, id) {
|
|||||||
* @returns {Promise} - Returns Number.
|
* @returns {Promise} - Returns Number.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Chain.prototype.getState = co(function* getState(prev, id) {
|
Chain.prototype.getState = co(function* getState(prev, deployment) {
|
||||||
var period = this.network.minerWindow;
|
var period = this.network.minerWindow;
|
||||||
var threshold = this.network.activationThreshold;
|
var threshold = this.network.activationThreshold;
|
||||||
var deployment = this.network.deployments[id];
|
|
||||||
var thresholdStates = constants.thresholdStates;
|
var thresholdStates = constants.thresholdStates;
|
||||||
var bit = deployment.bit;
|
var bit = deployment.bit;
|
||||||
var timeStart, timeTimeout, compute, height;
|
var compute = [];
|
||||||
var i, entry, count, state, block, medianTime;
|
var i, entry, count, state;
|
||||||
|
var block, time, height;
|
||||||
assert(deployment);
|
|
||||||
|
|
||||||
timeStart = deployment.startTime;
|
|
||||||
timeTimeout = deployment.timeout;
|
|
||||||
compute = [];
|
|
||||||
|
|
||||||
if (!prev)
|
if (!prev)
|
||||||
return thresholdStates.DEFINED;
|
return thresholdStates.DEFINED;
|
||||||
@ -1972,9 +1981,9 @@ Chain.prototype.getState = co(function* getState(prev, id) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
medianTime = yield entry.getMedianTimeAsync();
|
time = yield entry.getMedianTimeAsync();
|
||||||
|
|
||||||
if (medianTime < timeStart) {
|
if (time < deployment.startTime) {
|
||||||
state = thresholdStates.DEFINED;
|
state = thresholdStates.DEFINED;
|
||||||
this.db.stateCache.set(bit, entry, state);
|
this.db.stateCache.set(bit, entry, state);
|
||||||
break;
|
break;
|
||||||
@ -1991,23 +2000,23 @@ Chain.prototype.getState = co(function* getState(prev, id) {
|
|||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case thresholdStates.DEFINED:
|
case thresholdStates.DEFINED:
|
||||||
medianTime = yield entry.getMedianTimeAsync();
|
time = yield entry.getMedianTimeAsync();
|
||||||
|
|
||||||
if (medianTime >= timeTimeout) {
|
if (time >= deployment.timeout) {
|
||||||
state = thresholdStates.FAILED;
|
state = thresholdStates.FAILED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (medianTime >= timeStart) {
|
if (time >= deployment.startTime) {
|
||||||
state = thresholdStates.STARTED;
|
state = thresholdStates.STARTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case thresholdStates.STARTED:
|
case thresholdStates.STARTED:
|
||||||
medianTime = yield entry.getMedianTimeAsync();
|
time = yield entry.getMedianTimeAsync();
|
||||||
|
|
||||||
if (medianTime >= timeTimeout) {
|
if (time >= deployment.timeout) {
|
||||||
state = thresholdStates.FAILED;
|
state = thresholdStates.FAILED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2016,7 +2025,7 @@ Chain.prototype.getState = co(function* getState(prev, id) {
|
|||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
for (i = 0; i < period; i++) {
|
for (i = 0; i < period; i++) {
|
||||||
if (block.hasBit(deployment))
|
if (block.hasBit(bit))
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if (count >= threshold) {
|
if (count >= threshold) {
|
||||||
@ -2054,18 +2063,16 @@ Chain.prototype.getState = co(function* getState(prev, id) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Chain.prototype.computeBlockVersion = co(function* computeBlockVersion(prev) {
|
Chain.prototype.computeBlockVersion = co(function* computeBlockVersion(prev) {
|
||||||
var keys = Object.keys(this.network.deployments);
|
|
||||||
var version = 0;
|
var version = 0;
|
||||||
var i, id, deployment, state;
|
var i, deployment, state;
|
||||||
|
|
||||||
for (i = 0; i < keys.length; i++) {
|
for (i = 0; i < this.network.deploys.length; i++) {
|
||||||
id = keys[i];
|
deployment = this.network.deploys[i];
|
||||||
deployment = this.network.deployments[id];
|
state = yield this.getState(prev, deployment);
|
||||||
state = yield this.getState(prev, id);
|
|
||||||
|
|
||||||
if (state === constants.thresholdStates.LOCKED_IN
|
if (state === constants.thresholdStates.LOCKED_IN
|
||||||
|| state === constants.thresholdStates.STARTED) {
|
|| state === constants.thresholdStates.STARTED) {
|
||||||
version |= (1 << deployment.bit);
|
version |= 1 << deployment.bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2165,31 +2172,6 @@ Chain.prototype.getLocks = co(function* getLocks(prev, tx, flags) {
|
|||||||
return new LockTimes(minHeight, minTime);
|
return new LockTimes(minHeight, minTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluate sequence locks.
|
|
||||||
* @param {ChainEntry} prev
|
|
||||||
* @param {Number} minHeight
|
|
||||||
* @param {Number} minTime
|
|
||||||
* @returns {Promise} - Returns Boolean.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Chain.prototype.evalLocks = co(function* evalLocks(prev, minHeight, minTime) {
|
|
||||||
var medianTime;
|
|
||||||
|
|
||||||
if (minHeight >= prev.height + 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (minTime === -1)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
medianTime = yield prev.getMedianTimeAsync();
|
|
||||||
|
|
||||||
if (minTime >= medianTime)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify sequence locks.
|
* Verify sequence locks.
|
||||||
* @param {TX} tx
|
* @param {TX} tx
|
||||||
@ -2198,9 +2180,22 @@ Chain.prototype.evalLocks = co(function* evalLocks(prev, minHeight, minTime) {
|
|||||||
* @returns {Promise} - Returns Boolean.
|
* @returns {Promise} - Returns Boolean.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Chain.prototype.checkLocks = co(function* checkLocks(prev, tx, flags) {
|
Chain.prototype.verifyLocks = co(function* verifyLocks(prev, tx, flags) {
|
||||||
var times = yield this.getLocks(prev, tx, flags);
|
var locks = yield this.getLocks(prev, tx, flags);
|
||||||
return yield this.evalLocks(prev, times.height, times.time);
|
var medianTime;
|
||||||
|
|
||||||
|
if (locks.height >= prev.height + 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (locks.time === -1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
medianTime = yield prev.getMedianTimeAsync();
|
||||||
|
|
||||||
|
if (locks.time >= medianTime)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -144,6 +144,8 @@ ChainDB.prototype._open = co(function* open() {
|
|||||||
block = Block.fromRaw(this.network.genesisBlock, 'hex');
|
block = Block.fromRaw(this.network.genesisBlock, 'hex');
|
||||||
block.setHeight(0);
|
block.setHeight(0);
|
||||||
entry = ChainEntry.fromBlock(this.chain, block);
|
entry = ChainEntry.fromBlock(this.chain, block);
|
||||||
|
|
||||||
|
this.logger.info('Writing genesis block to ChainDB.');
|
||||||
yield this.save(entry, block, new CoinView());
|
yield this.save(entry, block, new CoinView());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -793,8 +795,8 @@ ChainDB.prototype.getStateCache = co(function* getStateCache() {
|
|||||||
var i, items, item;
|
var i, items, item;
|
||||||
|
|
||||||
items = yield this.db.range({
|
items = yield this.db.range({
|
||||||
gte: layout.s(0, constants.ZERO_HASH),
|
gte: layout.v(0, constants.ZERO_HASH),
|
||||||
lte: layout.s(255, constants.MAX_HASH),
|
lte: layout.v(255, constants.MAX_HASH),
|
||||||
values: true
|
values: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -816,8 +818,8 @@ ChainDB.prototype.invalidateCache = co(function* invalidateCache(bit, batch) {
|
|||||||
var i, keys, key;
|
var i, keys, key;
|
||||||
|
|
||||||
keys = yield this.db.keys({
|
keys = yield this.db.keys({
|
||||||
gte: layout.s(bit, constants.ZERO_HASH),
|
gte: layout.v(bit, constants.ZERO_HASH),
|
||||||
lte: layout.s(bit, constants.MAX_HASH)
|
lte: layout.v(bit, constants.MAX_HASH)
|
||||||
});
|
});
|
||||||
|
|
||||||
for (i = 0; i < keys.length; i++) {
|
for (i = 0; i < keys.length; i++) {
|
||||||
@ -833,11 +835,12 @@ ChainDB.prototype.invalidateCache = co(function* invalidateCache(bit, batch) {
|
|||||||
|
|
||||||
ChainDB.prototype.verifyDeployments = co(function* verifyDeployments() {
|
ChainDB.prototype.verifyDeployments = co(function* verifyDeployments() {
|
||||||
var expected = this.stateCache.toDeployments();
|
var expected = this.stateCache.toDeployments();
|
||||||
var current = yield this.db.get(layout.v);
|
var current = yield this.db.get(layout.V);
|
||||||
var i, invalid, bit, batch;
|
var i, invalid, bit, batch;
|
||||||
|
|
||||||
if (!current) {
|
if (!current) {
|
||||||
yield this.db.put(layout.v, expected);
|
this.logger.info('Writing deployment params to ChainDB.');
|
||||||
|
yield this.db.put(layout.V, expected);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -855,7 +858,7 @@ ChainDB.prototype.verifyDeployments = co(function* verifyDeployments() {
|
|||||||
yield this.invalidateCache(bit, batch);
|
yield this.invalidateCache(bit, batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.put(layout.v, expected);
|
batch.put(layout.V, expected);
|
||||||
|
|
||||||
yield batch.write();
|
yield batch.write();
|
||||||
|
|
||||||
@ -1358,7 +1361,7 @@ ChainDB.prototype.saveUpdates = function saveUpdates() {
|
|||||||
|
|
||||||
for (i = 0; i < updates.length; i++) {
|
for (i = 0; i < updates.length; i++) {
|
||||||
update = updates[i];
|
update = updates[i];
|
||||||
this.put(layout.s(update.bit, update.hash), update.toRaw());
|
this.put(layout.v(update.bit, update.hash), update.toRaw());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2001,34 +2004,33 @@ ChainState.fromRaw = function fromRaw(data) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function StateCache(network) {
|
function StateCache(network) {
|
||||||
this.deployments = network.deployments;
|
this.network = network;
|
||||||
this.bits = {};
|
this.cache = [];
|
||||||
this.cache = {};
|
|
||||||
this.updates = [];
|
this.updates = [];
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
|
|
||||||
StateCache.prototype._init = function _init() {
|
StateCache.prototype._init = function _init() {
|
||||||
var keys = Object.keys(this.deployments);
|
var i, deployment;
|
||||||
var i, key, deployment, bit;
|
|
||||||
|
|
||||||
for (i = 0; i < keys.length; i++) {
|
for (i = 0; i < 32; i++)
|
||||||
key = keys[i];
|
this.cache.push(null);
|
||||||
deployment = this.deployments[key];
|
|
||||||
bit = deployment.bit;
|
for (i = 0; i < this.network.deploys.length; i++) {
|
||||||
this.cache[bit] = {};
|
deployment = this.network.deploys[i];
|
||||||
this.bits[bit] = deployment;
|
assert(!this.cache[deployment.bit]);
|
||||||
|
this.cache[deployment.bit] = {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
StateCache.prototype.toDeployments = function toDeployments() {
|
StateCache.prototype.toDeployments = function toDeployments() {
|
||||||
var p = new BufferWriter();
|
var p = new BufferWriter();
|
||||||
var keys = Object.keys(this.deployments);
|
var i, deployment;
|
||||||
var i, key, deployment;
|
|
||||||
|
|
||||||
for (i = 0; i < keys.length; i++) {
|
p.writeU8(this.network.deploys.length);
|
||||||
key = keys[i];
|
|
||||||
deployment = this.deployments[key];
|
for (i = 0; i < this.network.deploys.length; i++) {
|
||||||
|
deployment = this.network.deploys[i];
|
||||||
p.writeU8(deployment.bit);
|
p.writeU8(deployment.bit);
|
||||||
p.writeU32(deployment.startTime);
|
p.writeU32(deployment.startTime);
|
||||||
p.writeU32(deployment.timeout);
|
p.writeU32(deployment.timeout);
|
||||||
@ -2040,13 +2042,16 @@ StateCache.prototype.toDeployments = function toDeployments() {
|
|||||||
StateCache.prototype.verifyDeployments = function verifyDeployments(raw) {
|
StateCache.prototype.verifyDeployments = function verifyDeployments(raw) {
|
||||||
var p = new BufferReader(raw);
|
var p = new BufferReader(raw);
|
||||||
var invalid = [];
|
var invalid = [];
|
||||||
var deployment, bit, start, timeout;
|
var i, count, deployment;
|
||||||
|
var bit, start, timeout;
|
||||||
|
|
||||||
while (p.left()) {
|
count = p.readU8();
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
bit = p.readU8();
|
bit = p.readU8();
|
||||||
start = p.readU32();
|
start = p.readU32();
|
||||||
timeout = p.readU32();
|
timeout = p.readU32();
|
||||||
deployment = this.bits[bit];
|
deployment = this.network.byBit(bit);
|
||||||
|
|
||||||
if (deployment
|
if (deployment
|
||||||
&& start === deployment.startTime
|
&& start === deployment.startTime
|
||||||
@ -2103,7 +2108,7 @@ StateCache.prototype.drop = function drop() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
StateCache.prototype.setRaw = function setRaw(key, value) {
|
StateCache.prototype.setRaw = function setRaw(key, value) {
|
||||||
var pair = layout.ss(key);
|
var pair = layout.vv(key);
|
||||||
var bit = pair[0];
|
var bit = pair[0];
|
||||||
var hash = pair[1];
|
var hash = pair[1];
|
||||||
var state = value[0];
|
var state = value[0];
|
||||||
|
|||||||
@ -362,16 +362,31 @@ ChainEntry.prototype.isHistorical = function isHistorical() {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the entry contains an unknown version bit.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
ChainEntry.prototype.hasUnknown = function hasUnknown() {
|
||||||
|
var bits = this.version & constants.versionbits.TOP_MASK;
|
||||||
|
var topBits = constants.versionbits.TOP_BITS;
|
||||||
|
|
||||||
|
if ((bits >>> 0) !== topBits)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (this.version & this.network.unknownBits) !== 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the entry contains a version bit.
|
* Test whether the entry contains a version bit.
|
||||||
* @param {Object} deployment
|
* @param {Object} deployment
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ChainEntry.prototype.hasBit = function hasBit(deployment) {
|
ChainEntry.prototype.hasBit = function hasBit(bit) {
|
||||||
var bits = this.version & constants.versionbits.TOP_MASK;
|
var bits = this.version & constants.versionbits.TOP_MASK;
|
||||||
var topBits = constants.versionbits.TOP_BITS;
|
var topBits = constants.versionbits.TOP_BITS;
|
||||||
var mask = 1 << deployment.bit;
|
var mask = 1 << bit;
|
||||||
return (bits >>> 0) === topBits && (this.version & mask) !== 0;
|
return (bits >>> 0) === topBits && (this.version & mask) !== 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ var pad32 = util.pad32;
|
|||||||
var layout = {
|
var layout = {
|
||||||
R: 'R',
|
R: 'R',
|
||||||
O: 'O',
|
O: 'O',
|
||||||
v: 'v',
|
V: 'v',
|
||||||
e: function e(hash) {
|
e: function e(hash) {
|
||||||
return 'e' + hex(hash);
|
return 'e' + hex(hash);
|
||||||
},
|
},
|
||||||
@ -41,10 +41,10 @@ var layout = {
|
|||||||
u: function u(hash) {
|
u: function u(hash) {
|
||||||
return 'u' + hex(hash);
|
return 'u' + hex(hash);
|
||||||
},
|
},
|
||||||
s: function s(bit, hash) {
|
v: function v(bit, hash) {
|
||||||
return 's' + pad8(bit) + hex(hash);
|
return 'v' + pad8(bit) + hex(hash);
|
||||||
},
|
},
|
||||||
ss: function ss(key) {
|
vv: function vv(key) {
|
||||||
return [+key.slice(1, 4), key.slice(4, 36)];
|
return [+key.slice(1, 4), key.slice(4, 36)];
|
||||||
},
|
},
|
||||||
T: function T(address, hash) {
|
T: function T(address, hash) {
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
var layout = {
|
var layout = {
|
||||||
R: new Buffer([0x52]),
|
R: new Buffer([0x52]),
|
||||||
O: new Buffer([0x4f]),
|
O: new Buffer([0x4f]),
|
||||||
v: new Buffer([0x76]),
|
V: new Buffer([0x76]),
|
||||||
e: function e(hash) {
|
e: function e(hash) {
|
||||||
return pair(0x65, hash);
|
return pair(0x65, hash);
|
||||||
},
|
},
|
||||||
@ -58,14 +58,14 @@ var layout = {
|
|||||||
u: function u(hash) {
|
u: function u(hash) {
|
||||||
return pair(0x75, hash);
|
return pair(0x75, hash);
|
||||||
},
|
},
|
||||||
s: function s(bit, hash) {
|
v: function v(bit, hash) {
|
||||||
var key = new Buffer(1 + 1 + 32);
|
var key = new Buffer(1 + 1 + 32);
|
||||||
key[0] = 0x73;
|
key[0] = 0x76;
|
||||||
key[1] = bit;
|
key[1] = bit;
|
||||||
write(key, hash, 2);
|
write(key, hash, 2);
|
||||||
return key;
|
return key;
|
||||||
},
|
},
|
||||||
ss: function ss(key) {
|
vv: function vv(key) {
|
||||||
return [key[1], key.toString('hex', 2, 34)];
|
return [key[1], key.toString('hex', 2, 34)];
|
||||||
},
|
},
|
||||||
T: function T(address, hash) {
|
T: function T(address, hash) {
|
||||||
|
|||||||
@ -848,7 +848,7 @@ Mempool.prototype.verify = co(function* verify(entry) {
|
|||||||
var ret = new VerifyResult();
|
var ret = new VerifyResult();
|
||||||
var now, minFee, count, result;
|
var now, minFee, count, result;
|
||||||
|
|
||||||
result = yield this.checkLocks(tx, lockFlags);
|
result = yield this.verifyLocks(tx, lockFlags);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
@ -1522,8 +1522,8 @@ Mempool.prototype.getSnapshot = function getSnapshot() {
|
|||||||
* @returns {Promise} - Returns Boolean.
|
* @returns {Promise} - Returns Boolean.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Mempool.prototype.checkLocks = function checkLocks(tx, flags) {
|
Mempool.prototype.verifyLocks = function verifyLocks(tx, flags) {
|
||||||
return this.chain.checkLocks(this.chain.tip, tx, flags);
|
return this.chain.verifyLocks(this.chain.tip, tx, flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -8,7 +8,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
|
var util = require('../utils/util');
|
||||||
var networks = require('./networks');
|
var networks = require('./networks');
|
||||||
|
var constants = require('./constants');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a network.
|
* Represents a network.
|
||||||
@ -39,6 +41,8 @@ function Network(options) {
|
|||||||
this.activationThreshold = options.activationThreshold;
|
this.activationThreshold = options.activationThreshold;
|
||||||
this.minerWindow = options.minerWindow;
|
this.minerWindow = options.minerWindow;
|
||||||
this.deployments = options.deployments;
|
this.deployments = options.deployments;
|
||||||
|
this.deploys = options.deploys;
|
||||||
|
this.unknownBits = ~constants.versionbits.TOP_MASK;
|
||||||
this.keyPrefix = options.keyPrefix;
|
this.keyPrefix = options.keyPrefix;
|
||||||
this.addressPrefix = options.addressPrefix;
|
this.addressPrefix = options.addressPrefix;
|
||||||
this.requireStandard = options.requireStandard;
|
this.requireStandard = options.requireStandard;
|
||||||
@ -49,6 +53,8 @@ function Network(options) {
|
|||||||
this.selfConnect = options.selfConnect;
|
this.selfConnect = options.selfConnect;
|
||||||
this.requestMempool = options.requestMempool;
|
this.requestMempool = options.requestMempool;
|
||||||
this.batchSize = options.batchSize;
|
this.batchSize = options.batchSize;
|
||||||
|
|
||||||
|
this._init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,6 +82,39 @@ Network.segnet3 = null;
|
|||||||
Network.segnet4 = null;
|
Network.segnet4 = null;
|
||||||
Network.simnet = null;
|
Network.simnet = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a deployment by bit index.
|
||||||
|
* @param {Number} bit
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Network.prototype._init = function _init() {
|
||||||
|
var bits = 0;
|
||||||
|
var i, deployment;
|
||||||
|
|
||||||
|
for (i = 0; i < this.deploys.length; i++) {
|
||||||
|
deployment = this.deploys[i];
|
||||||
|
bits |= 1 << deployment.bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bits |= constants.versionbits.TOP_MASK;
|
||||||
|
|
||||||
|
this.unknownBits = ~bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a deployment by bit index.
|
||||||
|
* @param {Number} bit
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Network.prototype.byBit = function byBit(bit) {
|
||||||
|
var index = util.binarySearch(this.deploys, bit, cmpBit);
|
||||||
|
if (index === -1)
|
||||||
|
return null;
|
||||||
|
return this.deploys[index];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine how many blocks to request
|
* Determine how many blocks to request
|
||||||
* based on current height of the chain.
|
* based on current height of the chain.
|
||||||
@ -240,6 +279,14 @@ Network.isNetwork = function isNetwork(obj) {
|
|||||||
|
|
||||||
Network.set(process.env.BCOIN_NETWORK || 'main');
|
Network.set(process.env.BCOIN_NETWORK || 'main');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helpers
|
||||||
|
*/
|
||||||
|
|
||||||
|
function cmpBit(a, b) {
|
||||||
|
return a.bit - b;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -334,24 +334,28 @@ main.minerWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
|
|||||||
|
|
||||||
main.deployments = {
|
main.deployments = {
|
||||||
testdummy: {
|
testdummy: {
|
||||||
|
name: 'testdummy',
|
||||||
bit: 28,
|
bit: 28,
|
||||||
startTime: 1199145601, // January 1, 2008
|
startTime: 1199145601, // January 1, 2008
|
||||||
timeout: 1230767999, // December 31, 2008
|
timeout: 1230767999, // December 31, 2008
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
csv: {
|
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
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
witness: {
|
witness: {
|
||||||
|
name: 'witness',
|
||||||
bit: 1,
|
bit: 1,
|
||||||
startTime: 1479168000, // November 15th, 2016.
|
startTime: 1479168000, // November 15th, 2016.
|
||||||
timeout: 1510704000, // November 15th, 2017.
|
timeout: 1510704000, // November 15th, 2017.
|
||||||
force: false
|
force: false
|
||||||
},
|
},
|
||||||
mast: {
|
mast: {
|
||||||
|
name: 'mast',
|
||||||
bit: 2,
|
bit: 2,
|
||||||
startTime: 0xffffffff, // Far in the future
|
startTime: 0xffffffff, // Far in the future
|
||||||
timeout: 0xffffffff,
|
timeout: 0xffffffff,
|
||||||
@ -359,6 +363,19 @@ main.deployments = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deployments for versionbits (array form, sorted).
|
||||||
|
* @const {Array}
|
||||||
|
* @default
|
||||||
|
*/
|
||||||
|
|
||||||
|
main.deploys = [
|
||||||
|
main.deployments.csv,
|
||||||
|
main.deployments.witness,
|
||||||
|
main.deployments.mast,
|
||||||
|
main.deployments.testdummy
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key prefixes.
|
* Key prefixes.
|
||||||
* @enum {Number}
|
* @enum {Number}
|
||||||
@ -562,24 +579,28 @@ testnet.minerWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
|
|||||||
|
|
||||||
testnet.deployments = {
|
testnet.deployments = {
|
||||||
testdummy: {
|
testdummy: {
|
||||||
|
name: 'testdummy',
|
||||||
bit: 28,
|
bit: 28,
|
||||||
startTime: 1199145601, // January 1, 2008
|
startTime: 1199145601, // January 1, 2008
|
||||||
timeout: 1230767999, // December 31, 2008
|
timeout: 1230767999, // December 31, 2008
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
csv: {
|
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
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
witness: {
|
witness: {
|
||||||
|
name: 'witness',
|
||||||
bit: 1,
|
bit: 1,
|
||||||
startTime: 1462060800, // May 1st 2016
|
startTime: 1462060800, // May 1st 2016
|
||||||
timeout: 1493596800, // May 1st 2017
|
timeout: 1493596800, // May 1st 2017
|
||||||
force: false
|
force: false
|
||||||
},
|
},
|
||||||
mast: {
|
mast: {
|
||||||
|
name: 'mast',
|
||||||
bit: 2,
|
bit: 2,
|
||||||
startTime: 0xffffffff, // Far in the future
|
startTime: 0xffffffff, // Far in the future
|
||||||
timeout: 0xffffffff,
|
timeout: 0xffffffff,
|
||||||
@ -587,6 +608,13 @@ testnet.deployments = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
testnet.deploys = [
|
||||||
|
testnet.deployments.csv,
|
||||||
|
testnet.deployments.witness,
|
||||||
|
testnet.deployments.mast,
|
||||||
|
testnet.deployments.testdummy
|
||||||
|
];
|
||||||
|
|
||||||
testnet.keyPrefix = {
|
testnet.keyPrefix = {
|
||||||
privkey: 0xef,
|
privkey: 0xef,
|
||||||
xpubkey: 0x043587cf,
|
xpubkey: 0x043587cf,
|
||||||
@ -709,24 +737,28 @@ regtest.minerWindow = 144; // Faster than normal for regtest (144 instead of 201
|
|||||||
|
|
||||||
regtest.deployments = {
|
regtest.deployments = {
|
||||||
testdummy: {
|
testdummy: {
|
||||||
|
name: 'testdummy',
|
||||||
bit: 28,
|
bit: 28,
|
||||||
startTime: 0,
|
startTime: 0,
|
||||||
timeout: 0xffffffff,
|
timeout: 0xffffffff,
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
csv: {
|
csv: {
|
||||||
|
name: 'csv',
|
||||||
bit: 0,
|
bit: 0,
|
||||||
startTime: 0,
|
startTime: 0,
|
||||||
timeout: 0xffffffff,
|
timeout: 0xffffffff,
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
witness: {
|
witness: {
|
||||||
|
name: 'witness',
|
||||||
bit: 1,
|
bit: 1,
|
||||||
startTime: 0,
|
startTime: 0,
|
||||||
timeout: 0xffffffff,
|
timeout: 0xffffffff,
|
||||||
force: false
|
force: false
|
||||||
},
|
},
|
||||||
mast: {
|
mast: {
|
||||||
|
name: 'mast',
|
||||||
bit: 2,
|
bit: 2,
|
||||||
startTime: 0xffffffff, // Far in the future
|
startTime: 0xffffffff, // Far in the future
|
||||||
timeout: 0xffffffff,
|
timeout: 0xffffffff,
|
||||||
@ -734,6 +766,13 @@ regtest.deployments = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
regtest.deploys = [
|
||||||
|
regtest.deployments.csv,
|
||||||
|
regtest.deployments.witness,
|
||||||
|
regtest.deployments.mast,
|
||||||
|
regtest.deployments.testdummy
|
||||||
|
];
|
||||||
|
|
||||||
regtest.keyPrefix = {
|
regtest.keyPrefix = {
|
||||||
privkey: 0xef,
|
privkey: 0xef,
|
||||||
xpubkey: 0x043587cf,
|
xpubkey: 0x043587cf,
|
||||||
@ -857,6 +896,8 @@ segnet3.minerWindow = 144;
|
|||||||
|
|
||||||
segnet3.deployments = {};
|
segnet3.deployments = {};
|
||||||
|
|
||||||
|
segnet3.deploys = [];
|
||||||
|
|
||||||
segnet3.keyPrefix = {
|
segnet3.keyPrefix = {
|
||||||
privkey: 0x9e,
|
privkey: 0x9e,
|
||||||
xpubkey: 0x053587cf,
|
xpubkey: 0x053587cf,
|
||||||
@ -978,18 +1019,21 @@ segnet4.minerWindow = 144;
|
|||||||
|
|
||||||
segnet4.deployments = {
|
segnet4.deployments = {
|
||||||
testdummy: {
|
testdummy: {
|
||||||
|
name: 'testdummy',
|
||||||
bit: 28,
|
bit: 28,
|
||||||
startTime: 1199145601, // January 1, 2008
|
startTime: 1199145601, // January 1, 2008
|
||||||
timeout: 1230767999, // December 31, 2008
|
timeout: 1230767999, // December 31, 2008
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
csv: {
|
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
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
witness: {
|
witness: {
|
||||||
|
name: 'witness',
|
||||||
bit: 1,
|
bit: 1,
|
||||||
startTime: 0,
|
startTime: 0,
|
||||||
timeout: 999999999999,
|
timeout: 999999999999,
|
||||||
@ -997,6 +1041,12 @@ segnet4.deployments = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
segnet4.deploys = [
|
||||||
|
segnet4.deployments.csv,
|
||||||
|
segnet4.deployments.witness,
|
||||||
|
segnet4.deployments.testdummy
|
||||||
|
];
|
||||||
|
|
||||||
segnet4.keyPrefix = {
|
segnet4.keyPrefix = {
|
||||||
privkey: 0x9e,
|
privkey: 0x9e,
|
||||||
xpubkey: 0x053587cf,
|
xpubkey: 0x053587cf,
|
||||||
@ -1120,24 +1170,28 @@ simnet.minerWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
|
|||||||
|
|
||||||
simnet.deployments = {
|
simnet.deployments = {
|
||||||
testdummy: {
|
testdummy: {
|
||||||
|
name: 'testdummy',
|
||||||
bit: 28,
|
bit: 28,
|
||||||
startTime: 1199145601, // January 1, 2008
|
startTime: 1199145601, // January 1, 2008
|
||||||
timeout: 1230767999, // December 31, 2008
|
timeout: 1230767999, // December 31, 2008
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
csv: {
|
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
|
||||||
force: true
|
force: true
|
||||||
},
|
},
|
||||||
witness: {
|
witness: {
|
||||||
|
name: 'witness',
|
||||||
bit: 1,
|
bit: 1,
|
||||||
startTime: 1462060800, // May 1st 2016
|
startTime: 1462060800, // May 1st 2016
|
||||||
timeout: 1493596800, // May 1st 2017
|
timeout: 1493596800, // May 1st 2017
|
||||||
force: false
|
force: false
|
||||||
},
|
},
|
||||||
mast: {
|
mast: {
|
||||||
|
name: 'mast',
|
||||||
bit: 2,
|
bit: 2,
|
||||||
startTime: 0xffffffff, // Far in the future
|
startTime: 0xffffffff, // Far in the future
|
||||||
timeout: 0xffffffff,
|
timeout: 0xffffffff,
|
||||||
@ -1145,6 +1199,13 @@ simnet.deployments = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
simnet.deploys = [
|
||||||
|
simnet.deployments.csv,
|
||||||
|
simnet.deployments.witness,
|
||||||
|
simnet.deployments.mast,
|
||||||
|
simnet.deployments.testdummy
|
||||||
|
];
|
||||||
|
|
||||||
simnet.keyPrefix = {
|
simnet.keyPrefix = {
|
||||||
privkey: 0x64,
|
privkey: 0x64,
|
||||||
xpubkey: 0x0420bd3a,
|
xpubkey: 0x0420bd3a,
|
||||||
|
|||||||
@ -263,10 +263,11 @@ describe('Chain', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should activate csv', cob(function* () {
|
it('should activate csv', cob(function* () {
|
||||||
|
var deployments = chain.network.deployments;
|
||||||
var i, block, prev, state, cache;
|
var i, block, prev, state, cache;
|
||||||
|
|
||||||
prev = yield chain.tip.getPrevious();
|
prev = yield chain.tip.getPrevious();
|
||||||
state = yield chain.getState(prev, 'csv');
|
state = yield chain.getState(prev, deployments.csv);
|
||||||
assert(state === 0);
|
assert(state === 0);
|
||||||
|
|
||||||
for (i = 0; i < 417; i++) {
|
for (i = 0; i < 417; i++) {
|
||||||
@ -275,17 +276,17 @@ describe('Chain', function() {
|
|||||||
switch (chain.height) {
|
switch (chain.height) {
|
||||||
case 144:
|
case 144:
|
||||||
prev = yield chain.tip.getPrevious();
|
prev = yield chain.tip.getPrevious();
|
||||||
state = yield chain.getState(prev, 'csv');
|
state = yield chain.getState(prev, deployments.csv);
|
||||||
assert(state === 1);
|
assert(state === 1);
|
||||||
break;
|
break;
|
||||||
case 288:
|
case 288:
|
||||||
prev = yield chain.tip.getPrevious();
|
prev = yield chain.tip.getPrevious();
|
||||||
state = yield chain.getState(prev, 'csv');
|
state = yield chain.getState(prev, deployments.csv);
|
||||||
assert(state === 2);
|
assert(state === 2);
|
||||||
break;
|
break;
|
||||||
case 432:
|
case 432:
|
||||||
prev = yield chain.tip.getPrevious();
|
prev = yield chain.tip.getPrevious();
|
||||||
state = yield chain.getState(prev, 'csv');
|
state = yield chain.getState(prev, deployments.csv);
|
||||||
assert(state === 3);
|
assert(state === 3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user