test: tx sigops tests. more chain tests.
This commit is contained in:
parent
389adee8f0
commit
cc16b48cf4
@ -3,6 +3,7 @@
|
||||
var assert = require('assert');
|
||||
var BN = require('bn.js');
|
||||
var consensus = require('../lib/protocol/consensus');
|
||||
var encoding = require('../lib/utils/encoding');
|
||||
var co = require('../lib/utils/co');
|
||||
var Coin = require('../lib/primitives/coin');
|
||||
var Script = require('../lib/script/script');
|
||||
@ -10,29 +11,47 @@ var Chain = require('../lib/blockchain/chain');
|
||||
var Miner = require('../lib/mining/miner');
|
||||
var MTX = require('../lib/primitives/mtx');
|
||||
var MemWallet = require('./util/memwallet');
|
||||
var Network = require('../lib/protocol/network');
|
||||
var Output = require('../lib/primitives/output');
|
||||
var util = require('../lib/utils/util');
|
||||
var opcodes = Script.opcodes;
|
||||
|
||||
describe('Chain', function() {
|
||||
var chain = new Chain({ db: 'memory', network: 'regtest' });
|
||||
var miner = new Miner({ chain: chain });
|
||||
var wallet = new MemWallet({ network: 'regtest' });
|
||||
var tip1, tip2, cb1, cb2, mineBlock;
|
||||
var network = Network.get('regtest');
|
||||
var chain = new Chain({ db: 'memory', network: network });
|
||||
var miner = new Miner({ chain: chain, version: 4 });
|
||||
var wallet = new MemWallet({ network: network });
|
||||
var wwallet = new MemWallet({ network: network, witness: true });
|
||||
var tip1, tip2, cb1, cb2, addBlock, mineCSV;
|
||||
|
||||
this.timeout(5000);
|
||||
this.timeout(45000);
|
||||
|
||||
mineBlock = co(function* mineBlock(tip, tx) {
|
||||
var attempt = yield miner.createBlock(tip);
|
||||
addBlock = co(function* addBlock(attempt) {
|
||||
var block = yield attempt.mineAsync();
|
||||
try {
|
||||
yield chain.add(block);
|
||||
} catch (e) {
|
||||
assert(e.type === 'VerifyError');
|
||||
return e.reason;
|
||||
}
|
||||
return 'OK';
|
||||
});
|
||||
|
||||
mineCSV = co(function* mineCSV(tx) {
|
||||
var attempt = yield miner.createBlock();
|
||||
var rtx;
|
||||
|
||||
if (!tx)
|
||||
return yield attempt.mineAsync();
|
||||
|
||||
rtx = new MTX();
|
||||
|
||||
rtx.addTX(tx, 0);
|
||||
rtx.addOutput({
|
||||
script: [
|
||||
Script.array(new BN(1)),
|
||||
Script.opcodes.OP_CHECKSEQUENCEVERIFY
|
||||
],
|
||||
value: 10000
|
||||
});
|
||||
|
||||
rtx.addOutput(wallet.getReceive(), 25 * 1e8);
|
||||
rtx.addOutput(wallet.getChange(), 5 * 1e8);
|
||||
rtx.addTX(tx, 0);
|
||||
|
||||
rtx.setLocktime(chain.height);
|
||||
|
||||
@ -52,40 +71,57 @@ describe('Chain', function() {
|
||||
});
|
||||
|
||||
it('should open chain and miner', co(function* () {
|
||||
consensus.COINBASE_MATURITY = 0;
|
||||
yield chain.open();
|
||||
yield miner.open();
|
||||
}));
|
||||
|
||||
it('should open wallet', co(function* () {
|
||||
it('should add addrs to miner', co(function* () {
|
||||
miner.addresses.length = 0;
|
||||
miner.addAddress(wallet.getReceive());
|
||||
}));
|
||||
|
||||
it('should mine a block', co(function* () {
|
||||
var block = yield miner.mineBlock();
|
||||
assert(block);
|
||||
yield chain.add(block);
|
||||
it('should mine a 200 blocks', co(function* () {
|
||||
var i, block;
|
||||
|
||||
for (i = 0; i < 200; i++) {
|
||||
block = yield miner.mineBlock();
|
||||
assert(block);
|
||||
yield chain.add(block);
|
||||
}
|
||||
|
||||
assert.equal(chain.height, 200);
|
||||
}));
|
||||
|
||||
it('should mine competing chains', co(function* () {
|
||||
var i, block1, block2;
|
||||
var i, mtx, at1, at2, blk1, blk2, hash1, hash2;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
block1 = yield mineBlock(tip1, cb1);
|
||||
cb1 = block1.txs[0];
|
||||
at1 = yield miner.createBlock(tip1);
|
||||
at2 = yield miner.createBlock(tip2);
|
||||
|
||||
block2 = yield mineBlock(tip2, cb2);
|
||||
cb2 = block2.txs[0];
|
||||
mtx = yield wallet.create({
|
||||
outputs: [{
|
||||
address: wallet.getAddress(),
|
||||
value: 10 * 1e8
|
||||
}]
|
||||
});
|
||||
|
||||
yield chain.add(block1);
|
||||
at1.addTX(mtx.toTX(), mtx.view);
|
||||
at2.addTX(mtx.toTX(), mtx.view);
|
||||
|
||||
yield chain.add(block2);
|
||||
blk1 = yield at1.mineAsync();
|
||||
blk2 = yield at2.mineAsync();
|
||||
|
||||
assert(chain.tip.hash === block1.hash('hex'));
|
||||
hash1 = blk1.hash('hex');
|
||||
hash2 = blk2.hash('hex');
|
||||
|
||||
tip1 = yield chain.db.getEntry(block1.hash('hex'));
|
||||
tip2 = yield chain.db.getEntry(block2.hash('hex'));
|
||||
yield chain.add(blk1);
|
||||
yield chain.add(blk2);
|
||||
|
||||
assert(chain.tip.hash === hash1);
|
||||
|
||||
tip1 = yield chain.db.getEntry(hash1);
|
||||
tip2 = yield chain.db.getEntry(hash2);
|
||||
|
||||
assert(tip1);
|
||||
assert(tip2);
|
||||
@ -97,22 +133,20 @@ describe('Chain', function() {
|
||||
}));
|
||||
|
||||
it('should have correct chain value', function() {
|
||||
assert.equal(chain.db.state.value, 55000000000);
|
||||
assert.equal(chain.db.state.coin, 20);
|
||||
assert.equal(chain.db.state.tx, 21);
|
||||
assert.equal(chain.db.state.value, 897500000000);
|
||||
assert.equal(chain.db.state.coin, 220);
|
||||
assert.equal(chain.db.state.tx, 221);
|
||||
});
|
||||
|
||||
it('should have correct balance', co(function* () {
|
||||
assert.equal(wallet.balance, 550 * 1e8);
|
||||
//assert.equal(wallet.unconfirmed, 550 * 1e8);
|
||||
//assert.equal(wallet.confirmed, 550 * 1e8);
|
||||
it('should have correct wallet balance', co(function* () {
|
||||
assert.equal(wallet.balance, 897500000000);
|
||||
}));
|
||||
|
||||
it('should handle a reorg', co(function* () {
|
||||
var entry, block, forked;
|
||||
var forked = false;
|
||||
var entry, block;
|
||||
|
||||
// assert.equal(wallet.height, chain.height);
|
||||
assert.equal(chain.height, 11);
|
||||
assert.equal(chain.height, 210);
|
||||
|
||||
entry = yield chain.db.getEntry(tip2.hash);
|
||||
assert(entry);
|
||||
@ -121,7 +155,6 @@ describe('Chain', function() {
|
||||
block = yield miner.mineBlock(entry);
|
||||
assert(block);
|
||||
|
||||
forked = false;
|
||||
chain.once('reorganize', function() {
|
||||
forked = true;
|
||||
});
|
||||
@ -134,15 +167,13 @@ describe('Chain', function() {
|
||||
}));
|
||||
|
||||
it('should have correct chain value', function() {
|
||||
assert.equal(chain.db.state.value, 60000000000);
|
||||
assert.equal(chain.db.state.coin, 21);
|
||||
assert.equal(chain.db.state.tx, 22);
|
||||
assert.equal(chain.db.state.value, 900000000000);
|
||||
assert.equal(chain.db.state.coin, 221);
|
||||
assert.equal(chain.db.state.tx, 222);
|
||||
});
|
||||
|
||||
it('should have correct balance', co(function* () {
|
||||
assert.equal(wallet.balance, 600 * 1e8);
|
||||
// assert.equal(wallet.unconfirmed, 1100 * 1e8);
|
||||
// assert.equal(wallet.confirmed, 600 * 1e8);
|
||||
it('should have correct wallet balance', co(function* () {
|
||||
assert.equal(wallet.balance, 900000000000);
|
||||
}));
|
||||
|
||||
it('should check main chain', co(function* () {
|
||||
@ -151,12 +182,14 @@ describe('Chain', function() {
|
||||
}));
|
||||
|
||||
it('should mine a block after a reorg', co(function* () {
|
||||
var block = yield mineBlock(null, cb2);
|
||||
var entry, result;
|
||||
var block = yield miner.mineBlock();
|
||||
var hash, entry, result;
|
||||
|
||||
yield chain.add(block);
|
||||
|
||||
entry = yield chain.db.getEntry(block.hash('hex'));
|
||||
hash = block.hash('hex');
|
||||
entry = yield chain.db.getEntry(hash);
|
||||
|
||||
assert(entry);
|
||||
assert(chain.tip.hash === entry.hash);
|
||||
|
||||
@ -165,9 +198,29 @@ describe('Chain', function() {
|
||||
}));
|
||||
|
||||
it('should prevent double spend on new chain', co(function* () {
|
||||
var block = yield mineBlock(null, cb2);
|
||||
var tip = chain.tip;
|
||||
var err;
|
||||
var attempt = yield miner.createBlock();
|
||||
var mtx, block, tip, err;
|
||||
|
||||
mtx = yield wallet.create({
|
||||
outputs: [{
|
||||
address: wallet.getAddress(),
|
||||
value: 10 * 1e8
|
||||
}]
|
||||
});
|
||||
|
||||
attempt.addTX(mtx.toTX(), mtx.view);
|
||||
|
||||
block = yield attempt.mineAsync();
|
||||
tip = yield chain.add(block);
|
||||
|
||||
attempt = yield miner.createBlock();
|
||||
|
||||
assert(mtx.outputs.length > 1);
|
||||
mtx.outputs.pop();
|
||||
|
||||
attempt.addTX(mtx.toTX(), mtx.view);
|
||||
|
||||
block = yield attempt.mineAsync();
|
||||
|
||||
try {
|
||||
yield chain.add(block);
|
||||
@ -181,9 +234,21 @@ describe('Chain', function() {
|
||||
}));
|
||||
|
||||
it('should fail to mine a block with coins on an alternate chain', co(function* () {
|
||||
var block = yield mineBlock(null, cb1);
|
||||
var tip = chain.tip;
|
||||
var err;
|
||||
var block = yield chain.db.getBlock(tip1.hash);
|
||||
var cb = block.txs[0];
|
||||
var mtx = new MTX();
|
||||
var attempt, block, err;
|
||||
|
||||
mtx.addTX(cb, 0);
|
||||
mtx.addOutput(wallet.getAddress(), 10 * 1e8);
|
||||
|
||||
wallet.sign(mtx);
|
||||
|
||||
attempt = yield miner.createBlock();
|
||||
attempt.addTX(mtx.toTX(), mtx.view);
|
||||
|
||||
block = yield attempt.mineAsync();
|
||||
|
||||
try {
|
||||
yield chain.add(block);
|
||||
@ -197,43 +262,50 @@ describe('Chain', function() {
|
||||
}));
|
||||
|
||||
it('should have correct chain value', function() {
|
||||
assert.equal(chain.db.state.value, 65000000000);
|
||||
assert.equal(chain.db.state.coin, 23);
|
||||
assert.equal(chain.db.state.tx, 24);
|
||||
assert.equal(chain.db.state.value, 905000000000);
|
||||
assert.equal(chain.db.state.coin, 224);
|
||||
assert.equal(chain.db.state.tx, 225);
|
||||
});
|
||||
|
||||
it('should get coin', co(function* () {
|
||||
var block, tx, output, coin;
|
||||
var mtx, attempt, block, tx, output, coin;
|
||||
|
||||
block = yield mineBlock();
|
||||
yield chain.add(block);
|
||||
mtx = yield wallet.send({
|
||||
outputs: [
|
||||
{
|
||||
address: wallet.getAddress(),
|
||||
value: 1e8
|
||||
},
|
||||
{
|
||||
address: wallet.getAddress(),
|
||||
value: 1e8
|
||||
},
|
||||
{
|
||||
address: wallet.getAddress(),
|
||||
value: 1e8
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
block = yield mineBlock(null, block.txs[0]);
|
||||
attempt = yield miner.createBlock();
|
||||
attempt.addTX(mtx.toTX(), mtx.view);
|
||||
|
||||
block = yield attempt.mineAsync();
|
||||
yield chain.add(block);
|
||||
|
||||
tx = block.txs[1];
|
||||
output = Coin.fromTX(tx, 1, chain.height);
|
||||
output = Coin.fromTX(tx, 2, chain.height);
|
||||
|
||||
coin = yield chain.db.getCoin(tx.hash('hex'), 1);
|
||||
coin = yield chain.db.getCoin(tx.hash('hex'), 2);
|
||||
|
||||
assert.deepEqual(coin.toRaw(), output.toRaw());
|
||||
}));
|
||||
|
||||
it('should get balance', co(function* () {
|
||||
var txs;
|
||||
|
||||
assert.equal(wallet.balance, 750 * 1e8);
|
||||
// assert.equal(wallet.unconfirmed, 1250 * 1e8);
|
||||
// assert.equal(wallet.confirmed, 750 * 1e8);
|
||||
|
||||
assert(wallet.receiveDepth >= 7);
|
||||
assert(wallet.changeDepth >= 6);
|
||||
|
||||
// assert.equal(wallet.height, chain.height);
|
||||
|
||||
// txs = wallet.getHistory();
|
||||
// assert.equal(txs.length, 45);
|
||||
assert.equal(wallet.txs, 26);
|
||||
it('should have correct wallet balance', co(function* () {
|
||||
assert.equal(wallet.balance, 907500000000);
|
||||
assert.equal(wallet.receiveDepth, 15);
|
||||
assert.equal(wallet.changeDepth, 14);
|
||||
assert.equal(wallet.txs, 226);
|
||||
}));
|
||||
|
||||
it('should get tips and remove chains', co(function* () {
|
||||
@ -258,41 +330,46 @@ describe('Chain', function() {
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
assert.equal(total, 26);
|
||||
assert.equal(total, 226);
|
||||
}));
|
||||
|
||||
it('should activate csv', co(function* () {
|
||||
var deployments = chain.network.deployments;
|
||||
var deployments = network.deployments;
|
||||
var i, block, prev, state, cache;
|
||||
|
||||
miner.options.version = -1;
|
||||
|
||||
assert.equal(chain.height, 214);
|
||||
|
||||
prev = yield chain.tip.getPrevious();
|
||||
state = yield chain.getState(prev, deployments.csv);
|
||||
assert(state === 0);
|
||||
assert.equal(state, 1);
|
||||
|
||||
for (i = 0; i < 417; i++) {
|
||||
block = yield miner.mineBlock();
|
||||
yield chain.add(block);
|
||||
switch (chain.height) {
|
||||
case 144:
|
||||
prev = yield chain.tip.getPrevious();
|
||||
state = yield chain.getState(prev, deployments.csv);
|
||||
assert(state === 1);
|
||||
break;
|
||||
case 288:
|
||||
prev = yield chain.tip.getPrevious();
|
||||
state = yield chain.getState(prev, deployments.csv);
|
||||
assert(state === 2);
|
||||
assert.equal(state, 1);
|
||||
break;
|
||||
case 432:
|
||||
prev = yield chain.tip.getPrevious();
|
||||
state = yield chain.getState(prev, deployments.csv);
|
||||
assert(state === 3);
|
||||
assert.equal(state, 2);
|
||||
break;
|
||||
case 576:
|
||||
prev = yield chain.tip.getPrevious();
|
||||
state = yield chain.getState(prev, deployments.csv);
|
||||
assert.equal(state, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(chain.height === 432);
|
||||
assert.equal(chain.height, 631);
|
||||
assert(chain.state.hasCSV());
|
||||
assert(chain.state.hasWitness());
|
||||
|
||||
cache = yield chain.db.getStateCache();
|
||||
assert.deepEqual(cache, chain.db.stateCache);
|
||||
@ -300,56 +377,38 @@ describe('Chain', function() {
|
||||
assert(yield chain.db.verifyDeployments());
|
||||
}));
|
||||
|
||||
var mineCSV = co(function* mineCSV(tx) {
|
||||
var attempt = yield miner.createBlock();
|
||||
var redeemer;
|
||||
|
||||
redeemer = new MTX();
|
||||
|
||||
redeemer.addOutput({
|
||||
script: [
|
||||
Script.array(new BN(1)),
|
||||
Script.opcodes.OP_CHECKSEQUENCEVERIFY
|
||||
],
|
||||
value: 10 * 1e8
|
||||
});
|
||||
|
||||
redeemer.addTX(tx, 0);
|
||||
|
||||
redeemer.setLocktime(chain.height);
|
||||
|
||||
wallet.sign(redeemer);
|
||||
|
||||
attempt.addTX(redeemer.toTX(), redeemer.view);
|
||||
|
||||
return yield attempt.mineAsync();
|
||||
});
|
||||
it('should have activated segwit', co(function* () {
|
||||
var deployments = network.deployments;
|
||||
var prev = yield chain.tip.getPrevious();
|
||||
var state = yield chain.getState(prev, deployments.segwit);
|
||||
assert.equal(state, 3);
|
||||
}));
|
||||
|
||||
it('should test csv', co(function* () {
|
||||
var tx = (yield chain.db.getBlock(chain.height)).txs[0];
|
||||
var tx = (yield chain.db.getBlock(chain.height - 100)).txs[0];
|
||||
var block = yield mineCSV(tx);
|
||||
var csv, attempt, redeemer;
|
||||
var csv, attempt, rtx;
|
||||
|
||||
yield chain.add(block);
|
||||
|
||||
csv = block.txs[1];
|
||||
|
||||
redeemer = new MTX();
|
||||
rtx = new MTX();
|
||||
|
||||
redeemer.addOutput({
|
||||
rtx.addOutput({
|
||||
script: [
|
||||
Script.array(new BN(2)),
|
||||
Script.opcodes.OP_CHECKSEQUENCEVERIFY
|
||||
],
|
||||
value: 10 * 1e8
|
||||
value: 10000
|
||||
});
|
||||
|
||||
redeemer.addTX(csv, 0);
|
||||
redeemer.setSequence(0, 1, false);
|
||||
rtx.addTX(csv, 0);
|
||||
rtx.setSequence(0, 1, false);
|
||||
|
||||
attempt = yield miner.createBlock();
|
||||
|
||||
attempt.addTX(redeemer.toTX(), redeemer.view);
|
||||
attempt.addTX(rtx.toTX(), rtx.view);
|
||||
|
||||
block = yield attempt.mineAsync();
|
||||
|
||||
@ -357,12 +416,11 @@ describe('Chain', function() {
|
||||
}));
|
||||
|
||||
it('should fail csv with bad sequence', co(function* () {
|
||||
var csv = (yield chain.db.getBlock(chain.height)).txs[1];
|
||||
var block, attempt, redeemer, err;
|
||||
var csv = (yield chain.db.getBlock(chain.height - 100)).txs[0];
|
||||
var rtx = new MTX();
|
||||
var block, attempt, err;
|
||||
|
||||
redeemer = new MTX();
|
||||
|
||||
redeemer.addOutput({
|
||||
rtx.addOutput({
|
||||
script: [
|
||||
Script.array(new BN(1)),
|
||||
Script.opcodes.OP_CHECKSEQUENCEVERIFY
|
||||
@ -370,12 +428,12 @@ describe('Chain', function() {
|
||||
value: 10 * 1e8
|
||||
});
|
||||
|
||||
redeemer.addTX(csv, 0);
|
||||
redeemer.setSequence(0, 1, false);
|
||||
rtx.addTX(csv, 0);
|
||||
rtx.setSequence(0, 1, false);
|
||||
|
||||
attempt = yield miner.createBlock();
|
||||
|
||||
attempt.addTX(redeemer.toTX(), redeemer.view);
|
||||
attempt.addTX(rtx.toTX(), rtx.view);
|
||||
|
||||
block = yield attempt.mineAsync();
|
||||
|
||||
@ -396,30 +454,30 @@ describe('Chain', function() {
|
||||
}));
|
||||
|
||||
it('should fail csv lock checks', co(function* () {
|
||||
var tx = (yield chain.db.getBlock(chain.height)).txs[0];
|
||||
var tx = (yield chain.db.getBlock(chain.height - 100)).txs[0];
|
||||
var block = yield mineCSV(tx);
|
||||
var csv, attempt, redeemer, err;
|
||||
var csv, attempt, rtx, err;
|
||||
|
||||
yield chain.add(block);
|
||||
|
||||
csv = block.txs[1];
|
||||
|
||||
redeemer = new MTX();
|
||||
rtx = new MTX();
|
||||
|
||||
redeemer.addOutput({
|
||||
rtx.addOutput({
|
||||
script: [
|
||||
Script.array(new BN(2)),
|
||||
Script.opcodes.OP_CHECKSEQUENCEVERIFY
|
||||
],
|
||||
value: 10 * 1e8
|
||||
value: 1 * 1e8
|
||||
});
|
||||
|
||||
redeemer.addTX(csv, 0);
|
||||
redeemer.setSequence(0, 2, false);
|
||||
rtx.addTX(csv, 0);
|
||||
rtx.setSequence(0, 2, false);
|
||||
|
||||
attempt = yield miner.createBlock();
|
||||
|
||||
attempt.addTX(redeemer.toTX(), redeemer.view);
|
||||
attempt.addTX(rtx.toTX(), rtx.view);
|
||||
|
||||
block = yield attempt.mineAsync();
|
||||
|
||||
@ -434,11 +492,376 @@ describe('Chain', function() {
|
||||
}));
|
||||
|
||||
it('should have correct wallet balance', co(function* () {
|
||||
assert.equal(wallet.balance, 1289250000000);
|
||||
assert.equal(wallet.balance, 1412499980000);
|
||||
}));
|
||||
|
||||
it('should fail to connect bad bits', co(function* () {
|
||||
var attempt = yield miner.createBlock();
|
||||
attempt.block.bits = 553713663;
|
||||
assert.equal(yield addBlock(attempt), 'bad-diffbits');
|
||||
}));
|
||||
|
||||
it('should fail to connect bad MTP', co(function* () {
|
||||
var mtp = yield chain.tip.getMedianTimeAsync();
|
||||
var attempt = yield miner.createBlock();
|
||||
attempt.block.ts = mtp - 1;
|
||||
assert.equal(yield addBlock(attempt), 'time-too-old');
|
||||
}));
|
||||
|
||||
it('should fail to connect bad time', co(function* () {
|
||||
var mtp = yield chain.tip.getMedianTimeAsync();
|
||||
var attempt = yield miner.createBlock();
|
||||
var now = network.now() + 3 * 60 * 60;
|
||||
attempt.block.ts = now;
|
||||
assert.equal(yield addBlock(attempt), 'time-too-new');
|
||||
}));
|
||||
|
||||
it('should fail to connect bad locktime', co(function* () {
|
||||
var attempt = yield miner.createBlock();
|
||||
var tx = yield wallet.send({ locktime: 100000 });
|
||||
attempt.block.txs.push(tx.toTX());
|
||||
attempt.refresh();
|
||||
assert.equal(yield addBlock(attempt), 'bad-txns-nonfinal');
|
||||
}));
|
||||
|
||||
it('should fail to connect bad cb height', co(function* () {
|
||||
var bip34height = network.block.bip34height;
|
||||
var attempt = yield miner.createBlock();
|
||||
var tx = attempt.block.txs[0];
|
||||
var input = tx.inputs[0];
|
||||
|
||||
input.script.set(0, new BN(10));
|
||||
input.script.compile();
|
||||
attempt.refresh();
|
||||
|
||||
try {
|
||||
network.block.bip34height = 0;
|
||||
assert.equal(yield addBlock(attempt), 'bad-cb-height');
|
||||
} finally {
|
||||
network.block.bip34height = bip34height;
|
||||
}
|
||||
}));
|
||||
|
||||
it('should fail to connect bad witness nonce size', co(function* () {
|
||||
var attempt = yield miner.createBlock();
|
||||
var tx = attempt.block.txs[0];
|
||||
var input = tx.inputs[0];
|
||||
input.witness.set(0, new Buffer(33));
|
||||
input.witness.compile();
|
||||
assert.equal(yield addBlock(attempt), 'bad-witness-merkle-size');
|
||||
}));
|
||||
|
||||
it('should fail to connect bad witness nonce', co(function* () {
|
||||
var attempt = yield miner.createBlock();
|
||||
var tx = attempt.block.txs[0];
|
||||
var input = tx.inputs[0];
|
||||
input.witness.set(0, encoding.ONE_HASH);
|
||||
input.witness.compile();
|
||||
assert.equal(yield addBlock(attempt), 'bad-witness-merkle-match');
|
||||
}));
|
||||
|
||||
it('should fail to connect bad witness commitment', co(function* () {
|
||||
var attempt = yield miner.createBlock();
|
||||
var tx = attempt.block.txs[0];
|
||||
var output = tx.outputs[1];
|
||||
var commit;
|
||||
|
||||
assert(output.script.isCommitment());
|
||||
|
||||
commit = util.copy(output.script.get(1));
|
||||
commit.fill(0, 10);
|
||||
output.script.set(1, commit);
|
||||
output.script.compile();
|
||||
|
||||
attempt.updateMerkle();
|
||||
assert.equal(yield addBlock(attempt), 'bad-witness-merkle-match');
|
||||
}));
|
||||
|
||||
it('should fail to connect unexpected witness', co(function* () {
|
||||
var attempt = yield miner.createBlock();
|
||||
var tx = attempt.block.txs[0];
|
||||
var output = tx.outputs[1];
|
||||
assert(output.script.isCommitment());
|
||||
tx.outputs.pop();
|
||||
attempt.updateMerkle();
|
||||
assert.equal(yield addBlock(attempt), 'unexpected-witness');
|
||||
}));
|
||||
|
||||
it('should add wit addrs to miner', co(function* () {
|
||||
miner.addresses.length = 0;
|
||||
miner.addAddress(wwallet.getReceive());
|
||||
assert.equal(wwallet.getReceive().getType(), 'witnesspubkeyhash');
|
||||
}));
|
||||
|
||||
it('should mine 2000 witness blocks', co(function* () {
|
||||
var i, block;
|
||||
|
||||
for (i = 0; i < 2001; i++) {
|
||||
block = yield miner.mineBlock();
|
||||
assert(block);
|
||||
yield chain.add(block);
|
||||
}
|
||||
|
||||
assert.equal(chain.height, 2636);
|
||||
}));
|
||||
|
||||
it('should mine a witness tx', co(function* () {
|
||||
var block = yield chain.db.getBlock(chain.height - 2000);
|
||||
var cb = block.txs[0];
|
||||
var mtx = new MTX();
|
||||
var attempt, block;
|
||||
|
||||
mtx.addTX(cb, 0);
|
||||
mtx.addOutput(wwallet.getAddress(), 1000);
|
||||
|
||||
wwallet.sign(mtx);
|
||||
|
||||
attempt = yield miner.createBlock();
|
||||
attempt.addTX(mtx.toTX(), mtx.view);
|
||||
|
||||
block = yield attempt.mineAsync();
|
||||
|
||||
yield chain.add(block);
|
||||
}));
|
||||
|
||||
it('should mine fail to mine too much weight', co(function* () {
|
||||
var start = chain.height - 2000;
|
||||
var end = chain.height - 200;
|
||||
var attempt = yield miner.createBlock();
|
||||
var mtx = new MTX();
|
||||
var i, j, block, cb, block;
|
||||
|
||||
for (i = start; i <= end; i++) {
|
||||
block = yield chain.db.getBlock(i);
|
||||
cb = block.txs[0];
|
||||
|
||||
mtx = new MTX();
|
||||
mtx.addTX(cb, 0);
|
||||
|
||||
for (j = 0; j < 16; j++)
|
||||
mtx.addOutput(wwallet.getAddress(), 1);
|
||||
|
||||
wwallet.sign(mtx);
|
||||
|
||||
attempt.block.txs.push(mtx.toTX());
|
||||
}
|
||||
|
||||
attempt.refresh();
|
||||
|
||||
assert.equal(yield addBlock(attempt), 'bad-blk-weight');
|
||||
}));
|
||||
|
||||
it('should mine fail to mine too much size', co(function* () {
|
||||
var start = chain.height - 2000;
|
||||
var end = chain.height - 200;
|
||||
var attempt = yield miner.createBlock();
|
||||
var mtx = new MTX();
|
||||
var i, j, block, cb, block;
|
||||
|
||||
for (i = start; i <= end; i++) {
|
||||
block = yield chain.db.getBlock(i);
|
||||
cb = block.txs[0];
|
||||
|
||||
mtx = new MTX();
|
||||
mtx.addTX(cb, 0);
|
||||
|
||||
for (j = 0; j < 20; j++)
|
||||
mtx.addOutput(wwallet.getAddress(), 1);
|
||||
|
||||
wwallet.sign(mtx);
|
||||
|
||||
attempt.block.txs.push(mtx.toTX());
|
||||
}
|
||||
|
||||
attempt.refresh();
|
||||
|
||||
assert.equal(yield addBlock(attempt), 'bad-blk-length');
|
||||
}));
|
||||
|
||||
it('should mine a big block', co(function* () {
|
||||
var start = chain.height - 2000;
|
||||
var end = chain.height - 200;
|
||||
var attempt = yield miner.createBlock();
|
||||
var mtx = new MTX();
|
||||
var i, j, block, cb, block;
|
||||
|
||||
for (i = start; i <= end; i++) {
|
||||
block = yield chain.db.getBlock(i);
|
||||
cb = block.txs[0];
|
||||
|
||||
mtx = new MTX();
|
||||
mtx.addTX(cb, 0);
|
||||
|
||||
for (j = 0; j < 15; j++)
|
||||
mtx.addOutput(wwallet.getAddress(), 1);
|
||||
|
||||
wwallet.sign(mtx);
|
||||
|
||||
attempt.block.txs.push(mtx.toTX());
|
||||
}
|
||||
|
||||
attempt.refresh();
|
||||
|
||||
assert.equal(yield addBlock(attempt), 'OK');
|
||||
}));
|
||||
|
||||
it('should fail to mine bad versions', co(function* () {
|
||||
var i, attempt;
|
||||
|
||||
for (i = 0; i <= 3; i++) {
|
||||
attempt = yield miner.createBlock();
|
||||
attempt.block.version = i;
|
||||
assert.equal(yield addBlock(attempt), 'bad-version');
|
||||
}
|
||||
}));
|
||||
|
||||
it('should fail to mine bad amount', co(function* () {
|
||||
var attempt = yield miner.createBlock();
|
||||
var i;
|
||||
|
||||
attempt.block.txs[0].outputs[0].value += 1;
|
||||
attempt.updateMerkle();
|
||||
assert.equal(yield addBlock(attempt), 'bad-cb-amount');
|
||||
}));
|
||||
|
||||
it('should fail to mine premature cb spend', co(function* () {
|
||||
var attempt = yield miner.createBlock();
|
||||
var block = yield chain.db.getBlock(chain.height - 98);
|
||||
var cb = block.txs[0];
|
||||
var mtx = new MTX();
|
||||
var i;
|
||||
|
||||
mtx.addTX(cb, 0);
|
||||
mtx.addOutput(wwallet.getAddress(), 1);
|
||||
|
||||
wwallet.sign(mtx);
|
||||
|
||||
attempt.addTX(mtx.toTX(), mtx.view);
|
||||
|
||||
assert.equal(yield addBlock(attempt),
|
||||
'bad-txns-premature-spend-of-coinbase');
|
||||
}));
|
||||
|
||||
it('should fail to mine vout belowout', co(function* () {
|
||||
var attempt = yield miner.createBlock();
|
||||
var block = yield chain.db.getBlock(chain.height - 99);
|
||||
var cb = block.txs[0];
|
||||
var mtx = new MTX();
|
||||
var i;
|
||||
|
||||
mtx.addTX(cb, 0);
|
||||
mtx.addOutput(wwallet.getAddress(), 1e8);
|
||||
|
||||
wwallet.sign(mtx);
|
||||
|
||||
attempt.block.txs.push(mtx.toTX());
|
||||
attempt.refresh();
|
||||
|
||||
assert.equal(yield addBlock(attempt),
|
||||
'bad-txns-in-belowout');
|
||||
}));
|
||||
|
||||
it('should fail to mine in out toolarge', co(function* () {
|
||||
var attempt = yield miner.createBlock();
|
||||
var block = yield chain.db.getBlock(chain.height - 99);
|
||||
var cb = block.txs[0];
|
||||
var mtx = new MTX();
|
||||
var i;
|
||||
|
||||
mtx.addTX(cb, 0);
|
||||
mtx.addOutput(wwallet.getAddress(), Math.floor(consensus.MAX_MONEY / 2));
|
||||
mtx.addOutput(wwallet.getAddress(), Math.floor(consensus.MAX_MONEY / 2));
|
||||
mtx.addOutput(wwallet.getAddress(), Math.floor(consensus.MAX_MONEY / 2));
|
||||
|
||||
wwallet.sign(mtx);
|
||||
|
||||
attempt.block.txs.push(mtx.toTX());
|
||||
attempt.refresh();
|
||||
|
||||
assert.equal(yield addBlock(attempt),
|
||||
'bad-txns-txouttotal-toolarge');
|
||||
}));
|
||||
|
||||
it('should mine 111 multisig blocks', co(function* () {
|
||||
var i, j, script, attempt, cb, output, val, block;
|
||||
|
||||
script = new Script();
|
||||
script.push(new BN(20));
|
||||
|
||||
for (i = 0; i < 20; i++)
|
||||
script.push(encoding.ZERO_KEY);
|
||||
|
||||
script.push(new BN(20));
|
||||
script.push(opcodes.OP_CHECKMULTISIG);
|
||||
script.compile();
|
||||
|
||||
script = Script.fromScripthash(script.hash160());
|
||||
|
||||
for (i = 0; i < 111; i++) {
|
||||
attempt = yield miner.createBlock();
|
||||
cb = attempt.block.txs[0];
|
||||
val = cb.outputs[0].value;
|
||||
|
||||
cb.outputs[0].value = 0;
|
||||
|
||||
for (j = 0; j < Math.min(100, val); j++) {
|
||||
output = new Output();
|
||||
output.script = script.clone();
|
||||
output.value = 1;
|
||||
|
||||
cb.outputs.push(output);
|
||||
}
|
||||
|
||||
attempt.updateMerkle();
|
||||
|
||||
block = yield attempt.mineAsync();
|
||||
yield chain.add(block);
|
||||
}
|
||||
|
||||
assert.equal(chain.height, 2749);
|
||||
}));
|
||||
|
||||
it('should mine fail to mine too many sigops', co(function* () {
|
||||
var start = chain.height - 110;
|
||||
var end = chain.height - 100;
|
||||
var attempt = yield miner.createBlock();
|
||||
var i, j, mtx, script, block, cb, block;
|
||||
|
||||
script = new Script();
|
||||
script.push(new BN(20));
|
||||
|
||||
for (i = 0; i < 20; i++)
|
||||
script.push(encoding.ZERO_KEY);
|
||||
|
||||
script.push(new BN(20));
|
||||
script.push(opcodes.OP_CHECKMULTISIG);
|
||||
script.compile();
|
||||
|
||||
for (i = start; i <= end; i++) {
|
||||
block = yield chain.db.getBlock(i);
|
||||
cb = block.txs[0];
|
||||
|
||||
if (cb.outputs.length === 2)
|
||||
continue;
|
||||
|
||||
mtx = new MTX();
|
||||
|
||||
for (j = 2; j < cb.outputs.length; j++) {
|
||||
mtx.addTX(cb, j);
|
||||
mtx.inputs[j - 2].script = new Script([script.toRaw()]);
|
||||
}
|
||||
|
||||
mtx.addOutput(wwallet.getAddress(), 1);
|
||||
|
||||
attempt.block.txs.push(mtx.toTX());
|
||||
}
|
||||
|
||||
attempt.refresh();
|
||||
|
||||
assert.equal(yield addBlock(attempt), 'bad-blk-sigops');
|
||||
}));
|
||||
|
||||
it('should cleanup', co(function* () {
|
||||
consensus.COINBASE_MATURITY = 100;
|
||||
yield miner.close();
|
||||
yield chain.close();
|
||||
}));
|
||||
|
||||
202
test/tx-test.js
202
test/tx-test.js
@ -12,7 +12,11 @@ var Block = require('../lib/primitives/block');
|
||||
var Coin = require('../lib/primitives/coin');
|
||||
var Output = require('../lib/primitives/output');
|
||||
var Script = require('../lib/script/script');
|
||||
var Witness = require('../lib/script/witness');
|
||||
var Input = require('../lib/primitives/input');
|
||||
var CoinView = require('../lib/coins/coinview');
|
||||
var KeyRing = require('../lib/primitives/keyring');
|
||||
var opcodes = Script.opcodes;
|
||||
|
||||
var valid = require('./data/tx_valid.json');
|
||||
var invalid = require('./data/tx_invalid.json');
|
||||
@ -102,6 +106,43 @@ function parseTest(data) {
|
||||
};
|
||||
}
|
||||
|
||||
function buildTX(spk, ss, wit, view) {
|
||||
var input, output, fund, spend, tx;
|
||||
|
||||
input = new Input();
|
||||
output = new Output();
|
||||
output.value = 1;
|
||||
output.script = spk;
|
||||
|
||||
fund = new TX();
|
||||
fund.version = 1;
|
||||
fund.inputs.push(input);
|
||||
fund.outputs.push(output);
|
||||
fund.refresh();
|
||||
|
||||
input = new Input();
|
||||
input.prevout.hash = fund.hash('hex');
|
||||
input.prevout.index = 0;
|
||||
input.script = ss;
|
||||
input.witness = wit;
|
||||
|
||||
output = new Output();
|
||||
output.value = 1;
|
||||
|
||||
spend = new TX();
|
||||
spend.version = 1;
|
||||
spend.inputs.push(input);
|
||||
spend.outputs.push(output);
|
||||
spend.refresh();
|
||||
|
||||
view.addTX(fund, 0);
|
||||
|
||||
return {
|
||||
fund: fund,
|
||||
spend: spend
|
||||
};
|
||||
}
|
||||
|
||||
describe('TX', function() {
|
||||
var raw = '010000000125393c67cd4f581456dd0805fa8e9db3abdf90dbe1d4b53e28' +
|
||||
'6490f35d22b6f2010000006b483045022100f4fa5ced20d2dbd2f905809d' +
|
||||
@ -687,4 +728,165 @@ describe('TX', function() {
|
||||
assert.equal(block.getReward(view, 0), -1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should count sigops for multisig', function() {
|
||||
var flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH;
|
||||
var view = new CoinView();
|
||||
var key = KeyRing.generate();
|
||||
var pub = key.publicKey;
|
||||
var txs, spk, ss, wit;
|
||||
|
||||
spk = Script.fromMultisig(1, 2, [pub, pub]);
|
||||
|
||||
ss = new Script([
|
||||
opcodes.OP_0,
|
||||
opcodes.OP_0
|
||||
]);
|
||||
|
||||
wit = new Witness();
|
||||
|
||||
txs = buildTX(spk, ss, wit, view);
|
||||
|
||||
assert.equal(txs.spend.getSigopsCost(view, flags), 0);
|
||||
assert.equal(txs.fund.getSigopsCost(view, flags),
|
||||
consensus.MAX_MULTISIG_PUBKEYS * consensus.WITNESS_SCALE_FACTOR);
|
||||
});
|
||||
|
||||
it('should count sigops for p2sh multisig', function() {
|
||||
var flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH;
|
||||
var view = new CoinView();
|
||||
var key = KeyRing.generate();
|
||||
var pub = key.publicKey;
|
||||
var txs, redeem, spk, ss, wit;
|
||||
|
||||
redeem = Script.fromMultisig(1, 2, [pub, pub]);
|
||||
spk = Script.fromScripthash(redeem.hash160());
|
||||
|
||||
ss = new Script([
|
||||
opcodes.OP_0,
|
||||
opcodes.OP_0,
|
||||
redeem.toRaw()
|
||||
]);
|
||||
|
||||
wit = new Witness();
|
||||
|
||||
txs = buildTX(spk, ss, wit, view);
|
||||
|
||||
assert.equal(txs.spend.getSigopsCost(view, flags),
|
||||
2 * consensus.WITNESS_SCALE_FACTOR);
|
||||
});
|
||||
|
||||
it('should count sigops for p2wpkh', function() {
|
||||
var flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH;
|
||||
var view = new CoinView();
|
||||
var key = KeyRing.generate();
|
||||
var pub = key.publicKey;
|
||||
var txs, p2pk, spk, ss, wit;
|
||||
|
||||
spk = Script.fromProgram(0, key.getKeyHash());
|
||||
|
||||
ss = new Script();
|
||||
|
||||
wit = new Witness([
|
||||
new Buffer([0]),
|
||||
new Buffer([0])
|
||||
]);
|
||||
|
||||
txs = buildTX(spk, ss, wit, view);
|
||||
|
||||
assert.equal(txs.spend.getSigopsCost(view, flags), 1);
|
||||
assert.equal(
|
||||
txs.spend.getSigopsCost(view, flags & ~Script.flags.VERIFY_WITNESS),
|
||||
0);
|
||||
|
||||
spk = Script.fromProgram(1, key.getKeyHash());
|
||||
txs = buildTX(spk, ss, wit, view);
|
||||
|
||||
assert.equal(txs.spend.getSigopsCost(view, flags), 0);
|
||||
|
||||
spk = Script.fromProgram(0, key.getKeyHash());
|
||||
txs = buildTX(spk, ss, wit, view);
|
||||
|
||||
txs.spend.inputs[0].prevout.hash = encoding.NULL_HASH;
|
||||
txs.spend.inputs[0].prevout.index = 0xffffffff;
|
||||
txs.spend.refresh();
|
||||
|
||||
assert.equal(txs.spend.getSigopsCost(view, flags), 0);
|
||||
});
|
||||
|
||||
it('should count sigops for nested p2wpkh', function() {
|
||||
var flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH;
|
||||
var view = new CoinView();
|
||||
var key = KeyRing.generate();
|
||||
var pub = key.publicKey;
|
||||
var txs, p2pk, spk, ss, wit;
|
||||
|
||||
p2pk = Script.fromProgram(0, key.getKeyHash());
|
||||
spk = Script.fromScripthash(p2pk.hash160());
|
||||
|
||||
ss = new Script([
|
||||
p2pk.toRaw()
|
||||
]);
|
||||
|
||||
wit = new Witness([
|
||||
new Buffer([0]),
|
||||
new Buffer([0])
|
||||
]);
|
||||
|
||||
txs = buildTX(spk, ss, wit, view);
|
||||
|
||||
assert.equal(txs.spend.getSigopsCost(view, flags), 1);
|
||||
});
|
||||
|
||||
it('should count sigops for p2wsh', function() {
|
||||
var flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH;
|
||||
var view = new CoinView();
|
||||
var key = KeyRing.generate();
|
||||
var pub = key.publicKey;
|
||||
var txs, ws, spk, ss, wit;
|
||||
|
||||
ws = Script.fromMultisig(1, 2, [pub, pub]);
|
||||
spk = Script.fromProgram(0, ws.sha256());
|
||||
|
||||
ss = new Script();
|
||||
|
||||
wit = new Witness([
|
||||
new Buffer([0]),
|
||||
new Buffer([0]),
|
||||
ws.toRaw()
|
||||
]);
|
||||
|
||||
txs = buildTX(spk, ss, wit, view);
|
||||
|
||||
assert.equal(txs.spend.getSigopsCost(view, flags), 2);
|
||||
assert.equal(
|
||||
txs.spend.getSigopsCost(view, flags & ~Script.flags.VERIFY_WITNESS),
|
||||
0);
|
||||
});
|
||||
|
||||
it('should count sigops for nested p2wsh', function() {
|
||||
var flags = Script.flags.VERIFY_WITNESS | Script.flags.VERIFY_P2SH;
|
||||
var view = new CoinView();
|
||||
var key = KeyRing.generate();
|
||||
var pub = key.publicKey;
|
||||
var txs, ws, p2sh, spk, ss, wit;
|
||||
|
||||
ws = Script.fromMultisig(1, 2, [pub, pub]);
|
||||
p2sh = Script.fromProgram(0, ws.sha256());
|
||||
spk = Script.fromScripthash(p2sh.hash160());
|
||||
|
||||
ss = new Script([
|
||||
p2sh.toRaw()
|
||||
]);
|
||||
|
||||
wit = new Witness([
|
||||
new Buffer([0]),
|
||||
new Buffer([0]),
|
||||
ws.toRaw()
|
||||
]);
|
||||
|
||||
txs = buildTX(spk, ss, wit, view);
|
||||
|
||||
assert.equal(txs.spend.getSigopsCost(view, flags), 2);
|
||||
});
|
||||
});
|
||||
|
||||
@ -15,6 +15,7 @@ var Bloom = require('../../lib/utils/bloom');
|
||||
var KeyRing = require('../../lib/primitives/keyring');
|
||||
var Outpoint = require('../../lib/primitives/outpoint');
|
||||
var Coin = require('../../lib/primitives/coin');
|
||||
var co = require('../../lib/utils/co');
|
||||
|
||||
function MemWallet(options) {
|
||||
if (!(this instanceof MemWallet))
|
||||
@ -23,13 +24,15 @@ function MemWallet(options) {
|
||||
this.network = Network.primary;
|
||||
this.master = null;
|
||||
this.key = null;
|
||||
this.witness = false;
|
||||
this.account = 0;
|
||||
this.receiveDepth = 1;
|
||||
this.changeDepth = 1;
|
||||
this.receive = null;
|
||||
this.change = null;
|
||||
this.map = {};
|
||||
this.coins = {};
|
||||
this.undo = {};
|
||||
this.spent = {};
|
||||
this.paths = {};
|
||||
this.balance = 0;
|
||||
this.txs = 0;
|
||||
@ -57,6 +60,11 @@ MemWallet.prototype.fromOptions = function fromOptions(options) {
|
||||
this.key = options.key;
|
||||
}
|
||||
|
||||
if (options.witness != null) {
|
||||
assert(typeof options.witness === 'boolean');
|
||||
this.witness = options.witness;
|
||||
}
|
||||
|
||||
if (options.account != null) {
|
||||
assert(typeof options.account === 'number');
|
||||
this.account = options.account;
|
||||
@ -128,10 +136,13 @@ MemWallet.prototype.derivePath = function derivePath(path) {
|
||||
MemWallet.prototype.deriveKey = function deriveKey(branch, index) {
|
||||
var key = this.master.deriveAccount44(this.account);
|
||||
key = key.derive(branch).derive(index);
|
||||
return new KeyRing({
|
||||
key = new KeyRing({
|
||||
network: this.network,
|
||||
privateKey: key.privateKey
|
||||
privateKey: key.privateKey,
|
||||
witness: this.witness
|
||||
});
|
||||
key.witness = this.witness;
|
||||
return key;
|
||||
};
|
||||
|
||||
MemWallet.prototype.getKey = function getKey(hash) {
|
||||
@ -150,7 +161,7 @@ MemWallet.prototype.getCoin = function getCoin(key) {
|
||||
};
|
||||
|
||||
MemWallet.prototype.getUndo = function getUndo(key) {
|
||||
return this.undo[key];
|
||||
return this.spent[key];
|
||||
};
|
||||
|
||||
MemWallet.prototype.addCoin = function addCoin(coin) {
|
||||
@ -159,7 +170,7 @@ MemWallet.prototype.addCoin = function addCoin(coin) {
|
||||
|
||||
this.filter.add(op.toRaw());
|
||||
|
||||
delete this.undo[key];
|
||||
delete this.spent[key];
|
||||
|
||||
this.coins[key] = coin;
|
||||
this.balance += coin.value;
|
||||
@ -171,7 +182,7 @@ MemWallet.prototype.removeCoin = function removeCoin(key) {
|
||||
if (!coin)
|
||||
return;
|
||||
|
||||
this.undo[key] = coin;
|
||||
this.spent[key] = coin;
|
||||
this.balance -= coin.value;
|
||||
|
||||
delete this.coins[key];
|
||||
@ -228,12 +239,16 @@ MemWallet.prototype.removeBlock = function removeBlock(entry, txs) {
|
||||
};
|
||||
|
||||
MemWallet.prototype.addTX = function addTX(tx, height) {
|
||||
var hash = tx.hash('hex');
|
||||
var result = false;
|
||||
var i, op, path, addr, coin, input, output;
|
||||
|
||||
if (height == null)
|
||||
height = -1;
|
||||
|
||||
if (this.map[hash])
|
||||
return true;
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
op = input.prevout.toKey();
|
||||
@ -266,8 +281,10 @@ MemWallet.prototype.addTX = function addTX(tx, height) {
|
||||
this.syncKey(path);
|
||||
}
|
||||
|
||||
if (result)
|
||||
if (result) {
|
||||
this.txs++;
|
||||
this.map[hash] = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
@ -277,6 +294,9 @@ MemWallet.prototype.removeTX = function removeTX(tx, height) {
|
||||
var result = false;
|
||||
var i, op, coin, input, output;
|
||||
|
||||
if (!this.map[hash])
|
||||
return false;
|
||||
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
output = tx.outputs[i];
|
||||
op = Outpoint(hash, i).toKey();
|
||||
@ -306,6 +326,8 @@ MemWallet.prototype.removeTX = function removeTX(tx, height) {
|
||||
if (result)
|
||||
this.txs--;
|
||||
|
||||
delete this.map[hash];
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@ -368,33 +390,32 @@ MemWallet.prototype.sign = function sign(mtx) {
|
||||
mtx.sign(keys);
|
||||
};
|
||||
|
||||
MemWallet.prototype.send = function send(options) {
|
||||
var self = this;
|
||||
MemWallet.prototype.create = co(function* create(options) {
|
||||
var mtx = new MTX(options);
|
||||
var tx;
|
||||
|
||||
this.fund(mtx, options).then(function() {
|
||||
assert(mtx.getFee() <= MTX.Selector.MAX_FEE, 'TX exceeds MAX_FEE.');
|
||||
yield this.fund(mtx, options);
|
||||
|
||||
mtx.sortMembers();
|
||||
assert(mtx.getFee() <= MTX.Selector.MAX_FEE, 'TX exceeds MAX_FEE.');
|
||||
|
||||
if (options.locktime != null)
|
||||
mtx.setLocktime(options.locktime);
|
||||
mtx.sortMembers();
|
||||
|
||||
self.sign(mtx);
|
||||
if (options.locktime != null)
|
||||
mtx.setLocktime(options.locktime);
|
||||
|
||||
if (!mtx.isSigned())
|
||||
throw new Error('Cannot sign tx.');
|
||||
this.sign(mtx);
|
||||
|
||||
tx = mtx.toTX();
|
||||
if (!mtx.isSigned())
|
||||
throw new Error('Cannot sign tx.');
|
||||
|
||||
self.addTX(tx);
|
||||
}).catch(function(err) {
|
||||
throw err;
|
||||
});
|
||||
return mtx;
|
||||
});
|
||||
|
||||
return tx;
|
||||
};
|
||||
MemWallet.prototype.send = co(function* send(options) {
|
||||
var mtx = yield this.create(options);
|
||||
this.addTX(mtx.toTX());
|
||||
return mtx;
|
||||
});
|
||||
|
||||
function Path(hash, branch, index) {
|
||||
this.hash = hash;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user