tx/mempool: fix mutated witnesses in rejects filter.
This commit is contained in:
parent
27e574c7e5
commit
c0f4225b32
@ -815,11 +815,21 @@ Mempool.prototype.verify = function verify(entry, callback) {
|
||||
0));
|
||||
}
|
||||
|
||||
if (self.requireStandard && !tx.hasStandardInputs()) {
|
||||
return callback(new VerifyError(tx,
|
||||
'nonstandard',
|
||||
'bad-txns-nonstandard-inputs',
|
||||
0));
|
||||
if (self.requireStandard) {
|
||||
if (!tx.hasStandardInputs()) {
|
||||
return callback(new VerifyError(tx,
|
||||
'nonstandard',
|
||||
'bad-txns-nonstandard-inputs',
|
||||
0));
|
||||
}
|
||||
// if (self.chain.state.hasWitness()) {
|
||||
// if (!tx.hasStandardWitness()) {
|
||||
// return callback(new VerifyError(tx,
|
||||
// 'nonstandard',
|
||||
// 'bad-witness-nonstandard',
|
||||
// 0));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
if (tx.getSigopsWeight(flags) > constants.tx.MAX_SIGOPS_WEIGHT) {
|
||||
|
||||
@ -1359,7 +1359,13 @@ Pool.prototype._handleTX = function _handleTX(tx, peer, callback) {
|
||||
if (err.type === 'VerifyError') {
|
||||
if (err.score !== -1)
|
||||
peer.reject(tx, err.code, err.reason, err.score);
|
||||
self.rejectsFilter.add(tx.hash());
|
||||
|
||||
// Once we test it more, we can do:
|
||||
// if (err.reason !== 'bad-witness-nonstandard')
|
||||
|
||||
if (!tx.hasWitness())
|
||||
self.rejectsFilter.add(tx.hash());
|
||||
|
||||
return callback(err);
|
||||
}
|
||||
return callback(err);
|
||||
|
||||
@ -1359,6 +1359,138 @@ TX.prototype.hasStandardInputs = function hasStandardInputs() {
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform contextual checks to verify coin and witness standardness.
|
||||
* @see IsBadWitness()
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
TX.prototype.hasStandardWitness = function hasStandardWitness(strict) {
|
||||
var i, j, input, prev, hash, redeem, m, n;
|
||||
|
||||
if (this.isCoinbase())
|
||||
return true;
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
|
||||
if (!input.coin)
|
||||
continue;
|
||||
|
||||
prev = input.coin.script;
|
||||
|
||||
if (prev.isScripthash()) {
|
||||
prev = input.script.getRedeem();
|
||||
if (!prev)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!prev.isProgram()) {
|
||||
if (input.witness.length !== 0)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prev.isWitnessPubkeyhash()) {
|
||||
if (input.witness.length !== 2)
|
||||
return false;
|
||||
|
||||
if (input.witness.get(0).length > 73)
|
||||
return false;
|
||||
|
||||
hash = crypto.hash160(input.witness.get(1));
|
||||
|
||||
if (!utils.equal(hash, prev.get(1)))
|
||||
return false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!prev.isWitnessScripthash()) {
|
||||
// Unknown program type,
|
||||
// let it through for now.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (input.witness.length === 0)
|
||||
return false;
|
||||
|
||||
// Based on Johnson Lau's calculations:
|
||||
if (input.witness.length - 1 > 604)
|
||||
return false;
|
||||
|
||||
if (strict) {
|
||||
if (input.witness.length - 1 > constants.script.MAX_P2WSH_STACK)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (j = 0; j < input.witness.length; j++) {
|
||||
if (input.witness.get(j).length > constants.script.MAX_PUSH)
|
||||
return false;
|
||||
|
||||
if (strict) {
|
||||
if (input.witness.get(j).length > constants.script.MAX_P2WSH_PUSH)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
redeem = input.witness.get(input.witness.length - 1);
|
||||
|
||||
if (redeem.length > constants.script.MAX_SIZE)
|
||||
return false;
|
||||
|
||||
if (strict) {
|
||||
if (redeem.length > constants.script.MAX_P2WSH_SIZE)
|
||||
return false;
|
||||
}
|
||||
|
||||
hash = crypto.sha256(redeem);
|
||||
|
||||
if (!utils.equal(hash, prev.get(1)))
|
||||
return false;
|
||||
|
||||
redeem = new bcoin.script(redeem);
|
||||
|
||||
if (redeem.isPubkey()) {
|
||||
if (input.witness.length - 1 !== 1)
|
||||
return false;
|
||||
|
||||
if (input.witness.get(0).length > 73)
|
||||
return false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (redeem.isPubkeyhash()) {
|
||||
if (input.witness.length - 1 !== 2)
|
||||
return false;
|
||||
|
||||
if (input.witness.get(0).length > 73)
|
||||
return false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (redeem.isMultisig()) {
|
||||
m = redeem.getSmall(0);
|
||||
n = redeem.getSmall(redeem.length - 2);
|
||||
|
||||
if (input.witness.length - 1 !== m + 1)
|
||||
return false;
|
||||
|
||||
if (input.witness.get(0).length !== 0)
|
||||
return false;
|
||||
|
||||
for (j = 1; j < input.witness.length - 1; j++) {
|
||||
if (input.witness.get(i).length > 73)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform contextual checks to verify input, output,
|
||||
* and fee values, as well as coinbase spend maturity
|
||||
|
||||
@ -441,7 +441,11 @@ exports.script = {
|
||||
MAX_MULTISIG_PUBKEYS: 20,
|
||||
MAX_SCRIPTHASH_SIGOPS: 15,
|
||||
MAX_OP_RETURN_BYTES: 83,
|
||||
MAX_OP_RETURN: 80
|
||||
MAX_OP_RETURN: 80,
|
||||
BYTES_PER_SIGOP: 20,
|
||||
MAX_P2WSH_STACK: 100,
|
||||
MAX_P2WSH_PUSH: 80,
|
||||
MAX_P2WSH_SIZE: 3600
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user