deployments.
This commit is contained in:
parent
69436cfd16
commit
f3c2134dfa
@ -11,24 +11,31 @@ var utils = require('./utils');
|
||||
* Bloom Filter
|
||||
* @exports Bloom
|
||||
* @constructor
|
||||
* @param {Number} size - Filter size in bytes.
|
||||
* @param {Number|Bufer} size - Filter size in bytes, or filter itself.
|
||||
* @param {Number} n - Number of hash functions.
|
||||
* @param {Number} tweak - Seed value.
|
||||
* @property {Buffer} filter
|
||||
* @property {Number} size
|
||||
* @property {Number} n
|
||||
* @property {Number} tweak
|
||||
* @property {Number} update - Update flag (see {@link constants.filterFlags}).
|
||||
*/
|
||||
|
||||
function Bloom(size, n, tweak) {
|
||||
function Bloom(size, n, tweak, update) {
|
||||
if (!(this instanceof Bloom))
|
||||
return new Bloom(size, n, tweak);
|
||||
return new Bloom(size, n, tweak, update);
|
||||
|
||||
if (Buffer.isBuffer(size)) {
|
||||
this.filter = size;
|
||||
this.size = this.filter.length * 8;
|
||||
} else {
|
||||
this.filter = new Buffer(Math.ceil(size / 8));
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
this.filter = new Buffer(Math.ceil(size / 8));
|
||||
this.size = size;
|
||||
this.n = n;
|
||||
this.tweak = tweak;
|
||||
this.update = null;
|
||||
this.update = update;
|
||||
|
||||
this.reset();
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ var VerifyError = utils.VerifyError;
|
||||
* @property {ChainBlock?} tip
|
||||
* @property {Number} height
|
||||
* @property {Boolean} segwitActive
|
||||
* @property {Boolean} csvActive
|
||||
* @property {Object} orphan - Orphan map.
|
||||
* @emits Chain#open
|
||||
* @emits Chain#error
|
||||
@ -78,6 +79,7 @@ function Chain(options) {
|
||||
this.tip = null;
|
||||
this.height = -1;
|
||||
this.segwitActive = null;
|
||||
this.csvActive = null;
|
||||
|
||||
this.orphan = {
|
||||
map: {},
|
||||
@ -218,11 +220,14 @@ Chain.prototype._init = function _init() {
|
||||
if (self.bestHeight === -1)
|
||||
network.height = tip.height;
|
||||
|
||||
self.isSegwitActive(function(err, result) {
|
||||
self._getInitialState(function(err) {
|
||||
if (err)
|
||||
return self.emit('error', err);
|
||||
|
||||
if (result)
|
||||
if (self.csvActive)
|
||||
bcoin.debug('CSV is active.');
|
||||
|
||||
if (self.segwitActive)
|
||||
bcoin.debug('Segwit is active.');
|
||||
|
||||
self.loaded = true;
|
||||
@ -463,11 +468,8 @@ Chain.prototype._verifyContext = function _verifyContext(block, prev, callback)
|
||||
|
||||
Chain.prototype._verify = function _verify(block, prev, callback) {
|
||||
var self = this;
|
||||
var flags = constants.flags.MANDATORY_VERIFY_FLAGS;
|
||||
var lockFlags = constants.flags.MANDATORY_LOCKTIME_FLAGS;
|
||||
var height, ts, i, tx, coinbaseHeight;
|
||||
var medianTime, segwit, commitmentHash;
|
||||
var ret = {};
|
||||
var height, ts, i, tx, medianTime, commitmentHash;
|
||||
|
||||
function done(err, result) {
|
||||
prev.free();
|
||||
@ -478,11 +480,11 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
||||
return done(new VerifyError(block, 'invalid', ret.reason, ret.score));
|
||||
|
||||
if (this.options.spv || block.type !== 'block')
|
||||
return done();
|
||||
return done(null, constants.flags.MANDATORY_VERIFY_FLAGS);
|
||||
|
||||
// Skip the genesis block
|
||||
if (block.isGenesis())
|
||||
return done(null, flags);
|
||||
return done(null, constants.flags.MANDATORY_VERIFY_FLAGS);
|
||||
|
||||
// Ensure it's not an orphan
|
||||
if (!prev)
|
||||
@ -502,103 +504,26 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
||||
if (block.bits !== self.getTarget(prev, block))
|
||||
return done(new VerifyError(block, 'invalid', 'bad-diffbits', 100));
|
||||
|
||||
// For some reason bitcoind has p2sh in the
|
||||
// mandatory flags by default, when in reality
|
||||
// it wasn't activated until march 30th 2012.
|
||||
// The first p2sh output and redeem script
|
||||
// appeared on march 7th 2012, only it did
|
||||
// not have a signature. See:
|
||||
// 6a26d2ecb67f27d1fa5524763b49029d7106e91e3cc05743073461a719776192
|
||||
// 9c08a4d78931342b37fd5f72900fb9983087e6f46c4a097d8a1f52c74e28eaf6
|
||||
if (block.ts < constants.block.BIP16_TIME)
|
||||
flags &= ~constants.flags.VERIFY_P2SH;
|
||||
self._checkDeployments(block, prev, function(err, state) {
|
||||
if (err)
|
||||
return done(err);
|
||||
|
||||
// Only allow version 2 blocks (coinbase height)
|
||||
// once the majority of blocks are using it.
|
||||
if (block.version < 2 && prev.isOutdated(2))
|
||||
return done(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||
// Expose the state of csv and segwit globally.
|
||||
self.csvActive = state.csv;
|
||||
self.segwitActive = state.segwit;
|
||||
|
||||
// Only allow version 3 blocks (sig validation)
|
||||
// once the majority of blocks are using it.
|
||||
if (block.version < 3 && prev.isOutdated(3))
|
||||
return done(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||
|
||||
// Only allow version 4 blocks (checklocktimeverify)
|
||||
// once the majority of blocks are using it.
|
||||
if (block.version < 4 && prev.isOutdated(4))
|
||||
return done(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||
|
||||
// Only allow version 5 blocks (segwit)
|
||||
// once the majority of blocks are using it.
|
||||
if (network.segwitHeight !== -1 && height >= network.segwitHeight) {
|
||||
if (block.version < 5 && prev.isOutdated(5))
|
||||
return done(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||
}
|
||||
|
||||
// Only allow version 8 blocks (locktime median past)
|
||||
// once the majority of blocks are using it.
|
||||
// if (block.version < 8 && prev.isOutdated(8))
|
||||
// return done(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||
|
||||
// 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))
|
||||
coinbaseHeight = true;
|
||||
}
|
||||
|
||||
// Signature validation is now enforced (bip66)
|
||||
if (block.version >= 3 && prev.isUpgraded(3))
|
||||
flags |= constants.flags.VERIFY_DERSIG;
|
||||
|
||||
// CHECKLOCKTIMEVERIFY is now usable (bip65)
|
||||
if (block.version >= 4 && prev.isUpgraded(4))
|
||||
flags |= constants.flags.VERIFY_CHECKLOCKTIMEVERIFY;
|
||||
|
||||
// Segregrated witness is now usable (bip141 - segnet3)
|
||||
if (network.segwitHeight !== -1 && height >= network.segwitHeight) {
|
||||
if (block.version >= 5) {
|
||||
if (prev.isUpgraded(5)) {
|
||||
flags |= constants.flags.VERIFY_WITNESS;
|
||||
segwit = true;
|
||||
self.segwitActive = true;
|
||||
} else {
|
||||
self.segwitActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Segregrated witness is now usable (bip141 - segnet4)
|
||||
if (network.deployments.witness) {
|
||||
self.getState(prev, 'witness', function(err, state) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (state === constants.thresholdStates.ACTIVE) {
|
||||
flags |= constants.flags.VERIFY_WITNESS;
|
||||
segwit = true;
|
||||
self.segwitActive = true;
|
||||
} else {
|
||||
self.segwitActive = false;
|
||||
}
|
||||
|
||||
return finish();
|
||||
});
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
|
||||
function finish() {
|
||||
// Can't verify any further when merkleblock or headers.
|
||||
if (block.type !== 'block')
|
||||
return done(null, flags);
|
||||
return done(null, state.flags);
|
||||
|
||||
// Make sure the height contained in the coinbase is correct.
|
||||
if (coinbaseHeight) {
|
||||
if (state.coinbaseHeight) {
|
||||
if (block.getCoinbaseHeight() !== height)
|
||||
return done(new VerifyError(block, 'invalid', 'bad-cb-height', 100));
|
||||
}
|
||||
|
||||
if (segwit) {
|
||||
// Check the commitment hash for segwit.
|
||||
if (state.segwit) {
|
||||
commitmentHash = block.commitmentHash;
|
||||
if (commitmentHash) {
|
||||
if (!block.witnessNonce) {
|
||||
@ -616,6 +541,8 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
// Blocks that do not commit to
|
||||
// witness data data cannot contain it.
|
||||
if (!commitmentHash) {
|
||||
if (block.hasWitness()) {
|
||||
return done(new VerifyError(block,
|
||||
@ -626,7 +553,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
||||
}
|
||||
|
||||
// Get timestamp for tx.isFinal().
|
||||
ts = (lockFlags & constants.flags.MEDIAN_TIME_PAST) !== 0
|
||||
ts = (state.lockFlags & constants.flags.MEDIAN_TIME_PAST) !== 0
|
||||
? medianTime
|
||||
: block.ts;
|
||||
|
||||
@ -644,8 +571,122 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
return done(null, flags);
|
||||
return done(null, state.flags);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Check all deployments on a chain, ranging from p2sh to segwit.
|
||||
* @private
|
||||
* @param {Block} block
|
||||
* @param {ChainBlock} prev
|
||||
* @param {Function} callback - Returns [{@link VerifyError}, Object].
|
||||
*/
|
||||
|
||||
Chain.prototype._checkDeployments = function _checkDeployments(block, prev, callback) {
|
||||
var self = this;
|
||||
var height = prev.height + 1;
|
||||
var state = {
|
||||
flags: constants.flags.MANDATORY_VERIFY_FLAGS,
|
||||
lockFlags: constants.flags.MANDATORY_LOCKTIME_FLAGS,
|
||||
coinbaseHeight: false,
|
||||
segwit: false,
|
||||
csv: false
|
||||
};
|
||||
|
||||
// For some reason bitcoind has p2sh in the
|
||||
// mandatory flags by default, when in reality
|
||||
// it wasn't activated until march 30th 2012.
|
||||
// The first p2sh output and redeem script
|
||||
// appeared on march 7th 2012, only it did
|
||||
// not have a signature. See:
|
||||
// 6a26d2ecb67f27d1fa5524763b49029d7106e91e3cc05743073461a719776192
|
||||
// 9c08a4d78931342b37fd5f72900fb9983087e6f46c4a097d8a1f52c74e28eaf6
|
||||
if (block.ts < constants.block.BIP16_TIME)
|
||||
state.flags &= ~constants.flags.VERIFY_P2SH;
|
||||
|
||||
// Only allow version 2 blocks (coinbase height)
|
||||
// once the majority of blocks are using it.
|
||||
if (block.version < 2 && prev.isOutdated(2))
|
||||
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||
|
||||
// Only allow version 3 blocks (sig validation)
|
||||
// once the majority of blocks are using it.
|
||||
if (block.version < 3 && prev.isOutdated(3))
|
||||
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||
|
||||
// Only allow version 4 blocks (checklocktimeverify)
|
||||
// once the majority of blocks are using it.
|
||||
if (block.version < 4 && prev.isOutdated(4))
|
||||
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||
|
||||
// Only allow version 5 blocks (segwit)
|
||||
// once the majority of blocks are using it.
|
||||
if (network.segwitHeight !== -1 && height >= network.segwitHeight) {
|
||||
if (block.version < 5 && prev.isOutdated(5))
|
||||
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Signature validation is now enforced (bip66)
|
||||
if (block.version >= 3 && prev.isUpgraded(3))
|
||||
state.flags |= constants.flags.VERIFY_DERSIG;
|
||||
|
||||
// CHECKLOCKTIMEVERIFY is now usable (bip65)
|
||||
if (block.version >= 4 && prev.isUpgraded(4))
|
||||
state.flags |= constants.flags.VERIFY_CHECKLOCKTIMEVERIFY;
|
||||
|
||||
// Segregrated witness is now usable (bip141 - segnet3)
|
||||
if (network.segwitHeight !== -1 && height >= network.segwitHeight) {
|
||||
if (block.version >= 5 && prev.isUpgraded(5)) {
|
||||
state.flags |= constants.flags.VERIFY_WITNESS;
|
||||
state.segwit = true;
|
||||
}
|
||||
}
|
||||
|
||||
utils.serial([
|
||||
function(next) {
|
||||
// CHECKSEQUENCEVERIFY and median time
|
||||
// past locktimes are now usable (bip9 & bip113).
|
||||
self.isActive(prev, 'csv', function(err, active) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (active) {
|
||||
state.flags |= constants.flags.VERIFY_CHECKSEQUENCEVERIFY;
|
||||
state.lockFlags |= constants.flags.VERIFY_SEQUENCE;
|
||||
state.lockFlags |= constants.flags.MEDIAN_TIME_PAST;
|
||||
state.csv = true;
|
||||
}
|
||||
|
||||
return next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
// Segregrated witness is now usable (bip141 - segnet4)
|
||||
self.isActive(prev, 'witness', function(err, active) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (active) {
|
||||
state.flags |= constants.flags.VERIFY_WITNESS;
|
||||
state.segwit = true;
|
||||
}
|
||||
|
||||
return next();
|
||||
});
|
||||
}
|
||||
], function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(null, state);
|
||||
});
|
||||
};
|
||||
|
||||
@ -2111,6 +2152,29 @@ Chain.prototype.findLocator = function findLocator(locator, callback) {
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether a versionbits deployment is active (BIP9: versionbits).
|
||||
* @example
|
||||
* chain.isActive(entry, 'witness', callback);
|
||||
* @see https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki
|
||||
* @param {ChainBlock} prev - Previous chain entry.
|
||||
* @param {String} id - Deployment id.
|
||||
* @param {Function} callback - Returns [Error, Number].
|
||||
*/
|
||||
|
||||
Chain.prototype.isActive = function isActive(prev, id, callback) {
|
||||
// Optimization for main
|
||||
if (network.type === 'main' && prev.height < 400000)
|
||||
return callback(null, false);
|
||||
|
||||
this.getState(prev, id, function(err, state) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(null, state === constants.thresholdStates.ACTIVE);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get chain entry state for a deployment (BIP9: versionbits).
|
||||
* @example
|
||||
@ -2292,70 +2356,46 @@ Chain.prototype.computeBlockVersion = function computeBlockVersion(prev, callbac
|
||||
* A helper function to test whether segwit is active at any
|
||||
* given time. Since segwit affects almost all of bitcoin, it
|
||||
* is one deployment that needs to be checked frequently.
|
||||
* @private
|
||||
* @param {Function} callback - Returns [Error, Boolean].
|
||||
*/
|
||||
|
||||
Chain.prototype.isSegwitActive = function isSegwitActive(callback, force) {
|
||||
Chain.prototype._getInitialState = function _getInitialState(callback) {
|
||||
var self = this;
|
||||
var unlock;
|
||||
|
||||
if (this.segwitActive != null)
|
||||
return utils.asyncify(callback)(null, this.segwitActive);
|
||||
|
||||
if (!network.witness) {
|
||||
this.segwitActive = false;
|
||||
return utils.asyncify(callback)(null, false);
|
||||
}
|
||||
return utils.nextTick(callback);
|
||||
|
||||
if (!this.tip)
|
||||
return utils.asyncify(callback)(null, false);
|
||||
|
||||
// unlock = this._lock(isSegwitActive, [callback], force);
|
||||
// if (!unlock)
|
||||
// return;
|
||||
// callback = utils.wrap(callback, unlock);
|
||||
|
||||
if (network.type === 'segnet4') {
|
||||
return this.tip.getPrevious(function(err, prev) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return self.getState(prev, 'witness', function(err, state) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
self.segwitActive = state === constants.thresholdStates.ACTIVE;
|
||||
return callback(null, self.segwitActive);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
assert(network.type === 'segnet3');
|
||||
|
||||
if (!(network.segwitHeight !== -1 && this.tip.height >= network.segwitHeight))
|
||||
return utils.asyncify(callback)(null, false);
|
||||
return utils.nextTick(callback);
|
||||
|
||||
return this.tip.getPrevious(function(err, prev) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!prev) {
|
||||
self.csvActive = false;
|
||||
self.segwitActive = false;
|
||||
return callback(null, false);
|
||||
return callback();
|
||||
}
|
||||
|
||||
prev.ensureAncestors(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (self.tip.version >= 5 && prev.isUpgraded(5)) {
|
||||
if (err) {
|
||||
prev.free();
|
||||
self.segwitActive = true;
|
||||
return callback(null, true);
|
||||
return callback(err);
|
||||
}
|
||||
self._checkDeployments(self.tip, prev, function(err, state) {
|
||||
if (err) {
|
||||
prev.free();
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
prev.free();
|
||||
self.segwitActive = false;
|
||||
return callback(null, false);
|
||||
self.csvActive = state.csv;
|
||||
self.segwitActive = state.segwit;
|
||||
|
||||
prev.free();
|
||||
return callback();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -2375,14 +2415,9 @@ Chain.prototype.isSegwitActive = function isSegwitActive(callback, force) {
|
||||
* @param {Function} callback - Returns [Error, Boolean].
|
||||
*/
|
||||
|
||||
Chain.prototype.checkFinal = function checkFinal(prev, tx, flags, callback, force) {
|
||||
Chain.prototype.checkFinal = function checkFinal(prev, tx, flags, callback) {
|
||||
var height = prev.height + 1;
|
||||
|
||||
// var unlock = this._lock(checkFinal, [prev, tx, flags, callback], force);
|
||||
// if (!unlock)
|
||||
// return;
|
||||
// callback = utils.wrap(callback, unlock);
|
||||
|
||||
function check(err, ts) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -2490,14 +2525,9 @@ Chain.prototype.evalLocks = function evalLocks(entry, minHeight, minTime, callba
|
||||
* @param {Function} callback - Returns [Error, Boolean].
|
||||
*/
|
||||
|
||||
Chain.prototype.checkLocks = function checkLocks(tx, flags, entry, callback, force) {
|
||||
Chain.prototype.checkLocks = function checkLocks(tx, flags, entry, callback) {
|
||||
var self = this;
|
||||
|
||||
// var unlock = this._lock(checkLocks, [tx, flags, entry, callback], force);
|
||||
// if (!unlock)
|
||||
// return;
|
||||
// callback = utils.wrap(callback, unlock);
|
||||
|
||||
this.getLocks(tx, flags, entry, function(err, minHeight, minTime) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -302,6 +302,22 @@ ChainBlock.prototype.getMedianTime = function getMedianTime(ancestors) {
|
||||
return median[median.length / 2 | 0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get median time past asynchronously (see {@link ChainBlock#getMedianTime}).
|
||||
* @param {Function} callback - Returns [Error, Number].
|
||||
*/
|
||||
|
||||
ChainBlock.prototype.getMedianTimeAsync = function getMedianTimeAsync(callback) {
|
||||
var self = this;
|
||||
|
||||
return this.getAncestors(constants.block.MEDIAN_TIMESPAN, function(err, ancestors) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(null, self.getMedianTime(ancestors));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Check isSuperMajority against majorityRejectOutdated.
|
||||
* @param {Number} version
|
||||
@ -313,6 +329,20 @@ ChainBlock.prototype.isOutdated = function isOutdated(version, ancestors) {
|
||||
return this.isSuperMajority(version, network.block.majorityRejectOutdated, ancestors);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check {@link ChainBlock#isUpgraded asynchronously}.
|
||||
* @param {Number} version
|
||||
* @param {Function} callback - Returns [Error, Boolean].
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
ChainBlock.prototype.isOutdatedAsync = function isOutdatedAsync(version, callback) {
|
||||
return this.isSuperMajorityAsync(
|
||||
version,
|
||||
network.block.majorityRejectOutdated,
|
||||
callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check isSuperMajority against majorityEnforceUpgrade.
|
||||
* @param {Number} version
|
||||
@ -324,6 +354,20 @@ ChainBlock.prototype.isUpgraded = function isUpgraded(version, ancestors) {
|
||||
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade, ancestors);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check {@link ChainBlock#isUpgraded} asynchronously.
|
||||
* @param {Number} version
|
||||
* @param {Function} callback
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
ChainBlock.prototype.isUpgradedAsync = function isUpgradedAsync(version, callback) {
|
||||
return this.isSuperMajorityAsync(
|
||||
version,
|
||||
network.block.majorityEnforceUpgrade,
|
||||
callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate found number of block versions within the majority window.
|
||||
* @param {Number} version
|
||||
@ -351,18 +395,21 @@ ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, require
|
||||
};
|
||||
|
||||
/**
|
||||
* Get median time past asynchronously.
|
||||
* @param {Function} callback - Returns [Error, Number].
|
||||
* Calculate {@link ChainBlock#isSuperMajority asynchronously}.
|
||||
* @param {Number} version
|
||||
* @param {Number} required
|
||||
* @param {Function} callback - Returns [Error, Boolean].
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
ChainBlock.prototype.getMedianTimeAsync = function getMedianTimeAsync(callback) {
|
||||
ChainBlock.prototype.isSuperMajorityAsync = function isSuperMajorityAsync(version, required, callback) {
|
||||
var self = this;
|
||||
|
||||
return this.getAncestors(constants.block.MEDIAN_TIMESPAN, function(err, ancestors) {
|
||||
return this.getAncestors(network.block.majorityWindow, function(err, ancestors) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(null, self.getMedianTime(ancestors));
|
||||
return callback(null, self.isSuperMajority(version, required, ancestors));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ module.exports = function(bcoin) {
|
||||
|
||||
var utils = require('./utils');
|
||||
var assert = utils.assert;
|
||||
var network = bcoin.protocol.network;
|
||||
|
||||
/**
|
||||
* Create a fullnode complete with a chain,
|
||||
@ -47,9 +48,6 @@ function Fullnode(options) {
|
||||
if (!(this instanceof Fullnode))
|
||||
return new Fullnode(options);
|
||||
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
bcoin.node.call(this, options);
|
||||
|
||||
this.loaded = false;
|
||||
@ -86,7 +84,7 @@ Fullnode.prototype._init = function _init() {
|
||||
this.pool = new bcoin.pool({
|
||||
chain: this.chain,
|
||||
mempool: this.mempool,
|
||||
witness: this.network.witness,
|
||||
witness: network.witness,
|
||||
listen: this.options.listen,
|
||||
selfish: this.options.selfish,
|
||||
spv: false
|
||||
|
||||
@ -89,63 +89,6 @@ function Mempool(options) {
|
||||
|
||||
utils.inherits(Mempool, EventEmitter);
|
||||
|
||||
/**
|
||||
* Standard verify flags.
|
||||
* @const {VerifyFlags}
|
||||
* @default
|
||||
*/
|
||||
|
||||
Mempool.flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||
|
||||
/**
|
||||
* Mandatory verify flags.
|
||||
* @const {VerifyFlags}
|
||||
* @default
|
||||
*/
|
||||
|
||||
Mempool.mandatory = constants.flags.MANDATORY_VERIFY_FLAGS;
|
||||
|
||||
/**
|
||||
* Locktime flags.
|
||||
* @const {LockFlags}
|
||||
* @default
|
||||
*/
|
||||
|
||||
Mempool.lockFlags = constants.flags.STANDARD_LOCKTIME_FLAGS;
|
||||
|
||||
/**
|
||||
* Ancestor limit.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
Mempool.ANCESTOR_LIMIT = 25;
|
||||
|
||||
/**
|
||||
* Maximum mempool size in bytes.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
Mempool.MAX_MEMPOOL_SIZE = 300 << 20;
|
||||
|
||||
/**
|
||||
* The time at which transactions
|
||||
* fall out of the mempool.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
Mempool.MEMPOOL_EXPIRY = 72 * 60 * 60;
|
||||
|
||||
/**
|
||||
* Maximum number of orphan transactions.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
Mempool.MAX_ORPHAN_TX = 100;
|
||||
|
||||
Mempool.prototype._lock = function _lock(func, args, force) {
|
||||
return this.locker.lock(func, args, force);
|
||||
};
|
||||
@ -340,12 +283,12 @@ Mempool.prototype.removeBlock = function removeBlock(block, callback, force) {
|
||||
Mempool.prototype.limitMempoolSize = function limitMempoolSize(callback) {
|
||||
var self = this;
|
||||
|
||||
if (this.size <= Mempool.MAX_MEMPOOL_SIZE)
|
||||
if (this.size <= constants.mempool.MAX_MEMPOOL_SIZE)
|
||||
return callback(null, true);
|
||||
|
||||
this.tx.getRange({
|
||||
start: 0,
|
||||
end: utils.now() - Mempool.MEMPOOL_EXPIRY
|
||||
end: utils.now() - constants.mempool.MEMPOOL_EXPIRY
|
||||
}, function(err, txs) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -360,7 +303,7 @@ Mempool.prototype.limitMempoolSize = function limitMempoolSize(callback) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(self.size <= Mempool.MAX_MEMPOOL_SIZE);
|
||||
return callback(self.size <= constants.mempool.MAX_MEMPOOL_SIZE);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -526,8 +469,8 @@ Mempool.prototype.hasTX = function hasTX(hash, callback) {
|
||||
|
||||
Mempool.prototype.addTX = function addTX(tx, callback, force) {
|
||||
var self = this;
|
||||
var flags = Mempool.flags;
|
||||
var lockFlags = Mempool.lockFlags;
|
||||
var flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||
var lockFlags = constants.flags.STANDARD_LOCKTIME_FLAGS;
|
||||
var ret = {};
|
||||
var now;
|
||||
|
||||
@ -561,6 +504,18 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) {
|
||||
if (tx.isCoinbase())
|
||||
return callback(new VerifyError(tx, 'invalid', 'coinbase', 100));
|
||||
|
||||
if (this.requireStandard) {
|
||||
if (!tx.isStandard(flags, ret))
|
||||
return callback(new VerifyError(tx, ret.reason, 0));
|
||||
|
||||
if (!this.chain.csvActive && tx.version >= 2) {
|
||||
return callback(new VerifyError(tx,
|
||||
'nonstandard',
|
||||
'premature-version2-tx',
|
||||
0));
|
||||
}
|
||||
}
|
||||
|
||||
this.chain.checkFinal(this.chain.tip, tx, lockFlags, function(err, isFinal) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -568,11 +523,6 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) {
|
||||
if (!isFinal)
|
||||
return callback(new VerifyError(tx, 'nonstandard', 'non-final', 0));
|
||||
|
||||
if (self.requireStandard) {
|
||||
if (!tx.isStandard(flags, ret))
|
||||
return callback(new VerifyError(tx, ret.reason, 0));
|
||||
}
|
||||
|
||||
self.seenTX(tx, function(err, exists) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -600,7 +550,7 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) {
|
||||
return callback(err);
|
||||
|
||||
if (!tx.hasCoins()) {
|
||||
if (self.totalSize > Mempool.MAX_MEMPOOL_SIZE) {
|
||||
if (self.totalSize > constants.mempool.MAX_MEMPOOL_SIZE) {
|
||||
return callback(new VerifyError(tx,
|
||||
'insufficientfee',
|
||||
'mempool full',
|
||||
@ -723,9 +673,9 @@ Mempool.prototype.removeUnchecked = function removeUnchecked(tx, callback) {
|
||||
Mempool.prototype.verify = function verify(tx, callback) {
|
||||
var self = this;
|
||||
var height = this.chain.height + 1;
|
||||
var lockFlags = Mempool.lockFlags;
|
||||
var flags = Mempool.flags;
|
||||
var mandatory = Mempool.mandatory;
|
||||
var lockFlags = constants.flags.STANDARD_LOCKTIME_FLAGS;
|
||||
var flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||
var mandatory = constants.flags.MANDATORY_VERIFY_FLAGS;
|
||||
var ret = {};
|
||||
var fee, now, free, minFee;
|
||||
|
||||
@ -808,7 +758,7 @@ Mempool.prototype.verify = function verify(tx, callback) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (count > Mempool.ANCESTOR_LIMIT) {
|
||||
if (count > constants.mempool.ANCESTOR_LIMIT) {
|
||||
return callback(new VerifyError(tx,
|
||||
'nonstandard',
|
||||
'too-long-mempool-chain',
|
||||
@ -934,7 +884,7 @@ Mempool.prototype.storeOrphan = function storeOrphan(tx, callback, force) {
|
||||
|
||||
batch.put('m/D/' + hash, tx.toExtended(true));
|
||||
|
||||
if (self.orphans > Mempool.MAX_ORPHAN_TX) {
|
||||
if (self.orphans > constants.mempool.MAX_ORPHAN_TX) {
|
||||
return self.purgeOrphans(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
module.exports = function(bcoin) {
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var network = bcoin.protocol.network;
|
||||
var utils = require('./utils');
|
||||
|
||||
/**
|
||||
@ -31,7 +30,6 @@ function Node(options) {
|
||||
|
||||
this.options = options;
|
||||
|
||||
this.network = network;
|
||||
this.mempool = null;
|
||||
this.pool = null;
|
||||
this.chain = null;
|
||||
|
||||
@ -645,10 +645,12 @@ Peer.prototype._emitMerkle = function _emitMerkle() {
|
||||
};
|
||||
|
||||
Peer.prototype._handleFilterLoad = function _handleFilterLoad(payload) {
|
||||
var size = payload.filter.length * 8;
|
||||
this.filter = new bcoin.bloom(size, payload.n, payload.tweak);
|
||||
this.filter.filter = payload.filter;
|
||||
this.filter.update = payload.update;
|
||||
this.filter = new bcoin.bloom(
|
||||
payload.filter,
|
||||
payload.n,
|
||||
payload.tweak,
|
||||
payload.update
|
||||
);
|
||||
this.relay = true;
|
||||
};
|
||||
|
||||
|
||||
@ -314,7 +314,6 @@ exports.hashTypeByVal = utils.revMap(exports.hashType);
|
||||
exports.block = {
|
||||
MAX_SIZE: 1000000,
|
||||
MAX_SIGOPS: 1000000 / 50,
|
||||
MAX_ORPHAN_TX: 1000000 / 100,
|
||||
MEDIAN_TIMESPAN: 11,
|
||||
BIP16_TIME: 1333238400,
|
||||
SIGHASH_LIMIT: 1300000000
|
||||
@ -355,6 +354,41 @@ exports.script = {
|
||||
MAX_OP_RETURN: 80
|
||||
};
|
||||
|
||||
exports.mempool = {};
|
||||
|
||||
/**
|
||||
* Ancestor limit.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
exports.mempool.ANCESTOR_LIMIT = 25;
|
||||
|
||||
/**
|
||||
* Maximum mempool size in bytes.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
exports.mempool.MAX_MEMPOOL_SIZE = 300 << 20;
|
||||
|
||||
/**
|
||||
* The time at which transactions
|
||||
* fall out of the mempool.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
exports.mempool.MEMPOOL_EXPIRY = 72 * 60 * 60;
|
||||
|
||||
/**
|
||||
* Maximum number of orphan transactions.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
exports.mempool.MAX_ORPHAN_TX = 100;
|
||||
|
||||
/**
|
||||
* Reject codes. Note that `internal` and higher
|
||||
* are not meant for use on the p2p network.
|
||||
|
||||
@ -9,6 +9,7 @@ module.exports = function(bcoin) {
|
||||
|
||||
var utils = require('./utils');
|
||||
var assert = utils.assert;
|
||||
var network = bcoin.protocol.network;
|
||||
|
||||
/**
|
||||
* Create an spv node which only maintains
|
||||
@ -36,9 +37,6 @@ function SPVNode(options) {
|
||||
if (!(this instanceof SPVNode))
|
||||
return new SPVNode(options);
|
||||
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
bcoin.node.call(this, options);
|
||||
|
||||
this.loaded = false;
|
||||
@ -62,7 +60,7 @@ SPVNode.prototype._init = function _init() {
|
||||
|
||||
this.pool = new bcoin.pool({
|
||||
chain: this.chain,
|
||||
witness: this.network.witness,
|
||||
witness: network.witness,
|
||||
selfish: true,
|
||||
listen: false,
|
||||
spv: true
|
||||
|
||||
Loading…
Reference in New Issue
Block a user