more refactoring.
This commit is contained in:
parent
ab610d6fa5
commit
997f0acbb0
@ -299,194 +299,6 @@ Block.prototype._verify = function _verify() {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Block.prototype.verifyContext = function verifyContext() {
|
|
||||||
var flags = {};
|
|
||||||
var sigops = 0;
|
|
||||||
var prev, height, ts, i, j, tx, cb, input;
|
|
||||||
|
|
||||||
if (this.isGenesis())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!this.chain)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
prev = this.chain.getBlock(this.prevBlock);
|
|
||||||
|
|
||||||
// Ensure it's not an orphan
|
|
||||||
if (!prev) {
|
|
||||||
utils.debug('Block has no previous entry: %s', this.rhash);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
height = prev.height + 1;
|
|
||||||
|
|
||||||
// Ensure the timestamp is correct
|
|
||||||
if (this.ts <= prev.getMedianTime()) {
|
|
||||||
utils.debug('Block time is lower than median: %s', this.rhash);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the miner's target is equal to what we expect
|
|
||||||
if (this.bits !== this.chain.getTarget(prev, this)) {
|
|
||||||
utils.debug('Block is using wrong target: %s', this.rhash);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only allow version 2 blocks (coinbase height)
|
|
||||||
// once the majority of blocks are using it.
|
|
||||||
if (this.version < 2 && prev.isOutdated(2)) {
|
|
||||||
utils.debug('Block is outdated (v2): %s', this.rhash);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only allow version 3 blocks (sig validation)
|
|
||||||
// once the majority of blocks are using it.
|
|
||||||
if (this.version < 3 && prev.isOutdated(3)) {
|
|
||||||
utils.debug('Block is outdated (v3): %s', this.rhash);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only allow version 4 blocks (checklocktimeverify)
|
|
||||||
// once the majority of blocks are using it.
|
|
||||||
if (this.version < 4 && prev.isOutdated(4)) {
|
|
||||||
utils.debug('Block is outdated (v4): %s', this.rhash);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only allow version 8 blocks (locktime median past)
|
|
||||||
// once the majority of blocks are using it.
|
|
||||||
// if (this.version < 8 && prev.isOutdated(8)) {
|
|
||||||
// utils.debug('Block is outdated (v8): %s', this.rhash);
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Can't verify any further when merkleblock or headers.
|
|
||||||
if (this.subtype !== 'block')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Make sure the height contained in the coinbase is correct.
|
|
||||||
if (this.version >= 2 && prev.isUpgraded(2)) {
|
|
||||||
cb = bcoin.script.getCoinbaseData(this.txs[0].inputs[0].script);
|
|
||||||
|
|
||||||
// Make sure the coinbase is parseable.
|
|
||||||
if (!cb) {
|
|
||||||
utils.debug('Block has malformed coinbase: %s', this.rhash);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure coinbase height is equal to the actual height.
|
|
||||||
if (cb.height !== height) {
|
|
||||||
utils.debug('Block has bad coinbase height: %s', this.rhash);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signature validation is now enforced (bip66)
|
|
||||||
if (!(this.version >= 3 && prev.isUpgraded(3)))
|
|
||||||
flags.dersig = false;
|
|
||||||
|
|
||||||
// CHECKLOCKTIMEVERIFY is now usable (bip65)
|
|
||||||
if (!(this.version >= 4 && prev.isUpgraded(4)))
|
|
||||||
flags.checklocktimeverify = false;
|
|
||||||
|
|
||||||
// Use nLockTime median past (bip113)
|
|
||||||
// https://github.com/btcdrak/bips/blob/d4c9a236ecb947866c61aefb868b284498489c2b/bip-0113.mediawiki
|
|
||||||
// Support version bits:
|
|
||||||
// https://gist.github.com/sipa/bf69659f43e763540550
|
|
||||||
// http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010396.html
|
|
||||||
// if (this.version >= 8 && prev.isUpgraded(8))
|
|
||||||
// flags.locktimeMedian = true;
|
|
||||||
|
|
||||||
// If we are an ancestor of a checkpoint, we can
|
|
||||||
// skip the input verification.
|
|
||||||
if (height < network.checkpoints.lastHeight && !network.checkpoints[height])
|
|
||||||
flags.scriptChecks = false;
|
|
||||||
|
|
||||||
// Get timestamp for tx.isFinal().
|
|
||||||
ts = flags.locktimeMedian
|
|
||||||
? prev.getMedianTime()
|
|
||||||
: this.ts;
|
|
||||||
|
|
||||||
// Check all transactions
|
|
||||||
for (i = 0; i < this.txs.length; i++) {
|
|
||||||
tx = this.txs[i];
|
|
||||||
|
|
||||||
// Transactions must be finalized with
|
|
||||||
// regards to nSequence and nLockTime.
|
|
||||||
if (!tx.isFinal(height, ts)) {
|
|
||||||
utils.debug('TX is not final: %s (%s)', this.rhash, i);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for tx sigops limits
|
|
||||||
// Bitcoind does not check for this when accepting
|
|
||||||
// a block even though it probably should.
|
|
||||||
// if (tx.getSigops(true) > constants.script.maxTxSigops) {
|
|
||||||
// // Block 71036 abused checksig to
|
|
||||||
// // include a huge number of sigops.
|
|
||||||
// utils.debug('Block TX has too many sigops: %s', this.rhash);
|
|
||||||
// if (!(network.type === 'main' && height === 71036))
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Check for block sigops limits
|
|
||||||
// Start counting P2SH sigops once block
|
|
||||||
// timestamps reach March 31st, 2012.
|
|
||||||
if (this.ts >= constants.block.bip16time)
|
|
||||||
sigops += tx.getSigops(true);
|
|
||||||
else
|
|
||||||
sigops += tx.getSigops();
|
|
||||||
|
|
||||||
if (sigops > constants.script.maxBlockSigops) {
|
|
||||||
utils.debug('Block has too many sigops: %s', this.rhash);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BIP30 - Ensure there are no duplicate txids
|
|
||||||
// this.node.hasTX(tx.hash('hex'), function(err, has) {
|
|
||||||
// if (has)
|
|
||||||
if (this.chain[tx.hash('hex')]) {
|
|
||||||
// Blocks 91842 and 91880 created duplicate
|
|
||||||
// txids by using the same exact output script
|
|
||||||
// and extraNonce.
|
|
||||||
utils.debug('Block is overwriting txids: %s', this.rhash);
|
|
||||||
if (!(network.type === 'main' && (height === 91842 || height === 91880)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the inputs of every tx (CheckInputs)
|
|
||||||
if (flags.scriptChecks !== false) {
|
|
||||||
if (tx.isCoinbase())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (j = 0; j < tx.inputs.length; j++) {
|
|
||||||
input = tx.inputs[j];
|
|
||||||
|
|
||||||
// We need the previous output in order
|
|
||||||
// to verify the script.
|
|
||||||
if (!input.output)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Ensure tx is not double spending an output
|
|
||||||
if (!input.output) {
|
|
||||||
utils.debug('Block is using spent inputs: %s (tx: %s, output: %s)',
|
|
||||||
this.rhash, tx.hash('hex'),
|
|
||||||
input.prevout.hash + '/' + input.prevout.index);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the script
|
|
||||||
if (!tx.verify(j, true, flags)) {
|
|
||||||
utils.debug('Block has invalid inputs: %s', this.rhash);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
Block.prototype.isGenesis = function isGenesis() {
|
Block.prototype.isGenesis = function isGenesis() {
|
||||||
return this.hash('hex') === network.genesis.hash;
|
return this.hash('hex') === network.genesis.hash;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -39,6 +39,8 @@ function Chain(options) {
|
|||||||
this.request = new utils.RequestCache();
|
this.request = new utils.RequestCache();
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.tip = null;
|
this.tip = null;
|
||||||
|
this.mempool = options.mempool;
|
||||||
|
this.blockdb = options.blockdb;
|
||||||
|
|
||||||
this.orphan = {
|
this.orphan = {
|
||||||
map: {},
|
map: {},
|
||||||
@ -261,16 +263,16 @@ Chain.prototype._preload = function _preload(callback) {
|
|||||||
|
|
||||||
Chain.prototype._saveBlock = function _saveBlock(block, callback) {
|
Chain.prototype._saveBlock = function _saveBlock(block, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var node = bcoin.node.global;
|
|
||||||
|
|
||||||
if (!node)
|
if (!this.blockdb)
|
||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
node.block.saveBlock(block, function(err) {
|
this.blockdb.block.saveBlock(block, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
node.mempool.addBlock(block);
|
if (self.mempool)
|
||||||
|
self.mempool.addBlock(block);
|
||||||
|
|
||||||
return callback();
|
return callback();
|
||||||
});
|
});
|
||||||
@ -278,19 +280,19 @@ Chain.prototype._saveBlock = function _saveBlock(block, callback) {
|
|||||||
|
|
||||||
Chain.prototype._removeBlock = function _removeBlock(tip, callback) {
|
Chain.prototype._removeBlock = function _removeBlock(tip, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var node = bcoin.node.global;
|
|
||||||
|
|
||||||
if (!node)
|
if (!this.blockdb)
|
||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
node.block.removeBlock(tip, function(err, block) {
|
this.blockdb.removeBlock(tip, function(err, block) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (!block)
|
if (!block)
|
||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
node.mempool.removeBlock(block);
|
if (self.mempool)
|
||||||
|
self.mempool.removeBlock(block);
|
||||||
|
|
||||||
self.emit('reorg block', block.hash('hex'));
|
self.emit('reorg block', block.hash('hex'));
|
||||||
|
|
||||||
@ -331,10 +333,9 @@ Chain.prototype._verifyContext = function _verifyContext(block, prev, callback)
|
|||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype._verify = function _verify(block, prev) {
|
Chain.prototype._verify = function _verify(block, prev) {
|
||||||
// var flags = constants.flags.MANDATORY_VERIFY_FLAGS;
|
var flags = constants.flags.MANDATORY_VERIFY_FLAGS;
|
||||||
var flags = {};
|
|
||||||
var sigops = 0;
|
var sigops = 0;
|
||||||
var height, ts, i, tx, cb, coinbaseHeight;
|
var height, ts, i, tx, cb, coinbaseHeight, medianTime, locktimeMedian;
|
||||||
|
|
||||||
// Skip the genesis block
|
// Skip the genesis block
|
||||||
if (block.isGenesis())
|
if (block.isGenesis())
|
||||||
@ -347,9 +348,10 @@ Chain.prototype._verify = function _verify(block, prev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
height = prev.height + 1;
|
height = prev.height + 1;
|
||||||
|
medianTime = prev.getMedianTime();
|
||||||
|
|
||||||
// Ensure the timestamp is correct
|
// Ensure the timestamp is correct
|
||||||
if (block.ts <= prev.getMedianTime()) {
|
if (block.ts <= medianTime) {
|
||||||
utils.debug('Block time is lower than median: %s', block.rhash);
|
utils.debug('Block time is lower than median: %s', block.rhash);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -393,12 +395,12 @@ Chain.prototype._verify = function _verify(block, prev) {
|
|||||||
coinbaseHeight = true;
|
coinbaseHeight = true;
|
||||||
|
|
||||||
// Signature validation is now enforced (bip66)
|
// Signature validation is now enforced (bip66)
|
||||||
if (!(block.version >= 3 && prev.isUpgraded(3)))
|
if (block.version >= 3 && prev.isUpgraded(3))
|
||||||
flags.dersig = false;
|
flags |= constants.flags.VERIFY_DERSIG;
|
||||||
|
|
||||||
// CHECKLOCKTIMEVERIFY is now usable (bip65)
|
// CHECKLOCKTIMEVERIFY is now usable (bip65)
|
||||||
if (!(block.version >= 4 && prev.isUpgraded(4)))
|
if (block.version >= 4 && prev.isUpgraded(4))
|
||||||
flags.checklocktimeverify = false;
|
flags |= constants.flags.VERIFY_CHECKLOCKTIMEVERIFY;
|
||||||
|
|
||||||
// Use nLockTime median past (bip113)
|
// Use nLockTime median past (bip113)
|
||||||
// https://github.com/btcdrak/bips/blob/d4c9a236ecb947866c61aefb868b284498489c2b/bip-0113.mediawiki
|
// https://github.com/btcdrak/bips/blob/d4c9a236ecb947866c61aefb868b284498489c2b/bip-0113.mediawiki
|
||||||
@ -406,7 +408,7 @@ Chain.prototype._verify = function _verify(block, prev) {
|
|||||||
// https://gist.github.com/sipa/bf69659f43e763540550
|
// https://gist.github.com/sipa/bf69659f43e763540550
|
||||||
// http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010396.html
|
// http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010396.html
|
||||||
// if (block.version >= 8 && prev.isUpgraded(8))
|
// if (block.version >= 8 && prev.isUpgraded(8))
|
||||||
// flags.locktimeMedian = true;
|
// locktimeMedian = true;
|
||||||
|
|
||||||
// Can't verify any further when merkleblock or headers.
|
// Can't verify any further when merkleblock or headers.
|
||||||
if (block.subtype !== 'block')
|
if (block.subtype !== 'block')
|
||||||
@ -430,9 +432,7 @@ Chain.prototype._verify = function _verify(block, prev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get timestamp for tx.isFinal().
|
// Get timestamp for tx.isFinal().
|
||||||
ts = flags.locktimeMedian
|
ts = locktimeMedian ? medianTime : block.ts;
|
||||||
? prev.getMedianTime()
|
|
||||||
: block.ts;
|
|
||||||
|
|
||||||
// Check all transactions
|
// Check all transactions
|
||||||
for (i = 0; i < block.txs.length; i++) {
|
for (i = 0; i < block.txs.length; i++) {
|
||||||
@ -474,12 +474,11 @@ Chain.prototype._verify = function _verify(block, prev) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callback) {
|
Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callback) {
|
||||||
var node = bcoin.node.global;
|
|
||||||
var height = prev.height + 1;
|
var height = prev.height + 1;
|
||||||
var pending = block.txs.length;
|
var pending = block.txs.length;
|
||||||
var called;
|
var called;
|
||||||
|
|
||||||
if (!node || block.subtype !== 'block')
|
if (!this.blockdb || block.subtype !== 'block')
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
|
|
||||||
if (block.isGenesis())
|
if (block.isGenesis())
|
||||||
@ -499,7 +498,7 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
|
|||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
|
|
||||||
// BIP30 - Ensure there are no duplicate txids
|
// BIP30 - Ensure there are no duplicate txids
|
||||||
node.block.hasTX(hash, function(err, result) {
|
self.blockdb.hasTX(hash, function(err, result) {
|
||||||
if (called)
|
if (called)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -522,10 +521,9 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
|
|||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callback) {
|
Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callback) {
|
||||||
var node = bcoin.node.global;
|
|
||||||
var height = prev.height + 1;
|
var height = prev.height + 1;
|
||||||
|
|
||||||
if (!node || block.subtype !== 'block')
|
if (!this.blockdb || block.subtype !== 'block')
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
|
|
||||||
if (block.isGenesis())
|
if (block.isGenesis())
|
||||||
@ -536,7 +534,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
|
|||||||
if (height < network.checkpoints.lastHeight && !network.checkpoints[height])
|
if (height < network.checkpoints.lastHeight && !network.checkpoints[height])
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
|
|
||||||
node.block.fillCoins(block.txs, function(err) {
|
this.blockdb.fillCoins(block.txs, function(err) {
|
||||||
var i, j, input, hash;
|
var i, j, input, hash;
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
|
|||||||
@ -52,12 +52,16 @@ ChainBlock.prototype.getProof = function getProof() {
|
|||||||
return new bn(1).ushln(256).div(target.addn(1));
|
return new bn(1).ushln(256).div(target.addn(1));
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainBlock.prototype.getChainwork = function() {
|
ChainBlock.prototype.getChainwork = function getChainwork() {
|
||||||
var prev = this.prev;
|
var prev = this.prev;
|
||||||
return (prev ? prev.chainwork : new bn(0)).add(this.getProof());
|
return (prev ? prev.chainwork : new bn(0)).add(this.getProof());
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainBlock.prototype.getMedianTime = function() {
|
ChainBlock.prototype.isGenesis = function isGenesis(version) {
|
||||||
|
return this.hash === network.genesis.hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.getMedianTime = function getMedianTime() {
|
||||||
var entry = this;
|
var entry = this;
|
||||||
var median = [];
|
var median = [];
|
||||||
var timeSpan = constants.block.medianTimespan;
|
var timeSpan = constants.block.medianTimespan;
|
||||||
@ -71,15 +75,15 @@ ChainBlock.prototype.getMedianTime = function() {
|
|||||||
return median[median.length / 2 | 0];
|
return median[median.length / 2 | 0];
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainBlock.prototype.isOutdated = function(version) {
|
ChainBlock.prototype.isOutdated = function isOutdated(version) {
|
||||||
return this.isSuperMajority(version, network.block.majorityRejectOutdated);
|
return this.isSuperMajority(version, network.block.majorityRejectOutdated);
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainBlock.prototype.isUpgraded = function(version) {
|
ChainBlock.prototype.isUpgraded = function isUpgraded(version) {
|
||||||
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade);
|
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade);
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainBlock.prototype.isSuperMajority = function(version, required) {
|
ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, required) {
|
||||||
var entry = this;
|
var entry = this;
|
||||||
var found = 0;
|
var found = 0;
|
||||||
var majorityWindow = network.block.majorityWindow;
|
var majorityWindow = network.block.majorityWindow;
|
||||||
@ -94,7 +98,7 @@ ChainBlock.prototype.isSuperMajority = function(version, required) {
|
|||||||
return found >= required;
|
return found >= required;
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainBlock.prototype.toJSON = function() {
|
ChainBlock.prototype.toJSON = function toJSON() {
|
||||||
return {
|
return {
|
||||||
hash: this.hash,
|
hash: this.hash,
|
||||||
version: this.version,
|
version: this.version,
|
||||||
@ -107,7 +111,7 @@ ChainBlock.prototype.toJSON = function() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainBlock.fromJSON = function(chain, json) {
|
ChainBlock.fromJSON = function fromJSON(chain, json) {
|
||||||
return new ChainBlock(chain, json);
|
return new ChainBlock(chain, json);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1213,9 +1213,13 @@ function pbkdf2(key, salt, iterations, dkLen) {
|
|||||||
|
|
||||||
if (typeof key === 'string')
|
if (typeof key === 'string')
|
||||||
key = new Buffer(key, 'ascii');
|
key = new Buffer(key, 'ascii');
|
||||||
|
else if (Array.isArray(key))
|
||||||
|
key = new Buffer(key);
|
||||||
|
|
||||||
if (typeof salt === 'string')
|
if (typeof salt === 'string')
|
||||||
salt = new Buffer(salt, 'ascii');
|
salt = new Buffer(salt, 'ascii');
|
||||||
|
else if (Array.isArray(key))
|
||||||
|
salt = new Buffer(salt);
|
||||||
|
|
||||||
var DK = new Buffer(dkLen);
|
var DK = new Buffer(dkLen);
|
||||||
var U = new Buffer(hLen);
|
var U = new Buffer(hLen);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ var fs = bcoin.fs;
|
|||||||
* Mempool
|
* Mempool
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Mempool(node, options) {
|
function Mempool(pool, options) {
|
||||||
if (!(this instanceof Mempool))
|
if (!(this instanceof Mempool))
|
||||||
return new Mempool(pool, options);
|
return new Mempool(pool, options);
|
||||||
|
|
||||||
@ -27,9 +27,8 @@ function Mempool(node, options) {
|
|||||||
options = {};
|
options = {};
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.node = node;
|
this.pool = pool;
|
||||||
this.pool = node.pool;
|
this.blockdb = pool.blockdb;
|
||||||
this.block = node.block;
|
|
||||||
|
|
||||||
this.txs = {};
|
this.txs = {};
|
||||||
this.spent = {};
|
this.spent = {};
|
||||||
@ -38,6 +37,8 @@ function Mempool(node, options) {
|
|||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.locked = false;
|
this.locked = false;
|
||||||
|
|
||||||
|
Mempool.global = this;
|
||||||
|
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,6 +179,7 @@ Mempool.prototype.hasTX = function hasTX(hash) {
|
|||||||
Mempool.prototype.add =
|
Mempool.prototype.add =
|
||||||
Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
|
|
||||||
assert(tx.ts === 0);
|
assert(tx.ts === 0);
|
||||||
@ -201,7 +203,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
|||||||
|
|
||||||
this._lockTX(tx);
|
this._lockTX(tx);
|
||||||
|
|
||||||
this.block.fillCoin(tx, function(err) {
|
this.blockdb.fillCoin(tx, function(err) {
|
||||||
var i, input, dup, height, ts, priority;
|
var i, input, dup, height, ts, priority;
|
||||||
|
|
||||||
self._unlockTX(tx);
|
self._unlockTX(tx);
|
||||||
@ -294,7 +296,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tx.verify(null, true)) {
|
if (!tx.verify(null, true, flags)) {
|
||||||
return callback(new Error('TX did not verify.'));
|
return callback(new Error('TX did not verify.'));
|
||||||
peer.reject({
|
peer.reject({
|
||||||
data: tx.hash(),
|
data: tx.hash(),
|
||||||
@ -340,6 +342,8 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
|||||||
self.txs[hash] = tx;
|
self.txs[hash] = tx;
|
||||||
self.count++;
|
self.count++;
|
||||||
self.size += tx.getSize();
|
self.size += tx.getSize();
|
||||||
|
|
||||||
|
self.emit('tx', tx);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -425,6 +429,7 @@ Mempool.prototype.removeTX = function removeTX(hash, callback) {
|
|||||||
delete this.txs[hash];
|
delete this.txs[hash];
|
||||||
this.count--;
|
this.count--;
|
||||||
this.size -= tx.getSize();
|
this.size -= tx.getSize();
|
||||||
|
this.emit('remove tx', tx);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Need to lock the mempool when
|
// Need to lock the mempool when
|
||||||
|
|||||||
@ -137,46 +137,47 @@ Miner.prototype.addBlock = function addBlock(block) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Miner.prototype.addTX = function addTX(tx) {
|
Miner.prototype.addTX = function addTX(tx) {
|
||||||
var full, ts;
|
var flags, height, ts;
|
||||||
|
|
||||||
full = this.index.inputs.every(function(input) {
|
flags = constants.flags.MANDATORY_VERIFY_FLAGS
|
||||||
return !!input.output;
|
| constants.flags.VERIFY_DERSIG
|
||||||
});
|
| constants.flags.VERIFY_CHECKLOCKTIMEVERIFY;
|
||||||
|
|
||||||
// Cannot calculate fee if we don't have the prev_out.
|
// Cannot calculate fee if we don't have the prev_out.
|
||||||
// Could possibly just burn some coins.
|
// Could possibly just burn some coins.
|
||||||
if (this.options.burn === false) {
|
if (this.options.burn === false) {
|
||||||
if (!full)
|
if (!tx.hasPrevout())
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore if it's already in a block
|
// Ignore if it's already in a block
|
||||||
if (tx.height !== -1)
|
if (tx.height !== -1)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
if (!tx.verify(null, true))
|
if (!tx.verify(null, true, flags))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
if (tx.isCoinbase())
|
if (tx.isCoinbase())
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Get timestamp for tx.isFinal() - bip113
|
// Get timestamp for tx.isFinal() - bip113
|
||||||
ts = this.block.version === 8
|
height = this.last.height + 1;
|
||||||
|
ts = this.block.version >= 8
|
||||||
? this.last.getMedianTime()
|
? this.last.getMedianTime()
|
||||||
: this.block.ts;
|
: this.block.ts;
|
||||||
|
|
||||||
if (!tx.isFinal(this.last.height + 1, ts))
|
if (!tx.isFinal(height, ts))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Deliver me from the block size debate, please
|
// Deliver me from the block size debate, please
|
||||||
if (this.block.getSize() + tx.getSize() > constants.blocks.maxSize)
|
if (this.block.getSize() + tx.getSize() > constants.blocks.maxSize)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Add the tx to our block
|
// Add the tx to our block
|
||||||
this.block.txs.push(tx);
|
this.block.txs.push(tx);
|
||||||
|
|
||||||
// Calculate our new reward fee
|
// Calculate our new reward fee
|
||||||
if (full)
|
if (tx.hasPrevout())
|
||||||
this.fee.iadd(tx.getFee());
|
this.fee.iadd(tx.getFee());
|
||||||
|
|
||||||
// Update coinbase value
|
// Update coinbase value
|
||||||
|
|||||||
@ -35,7 +35,7 @@ function Node(options) {
|
|||||||
if (this.options.network)
|
if (this.options.network)
|
||||||
network.set(this.options.network);
|
network.set(this.options.network);
|
||||||
|
|
||||||
this.block = null;
|
this.blockdb = null;
|
||||||
this.mempool = null;
|
this.mempool = null;
|
||||||
this.pool = null;
|
this.pool = null;
|
||||||
this.chain = null;
|
this.chain = null;
|
||||||
@ -50,80 +50,27 @@ inherits(Node, EventEmitter);
|
|||||||
Node.prototype._init = function _init() {
|
Node.prototype._init = function _init() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
this.blockdb = new bcoin.blockdb(this.options.blockdb);
|
||||||
|
this.mempool = new bcoin.mempool(this, this.options.mempool);
|
||||||
|
|
||||||
if (!this.options.pool)
|
if (!this.options.pool)
|
||||||
this.options.pool = {};
|
this.options.pool = {};
|
||||||
|
|
||||||
this.options.pool.type = 'full';
|
this.options.pool.spv = false;
|
||||||
|
this.options.pool.blockdb = this.blockdb;
|
||||||
|
this.options.pool.mempool = this.mempool;
|
||||||
|
|
||||||
this.block = new bcoin.blockdb(this.options.block);
|
|
||||||
this.mempool = new bcoin.mempool(this, this.options.mempool);
|
|
||||||
this.pool = new bcoin.pool(this.options.pool);
|
this.pool = new bcoin.pool(this.options.pool);
|
||||||
this.chain = this.pool.chain;
|
this.chain = this.pool.chain;
|
||||||
|
|
||||||
if (0)
|
|
||||||
this.pool.on('block', function(block, peer) {
|
|
||||||
self.mempool.addBlock(block);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (0)
|
|
||||||
this.pool.on('block', function(block, peer) {
|
|
||||||
self.block.saveBlock(block, function(err) {
|
|
||||||
if (err)
|
|
||||||
throw err;
|
|
||||||
|
|
||||||
self.mempool.addBlock(block);
|
|
||||||
if (0)
|
|
||||||
var hash = block.txs[0].hash('hex');
|
|
||||||
if (0)
|
|
||||||
self.block.getTX(hash, function(err, tx) {
|
|
||||||
if (err) throw err;
|
|
||||||
utils.print(tx);
|
|
||||||
});
|
|
||||||
if (0)
|
|
||||||
self.block.getCoin(hash, 0, function(err, tx) {
|
|
||||||
if (err) throw err;
|
|
||||||
utils.print(tx);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.mempool.on('error', function(err) {
|
this.mempool.on('error', function(err) {
|
||||||
self.emit('error', err);
|
self.emit('error', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.chain.on('error', function(err) {
|
|
||||||
self.emit('error', err);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.pool.on('error', function(err) {
|
this.pool.on('error', function(err) {
|
||||||
self.emit('error', err);
|
self.emit('error', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.pool.on('fork', function(data) {
|
|
||||||
if (data.block)
|
|
||||||
self.mempool.removeBlock(block);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (0)
|
|
||||||
this.pool.on('fork', function(a, b) {
|
|
||||||
[a, b].forEach(function(hash) {
|
|
||||||
self.block.removeBlock(hash, function(err, block) {
|
|
||||||
if (err)
|
|
||||||
throw err;
|
|
||||||
|
|
||||||
if (!block)
|
|
||||||
return;
|
|
||||||
|
|
||||||
self.mempool.removeBlock(block);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.pool.on('tx', function(tx, peer) {
|
|
||||||
assert(tx.ts === 0);
|
|
||||||
self.mempool.addTX(tx, peer);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.pool.startSync();
|
this.pool.startSync();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,12 +87,12 @@ Node.prototype.getCoin = function getCoin(hash, index, callback) {
|
|||||||
if (this.mempool.isSpent(hash, index))
|
if (this.mempool.isSpent(hash, index))
|
||||||
return callback(null, null);
|
return callback(null, null);
|
||||||
|
|
||||||
this.block.getCoin(hash, index, function(err, coin) {
|
this.blockdb.getCoin(hash, index, function(err, coin) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (!coin)
|
if (!coin)
|
||||||
return;
|
return callback();
|
||||||
|
|
||||||
return callback(null, coin);
|
return callback(null, coin);
|
||||||
});
|
});
|
||||||
@ -159,7 +106,7 @@ Node.prototype.getCoinByAddress = function getCoinsByAddress(addresses, callback
|
|||||||
|
|
||||||
mempool = this.mempool.getCoinsByAddress(addresses);
|
mempool = this.mempool.getCoinsByAddress(addresses);
|
||||||
|
|
||||||
this.block.getCoinsByAddress(addresses, function(err, coins) {
|
this.blockdb.getCoinsByAddress(addresses, function(err, coins) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -181,10 +128,13 @@ Node.prototype.getTX = function getTX(hash, callback) {
|
|||||||
if (tx)
|
if (tx)
|
||||||
return callback(null, tx);
|
return callback(null, tx);
|
||||||
|
|
||||||
this.block.getTX(hash, function(err, tx) {
|
this.blockdb.getTX(hash, function(err, tx) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
|
if (!tx)
|
||||||
|
return callback();
|
||||||
|
|
||||||
return callback(null, tx);
|
return callback(null, tx);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -197,7 +147,7 @@ Node.prototype.isSpent = function isSpent(hash, index, callback) {
|
|||||||
if (this.mempool.isSpent(hash, index))
|
if (this.mempool.isSpent(hash, index))
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
|
|
||||||
this.block.isSpent(hash, index, callback);
|
this.blockdb.isSpent(hash, index, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Node.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
|
Node.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
|
||||||
@ -208,7 +158,7 @@ Node.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
|
|||||||
|
|
||||||
mempool = this.mempool.getTXByAddress(addresses);
|
mempool = this.mempool.getTXByAddress(addresses);
|
||||||
|
|
||||||
this.block.getTXByAddress(addresses, function(err, txs) {
|
this.blockdb.getTXByAddress(addresses, function(err, txs) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -218,16 +168,20 @@ Node.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
|
|||||||
|
|
||||||
Node.prototype.fillCoin = function fillCoin(tx, callback) {
|
Node.prototype.fillCoin = function fillCoin(tx, callback) {
|
||||||
callback = utils.asyncify(callback);
|
callback = utils.asyncify(callback);
|
||||||
|
|
||||||
if (this.mempool.fillCoin(tx))
|
if (this.mempool.fillCoin(tx))
|
||||||
return callback();
|
return callback();
|
||||||
this.block.fillCoin(tx, callback);
|
|
||||||
|
this.blockdb.fillCoin(tx, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Node.prototype.fillTX = function fillTX(tx, callback) {
|
Node.prototype.fillTX = function fillTX(tx, callback) {
|
||||||
callback = utils.asyncify(callback);
|
callback = utils.asyncify(callback);
|
||||||
|
|
||||||
if (this.mempool.fillTX(tx))
|
if (this.mempool.fillTX(tx))
|
||||||
return callback();
|
return callback();
|
||||||
this.block.fillTX(tx, callback);
|
|
||||||
|
this.blockdb.fillTX(tx, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -144,13 +144,11 @@ Peer.prototype._init = function init() {
|
|||||||
self.pool.setMisbehavior(self, 100);
|
self.pool.setMisbehavior(self, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.pool.options.fullNode) {
|
this.once('version', function() {
|
||||||
this.once('version', function() {
|
utils.debug(
|
||||||
utils.debug(
|
'Sent version (%s): height=%s',
|
||||||
'Sent version (%s): height=%s',
|
self.host, this.pool.chain.height());
|
||||||
self.host, this.pool.chain.height());
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this._ping.timer = setInterval(function() {
|
this._ping.timer = setInterval(function() {
|
||||||
self.challenge = utils.nonce();
|
self.challenge = utils.nonce();
|
||||||
@ -269,7 +267,7 @@ Peer.prototype.broadcast = function broadcast(items) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Peer.prototype.updateWatch = function updateWatch() {
|
Peer.prototype.updateWatch = function updateWatch() {
|
||||||
if (this.pool.options.fullNode)
|
if (!this.pool.options.spv)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this.ack)
|
if (this.ack)
|
||||||
|
|||||||
@ -32,24 +32,24 @@ function Pool(options) {
|
|||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
|
||||||
if (this.options.debug)
|
if (options.debug)
|
||||||
bcoin.debug = this.options.debug;
|
bcoin.debug = this.options.debug;
|
||||||
|
|
||||||
if (this.options.network)
|
if (options.network)
|
||||||
network.set(this.options.network);
|
network.set(options.network);
|
||||||
|
|
||||||
this.options.fullNode = !!this.options.fullNode;
|
options.spv = options.spv !== false;
|
||||||
|
|
||||||
if (options.type === 'spv')
|
if (options.type === 'spv')
|
||||||
this.options.fullNode = false;
|
options.spv = true;
|
||||||
else if (options.type === 'full')
|
else if (options.type === 'full')
|
||||||
this.options.fullNode = true;
|
options.spv = false;
|
||||||
|
|
||||||
this.options.headers = this.options.headers;
|
options.headers = options.headers;
|
||||||
this.options.multiplePeers = this.options.multiplePeers;
|
options.multiplePeers = options.multiplePeers;
|
||||||
this.options.relay = this.options.relay == null
|
options.relay = options.relay == null
|
||||||
? (this.options.fullNode ? true : false)
|
? (!options.spv ? true : false)
|
||||||
: this.options.relay;
|
: options.relay;
|
||||||
|
|
||||||
this.originalSeeds = (options.seeds || network.seeds).map(utils.parseHost);
|
this.originalSeeds = (options.seeds || network.seeds).map(utils.parseHost);
|
||||||
this.setSeeds([]);
|
this.setSeeds([]);
|
||||||
@ -58,20 +58,23 @@ function Pool(options) {
|
|||||||
this.destroyed = false;
|
this.destroyed = false;
|
||||||
this.size = options.size || 32;
|
this.size = options.size || 32;
|
||||||
|
|
||||||
if (!this.options.fullNode) {
|
this.blockdb = options.blockdb;
|
||||||
if (this.options.headers == null)
|
this.mempool = options.mempool;
|
||||||
this.options.headers = true;
|
|
||||||
if (this.options.multiplePeers == null)
|
if (options.spv) {
|
||||||
this.options.multiplePeers = true;
|
if (options.headers == null)
|
||||||
|
options.headers = true;
|
||||||
|
if (options.multiplePeers == null)
|
||||||
|
options.multiplePeers = true;
|
||||||
} else {
|
} else {
|
||||||
if (this.options.headers == null)
|
if (options.headers == null)
|
||||||
this.options.headers = false;
|
options.headers = false;
|
||||||
if (this.options.multiplePeers == null)
|
if (options.multiplePeers == null)
|
||||||
this.options.multiplePeers = false;
|
options.multiplePeers = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.options.headers)
|
if (!options.headers)
|
||||||
this.options.multiplePeers = false;
|
options.multiplePeers = false;
|
||||||
|
|
||||||
this.syncing = false;
|
this.syncing = false;
|
||||||
this.synced = false;
|
this.synced = false;
|
||||||
@ -84,9 +87,11 @@ function Pool(options) {
|
|||||||
this.requestTimeout = options.requestTimeout || 600000;
|
this.requestTimeout = options.requestTimeout || 600000;
|
||||||
|
|
||||||
this.chain = new bcoin.chain({
|
this.chain = new bcoin.chain({
|
||||||
fullNode: this.options.fullNode,
|
spv: options.spv,
|
||||||
multiplePeers: this.options.multiplePeers,
|
multiplePeers: options.multiplePeers,
|
||||||
preload: this.options.preload
|
preload: options.preload,
|
||||||
|
blockdb: options.blockdb,
|
||||||
|
mempool: options.mempool
|
||||||
});
|
});
|
||||||
|
|
||||||
this.watchMap = {};
|
this.watchMap = {};
|
||||||
@ -115,7 +120,7 @@ function Pool(options) {
|
|||||||
this.block = {
|
this.block = {
|
||||||
bestHeight: 0,
|
bestHeight: 0,
|
||||||
bestHash: null,
|
bestHash: null,
|
||||||
type: this.options.fullNode ? 'block' : 'filtered',
|
type: !options.spv ? 'block' : 'filtered',
|
||||||
invalid: {}
|
invalid: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -133,10 +138,6 @@ function Pool(options) {
|
|||||||
this.validate = {
|
this.validate = {
|
||||||
// 5 days scan delta for obtaining TXs
|
// 5 days scan delta for obtaining TXs
|
||||||
delta: 5 * 24 * 3600,
|
delta: 5 * 24 * 3600,
|
||||||
|
|
||||||
// Minimum verification depth
|
|
||||||
minDepth: options.minValidateDepth || 0,
|
|
||||||
|
|
||||||
// getTX map
|
// getTX map
|
||||||
map: {}
|
map: {}
|
||||||
};
|
};
|
||||||
@ -148,7 +149,7 @@ function Pool(options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Added and watched wallets
|
// Added and watched wallets
|
||||||
this.options.wallets = this.options.wallets || [];
|
options.wallets = options.wallets || [];
|
||||||
this.wallets = [];
|
this.wallets = [];
|
||||||
|
|
||||||
Pool.global = this;
|
Pool.global = this;
|
||||||
@ -615,7 +616,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer, callback) {
|
|||||||
requested = self._response(block);
|
requested = self._response(block);
|
||||||
|
|
||||||
// Emulate BIP37: emit all the filtered transactions.
|
// Emulate BIP37: emit all the filtered transactions.
|
||||||
if (self.options.fullNode && self.listeners('watched').length > 0) {
|
if (!self.options.spv && self.listeners('watched').length > 0) {
|
||||||
block.txs.forEach(function(tx) {
|
block.txs.forEach(function(tx) {
|
||||||
if (self.isWatched(tx))
|
if (self.isWatched(tx))
|
||||||
self.emit('watched', tx, peer);
|
self.emit('watched', tx, peer);
|
||||||
@ -857,22 +858,35 @@ Pool.prototype._handleTX = function _handleTX(tx, peer, callback) {
|
|||||||
|
|
||||||
callback = utils.asyncify(callback);
|
callback = utils.asyncify(callback);
|
||||||
|
|
||||||
this._prehandleTX(tx, peer, function(err) {
|
function addMempool(tx, peer, callback) {
|
||||||
var requested, added;
|
if (!self.mempool)
|
||||||
|
return callback();
|
||||||
|
if (tx.ts !== 0)
|
||||||
|
return callback();
|
||||||
|
self.mempool.addTX(tx, peer, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._prehandleTX(tx, peer, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
requested = self._response(tx);
|
addMempool(tx, peer, function(err) {
|
||||||
added = self._addTX(tx, 1);
|
var requested, added;
|
||||||
|
|
||||||
if (added || tx.block)
|
if (err)
|
||||||
self.emit('tx', tx, peer);
|
utils.debug('Mempool error: %s', err.message);
|
||||||
|
|
||||||
if (!self.options.fullNode && tx.block)
|
requested = self._response(tx);
|
||||||
self.emit('watched', tx, peer);
|
added = self._addTX(tx, 1);
|
||||||
|
|
||||||
return callback();
|
if (added || tx.block)
|
||||||
|
self.emit('tx', tx, peer);
|
||||||
|
|
||||||
|
if (self.options.spv && tx.block)
|
||||||
|
self.emit('watched', tx, peer);
|
||||||
|
|
||||||
|
return callback();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1232,7 +1246,7 @@ Pool.prototype.addWallet = function addWallet(w) {
|
|||||||
self.sendTX(tx);
|
self.sendTX(tx);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (self.options.fullNode)
|
if (!self.options.spv)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (self._pendingSearch)
|
if (self._pendingSearch)
|
||||||
@ -1323,7 +1337,7 @@ Pool.prototype.searchWallet = function(w, h) {
|
|||||||
|
|
||||||
assert(!this.loading);
|
assert(!this.loading);
|
||||||
|
|
||||||
if (this.options.fullNode)
|
if (!this.options.spv)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (w == null) {
|
if (w == null) {
|
||||||
@ -1393,7 +1407,7 @@ Pool.prototype.search = function search(id, range, e) {
|
|||||||
|
|
||||||
assert(!this.loading);
|
assert(!this.loading);
|
||||||
|
|
||||||
if (this.options.fullNode)
|
if (!this.options.spv)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (typeof e === 'function') {
|
if (typeof e === 'function') {
|
||||||
@ -1570,7 +1584,7 @@ Pool.prototype.getTX = function getTX(hash, range, cb) {
|
|||||||
if (!this.peers.load)
|
if (!this.peers.load)
|
||||||
return setTimeout(this.getBlock.bind(this, hash, cb), 1000);
|
return setTimeout(this.getBlock.bind(this, hash, cb), 1000);
|
||||||
|
|
||||||
if (this.options.fullNode)
|
if (!this.options.spv)
|
||||||
return cb(new Error('Cannot get tx with full node'));
|
return cb(new Error('Cannot get tx with full node'));
|
||||||
|
|
||||||
hash = utils.toHex(hash);
|
hash = utils.toHex(hash);
|
||||||
|
|||||||
@ -272,3 +272,33 @@ exports.userAgent = '/bcoin:' + exports.userVersion + '/';
|
|||||||
|
|
||||||
exports.banTime = 24 * 60 * 60;
|
exports.banTime = 24 * 60 * 60;
|
||||||
exports.banScore = 100;
|
exports.banScore = 100;
|
||||||
|
|
||||||
|
// Script and locktime flags
|
||||||
|
exports.flags = {
|
||||||
|
VERIFY_NONE: 0,
|
||||||
|
VERIFY_P2SH: (1 << 0),
|
||||||
|
VERIFY_STRICTENC: (1 << 1),
|
||||||
|
VERIFY_DERSIG: (1 << 2),
|
||||||
|
VERIFY_LOW_S: (1 << 3),
|
||||||
|
VERIFY_NULLDUMMY: (1 << 4),
|
||||||
|
VERIFY_SIGPUSHONLY: (1 << 5),
|
||||||
|
VERIFY_MINIMALDATA: (1 << 6),
|
||||||
|
VERIFY_DISCOURAGE_UPGRADABLE_NOPS: (1 << 7),
|
||||||
|
VERIFY_CLEANSTACK: (1 << 8),
|
||||||
|
VERIFY_CHECKLOCKTIMEVERIFY: (1 << 9)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Block validation
|
||||||
|
exports.flags.MANDATORY_VERIFY_FLAGS = exports.flags.VERIFY_P2SH;
|
||||||
|
|
||||||
|
// Mempool validation
|
||||||
|
exports.flags.STANDARD_VERIFY_FLAGS =
|
||||||
|
exports.flags.MANDATORY_VERIFY_FLAGS
|
||||||
|
| exports.flags.VERIFY_DERSIG
|
||||||
|
| exports.flags.VERIFY_STRICTENC
|
||||||
|
| exports.flags.VERIFY_MINIMALDATA
|
||||||
|
| exports.flags.VERIFY_NULLDUMMY
|
||||||
|
| exports.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS
|
||||||
|
| exports.flags.VERIFY_CLEANSTACK
|
||||||
|
| exports.flags.VERIFY_CHECKLOCKTIMEVERIFY
|
||||||
|
| exports.flags.VERIFY_LOW_S;
|
||||||
|
|||||||
@ -198,10 +198,10 @@ script.verify = function verify(input, output, tx, i, flags) {
|
|||||||
var copy, res, redeem;
|
var copy, res, redeem;
|
||||||
var stack = [];
|
var stack = [];
|
||||||
|
|
||||||
if (!flags)
|
if (flags == null)
|
||||||
flags = {};
|
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||||
|
|
||||||
if (flags.sigpushonly !== false) {
|
if (flags & constants.flags.VERIFY_SIGPUSHONLY) {
|
||||||
if (!script.isPushOnly(input))
|
if (!script.isPushOnly(input))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -210,7 +210,7 @@ script.verify = function verify(input, output, tx, i, flags) {
|
|||||||
script.execute(input, stack, tx, i, flags);
|
script.execute(input, stack, tx, i, flags);
|
||||||
|
|
||||||
// Copy the stack for P2SH
|
// Copy the stack for P2SH
|
||||||
if (flags.verifyp2sh !== false)
|
if (flags & constants.flags.VERIFY_P2SH)
|
||||||
copy = stack.slice();
|
copy = stack.slice();
|
||||||
|
|
||||||
// Execute the previous output script
|
// Execute the previous output script
|
||||||
@ -221,7 +221,7 @@ script.verify = function verify(input, output, tx, i, flags) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// If the script is P2SH, execute the real output script
|
// If the script is P2SH, execute the real output script
|
||||||
if (flags.verifyp2sh !== false && script.isScripthash(output)) {
|
if ((flags & constants.flags.VERIFY_P2SH) && script.isScripthash(output)) {
|
||||||
// P2SH can only have push ops in the scriptSig
|
// P2SH can only have push ops in the scriptSig
|
||||||
if (!script.isPushOnly(input))
|
if (!script.isPushOnly(input))
|
||||||
return false;
|
return false;
|
||||||
@ -250,7 +250,7 @@ script.verify = function verify(input, output, tx, i, flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure there is nothing left on the stack
|
// Ensure there is nothing left on the stack
|
||||||
if (flags.cleanstack !== false) {
|
if (flags & constants.flags.VERIFY_CLEANSTACK) {
|
||||||
if (stack.length !== 0)
|
if (stack.length !== 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -370,8 +370,8 @@ script._next = function _next(to, s, pc) {
|
|||||||
script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
||||||
var s = data.slice();
|
var s = data.slice();
|
||||||
|
|
||||||
if (!flags)
|
if (flags == null)
|
||||||
flags = {};
|
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||||
|
|
||||||
if (s.length > constants.script.maxOps)
|
if (s.length > constants.script.maxOps)
|
||||||
return false;
|
return false;
|
||||||
@ -418,7 +418,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
|||||||
case 'nop8':
|
case 'nop8':
|
||||||
case 'nop9':
|
case 'nop9':
|
||||||
case 'nop10': {
|
case 'nop10': {
|
||||||
if (flags.discourage_nops !== false)
|
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -908,7 +908,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
|||||||
|
|
||||||
val = stack.pop();
|
val = stack.pop();
|
||||||
|
|
||||||
if (flags.verifynulldummy !== false) {
|
if (flags & constants.flags.VERIFY_NULLDUMMY) {
|
||||||
if (!script.isDummy(val))
|
if (!script.isDummy(val))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -925,8 +925,8 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
|||||||
}
|
}
|
||||||
case 'checklocktimeverify': {
|
case 'checklocktimeverify': {
|
||||||
// OP_CHECKLOCKTIMEVERIFY = OP_NOP2
|
// OP_CHECKLOCKTIMEVERIFY = OP_NOP2
|
||||||
if (flags.checklocktimeverify === false) {
|
if (!(flags & constants.flags.VERIFY_CHECKLOCKTIMEVERIFY)) {
|
||||||
if (flags.discourage_nops !== false)
|
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -965,8 +965,8 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
|||||||
}
|
}
|
||||||
case 'nop1': {
|
case 'nop1': {
|
||||||
// OP_EVAL = OP_NOP1
|
// OP_EVAL = OP_NOP1
|
||||||
if (flags['eval'] !== true) {
|
if (!script.allowEval) {
|
||||||
if (flags.discourage_nops !== false)
|
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1126,10 +1126,13 @@ script.removeData = function removeData(s, data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
script.checkPush = function checkPush(op, value, flags) {
|
script.checkPush = function checkPush(op, value, flags) {
|
||||||
if (!flags)
|
if (flags == null)
|
||||||
flags = {};
|
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||||
|
|
||||||
if (flags.minimaldata === false)
|
// Disabled for now.
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!(flags & constants.flags.VERIFY_MINIMALDATA))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!op.pushdata)
|
if (!op.pushdata)
|
||||||
@ -2038,13 +2041,13 @@ script.isData = function isData(data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
script.isValidKey = function isValidKey(key, flags) {
|
script.isValidKey = function isValidKey(key, flags) {
|
||||||
if (!flags)
|
if (flags == null)
|
||||||
flags = {};
|
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||||
|
|
||||||
if (!utils.isBuffer(key))
|
if (!utils.isBuffer(key))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (flags.strictenc !== false) {
|
if (flags & constants.flags.VERIFY_STRICTENC) {
|
||||||
if (!script.isKeyEncoding(key))
|
if (!script.isKeyEncoding(key))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2073,8 +2076,8 @@ script.isKeyEncoding = function isKeyEncoding(key) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
script.isValidSignature = function isValidSignature(sig, flags) {
|
script.isValidSignature = function isValidSignature(sig, flags) {
|
||||||
if (!flags)
|
if (flags == null)
|
||||||
flags = {};
|
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||||
|
|
||||||
if (!utils.isBuffer(sig))
|
if (!utils.isBuffer(sig))
|
||||||
return false;
|
return false;
|
||||||
@ -2083,19 +2086,19 @@ script.isValidSignature = function isValidSignature(sig, flags) {
|
|||||||
if (sig.length === 0)
|
if (sig.length === 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (flags.dersig !== false
|
if ((flags & constants.flags.VERIFY_DERSIG)
|
||||||
|| flags.low_s !== false
|
|| (flags & constants.flags.VERIFY_LOW_S)
|
||||||
|| flags.strictenc !== false) {
|
|| (flags & constants.flags.VERIFY_STRICTENC)) {
|
||||||
if (!script.isSignatureEncoding(sig))
|
if (!script.isSignatureEncoding(sig))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags.low_s !== false) {
|
if (flags & constants.flags.VERIFY_LOW_S) {
|
||||||
if (!script.isLowDER(sig))
|
if (!script.isLowDER(sig))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags.strictenc !== false) {
|
if (flags & constants.flags.VERIFY_STRICTENC) {
|
||||||
if (!script.isHashType(sig))
|
if (!script.isHashType(sig))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -809,13 +809,6 @@ TX.prototype.signatureHash = function signatureHash(index, s, type) {
|
|||||||
if (typeof index !== 'number')
|
if (typeof index !== 'number')
|
||||||
index = this.inputs.indexOf(index);
|
index = this.inputs.indexOf(index);
|
||||||
|
|
||||||
if (!Array.isArray(s)) {
|
|
||||||
type = s;
|
|
||||||
s = this.inputs[index].output.script;
|
|
||||||
if (bcoin.script.isScripthash(s))
|
|
||||||
s = bcoin.script.getRedeem(this.inputs[index].script);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof type === 'string')
|
if (typeof type === 'string')
|
||||||
type = constants.hashType[type];
|
type = constants.hashType[type];
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user