contextual verification. misc.
This commit is contained in:
parent
e912f78814
commit
fe46d1ada5
@ -581,8 +581,6 @@ BlockDB.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||
var id = 'u/t/' + hash + '/' + index;
|
||||
|
||||
this.index.get(id, function(err, record) {
|
||||
var record;
|
||||
|
||||
if (err) {
|
||||
if (err.type === 'NotFoundError')
|
||||
return callback();
|
||||
@ -731,8 +729,6 @@ BlockDB.prototype.getTX = function getTX(hash, callback) {
|
||||
var id = 't/t/' + hash;
|
||||
|
||||
this.index.get(id, function(err, record) {
|
||||
var record;
|
||||
|
||||
if (err) {
|
||||
if (err.type === 'NotFoundError')
|
||||
return callback();
|
||||
@ -775,8 +771,6 @@ BlockDB.prototype.getBlock = function getBlock(hash, callback) {
|
||||
id = 'b/h/' + value;
|
||||
|
||||
this.index.get(id, function(err, record) {
|
||||
var record;
|
||||
|
||||
if (err) {
|
||||
if (err.type === 'NotFoundError')
|
||||
return callback();
|
||||
@ -816,12 +810,34 @@ BlockDB.prototype.getBlock = function getBlock(hash, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
BlockDB.prototype.hasCoin = function hasCoin(hash, index, callback) {
|
||||
var id = 'u/t/' + hash + '/' + index;
|
||||
|
||||
this.index.get(id, function(err, record) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
|
||||
return callback(null, record ? true : false);
|
||||
});
|
||||
};
|
||||
|
||||
BlockDB.prototype.hasTX = function hasTX(hash, callback) {
|
||||
var id = 't/t/' + hash;
|
||||
|
||||
this.index.get(id, function(err, record) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
|
||||
return callback(null, record ? true : false);
|
||||
});
|
||||
};
|
||||
|
||||
BlockDB.prototype.isSpent = function isSpent(hash, index, callback) {
|
||||
this.getCoin(hash, index, function(err, coin) {
|
||||
return this.hasCoin(hash, index, function(err, result) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(null, coin ? false : true);
|
||||
return callback(null, !result);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -260,6 +260,7 @@ Chain.prototype._preload = function _preload(callback) {
|
||||
};
|
||||
|
||||
Chain.prototype._saveBlock = function _saveBlock(block, callback) {
|
||||
var self = this;
|
||||
var node = bcoin.node.global;
|
||||
|
||||
if (!node)
|
||||
@ -275,74 +276,8 @@ Chain.prototype._saveBlock = function _saveBlock(block, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
Chain.prototype._fillCoins = function _fillCoin(block, callback) {
|
||||
var node = bcoin.node.global;
|
||||
|
||||
if (!node)
|
||||
return callback();
|
||||
|
||||
node.block.fillCoins(block, callback);
|
||||
};
|
||||
|
||||
Chain.prototype._verifyContext = function _verifyContext(block, prev, callback) {
|
||||
var node = bcoin.node.global;
|
||||
|
||||
if (!node)
|
||||
return callback(null, block.verifyContext());
|
||||
|
||||
var height = prev.height + 1;
|
||||
var scriptChecks = true;
|
||||
|
||||
node.block.fillCoins(block, function(err) {
|
||||
var pending;
|
||||
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
pending = block.txs.length;
|
||||
|
||||
// If we are an ancestor of a checkpoint, we can
|
||||
// skip the input verification.
|
||||
if (height < network.checkpoints.lastHeight && !network.checkpoints[height])
|
||||
scriptChecks = false;
|
||||
|
||||
if (!block.verifyContext())
|
||||
return callback(null, false);
|
||||
|
||||
if (!pending)
|
||||
return callback(null, true);
|
||||
|
||||
// Check all transactions
|
||||
block.txs.forEach(function(tx) {
|
||||
var i;
|
||||
for (i = 0; j < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
// 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 callback(null, false);
|
||||
}
|
||||
}
|
||||
// BIP30 - Ensure there are no duplicate txids
|
||||
node.block.hasTX(tx.hash('hex'), function(err, has) {
|
||||
// Blocks 91842 and 91880 created duplicate
|
||||
// txids by using the same exact output script
|
||||
// and extraNonce.
|
||||
if (has) {
|
||||
utils.debug('Block is overwriting txids: %s', this.rhash);
|
||||
if (!(network.type === 'main' && (height === 91842 || height === 91880)))
|
||||
return callback(null, false);
|
||||
}
|
||||
return callback(null, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Chain.prototype._removeBlock = function _removeBlock(tip, callback) {
|
||||
var self = this;
|
||||
var node = bcoin.node.global;
|
||||
|
||||
if (!node)
|
||||
@ -353,9 +288,289 @@ Chain.prototype._removeBlock = function _removeBlock(tip, callback) {
|
||||
return callback(err);
|
||||
|
||||
if (!block)
|
||||
return;
|
||||
return callback();
|
||||
|
||||
node.mempool.removeBlock(block);
|
||||
|
||||
self.emit('reorg block', block.hash('hex'));
|
||||
|
||||
block.txs.forEach(function(tx) {
|
||||
self.emit('reorg tx', tx.hash('hex'));
|
||||
});
|
||||
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
Chain.prototype._verifyContext = function _verifyContext(block, prev, callback) {
|
||||
var self = this;
|
||||
var flags;
|
||||
|
||||
flags = this._verify(block, prev);
|
||||
|
||||
if (flags === false)
|
||||
return callback(null, false);
|
||||
|
||||
this._checkDuplicates(block, prev, function(err, result) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!result)
|
||||
return callback(null, false);
|
||||
|
||||
self._checkInputs(block, prev, flags, function(err, result) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!result)
|
||||
return callback(null, false);
|
||||
|
||||
return callback(null, true);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Chain.prototype._verify = function _verify(block, prev) {
|
||||
// var flags = constants.flags.MANDATORY_VERIFY_FLAGS;
|
||||
var flags = {};
|
||||
var sigops = 0;
|
||||
var height, ts, i, tx, cb, coinbaseHeight;
|
||||
|
||||
// Skip the genesis block
|
||||
if (block.isGenesis())
|
||||
return flags;
|
||||
|
||||
// Ensure it's not an orphan
|
||||
if (!prev) {
|
||||
utils.debug('Block has no previous entry: %s', block.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
height = prev.height + 1;
|
||||
|
||||
// Ensure the timestamp is correct
|
||||
if (block.ts <= prev.getMedianTime()) {
|
||||
utils.debug('Block time is lower than median: %s', block.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the miner's target is equal to what we expect
|
||||
if (block.bits !== block.chain.getTarget(prev, block)) {
|
||||
utils.debug('Block is using wrong target: %s', block.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow version 2 blocks (coinbase height)
|
||||
// once the majority of blocks are using it.
|
||||
if (block.version < 2 && prev.isOutdated(2)) {
|
||||
utils.debug('Block is outdated (v2): %s', block.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow version 3 blocks (sig validation)
|
||||
// once the majority of blocks are using it.
|
||||
if (block.version < 3 && prev.isOutdated(3)) {
|
||||
utils.debug('Block is outdated (v3): %s', block.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow version 4 blocks (checklocktimeverify)
|
||||
// once the majority of blocks are using it.
|
||||
if (block.version < 4 && prev.isOutdated(4)) {
|
||||
utils.debug('Block is outdated (v4): %s', block.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow version 8 blocks (locktime median past)
|
||||
// once the majority of blocks are using it.
|
||||
// if (block.version < 8 && prev.isOutdated(8)) {
|
||||
// utils.debug('Block is outdated (v8): %s', block.rhash);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// Make sure the height contained in the coinbase is correct.
|
||||
if (block.version >= 2 && prev.isUpgraded(2))
|
||||
coinbaseHeight = true;
|
||||
|
||||
// Signature validation is now enforced (bip66)
|
||||
if (!(block.version >= 3 && prev.isUpgraded(3)))
|
||||
flags.dersig = false;
|
||||
|
||||
// CHECKLOCKTIMEVERIFY is now usable (bip65)
|
||||
if (!(block.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 (block.version >= 8 && prev.isUpgraded(8))
|
||||
// flags.locktimeMedian = true;
|
||||
|
||||
// Can't verify any further when merkleblock or headers.
|
||||
if (block.subtype !== 'block')
|
||||
return flags;
|
||||
|
||||
// Make sure the height contained in the coinbase is correct.
|
||||
if (coinbaseHeight) {
|
||||
cb = bcoin.script.getCoinbaseData(block.txs[0].inputs[0].script);
|
||||
|
||||
// Make sure the coinbase is parseable.
|
||||
if (!cb) {
|
||||
utils.debug('Block has malformed coinbase: %s', block.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', block.rhash);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get timestamp for tx.isFinal().
|
||||
ts = flags.locktimeMedian
|
||||
? prev.getMedianTime()
|
||||
: block.ts;
|
||||
|
||||
// Check all transactions
|
||||
for (i = 0; i < block.txs.length; i++) {
|
||||
tx = block.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)', block.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', block.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 (block.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', block.rhash);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
};
|
||||
|
||||
Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callback) {
|
||||
var node = bcoin.node.global;
|
||||
var height = prev.height + 1;
|
||||
var pending = block.txs.length;
|
||||
var called;
|
||||
|
||||
if (!node || block.subtype !== 'block')
|
||||
return callback(null, true);
|
||||
|
||||
if (block.isGenesis())
|
||||
return callback(null, true);
|
||||
|
||||
assert(pending);
|
||||
|
||||
function done(err, result) {
|
||||
if (called)
|
||||
return;
|
||||
called = true;
|
||||
callback(err, result);
|
||||
}
|
||||
|
||||
// Check all transactions
|
||||
block.txs.forEach(function(tx) {
|
||||
var hash = tx.hash('hex');
|
||||
|
||||
// BIP30 - Ensure there are no duplicate txids
|
||||
node.block.hasTX(hash, function(err, result) {
|
||||
if (called)
|
||||
return;
|
||||
|
||||
if (err)
|
||||
return done(err);
|
||||
|
||||
// Blocks 91842 and 91880 created duplicate
|
||||
// txids by using the same exact output script
|
||||
// and extraNonce.
|
||||
if (result) {
|
||||
utils.debug('Block is overwriting txids: %s', block.rhash);
|
||||
if (!(network.type === 'main' && (height === 91842 || height === 91880)))
|
||||
return done(null, false);
|
||||
}
|
||||
|
||||
if (!--pending)
|
||||
return done(null, true);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callback) {
|
||||
var node = bcoin.node.global;
|
||||
var height = prev.height + 1;
|
||||
|
||||
if (!node || block.subtype !== 'block')
|
||||
return callback(null, true);
|
||||
|
||||
if (block.isGenesis())
|
||||
return callback(null, true);
|
||||
|
||||
// If we are an ancestor of a checkpoint, we can
|
||||
// skip the input verification.
|
||||
if (height < network.checkpoints.lastHeight && !network.checkpoints[height])
|
||||
return callback(null, true);
|
||||
|
||||
node.block.fillCoins(block.txs, function(err) {
|
||||
var i, j, input, hash;
|
||||
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
// Check all transactions
|
||||
for (i = 0; i < block.txs.length; i++) {
|
||||
tx = blocks.txs[i];
|
||||
hash = tx.hash('hex');
|
||||
|
||||
for (j = 0; j < tx.inputs.length; j++) {
|
||||
input = tx.inputs[j];
|
||||
|
||||
// Coinbases do not have prevouts
|
||||
if (tx.isCoinbase())
|
||||
continue;
|
||||
|
||||
// Ensure tx is not double spending an output
|
||||
if (!input.output) {
|
||||
utils.debug('Block is using spent inputs: %s (tx: %s, output: %s)',
|
||||
block.rhash, tx.rhash,
|
||||
input.prevout.rhash + '/' + input.prevout.index);
|
||||
return callback(null, false);
|
||||
}
|
||||
|
||||
// Verify the scripts
|
||||
if (!tx.verify(j, true, flags)) {
|
||||
utils.debug('Block has invalid inputs: %s', block.rhash);
|
||||
return callback(null, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return callback(null, true);
|
||||
});
|
||||
};
|
||||
|
||||
@ -371,7 +586,7 @@ Chain.prototype._addEntry = function _addEntry(entry, block, callback) {
|
||||
return callback(null, Chain.codes.unchanged);
|
||||
}
|
||||
|
||||
// Duplicate height
|
||||
// Duplicate height (do a sync call here since this is cached)
|
||||
existing = this.db.get(entry.height);
|
||||
if (existing && existing.hash === entry.hash)
|
||||
return callback(null, Chain.codes.unchanged);
|
||||
@ -380,7 +595,7 @@ Chain.prototype._addEntry = function _addEntry(entry, block, callback) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
self._saveEntry(entry, function(err) {
|
||||
self._saveEntry(entry, true, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -389,7 +604,7 @@ Chain.prototype._addEntry = function _addEntry(entry, block, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
Chain.prototype._saveEntry = function _saveEntry(entry, callback) {
|
||||
Chain.prototype._saveEntry = function _saveEntry(entry, save, callback) {
|
||||
this.heightLookup[entry.hash] = entry.height;
|
||||
|
||||
if (!this.tip || entry.height > this.tip.height) {
|
||||
@ -397,11 +612,8 @@ Chain.prototype._saveEntry = function _saveEntry(entry, callback) {
|
||||
this.emit('tip', this.tip);
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
if (typeof callback !== 'function')
|
||||
callback = null;
|
||||
if (save)
|
||||
this.db.save(entry, callback);
|
||||
}
|
||||
};
|
||||
|
||||
Chain.prototype.resetLastCheckpoint = function resetLastCheckpoint(height) {
|
||||
@ -461,6 +673,12 @@ Chain.prototype.add = function add(block, peer, callback) {
|
||||
var hash, prevHash, prevHeight, entry, tip, existing, checkpoint;
|
||||
var total = 0;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (this._locked)
|
||||
return callback(null, total);
|
||||
|
||||
// (function next(block) {
|
||||
(function next() {
|
||||
hash = block.hash('hex');
|
||||
prevHash = block.prevBlock;
|
||||
@ -553,17 +771,19 @@ Chain.prototype.add = function add(block, peer, callback) {
|
||||
// The block has equal chainwork (an
|
||||
// alternate tip). Reset the chain, find
|
||||
// a new peer, and wait to see who wins.
|
||||
self.resetHeight(entry.height - 1);
|
||||
self.emit('fork', {
|
||||
height: prevHeight + 1,
|
||||
expected: tip.hash,
|
||||
received: hash,
|
||||
checkpoint: false
|
||||
}, peer);
|
||||
code = Chain.codes.forked;
|
||||
self._locked = true;
|
||||
return self._removeBlock(tip.hash, function(err) {
|
||||
self._locked = false;
|
||||
if (err)
|
||||
return done(err);
|
||||
self.resetHeight(entry.height - 1);
|
||||
self.emit('fork', {
|
||||
height: prevHeight + 1,
|
||||
expected: tip.hash,
|
||||
received: hash,
|
||||
checkpoint: false
|
||||
}, peer);
|
||||
code = Chain.codes.forked;
|
||||
return done(null, code);
|
||||
});
|
||||
}
|
||||
@ -595,14 +815,12 @@ Chain.prototype.add = function add(block, peer, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
// Could fill here for contextual verification.
|
||||
// Also check isSpent here!
|
||||
// self._fillCoins(block, function(err) {
|
||||
// self._verifyContext(block, prev, function(err, verified) {
|
||||
|
||||
// Do "contextual" verification on our block
|
||||
// now that we're certain its previous
|
||||
// block is in the chain.
|
||||
if (!block.verifyContext()) {
|
||||
if (!block.verifyContext(prev)) {
|
||||
code = Chain.codes.invalid;
|
||||
self.emit('invalid', {
|
||||
height: prevHeight + 1,
|
||||
|
||||
@ -196,6 +196,9 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
||||
if (this.txs[hash])
|
||||
return callback(new Error('Already have TX.'));
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return callback(new Error('What?'));
|
||||
|
||||
this._lockTX(tx);
|
||||
|
||||
this.block.fillCoin(tx, function(err) {
|
||||
@ -260,15 +263,6 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
if (input.output.spent) {
|
||||
return callback(new Error('TX is spending old outputs.'));
|
||||
peer.reject({
|
||||
data: tx.hash(),
|
||||
reason: 'old-outputs'
|
||||
});
|
||||
pool.setMisbehavior(peer, 100);
|
||||
return callback(new Error('TX is spending old outputs.'));
|
||||
}
|
||||
dup = self.spent[input.prevout.hash + '/' + input.prevout.index];
|
||||
if (dup) {
|
||||
// Replace-by-fee
|
||||
@ -283,7 +277,6 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
||||
data: tx.hash(),
|
||||
reason: 'double-spend'
|
||||
});
|
||||
pool.setMisbehavior(peer, 100);
|
||||
return callback(new Error('TX is double spending.'));
|
||||
}
|
||||
}
|
||||
@ -301,7 +294,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!tx.verify(true)) {
|
||||
if (!tx.verify(null, true)) {
|
||||
return callback(new Error('TX did not verify.'));
|
||||
peer.reject({
|
||||
data: tx.hash(),
|
||||
@ -314,15 +307,12 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
self.spent[input.prevout.hash + '/' + input.prevout.index] = tx;
|
||||
self.size += input.output.getSize();
|
||||
}
|
||||
|
||||
// Possibly do something bitcoinxt-like here with priority
|
||||
priority = tx.getPriority();
|
||||
|
||||
self.txs[hash] = tx;
|
||||
self.count++;
|
||||
self.size += tx.getSize();
|
||||
|
||||
tx.inputs.forEach(function(input) {
|
||||
var address = input.getAddress();
|
||||
|
||||
@ -346,6 +336,10 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
||||
|
||||
self.addresses[address][hash] = true;
|
||||
});
|
||||
|
||||
self.txs[hash] = tx;
|
||||
self.count++;
|
||||
self.size += tx.getSize();
|
||||
});
|
||||
};
|
||||
|
||||
@ -402,11 +396,6 @@ Mempool.prototype.removeTX = function removeTX(hash, callback) {
|
||||
delete this.spent[id];
|
||||
}
|
||||
|
||||
delete this.txs[hash];
|
||||
|
||||
this.count--;
|
||||
this.size -= tx.getSize();
|
||||
|
||||
tx.inputs.forEach(function(input) {
|
||||
var address = input.getAddress();
|
||||
|
||||
@ -432,6 +421,10 @@ Mempool.prototype.removeTX = function removeTX(hash, callback) {
|
||||
delete self.addresses[address];
|
||||
}
|
||||
});
|
||||
|
||||
delete this.txs[hash];
|
||||
this.count--;
|
||||
this.size -= tx.getSize();
|
||||
};
|
||||
|
||||
// Need to lock the mempool when
|
||||
|
||||
@ -918,6 +918,9 @@ TX.prototype.verify = function verify(index, force, flags) {
|
||||
if (index != null)
|
||||
assert(this.inputs[index]);
|
||||
|
||||
if (this.isCoinbase())
|
||||
return true;
|
||||
|
||||
return this.inputs.every(function(input, i) {
|
||||
if (index != null && i !== index)
|
||||
return true;
|
||||
@ -1552,6 +1555,10 @@ TX.prototype.isStandard = function isStandard() {
|
||||
if (bcoin.script.getSize(input.script) > 1650)
|
||||
return false;
|
||||
|
||||
// Not accurate?
|
||||
if (this.isCoinbase())
|
||||
continue;
|
||||
|
||||
if (!bcoin.script.isPushOnly(input.script))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1405,7 +1405,8 @@ utils.cmp = function(a, b) {
|
||||
// This protects us against timing attacks when
|
||||
// comparing an input against a secret string.
|
||||
utils.ccmp = function(a, b) {
|
||||
var res, i;
|
||||
var res = 0;
|
||||
var i;
|
||||
|
||||
assert(a.length === b.length);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user