test: add more mempool tests.

This commit is contained in:
Christopher Jeffrey 2016-09-19 13:43:37 -07:00
parent d18482507a
commit 72597c9faf
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 198 additions and 31 deletions

View File

@ -99,6 +99,7 @@ function Mempool(options) {
: this.network.requireStandard;
this.rejectAbsurdFees = this.options.rejectAbsurdFees !== false;
this.prematureWitness = !!this.options.prematureWitness;
this.paranoid = !!this.options.paranoid;
this.maxSize = options.maxSize || constants.mempool.MAX_MEMPOOL_SIZE;
this.expiryTime = options.expiryTime || constants.mempool.MEMPOOL_EXPIRY;
@ -866,16 +867,16 @@ Mempool.prototype.verify = function verify(entry, callback) {
'bad-txns-nonstandard-inputs',
0));
}
// if (self.chain.state.hasWitness()) {
// if (!tx.hasStandardWitness(true, ret)) {
// ret = new VerifyError(tx,
// 'nonstandard',
// ret.reason,
// ret.score);
// ret.malleated = ret.score > 0;
// return callback(ret);
// }
// }
if (self.chain.state.hasWitness()) {
if (!tx.hasStandardWitness(ret)) {
ret = new VerifyError(tx,
'nonstandard',
ret.reason,
ret.score);
ret.malleated = ret.score > 0;
return callback(ret);
}
}
}
if (tx.getSigopsWeight(flags) > constants.tx.MAX_SIGOPS_WEIGHT) {
@ -954,6 +955,9 @@ Mempool.prototype.verify = function verify(entry, callback) {
// Standard verification
self.checkInputs(tx, flags1, function(error) {
if (!error) {
if (!self.paranoid)
return callback();
return self.checkResult(tx, mandatory, function(err, result) {
if (err) {
assert(err.type !== 'VerifyError',
@ -1192,8 +1196,7 @@ Mempool.prototype.getDepends = function getDepends(tx) {
*/
Mempool.prototype.storeOrphan = function storeOrphan(tx) {
var prevout = {};
var missing = [];
var missing = {};
var i, hash, input, prev;
if (tx.getWeight() > constants.tx.MAX_WEIGHT) {
@ -1211,26 +1214,26 @@ Mempool.prototype.storeOrphan = function storeOrphan(tx) {
if (this.hasReject(input.prevout.hash)) {
this.logger.debug('Not storing orphan %s (rejected parents).', tx.rhash);
this.rejects.add(tx.hash());
return;
}
missing.push(input.prevout.hash);
}
hash = tx.hash('hex');
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
if (!input.coin)
prevout[input.prevout.hash] = true;
if (input.coin)
continue;
missing[input.prevout.hash] = true;
}
prevout = Object.keys(prevout);
missing = Object.keys(missing);
assert(prevout.length > 0);
assert(missing.length > 0);
for (i = 0; i < prevout.length; i++) {
prev = prevout[i];
for (i = 0; i < missing.length; i++) {
prev = missing[i];
if (!this.waiting[prev])
this.waiting[prev] = [];
this.waiting[prev].push(hash);

View File

@ -1374,13 +1374,13 @@ TX.prototype.hasStandardInputs = function hasStandardInputs() {
* @returns {Boolean}
*/
TX.prototype.hasStandardWitness = function hasStandardWitness(strict, ret) {
TX.prototype.hasStandardWitness = function hasStandardWitness(ret) {
var result;
if (!ret)
ret = new VerifyResult();
result = this._hasStandardWitness();
result = this.getWitnessStandard();
switch (result) {
case BAD_WITNESS:
@ -1392,12 +1392,9 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(strict, ret) {
ret.score = 100;
return false;
case BAD_NONSTD_P2WSH:
if (strict) {
ret.reason = 'bad-witness-nonstandard';
ret.score = 0;
return false;
}
return true;
ret.reason = 'bad-witness-nonstandard';
ret.score = 0;
return false;
}
return true;
@ -1410,7 +1407,7 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(strict, ret) {
* @returns {Boolean}
*/
TX.prototype._hasStandardWitness = function _hasStandardWitness() {
TX.prototype.getWitnessStandard = function getWitnessStandard() {
var ret = BAD_OKAY;
var i, j, input, prev, hash, redeem, m, n;

View File

@ -28,12 +28,16 @@ describe('Mempool', function() {
verify: true
});
var w;
var w, cached;
mempool.on('error', function() {});
it('should open mempool', function(cb) {
mempool.open(cb);
mempool.open(function(err) {
assert.ifError(err);
chain.state.flags |= constants.flags.VERIFY_WITNESS;
cb();
});
});
it('should open walletdb', function(cb) {
@ -233,6 +237,169 @@ describe('Mempool', function() {
});
});
it('should not cache a malleated wtx with mutated sig', function(cb) {
var kp = bcoin.keyring.generate();
kp.witness = true;
// Coinbase
var t1 = bcoin.mtx().addOutput(w, 50000).addOutput(w, 10000); // 10000 instead of 1000
var prev = new bcoin.script([0, kp.keyHash]);
var prevHash = crypto.randomBytes(32).toString('hex');
var dummyInput = {
prevout: {
hash: prevHash,
index: 0
},
coin: {
version: 1,
height: 0,
value: 70000,
script: prev,
coinbase: false,
hash: prevHash,
index: 0
},
script: new bcoin.script([]),
sequence: 0xffffffff
};
t1.addInput(dummyInput);
var prevs = bcoin.script.fromPubkeyhash(kp.keyHash);
var sig = new bcoin.witness([t1.signature(0, prevs, kp.privateKey, 'all', 1), kp.publicKey]);
var sig2 = new bcoin.witness([t1.signature(0, prevs, kp.privateKey, 'all', 1), kp.publicKey]);
sig2.items[0][sig2.items[0].length - 1] = 0;
t1.inputs[0].witness = sig2;
var tx = t1.toTX();
mempool.addTX(tx, function(err) {
assert(err);
assert(!mempool.hasReject(tx.hash()));
cb();
});
});
it('should not cache a malleated tx with unnecessary witness', function(cb) {
var kp = bcoin.keyring.generate();
// Coinbase
var t1 = bcoin.mtx().addOutput(w, 50000).addOutput(w, 10000); // 10000 instead of 1000
var prev = new bcoin.script([kp.publicKey, opcodes.OP_CHECKSIG]);
var prevHash = crypto.randomBytes(32).toString('hex');
var dummyInput = {
prevout: {
hash: prevHash,
index: 0
},
coin: {
version: 1,
height: 0,
value: 70000,
script: prev,
coinbase: false,
hash: prevHash,
index: 0
},
script: new bcoin.script([]),
sequence: 0xffffffff
};
t1.addInput(dummyInput);
t1.inputs[0].script = new bcoin.script([t1.signature(0, prev, kp.privateKey, 'all', 0)]),
t1.inputs[0].witness.push(new Buffer(0));
var tx = t1.toTX();
mempool.addTX(tx, function(err) {
assert(err);
assert(!mempool.hasReject(tx.hash()));
cb();
});
});
it('should not cache a malleated wtx with wit removed', function(cb) {
var kp = bcoin.keyring.generate();
kp.witness = true;
// Coinbase
var t1 = bcoin.mtx().addOutput(w, 50000).addOutput(w, 10000); // 10000 instead of 1000
var prev = new bcoin.script([0, kp.keyHash]);
var prevHash = crypto.randomBytes(32).toString('hex');
var dummyInput = {
prevout: {
hash: prevHash,
index: 0
},
coin: {
version: 1,
height: 0,
value: 70000,
script: prev,
coinbase: false,
hash: prevHash,
index: 0
},
script: new bcoin.script([]),
sequence: 0xffffffff
};
t1.addInput(dummyInput);
var tx = t1.toTX();
mempool.addTX(tx, function(err) {
assert(err);
assert(err.malleated);
assert(!mempool.hasReject(tx.hash()));
cb();
});
});
it('should cache non-malleated tx without sig', function(cb) {
var kp = bcoin.keyring.generate();
// Coinbase
var t1 = bcoin.mtx().addOutput(w, 50000).addOutput(w, 10000); // 10000 instead of 1000
var prev = new bcoin.script([kp.publicKey, opcodes.OP_CHECKSIG]);
var prevHash = crypto.randomBytes(32).toString('hex');
var dummyInput = {
prevout: {
hash: prevHash,
index: 0
},
coin: {
version: 1,
height: 0,
value: 70000,
script: prev,
coinbase: false,
hash: prevHash,
index: 0
},
script: new bcoin.script([]),
sequence: 0xffffffff
};
t1.addInput(dummyInput);
var tx = t1.toTX();
mempool.addTX(tx, function(err) {
assert(err);
assert(!err.malleated);
assert(mempool.hasReject(tx.hash()));
cached = tx;
cb();
});
});
it('should clear reject cache', function(cb) {
var t1 = bcoin.mtx().addOutput(w, 50000);
var dummyInput = {
prevout: {
hash: constants.NULL_HASH,
index: 0xffffffff
},
coin: null,
script: new bcoin.script(),
sequence: 0xffffffff
};
t1.addInput(dummyInput);
var tx = t1.toTX();
var block = new bcoin.block();
block.txs.push(tx);
assert(mempool.hasReject(cached.hash()));
mempool.addBlock(block, function(err) {
assert(!err);
assert(!mempool.hasReject(cached.hash()));
cb();
});
});
it('should destroy mempool', function(cb) {
mempool.close(cb);
});