tests: use generators.
This commit is contained in:
parent
ed66e0b7cc
commit
44b78dd345
@ -14,7 +14,7 @@ var c = require('../lib/utils/spawn').cb;
|
||||
|
||||
describe('Chain', function() {
|
||||
var chain, wallet, node, miner, walletdb;
|
||||
var competingTip, oldTip, tip1, tip2, cb1, cb2;
|
||||
var tip1, tip2, cb1, cb2;
|
||||
|
||||
this.timeout(5000);
|
||||
|
||||
@ -24,254 +24,233 @@ describe('Chain', function() {
|
||||
miner = node.miner;
|
||||
node.on('error', function() {});
|
||||
|
||||
function mineBlock(tip, tx, callback) {
|
||||
c(miner.createBlock(tip), function(err, attempt) {
|
||||
assert.ifError(err);
|
||||
if (tx) {
|
||||
var redeemer = bcoin.mtx();
|
||||
redeemer.addOutput({
|
||||
address: wallet.receiveAddress.getAddress(),
|
||||
value: utils.satoshi('25.0')
|
||||
});
|
||||
redeemer.addOutput({
|
||||
address: wallet.changeAddress.getAddress(),
|
||||
value: utils.satoshi('5.0')
|
||||
});
|
||||
redeemer.addInput(tx, 0);
|
||||
redeemer.setLocktime(chain.height);
|
||||
return c(wallet.sign(redeemer), function(err) {
|
||||
assert.ifError(err);
|
||||
attempt.addTX(redeemer.toTX());
|
||||
callback(null, attempt.mineSync());
|
||||
});
|
||||
}
|
||||
callback(null, attempt.mineSync());
|
||||
var mineBlock = co(function* mineBlock(tip, tx) {
|
||||
var attempt = yield miner.createBlock(tip);
|
||||
var redeemer;
|
||||
|
||||
if (!tx)
|
||||
return attempt.mineSync();
|
||||
|
||||
redeemer = bcoin.mtx();
|
||||
|
||||
redeemer.addOutput({
|
||||
address: wallet.receiveAddress.getAddress(),
|
||||
value: 25 * 1e8
|
||||
});
|
||||
}
|
||||
|
||||
redeemer.addOutput({
|
||||
address: wallet.changeAddress.getAddress(),
|
||||
value: 5 * 1e8
|
||||
});
|
||||
|
||||
redeemer.addInput(tx, 0);
|
||||
|
||||
redeemer.setLocktime(chain.height);
|
||||
|
||||
yield wallet.sign(redeemer);
|
||||
|
||||
attempt.addTX(redeemer.toTX());
|
||||
|
||||
return attempt.mineSync();
|
||||
});
|
||||
|
||||
function deleteCoins(tx) {
|
||||
var i;
|
||||
|
||||
if (tx.txs) {
|
||||
deleteCoins(tx.txs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(tx)) {
|
||||
tx.forEach(deleteCoins);
|
||||
for (i = 0; i < tx.length; i++)
|
||||
deleteCoins(tx[i]);
|
||||
return;
|
||||
}
|
||||
tx.inputs.forEach(function(input) {
|
||||
input.coin = null;
|
||||
});
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++)
|
||||
tx.inputs[i].coin = null;
|
||||
}
|
||||
|
||||
it('should open chain and miner', function(cb) {
|
||||
it('should open chain and miner', cob(function *() {
|
||||
miner.mempool = null;
|
||||
constants.tx.COINBASE_MATURITY = 0;
|
||||
c(node.open(), cb);
|
||||
});
|
||||
yield node.open();
|
||||
}));
|
||||
|
||||
it('should open walletdb', function(cb) {
|
||||
c(walletdb.create({}), function(err, w) {
|
||||
assert.ifError(err);
|
||||
wallet = w;
|
||||
miner.address = wallet.getAddress();
|
||||
cb();
|
||||
});
|
||||
});
|
||||
it('should open walletdb', cob(function *() {
|
||||
wallet = yield walletdb.create();
|
||||
miner.address = wallet.getAddress();
|
||||
}));
|
||||
|
||||
it('should mine a block', function(cb) {
|
||||
c(miner.mineBlock(), function(err, block) {
|
||||
assert.ifError(err);
|
||||
assert(block);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
it('should mine a block', cob(function *() {
|
||||
var block = yield miner.mineBlock();
|
||||
assert(block);
|
||||
}));
|
||||
|
||||
it('should mine competing chains', function(cb) {
|
||||
utils.forRangeSerial(0, 10, function(i, next) {
|
||||
mineBlock(tip1, cb1, function(err, block1) {
|
||||
assert.ifError(err);
|
||||
cb1 = block1.txs[0];
|
||||
mineBlock(tip2, cb2, function(err, block2) {
|
||||
assert.ifError(err);
|
||||
cb2 = block2.txs[0];
|
||||
deleteCoins(block1);
|
||||
c(chain.add(block1), function(err) {
|
||||
assert.ifError(err);
|
||||
deleteCoins(block2);
|
||||
c(chain.add(block2), function(err) {
|
||||
assert.ifError(err);
|
||||
assert(chain.tip.hash === block1.hash('hex'));
|
||||
competingTip = block2.hash('hex');
|
||||
c(chain.db.get(block1.hash('hex')), function(err, entry1) {
|
||||
assert.ifError(err);
|
||||
c(chain.db.get(block2.hash('hex')), function(err, entry2) {
|
||||
assert.ifError(err);
|
||||
assert(entry1);
|
||||
assert(entry2);
|
||||
tip1 = entry1;
|
||||
tip2 = entry2;
|
||||
c(chain.db.isMainChain(block2.hash('hex')), function(err, result) {
|
||||
assert.ifError(err);
|
||||
assert(!result);
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}, cb);
|
||||
});
|
||||
it('should mine competing chains', cob(function *() {
|
||||
var i, block1, block2;
|
||||
|
||||
it('should have correct balance', function(cb) {
|
||||
setTimeout(function() {
|
||||
c(wallet.getBalance(), function(err, balance) {
|
||||
assert.equal(balance.unconfirmed, 0);
|
||||
assert.equal(balance.confirmed, 500 * 1e8);
|
||||
assert.equal(balance.total, 500 * 1e8);
|
||||
cb();
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
for (i = 0; i < 10; i++) {
|
||||
block1 = yield mineBlock(tip1, cb1);
|
||||
cb1 = block1.txs[0];
|
||||
|
||||
block2 = yield mineBlock(tip2, cb2);
|
||||
cb2 = block2.txs[0];
|
||||
|
||||
deleteCoins(block1);
|
||||
yield chain.add(block1);
|
||||
|
||||
deleteCoins(block2);
|
||||
yield chain.add(block2);
|
||||
|
||||
assert(chain.tip.hash === block1.hash('hex'));
|
||||
|
||||
tip1 = yield chain.db.get(block1.hash('hex'));
|
||||
tip2 = yield chain.db.get(block2.hash('hex'));
|
||||
|
||||
assert(tip1);
|
||||
assert(tip2);
|
||||
|
||||
assert(!(yield tip2.isMainChain()));
|
||||
}
|
||||
}));
|
||||
|
||||
it('should have correct balance', cob(function* () {
|
||||
var balance;
|
||||
|
||||
yield spawn.timeout(100);
|
||||
|
||||
balance = yield wallet.getBalance();
|
||||
assert.equal(balance.unconfirmed, 0);
|
||||
assert.equal(balance.confirmed, 500 * 1e8);
|
||||
assert.equal(balance.total, 500 * 1e8);
|
||||
}));
|
||||
|
||||
it('should handle a reorg', cob(function *() {
|
||||
var entry, block, forked;
|
||||
|
||||
it('should handle a reorg', function(cb) {
|
||||
assert.equal(walletdb.height, chain.height);
|
||||
assert.equal(chain.height, 10);
|
||||
oldTip = chain.tip;
|
||||
c(chain.db.get(competingTip), function(err, entry) {
|
||||
assert.ifError(err);
|
||||
assert(entry);
|
||||
assert(chain.height === entry.height);
|
||||
c(miner.mineBlock(entry), function(err, block) {
|
||||
assert.ifError(err);
|
||||
assert(block);
|
||||
var forked = false;
|
||||
chain.once('reorganize', function() {
|
||||
forked = true;
|
||||
});
|
||||
deleteCoins(block);
|
||||
c(chain.add(block), function(err) {
|
||||
assert.ifError(err);
|
||||
assert(forked);
|
||||
assert(chain.tip.hash === block.hash('hex'));
|
||||
assert(chain.tip.chainwork.cmp(oldTip.chainwork) > 0);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
||||
entry = yield chain.db.get(tip2.hash);
|
||||
assert(entry);
|
||||
assert(chain.height === entry.height);
|
||||
|
||||
block = yield miner.mineBlock(entry);
|
||||
assert(block);
|
||||
|
||||
forked = false;
|
||||
chain.once('reorganize', function() {
|
||||
forked = true;
|
||||
});
|
||||
});
|
||||
|
||||
it('should have correct balance', function(cb) {
|
||||
setTimeout(function() {
|
||||
c(wallet.getBalance(), function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.unconfirmed, 500 * 1e8);
|
||||
assert.equal(balance.confirmed, 550 * 1e8);
|
||||
assert.equal(balance.total, 1050 * 1e8);
|
||||
cb();
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
deleteCoins(block);
|
||||
|
||||
it('should check main chain', function(cb) {
|
||||
c(chain.db.isMainChain(oldTip), function(err, result) {
|
||||
assert.ifError(err);
|
||||
assert(!result);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
yield chain.add(block);
|
||||
|
||||
it('should mine a block after a reorg', function(cb) {
|
||||
mineBlock(null, cb2, function(err, block) {
|
||||
assert.ifError(err);
|
||||
deleteCoins(block);
|
||||
c(chain.add(block), function(err) {
|
||||
assert.ifError(err);
|
||||
c(chain.db.get(block.hash('hex')), function(err, entry) {
|
||||
assert.ifError(err);
|
||||
assert(entry);
|
||||
assert(chain.tip.hash === entry.hash);
|
||||
c(chain.db.isMainChain(entry.hash), function(err, result) {
|
||||
assert.ifError(err);
|
||||
assert(result);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
assert(forked);
|
||||
assert(chain.tip.hash === block.hash('hex'));
|
||||
assert(chain.tip.chainwork.cmp(tip1.chainwork) > 0);
|
||||
}));
|
||||
|
||||
it('should fail to mine a block with coins on an alternate chain', function(cb) {
|
||||
mineBlock(null, cb1, function(err, block) {
|
||||
assert.ifError(err);
|
||||
deleteCoins(block);
|
||||
c(chain.add(block), function(err) {
|
||||
assert(err);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should have correct balance', cob(function *() {
|
||||
var balance;
|
||||
|
||||
it('should get coin', function(cb) {
|
||||
mineBlock(null, null, function(err, block) {
|
||||
assert.ifError(err);
|
||||
c(chain.add(block), function(err) {
|
||||
assert.ifError(err);
|
||||
mineBlock(null, block.txs[0], function(err, block) {
|
||||
assert.ifError(err);
|
||||
c(chain.add(block), function(err) {
|
||||
assert.ifError(err);
|
||||
var tx = block.txs[1];
|
||||
var output = bcoin.coin.fromTX(tx, 1);
|
||||
c(chain.db.getCoin(tx.hash('hex'), 1), function(err, coin) {
|
||||
assert.ifError(err);
|
||||
assert.deepEqual(coin.toRaw(), output.toRaw());
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
yield spawn.timeout(100);
|
||||
|
||||
it('should get balance', function(cb) {
|
||||
setTimeout(function() {
|
||||
c(wallet.getBalance(), function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.unconfirmed, 500 * 1e8);
|
||||
assert.equal(balance.confirmed, 700 * 1e8);
|
||||
assert.equal(balance.total, 1200 * 1e8);
|
||||
assert(wallet.account.receiveDepth >= 8);
|
||||
assert(wallet.account.changeDepth >= 7);
|
||||
assert.equal(walletdb.height, chain.height);
|
||||
assert.equal(walletdb.tip, chain.tip.hash);
|
||||
c(wallet.getHistory(), function(err, txs) {
|
||||
assert.ifError(err);
|
||||
assert.equal(txs.length, 44);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
balance = yield wallet.getBalance();
|
||||
assert.equal(balance.unconfirmed, 500 * 1e8);
|
||||
assert.equal(balance.confirmed, 550 * 1e8);
|
||||
assert.equal(balance.total, 1050 * 1e8);
|
||||
}));
|
||||
|
||||
it('should rescan for transactions', function(cb) {
|
||||
it('should check main chain', cob(function *() {
|
||||
var result = yield tip1.isMainChain();
|
||||
assert(!result);
|
||||
}));
|
||||
|
||||
it('should mine a block after a reorg', cob(function *() {
|
||||
var block, entry, result;
|
||||
|
||||
block = yield mineBlock(null, cb2);
|
||||
deleteCoins(block);
|
||||
yield chain.add(block);
|
||||
|
||||
entry = yield chain.db.get(block.hash('hex'));
|
||||
assert(entry);
|
||||
assert(chain.tip.hash === entry.hash);
|
||||
|
||||
result = yield entry.isMainChain();
|
||||
assert(result);
|
||||
}));
|
||||
|
||||
it('should fail to mine a block with coins on an alternate chain', cob(function *() {
|
||||
var block = yield mineBlock(null, cb1);
|
||||
var err;
|
||||
|
||||
deleteCoins(block);
|
||||
|
||||
try {
|
||||
yield chain.add(block);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err);
|
||||
assert.equal(err.reason, 'bad-txns-inputs-missingorspent');
|
||||
}));
|
||||
|
||||
it('should get coin', cob(function *() {
|
||||
var block, tx, output, coin;
|
||||
|
||||
block = yield mineBlock();
|
||||
yield chain.add(block);
|
||||
block = yield mineBlock(null, block.txs[0]);
|
||||
yield chain.add(block);
|
||||
|
||||
tx = block.txs[1];
|
||||
output = bcoin.coin.fromTX(tx, 1);
|
||||
|
||||
coin = yield chain.db.getCoin(tx.hash('hex'), 1);
|
||||
|
||||
assert.deepEqual(coin.toRaw(), output.toRaw());
|
||||
}));
|
||||
|
||||
it('should get balance', cob(function *() {
|
||||
var balance, txs;
|
||||
|
||||
yield spawn.timeout(100);
|
||||
|
||||
balance = yield wallet.getBalance();
|
||||
assert.equal(balance.unconfirmed, 500 * 1e8);
|
||||
assert.equal(balance.confirmed, 700 * 1e8);
|
||||
assert.equal(balance.total, 1200 * 1e8);
|
||||
|
||||
assert(wallet.account.receiveDepth >= 8);
|
||||
assert(wallet.account.changeDepth >= 7);
|
||||
|
||||
assert.equal(walletdb.height, chain.height);
|
||||
assert.equal(walletdb.tip, chain.tip.hash);
|
||||
|
||||
txs = yield wallet.getHistory();
|
||||
assert.equal(txs.length, 44);
|
||||
}));
|
||||
|
||||
it('should rescan for transactions', cob(function *() {
|
||||
var total = 0;
|
||||
c(walletdb.getAddressHashes(), function(err, hashes) {
|
||||
assert.ifError(err);
|
||||
c(chain.db.scan(null, hashes, function(block, txs) {
|
||||
total += txs.length;
|
||||
return Promise.resolve(null);
|
||||
}), function(err) {
|
||||
assert.ifError(err);
|
||||
assert.equal(total, 25);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
var hashes = yield walletdb.getAddressHashes();
|
||||
|
||||
it('should cleanup', function(cb) {
|
||||
yield chain.db.scan(null, hashes, function(block, txs) {
|
||||
total += txs.length;
|
||||
return Promise.resolve(null);
|
||||
});
|
||||
|
||||
assert.equal(total, 25);
|
||||
}));
|
||||
|
||||
it('should cleanup', cob(function *() {
|
||||
constants.tx.COINBASE_MATURITY = 100;
|
||||
c(node.close(), cb);
|
||||
});
|
||||
yield node.close();
|
||||
}));
|
||||
});
|
||||
|
||||
@ -8,379 +8,356 @@ var crypto = require('../lib/crypto/crypto');
|
||||
var assert = require('assert');
|
||||
var opcodes = constants.opcodes;
|
||||
var c = require('../lib/utils/spawn').cb;
|
||||
var cob = require('../lib/utils/spawn').cob;
|
||||
|
||||
function dummy(prev, prevHash) {
|
||||
if (!prevHash)
|
||||
prevHash = constants.ONE_HASH.toString('hex');
|
||||
|
||||
return {
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
describe('Mempool', function() {
|
||||
var chain, mempool, walletdb;
|
||||
var wallet, cached;
|
||||
|
||||
this.timeout(5000);
|
||||
|
||||
var chain = new bcoin.chain({
|
||||
chain = new bcoin.chain({
|
||||
name: 'mp-chain',
|
||||
db: 'memory'
|
||||
});
|
||||
|
||||
var mempool = new bcoin.mempool({
|
||||
mempool = new bcoin.mempool({
|
||||
chain: chain,
|
||||
name: 'mempool-test',
|
||||
db: 'memory'
|
||||
});
|
||||
|
||||
var walletdb = new bcoin.walletdb({
|
||||
walletdb = new bcoin.walletdb({
|
||||
name: 'mempool-wallet-test',
|
||||
db: 'memory',
|
||||
verify: true
|
||||
});
|
||||
|
||||
var w, cached;
|
||||
it('should open mempool', cob(function *() {
|
||||
yield mempool.open();
|
||||
chain.state.flags |= constants.flags.VERIFY_WITNESS;
|
||||
}));
|
||||
|
||||
mempool.on('error', function() {});
|
||||
it('should open walletdb', cob(function *() {
|
||||
yield walletdb.open();
|
||||
}));
|
||||
|
||||
it('should open mempool', function(cb) {
|
||||
c(mempool.open(), function(err) {
|
||||
assert.ifError(err);
|
||||
chain.state.flags |= constants.flags.VERIFY_WITNESS;
|
||||
cb();
|
||||
});
|
||||
});
|
||||
it('should open wallet', cob(function *() {
|
||||
wallet = yield walletdb.create();
|
||||
}));
|
||||
|
||||
it('should open walletdb', function(cb) {
|
||||
c(walletdb.open(), cb);
|
||||
});
|
||||
|
||||
it('should open wallet', function(cb) {
|
||||
c(walletdb.create({}), function(err, wallet) {
|
||||
assert.ifError(err);
|
||||
w = wallet;
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle incoming orphans and TXs', function(cb) {
|
||||
it('should handle incoming orphans and TXs', cob(function *() {
|
||||
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 dummyInput = {
|
||||
prevout: {
|
||||
hash: constants.ONE_HASH.toString('hex'),
|
||||
index: 0
|
||||
},
|
||||
coin: {
|
||||
version: 1,
|
||||
height: 0,
|
||||
value: 70000,
|
||||
script: prev,
|
||||
coinbase: false,
|
||||
hash: constants.ONE_HASH.toString('hex'),
|
||||
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)]),
|
||||
var w = wallet;
|
||||
var t1, t2, t3, t4, f1, fake, prev, sig, balance, txs;
|
||||
|
||||
t1 = bcoin.mtx()
|
||||
.addOutput(w.getAddress(), 50000)
|
||||
.addOutput(w.getAddress(), 10000);
|
||||
|
||||
prev = new bcoin.script([kp.publicKey, opcodes.OP_CHECKSIG]);
|
||||
t1.addInput(dummy(prev));
|
||||
sig = t1.signature(0, prev, kp.privateKey, 'all', 0);
|
||||
t1.inputs[0].script = new bcoin.script([sig]),
|
||||
|
||||
// balance: 51000
|
||||
c(w.sign(t1), function(err, total) {
|
||||
assert.ifError(err);
|
||||
t1 = t1.toTX();
|
||||
var t2 = bcoin.mtx().addInput(t1, 0) // 50000
|
||||
.addOutput(w, 20000)
|
||||
.addOutput(w, 20000);
|
||||
// balance: 49000
|
||||
c(w.sign(t2), function(err, total) {
|
||||
assert.ifError(err);
|
||||
t2 = t2.toTX();
|
||||
var t3 = bcoin.mtx().addInput(t1, 1) // 10000
|
||||
.addInput(t2, 0) // 20000
|
||||
.addOutput(w, 23000);
|
||||
// balance: 47000
|
||||
c(w.sign(t3), function(err, total) {
|
||||
assert.ifError(err);
|
||||
t3 = t3.toTX();
|
||||
var t4 = bcoin.mtx().addInput(t2, 1) // 24000
|
||||
.addInput(t3, 0) // 23000
|
||||
.addOutput(w, 11000)
|
||||
.addOutput(w, 11000);
|
||||
// balance: 22000
|
||||
c(w.sign(t4), function(err, total) {
|
||||
assert.ifError(err);
|
||||
t4 = t4.toTX();
|
||||
var f1 = bcoin.mtx().addInput(t4, 1) // 11000
|
||||
.addOutput(bcoin.address.fromData(new Buffer([])).toBase58(), 9000);
|
||||
// balance: 11000
|
||||
c(w.sign(f1), function(err, total) {
|
||||
assert.ifError(err);
|
||||
f1 = f1.toTX();
|
||||
var fake = bcoin.mtx().addInput(t1, 1) // 1000 (already redeemed)
|
||||
.addOutput(w, 6000); // 6000 instead of 500
|
||||
// Script inputs but do not sign
|
||||
c(w.template(fake), function(err) {
|
||||
assert.ifError(err);
|
||||
// Fake signature
|
||||
fake.inputs[0].script.set(0, new Buffer([0,0,0,0,0,0,0,0,0]));
|
||||
fake.inputs[0].script.compile();
|
||||
fake = fake.toTX();
|
||||
// balance: 11000
|
||||
[t2, t3, t4, f1, fake].forEach(function(tx) {
|
||||
tx.inputs.forEach(function(input) {
|
||||
input.coin = null;
|
||||
});
|
||||
});
|
||||
yield w.sign(t1);
|
||||
t1 = t1.toTX();
|
||||
|
||||
c(mempool.addTX(fake), function(err) {
|
||||
assert.ifError(err);
|
||||
c(mempool.addTX(t4), function(err) {
|
||||
assert.ifError(err);
|
||||
var balance = mempool.getBalance();
|
||||
assert.equal(balance, 0);
|
||||
c(mempool.addTX(t1), function(err) {
|
||||
assert.ifError(err);
|
||||
var balance = mempool.getBalance();
|
||||
assert.equal(balance, 60000);
|
||||
c(mempool.addTX(t2), function(err) {
|
||||
assert.ifError(err);
|
||||
var balance = mempool.getBalance();
|
||||
assert.equal(balance, 50000);
|
||||
c(mempool.addTX(t3), function(err) {
|
||||
assert.ifError(err);
|
||||
var balance = mempool.getBalance();
|
||||
assert.equal(balance, 22000);
|
||||
c(mempool.addTX(f1), function(err) {
|
||||
assert.ifError(err);
|
||||
var balance = mempool.getBalance();
|
||||
assert.equal(balance, 20000);
|
||||
var txs = mempool.getHistory();
|
||||
assert(txs.some(function(tx) {
|
||||
return tx.hash('hex') === f1.hash('hex');
|
||||
}));
|
||||
t2 = bcoin.mtx()
|
||||
.addInput(t1, 0) // 50000
|
||||
.addOutput(w.getAddress(), 20000)
|
||||
.addOutput(w.getAddress(), 20000);
|
||||
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
// balance: 49000
|
||||
yield w.sign(t2);
|
||||
t2 = t2.toTX();
|
||||
|
||||
t3 = bcoin.mtx()
|
||||
.addInput(t1, 1) // 10000
|
||||
.addInput(t2, 0) // 20000
|
||||
.addOutput(w.getAddress(), 23000);
|
||||
|
||||
// balance: 47000
|
||||
yield w.sign(t3);
|
||||
t3 = t3.toTX();
|
||||
|
||||
t4 = bcoin.mtx()
|
||||
.addInput(t2, 1) // 24000
|
||||
.addInput(t3, 0) // 23000
|
||||
.addOutput(w.getAddress(), 11000)
|
||||
.addOutput(w.getAddress(), 11000);
|
||||
|
||||
// balance: 22000
|
||||
yield w.sign(t4);
|
||||
t4 = t4.toTX();
|
||||
|
||||
f1 = bcoin.mtx()
|
||||
.addInput(t4, 1) // 11000
|
||||
.addOutput(new bcoin.address(), 9000);
|
||||
|
||||
// balance: 11000
|
||||
yield w.sign(f1);
|
||||
f1 = f1.toTX();
|
||||
|
||||
fake = bcoin.mtx()
|
||||
.addInput(t1, 1) // 1000 (already redeemed)
|
||||
.addOutput(w.getAddress(), 6000); // 6000 instead of 500
|
||||
|
||||
// Script inputs but do not sign
|
||||
yield w.template(fake);
|
||||
|
||||
// Fake signature
|
||||
fake.inputs[0].script.set(0, constants.ZERO_SIG);
|
||||
fake.inputs[0].script.compile();
|
||||
fake = fake.toTX();
|
||||
// balance: 11000
|
||||
|
||||
[t2, t3, t4, f1, fake].forEach(function(tx) {
|
||||
tx.inputs.forEach(function(input) {
|
||||
input.coin = null;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle locktime', function(cb) {
|
||||
yield mempool.addTX(fake);
|
||||
yield mempool.addTX(t4);
|
||||
|
||||
balance = mempool.getBalance();
|
||||
assert.equal(balance, 0);
|
||||
|
||||
yield mempool.addTX(t1);
|
||||
|
||||
balance = mempool.getBalance();
|
||||
assert.equal(balance, 60000);
|
||||
|
||||
yield mempool.addTX(t2);
|
||||
|
||||
balance = mempool.getBalance();
|
||||
assert.equal(balance, 50000);
|
||||
|
||||
yield mempool.addTX(t3);
|
||||
|
||||
balance = mempool.getBalance();
|
||||
assert.equal(balance, 22000);
|
||||
|
||||
yield mempool.addTX(f1);
|
||||
|
||||
balance = mempool.getBalance();
|
||||
assert.equal(balance, 20000);
|
||||
|
||||
txs = mempool.getHistory();
|
||||
assert(txs.some(function(tx) {
|
||||
return tx.hash('hex') === f1.hash('hex');
|
||||
}));
|
||||
}));
|
||||
|
||||
it('should handle locktime', cob(function *() {
|
||||
var w = wallet;
|
||||
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.setLocktime(200);
|
||||
var tx, prev, prevHash, sig;
|
||||
|
||||
tx = bcoin.mtx()
|
||||
.addOutput(w.getAddress(), 50000)
|
||||
.addOutput(w.getAddress(), 10000);
|
||||
|
||||
prev = new bcoin.script([kp.publicKey, opcodes.OP_CHECKSIG]);
|
||||
prevHash = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
tx.addInput(dummy(prev, prevHash));
|
||||
tx.setLocktime(200);
|
||||
|
||||
chain.tip.height = 200;
|
||||
t1.inputs[0].script = new bcoin.script([t1.signature(0, prev, kp.privateKey, 'all', 0)]),
|
||||
t1 = t1.toTX();
|
||||
c(mempool.addTX(t1), function(err) {
|
||||
chain.tip.height = 0;
|
||||
assert.ifError(err);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle invalid locktime', function(cb) {
|
||||
sig = tx.signature(0, prev, kp.privateKey, 'all', 0);
|
||||
tx.inputs[0].script = new bcoin.script([sig]),
|
||||
|
||||
tx = tx.toTX();
|
||||
|
||||
yield mempool.addTX(tx);
|
||||
chain.tip.height = 0;
|
||||
}));
|
||||
|
||||
it('should handle invalid locktime', cob(function *() {
|
||||
var w = wallet;
|
||||
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.setLocktime(200);
|
||||
var tx, prev, prevHash, sig, err;
|
||||
|
||||
tx = bcoin.mtx()
|
||||
.addOutput(w.getAddress(), 50000)
|
||||
.addOutput(w.getAddress(), 10000);
|
||||
|
||||
prev = new bcoin.script([kp.publicKey, opcodes.OP_CHECKSIG]);
|
||||
prevHash = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
tx.addInput(dummy(prev, prevHash));
|
||||
tx.setLocktime(200);
|
||||
chain.tip.height = 200 - 1;
|
||||
t1.inputs[0].script = new bcoin.script([t1.signature(0, prev, kp.privateKey, 'all', 0)]),
|
||||
t1 = t1.toTX();
|
||||
c(mempool.addTX(t1), function(err) {
|
||||
chain.tip.height = 0;
|
||||
assert(err);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not cache a malleated wtx with mutated sig', function(cb) {
|
||||
sig = tx.signature(0, prev, kp.privateKey, 'all', 0);
|
||||
tx.inputs[0].script = new bcoin.script([sig]),
|
||||
tx = tx.toTX();
|
||||
|
||||
try {
|
||||
yield mempool.addTX(tx);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err);
|
||||
|
||||
chain.tip.height = 0;
|
||||
}));
|
||||
|
||||
it('should not cache a malleated wtx with mutated sig', cob(function *() {
|
||||
var w = wallet;
|
||||
var kp = bcoin.keyring.generate();
|
||||
var tx, prev, prevHash, prevs, sig, tx, err;
|
||||
|
||||
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();
|
||||
c(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();
|
||||
c(mempool.addTX(tx), function(err) {
|
||||
assert(err);
|
||||
assert(!mempool.hasReject(tx.hash()));
|
||||
cb();
|
||||
});
|
||||
});
|
||||
tx = bcoin.mtx()
|
||||
.addOutput(w.getAddress(), 50000)
|
||||
.addOutput(w.getAddress(), 10000);
|
||||
|
||||
it('should not cache a malleated wtx with wit removed', function(cb) {
|
||||
prev = new bcoin.script([0, kp.keyHash]);
|
||||
prevHash = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
tx.addInput(dummy(prev, prevHash));
|
||||
|
||||
prevs = bcoin.script.fromPubkeyhash(kp.keyHash);
|
||||
|
||||
sig = tx.signature(0, prevs, kp.privateKey, 'all', 1);
|
||||
sig[sig.length - 1] = 0;
|
||||
tx.inputs[0].witness = new bcoin.witness([sig, kp.publicKey]);
|
||||
tx = tx.toTX();
|
||||
|
||||
try {
|
||||
yield mempool.addTX(tx);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err);
|
||||
assert(!mempool.hasReject(tx.hash()));
|
||||
}));
|
||||
|
||||
it('should not cache a malleated tx with unnecessary witness', cob(function *() {
|
||||
var w = wallet;
|
||||
var kp = bcoin.keyring.generate();
|
||||
var tx, prev, prevHash, sig, tx, err;
|
||||
|
||||
tx = bcoin.mtx()
|
||||
.addOutput(w.getAddress(), 50000)
|
||||
.addOutput(w.getAddress(), 10000);
|
||||
|
||||
prev = new bcoin.script([kp.publicKey, opcodes.OP_CHECKSIG]);
|
||||
prevHash = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
tx.addInput(dummy(prev, prevHash));
|
||||
|
||||
sig = tx.signature(0, prev, kp.privateKey, 'all', 0);
|
||||
tx.inputs[0].script = new bcoin.script([sig]);
|
||||
tx.inputs[0].witness.push(new Buffer(0));
|
||||
tx = tx.toTX();
|
||||
|
||||
try {
|
||||
yield mempool.addTX(tx);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err);
|
||||
assert(!mempool.hasReject(tx.hash()));
|
||||
}));
|
||||
|
||||
it('should not cache a malleated wtx with wit removed', cob(function *() {
|
||||
var w = wallet;
|
||||
var kp = bcoin.keyring.generate();
|
||||
var tx, prev, prevHash, tx, err;
|
||||
|
||||
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();
|
||||
c(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) {
|
||||
tx = bcoin.mtx()
|
||||
.addOutput(w.getAddress(), 50000)
|
||||
.addOutput(w.getAddress(), 10000);
|
||||
|
||||
prev = new bcoin.script([0, kp.keyHash]);
|
||||
prevHash = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
tx.addInput(dummy(prev, prevHash));
|
||||
|
||||
tx = tx.toTX();
|
||||
|
||||
try {
|
||||
yield mempool.addTX(tx);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err);
|
||||
assert(err.malleated);
|
||||
assert(!mempool.hasReject(tx.hash()));
|
||||
}));
|
||||
|
||||
it('should cache non-malleated tx without sig', cob(function *() {
|
||||
var w = wallet;
|
||||
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();
|
||||
c(mempool.addTX(tx), function(err) {
|
||||
assert(err);
|
||||
assert(!err.malleated);
|
||||
assert(mempool.hasReject(tx.hash()));
|
||||
cached = tx;
|
||||
cb();
|
||||
});
|
||||
});
|
||||
var tx, prev, prevHash, tx, err;
|
||||
|
||||
it('should clear reject cache', function(cb) {
|
||||
var t1 = bcoin.mtx().addOutput(w, 50000);
|
||||
var dummyInput = {
|
||||
tx = bcoin.mtx()
|
||||
.addOutput(w.getAddress(), 50000)
|
||||
.addOutput(w.getAddress(), 10000);
|
||||
|
||||
prev = new bcoin.script([kp.publicKey, opcodes.OP_CHECKSIG]);
|
||||
prevHash = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
tx.addInput(dummy(prev, prevHash));
|
||||
|
||||
tx = tx.toTX();
|
||||
|
||||
try {
|
||||
yield mempool.addTX(tx);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(err);
|
||||
assert(!err.malleated);
|
||||
assert(mempool.hasReject(tx.hash()));
|
||||
cached = tx;
|
||||
}));
|
||||
|
||||
it('should clear reject cache', cob(function *() {
|
||||
var w = wallet;
|
||||
var tx, input, tx, block;
|
||||
|
||||
tx = bcoin.mtx()
|
||||
.addOutput(w.getAddress(), 50000);
|
||||
|
||||
input = {
|
||||
prevout: {
|
||||
hash: constants.NULL_HASH,
|
||||
index: 0xffffffff
|
||||
@ -389,19 +366,20 @@ describe('Mempool', function() {
|
||||
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()));
|
||||
c(mempool.addBlock(block), function(err) {
|
||||
assert(!err);
|
||||
assert(!mempool.hasReject(cached.hash()));
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
||||
it('should destroy mempool', function(cb) {
|
||||
c(mempool.close(), cb);
|
||||
});
|
||||
tx.addInput(input);
|
||||
|
||||
tx = tx.toTX();
|
||||
|
||||
block = new bcoin.block();
|
||||
block.txs.push(tx);
|
||||
|
||||
assert(mempool.hasReject(cached.hash()));
|
||||
yield mempool.addBlock(block);
|
||||
assert(!mempool.hasReject(cached.hash()));
|
||||
}));
|
||||
|
||||
it('should destroy mempool', cob(function *() {
|
||||
yield mempool.close();
|
||||
}));
|
||||
});
|
||||
|
||||
1666
test/wallet-test.js
1666
test/wallet-test.js
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user