chain accuracy.

This commit is contained in:
Christopher Jeffrey 2016-04-17 14:46:40 -07:00
parent d5bfb124cf
commit dee60da2e2
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 168 additions and 47 deletions

View File

@ -78,6 +78,7 @@ function Chain(options) {
this.lastUpdate = utils.now();
this.tip = null;
this.height = -1;
this.synced = false;
this.segwitActive = null;
this.csvActive = null;
@ -217,8 +218,10 @@ Chain.prototype._init = function _init() {
self.tip = tip;
self.height = tip.height;
if (self.bestHeight === -1)
if (tip.height > self.bestHeight) {
self.bestHeight = tip.height;
network.height = tip.height;
}
self._getInitialState(function(err) {
if (err)
@ -234,8 +237,10 @@ Chain.prototype._init = function _init() {
self.emit('open');
self.emit('tip', tip);
if (self.isFull())
if (!self.synced && self.isFull()) {
self.synced = true;
self.emit('full');
}
});
});
});
@ -621,7 +626,7 @@ Chain.prototype._checkDeployments = function _checkDeployments(block, prev, call
if (block.version < 4 && prev.isOutdated(4))
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
// Only allow version 5 blocks (segwit)
// Only allow version 5 blocks (bip141 - segnet3)
// once the majority of blocks are using it.
if (network.segwitHeight !== -1 && height >= network.segwitHeight) {
if (block.version < 5 && prev.isOutdated(5))
@ -629,10 +634,8 @@ Chain.prototype._checkDeployments = function _checkDeployments(block, prev, call
}
// Make sure the height contained in the coinbase is correct.
if (network.block.bip34height !== -1 && height >= network.block.bip34height) {
if (block.version >= 2 && prev.isUpgraded(2))
state.coinbaseHeight = true;
}
if (block.version >= 2 && prev.isUpgraded(2))
state.coinbaseHeight = true;
// Signature validation is now enforced (bip66)
if (block.version >= 3 && prev.isUpgraded(3))
@ -691,9 +694,9 @@ Chain.prototype._checkDeployments = function _checkDeployments(block, prev, call
};
/**
* Check block for duplicate txids in blockchain
* history (BIP30). Note that txids are only considered
* duplicate if they are not yet completely spent.
* Determine whether to check block for duplicate txids in blockchain
* history (BIP30). If we're on a chain that has bip34 activated, we
* can skip this.
* @private
* @see https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki
* @param {Block|MerkleBlock} block
@ -711,6 +714,38 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
if (block.isGenesis())
return callback();
if (network.block.bip34height === -1 || height <= network.block.bip34height)
return this._findDuplicates(block, prev, callback);
self.db.get(network.block.bip34height, function(err, entry) {
if (err)
return callback(err);
// It was no longer possible to create duplicate
// TXs once bip34 went into effect. We can check
// for this to avoid a DB lookup.
if (entry && entry.hash === network.block.bip34hash)
return callback();
return self._findDuplicates(block, prev, callback);
});
};
/**
* Check block for duplicate txids in blockchain
* history (BIP30). Note that txids are only considered
* duplicate if they are not yet completely spent.
* @private
* @see https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki
* @param {Block|MerkleBlock} block
* @param {ChainBlock} prev
* @param {Function} callback - Returns [{@link VerifyError}].
*/
Chain.prototype._findDuplicates = function _findDuplicates(block, prev, callback) {
var self = this;
var height = prev.height + 1;
// Check all transactions
utils.forEachSerial(block.txs, function(tx, next) {
var hash = tx.hash('hex');
@ -724,8 +759,8 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
// Blocks 91842 and 91880 created duplicate
// txids by using the same exact output script
// and extraNonce.
if (network.type === 'main') {
if (height === 91842 || height === 91880)
if (constants.bip30[height]) {
if (block.hash('hex') === constants.bip30[height])
return next();
}
return next(new VerifyError(block, 'invalid', 'bad-txns-BIP30', 100));
@ -1051,8 +1086,8 @@ Chain.prototype.disconnect = function disconnect(entry, callback) {
self.tip = entry;
self.height = entry.height;
if (self.bestHeight === -1)
network.height = entry.height;
self.bestHeight = entry.height;
network.height = entry.height;
self.emit('tip', entry);
@ -1106,8 +1141,8 @@ Chain.prototype.connect = function connect(entry, callback) {
self.tip = entry;
self.height = entry.height;
if (self.bestHeight === -1)
network.height = entry.height;
self.bestHeight = entry.height;
network.height = entry.height;
self.emit('tip', entry);
@ -1164,9 +1199,6 @@ Chain.prototype._setBestChain = function _setBestChain(entry, prev, block, callb
self.tip = entry;
self.height = entry.height;
if (self.bestHeight === -1)
network.height = entry.height;
self.emit('tip', entry);
return callback();
@ -1409,6 +1441,11 @@ Chain.prototype.add = function add(block, callback, force) {
network.height = self.bestHeight;
}
if (height > self.bestHeight) {
self.bestHeight = height;
network.height = height;
}
// If previous block wasn't ever seen,
// add it current to orphans and break.
if (!prev) {
@ -1554,8 +1591,10 @@ Chain.prototype.add = function add(block, callback, force) {
}
utils.nextTick(function() {
if (self.isFull())
if (!self.synced && self.isFull()) {
self.synced = true;
self.emit('full');
}
if (err)
callback(err);
@ -1793,7 +1832,7 @@ Chain.prototype.getOrphan = function getOrphan(hash) {
* @returns {Boolean}
*/
Chain.prototype.isFull = function isFull() {
Chain.prototype.isFullLegacy = function isFull() {
var delta;
if (!this.tip)
@ -1804,6 +1843,15 @@ Chain.prototype.isFull = function isFull() {
return delta < 4 * 60 * 60;
};
/**
* Test the chain to see if it is synced.
* @returns {Boolean}
*/
Chain.prototype.isFull = function isFull() {
return !this.isInitial();
};
/**
* Test the chain to see if it is still in the initial
* syncing phase. Mimic's bitcoind's `IsInitialBlockDownload()`
@ -1812,7 +1860,7 @@ Chain.prototype.isFull = function isFull() {
* @returns {Boolean}
*/
Chain.prototype.isInitial = function isInitial() {
Chain.prototype.isInitialLegacy = function isInitial() {
var now, delta;
if (!this.tip)
@ -1825,6 +1873,28 @@ Chain.prototype.isInitial = function isInitial() {
return delta < 10 && this.tip.ts < now - 24 * 60 * 60;
};
/**
* Test the chain to see if it is still in the initial
* syncing phase. Mimic's bitcoind's `IsInitialBlockDownload()`
* function.
* @see IsInitalBlockDownload()
* @returns {Boolean}
*/
Chain.prototype.isInitial = function isInitial() {
if (!this.tip)
return true;
if (this.synced)
return false;
if (this.height < network.checkpoints.lastHeight)
return true;
return this.height < this.bestHeight - 24 * 6
|| this.tip.ts < utils.now() - network.block.maxTipAge;
};
/**
* Get the fill percentage.
* @returns {Number} percent - Ranges from 0.0 to 1.0.

View File

@ -1545,8 +1545,7 @@ ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) {
if (!this.prune)
return callback();
// Keep the genesis block
if (block.isGenesis())
if (block.height <= network.block.pruneAfterHeight)
return callback();
futureHeight = pad32(block.height + this.keepBlocks);

View File

@ -330,6 +330,16 @@ exports.block = {
SIGHASH_LIMIT: 1300000000
};
/**
* Map of historical blocks which create duplicate transactions hashes.
* @see https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki
*/
exports.bip30 = {
91842: 'eccae000e3c8e4e093936360431f3b7603c563c1ff6181390a4d0a0000000000',
91880: '21d77ccb4c08386a04ac0196ae10f6a1d2c2a377558ca190f143070000000000'
};
/**
* TX-related constants.
* @enum {Number}

View File

@ -229,7 +229,10 @@ main.block = {
majorityEnforceUpgrade: 750,
majorityRejectOutdated: 950,
majorityWindow: 1000,
bip34height: 227931
bip34height: 227931,
bip34hash: 'b808089c756add1591b1d17bab44bba3fed9e02f942ab4894b02000000000000',
pruneAfterHeight: 100000,
maxTipAge: 24 * 60 * 60
};
/**
@ -271,10 +274,20 @@ main.minerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
*/
main.deployments = {
testdummy: {
bit: 28,
startTime: 1199145601, // January 1, 2008
timeout: 1230767999 // December 31, 2008
},
csv: {
bit: 0,
startTime: 1459468800, // April 1st, 2016
timeout: 1491004800 // April 1st, 2017
startTime: 1462060800, // May 1st, 2016
timeout: 1493596800 // May 1st, 2017
},
witness: {
bit: 1,
startTime: 2000000000, // Far in the future
timeout: 2100000000
}
// bip109: {
// bit: 4,
@ -418,7 +431,10 @@ testnet.block = {
majorityEnforceUpgrade: 51,
majorityRejectOutdated: 75,
majorityWindow: 100,
bip34height: 21111
bip34height: 21111,
bip34hash: 'f88ecd9912d00d3f5c2a8e0f50417d3e415c75b3abe584346da9b32300000000',
pruneAfterHeight: 1000,
maxTipAge: 0x7fffffff
};
testnet.witness = false;
@ -428,10 +444,20 @@ testnet.segwitHeight = 2000000000;
testnet.ruleChangeActivationThreshold = 1512; // 75% for testchains
testnet.minerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
testnet.deployments = {
testdummy: {
bit: 28,
startTime: 1199145601, // January 1, 2008
timeout: 1230767999 // December 31, 2008
},
csv: {
bit: 0,
startTime: 1459468800,
timeout: 1491004800
startTime: 1456790400, // March 1st, 2016
timeout: 1493596800 // May 1st, 2017
},
witness: {
bit: 1,
startTime: 2000000000, // Far in the future
timeout: 2100000000
}
};
@ -529,7 +555,10 @@ regtest.block = {
majorityEnforceUpgrade: 750,
majorityRejectOutdated: 950,
majorityWindow: 1000,
bip34height: -1
bip34height: -1,
bip34hash: null,
pruneAfterHeight: 1000,
maxTipAge: 24 * 60 * 60
};
regtest.witness = false;
@ -539,10 +568,20 @@ regtest.segwitHeight = -1;
regtest.ruleChangeActivationThreshold = 108; // 75% for testchains
regtest.minerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
regtest.deployments = {
testdummy: {
bit: 28,
startTime: 0,
timeout: 999999999999
},
csv: {
bit: 0,
startTime: 0,
timeout: 999999999999
},
witness: {
bit: 1,
startTime: 0,
timeout: 999999999999
}
};
@ -591,12 +630,8 @@ segnet3.magic = 0xcaea962e;
segnet3.port = 28333;
segnet3.alertKey = new Buffer(''
+ '04302390343f91cc401d56d68b123028bf52e5f'
+ 'ca1939df127f63c6467cdf9c8e2c14b61104cf8'
+ '17d0b780da337893ecc4aaff1309e536162dabb'
+ 'db45200ca2b0a',
'hex');
segnet3.alertKey = new Buffer(
'0300000000000000000000003b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63', 'hex');
segnet3.checkpoints = {};
segnet3.checkpoints.tsLastCheckpoint = 0;
@ -643,7 +678,10 @@ segnet3.block = {
majorityEnforceUpgrade: 7,
majorityRejectOutdated: 9,
majorityWindow: 10,
bip34height: -1
bip34height: -1,
bip34hash: null,
pruneAfterHeight: 1000,
maxTipAge: 0x7fffffff
};
segnet3.witness = true;
@ -696,12 +734,8 @@ segnet4.magic = 0xc4a1abdc;
segnet4.port = 28901;
segnet4.alertKey = new Buffer(''
+ '04302390343f91cc401d56d68b123028bf52e5f'
+ 'ca1939df127f63c6467cdf9c8e2c14b61104cf8'
+ '17d0b780da337893ecc4aaff1309e536162dabb'
+ 'db45200ca2b0a',
'hex');
segnet4.alertKey = new Buffer(
'0300000000000000000000003b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63', 'hex');
segnet4.checkpoints = {};
segnet4.checkpoints.tsLastCheckpoint = 0;
@ -749,7 +783,10 @@ segnet4.block = {
majorityEnforceUpgrade: 7,
majorityRejectOutdated: 9,
majorityWindow: 10,
bip34height: -1
bip34height: -1,
bip34hash: null,
pruneAfterHeight: 1000,
maxTipAge: 0x7fffffff
};
segnet4.witness = true;
@ -759,10 +796,15 @@ segnet4.segwitHeight = -1;
segnet4.ruleChangeActivationThreshold = 108;
segnet4.minerConfirmationWindow = 144;
segnet4.deployments = {
testdummy: {
bit: 28,
startTime: 1199145601, // January 1, 2008
timeout: 1230767999 // December 31, 2008
},
csv: {
bit: 0,
startTime: 1459468800, // April 1st, 2016
timeout: 1491004800 // April 1st, 2017
startTime: 1456790400, // March 1st, 2016
timeout: 1493596800 // May 1st, 2017
},
witness: {
bit: 1,