255 lines
5.8 KiB
JavaScript
255 lines
5.8 KiB
JavaScript
'use strict';
|
|
|
|
var BN = require('bn.js');
|
|
var bcoin = require('../').set('regtest');
|
|
var constants = bcoin.constants;
|
|
var utils = bcoin.utils;
|
|
var crypto = require('../lib/crypto/crypto');
|
|
var assert = require('assert');
|
|
var opcodes = constants.opcodes;
|
|
var co = require('../lib/utils/co');
|
|
var cob = co.cob;
|
|
|
|
describe('Chain', function() {
|
|
var chain, wallet, node, miner, walletdb;
|
|
var tip1, tip2, cb1, cb2;
|
|
|
|
this.timeout(5000);
|
|
|
|
node = new bcoin.fullnode({ db: 'memory' });
|
|
chain = node.chain;
|
|
walletdb = node.walletdb;
|
|
miner = node.miner;
|
|
node.on('error', function() {});
|
|
|
|
var mineBlock = co(function* mineBlock(tip, tx) {
|
|
var attempt = yield miner.createBlock(tip);
|
|
var redeemer;
|
|
|
|
if (!tx)
|
|
return yield attempt.mineAsync();
|
|
|
|
redeemer = bcoin.mtx();
|
|
|
|
redeemer.addOutput({
|
|
address: wallet.receive.getAddress(),
|
|
value: 25 * 1e8
|
|
});
|
|
|
|
redeemer.addOutput({
|
|
address: wallet.change.getAddress(),
|
|
value: 5 * 1e8
|
|
});
|
|
|
|
redeemer.addInput(tx, 0);
|
|
|
|
redeemer.setLocktime(chain.height);
|
|
|
|
yield wallet.sign(redeemer);
|
|
|
|
attempt.addTX(redeemer.toTX());
|
|
|
|
return yield attempt.mineAsync();
|
|
});
|
|
|
|
function deleteCoins(tx) {
|
|
var i;
|
|
|
|
if (tx.txs) {
|
|
deleteCoins(tx.txs);
|
|
return;
|
|
}
|
|
|
|
if (Array.isArray(tx)) {
|
|
for (i = 0; i < tx.length; i++)
|
|
deleteCoins(tx[i]);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < tx.inputs.length; i++)
|
|
tx.inputs[i].coin = null;
|
|
}
|
|
|
|
it('should open chain and miner', cob(function* () {
|
|
miner.mempool = null;
|
|
constants.tx.COINBASE_MATURITY = 0;
|
|
yield node.open();
|
|
}));
|
|
|
|
it('should open walletdb', cob(function* () {
|
|
wallet = yield walletdb.create();
|
|
miner.address = wallet.getAddress();
|
|
}));
|
|
|
|
it('should mine a block', cob(function* () {
|
|
var block = yield miner.mineBlock();
|
|
assert(block);
|
|
}));
|
|
|
|
it('should mine competing chains', cob(function* () {
|
|
var i, block1, block2;
|
|
|
|
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 co.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;
|
|
|
|
assert.equal(walletdb.height, chain.height);
|
|
assert.equal(chain.height, 10);
|
|
|
|
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;
|
|
});
|
|
|
|
deleteCoins(block);
|
|
|
|
yield chain.add(block);
|
|
|
|
assert(forked);
|
|
assert(chain.tip.hash === block.hash('hex'));
|
|
assert(chain.tip.chainwork.cmp(tip1.chainwork) > 0);
|
|
}));
|
|
|
|
it('should have correct balance', cob(function* () {
|
|
var balance;
|
|
|
|
yield co.timeout(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 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 co.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;
|
|
var hashes = yield walletdb.getHashes();
|
|
|
|
yield chain.db.scan(null, hashes, function(block, txs) {
|
|
total += txs.length;
|
|
return Promise.resolve();
|
|
});
|
|
|
|
assert.equal(total, 25);
|
|
}));
|
|
|
|
it('should cleanup', cob(function* () {
|
|
constants.tx.COINBASE_MATURITY = 100;
|
|
yield node.close();
|
|
}));
|
|
});
|