181 lines
4.8 KiB
JavaScript
181 lines
4.8 KiB
JavaScript
var bn = require('bn.js');
|
|
delete process.env.BCOIN_NETWORK;
|
|
var bcoin = require('../')({ network: 'regtest', db: 'memory' });
|
|
process.env.BCOIN_NETWORK = 'main';
|
|
var constants = bcoin.protocol.constants;
|
|
var utils = bcoin.utils;
|
|
var assert = utils.assert;
|
|
var opcodes = constants.opcodes;
|
|
|
|
constants.tx.coinbaseMaturity = 0;
|
|
|
|
describe('Chain', function() {
|
|
var chain, wallet, miner;
|
|
var competingTip, oldTip, ch1, ch2, cb1, cb2;
|
|
|
|
chain = new bcoin.chain();
|
|
wallet = new bcoin.wallet();
|
|
miner = new bcoin.miner({
|
|
chain: chain,
|
|
address: wallet.getAddress()
|
|
});
|
|
|
|
chain.on('error', function() {});
|
|
miner.on('error', function() {});
|
|
|
|
function mineBlock(entry, tx, callback) {
|
|
var realTip;
|
|
if (entry) {
|
|
realTip = chain.tip;
|
|
chain.tip = entry;
|
|
}
|
|
miner.createBlock(function(err, attempt) {
|
|
if (realTip)
|
|
chain.tip = realTip;
|
|
assert.noError(err);
|
|
if (tx) {
|
|
var redeemer = bcoin.mtx();
|
|
redeemer.addOutput({
|
|
address: wallet.getAddress(),
|
|
value: utils.satoshi('25.0')
|
|
});
|
|
redeemer.addInput(tx, 0);
|
|
wallet.sign(redeemer);
|
|
attempt.addTX(redeemer);
|
|
}
|
|
callback(null, attempt.mineSync());
|
|
});
|
|
}
|
|
|
|
function deleteCoins(tx) {
|
|
if (Array.isArray(tx)) {
|
|
tx.forEach(deleteCoins);
|
|
return;
|
|
}
|
|
tx.inputs.forEach(function(input) {
|
|
delete input.coin;
|
|
});
|
|
}
|
|
|
|
it('should open chain and miner', function(cb) {
|
|
miner.open(cb);
|
|
});
|
|
|
|
it('should mine a block', function(cb) {
|
|
miner.mineBlock(function(err, block) {
|
|
assert.noError(err);
|
|
assert(block);
|
|
cb();
|
|
});
|
|
});
|
|
|
|
it('should mine competing chains', function(cb) {
|
|
utils.forRangeSerial(0, 10, function(i, next) {
|
|
mineBlock(ch1, cb1, function(err, chain1) {
|
|
assert.noError(err);
|
|
cb1 = chain1.txs[0];
|
|
mineBlock(ch2, cb2, function(err, chain2) {
|
|
assert.noError(err);
|
|
cb2 = chain2.txs[0];
|
|
deleteCoins(chain1.txs);
|
|
chain.add(chain1, function(err) {
|
|
assert.noError(err);
|
|
deleteCoins(chain2.txs);
|
|
chain.add(chain2, function(err) {
|
|
assert.noError(err);
|
|
assert(chain.tip.hash === chain1.hash('hex'));
|
|
competingTip = chain2.hash('hex');
|
|
chain.db.get(chain1.hash('hex'), function(err, entry1) {
|
|
assert.noError(err);
|
|
chain.db.get(chain2.hash('hex'), function(err, entry2) {
|
|
assert.noError(err);
|
|
assert(entry1);
|
|
assert(entry2);
|
|
ch1 = entry1;
|
|
ch2 = entry2;
|
|
chain.db.isMainChain(chain2.hash('hex'), function(err, result) {
|
|
assert.noError(err);
|
|
assert(!result);
|
|
next();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}, cb);
|
|
});
|
|
|
|
it('should handle a reorg', function(cb) {
|
|
oldTip = chain.tip;
|
|
chain.db.get(competingTip, function(err, entry) {
|
|
assert.noError(err);
|
|
assert(entry);
|
|
assert(chain.height === entry.height);
|
|
chain.tip = entry;
|
|
miner.mineBlock(function(err, reorg) {
|
|
assert.noError(err);
|
|
assert(reorg);
|
|
chain.tip = oldTip;
|
|
var forked = false;
|
|
chain.once('fork', function() {
|
|
forked = true;
|
|
});
|
|
deleteCoins(reorg.txs);
|
|
chain.add(reorg, function(err) {
|
|
assert.noError(err);
|
|
assert(forked);
|
|
assert(chain.tip.hash === reorg.hash('hex'));
|
|
assert(chain.tip.chainwork.cmp(oldTip.chainwork) > 0);
|
|
cb();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should check main chain', function(cb) {
|
|
chain.db.isMainChain(oldTip, function(err, result) {
|
|
assert.noError(err);
|
|
assert(!result);
|
|
cb();
|
|
});
|
|
});
|
|
|
|
it('should mine a block after a reorg', function(cb) {
|
|
mineBlock(null, cb2, function(err, block) {
|
|
assert.noError(err);
|
|
deleteCoins(block.txs);
|
|
chain.add(block, function(err) {
|
|
assert.noError(err);
|
|
chain.db.get(block.hash('hex'), function(err, entry) {
|
|
assert.noError(err);
|
|
assert(entry);
|
|
assert(chain.tip.hash === entry.hash);
|
|
chain.db.isMainChain(entry.hash, function(err, result) {
|
|
assert.noError(err);
|
|
assert(result);
|
|
cb();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should fail to mine a block with coins on a side chain', function(cb) {
|
|
mineBlock(null, cb1, function(err, block) {
|
|
assert.noError(err);
|
|
deleteCoins(block.txs);
|
|
chain.add(block, function(err) {
|
|
assert(err);
|
|
cb();
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should cleanup', function(cb) {
|
|
constants.tx.coinbaseMaturity = 100;
|
|
cb();
|
|
});
|
|
});
|