diff --git a/README.md b/README.md index 2570510b..cd41e570 100644 --- a/README.md +++ b/README.md @@ -415,8 +415,8 @@ cb.addOutput({ // Create our redeeming transaction. var mtx = new bcoin.mtx(); -// Add output 0 from our coinbase. -mtx.addInput(cb, 0); +// Add output 0 from our coinbase as an input. +mtx.addTX(cb, 0); // Send 10,000 satoshis to ourself, // creating a fee of 40,000 satoshis. diff --git a/bench/walletdb.js b/bench/walletdb.js index 49d6e667..53d000e6 100644 --- a/bench/walletdb.js +++ b/bench/walletdb.js @@ -5,16 +5,12 @@ var co = require('../lib/utils/co'); var crypto = require('../lib/crypto/crypto'); var WalletDB = require('../lib/wallet/walletdb'); var MTX = require('../lib/primitives/mtx'); +var Outpoint = require('../lib/primitives/outpoint'); var walletdb, runBench; function dummy() { var hash = crypto.randomBytes(32).toString('hex'); - return { - prevout: { - hash: hash, - index: 0 - } - }; + return new Outpoint(hash, 0); } walletdb = new WalletDB({ @@ -62,13 +58,13 @@ runBench = co(function* runBench() { // TX deposit jobs = []; for (i = 0; i < 10000; i++) { - tx = new MTX() - .addInput(dummy()) - .addOutput(addrs[(i + 0) % addrs.length], 50460) - .addOutput(addrs[(i + 1) % addrs.length], 50460) - .addOutput(addrs[(i + 2) % addrs.length], 50460) - .addOutput(addrs[(i + 3) % addrs.length], 50460) - .toTX(); + tx = new MTX(); + tx.addOutpoint(dummy()); + tx.addOutput(addrs[(i + 0) % addrs.length], 50460); + tx.addOutput(addrs[(i + 1) % addrs.length], 50460); + tx.addOutput(addrs[(i + 2) % addrs.length], 50460); + tx.addOutput(addrs[(i + 3) % addrs.length], 50460); + tx = tx.toTX(); jobs.push(walletdb.addTX(tx)); } @@ -80,16 +76,16 @@ runBench = co(function* runBench() { // TX redemption jobs = []; for (i = 0; i < 10000; i++) { - tx = new MTX() - .addInput(tx, 0) - .addInput(tx, 1) - .addInput(tx, 2) - .addInput(tx, 3) - .addOutput(addrs[(i + 0) % addrs.length], 50460) - .addOutput(addrs[(i + 1) % addrs.length], 50460) - .addOutput(addrs[(i + 2) % addrs.length], 50460) - .addOutput(addrs[(i + 3) % addrs.length], 50460) - .toTX(); + tx = new MTX(); + tx.addTX(tx, 0); + tx.addTX(tx, 1); + tx.addTX(tx, 2); + tx.addTX(tx, 3); + tx.addOutput(addrs[(i + 0) % addrs.length], 50460); + tx.addOutput(addrs[(i + 1) % addrs.length], 50460); + tx.addOutput(addrs[(i + 2) % addrs.length], 50460); + tx.addOutput(addrs[(i + 3) % addrs.length], 50460); + tx = tx.toTX(); jobs.push(walletdb.addTX(tx)); } diff --git a/lib/primitives/coin.js b/lib/primitives/coin.js index 4ea2ec10..480f54c9 100644 --- a/lib/primitives/coin.js +++ b/lib/primitives/coin.js @@ -42,7 +42,7 @@ function Coin(options) { this.height = -1; this.value = 0; this.script = new Script(); - this.coinbase = true; + this.coinbase = false; this.hash = encoding.NULL_HASH; this.index = 0; diff --git a/lib/primitives/mtx.js b/lib/primitives/mtx.js index a3bee6b8..132ce472 100644 --- a/lib/primitives/mtx.js +++ b/lib/primitives/mtx.js @@ -125,18 +125,34 @@ MTX.prototype.clone = function clone() { }; /** - * Add an outpoint as an input. - * @param {Outpoint} outpoint + * Add an input to the transaction. + * @example + * tx.addInput({ prevout: { hash: ... }, script: ... }); + * tx.addInput(new Input()); + * @param {Input|Object} options */ -MTX.prototype.addOutpoint = function addOutpoint(outpoint) { - var input = Input.fromOutpoint(outpoint); +MTX.prototype.addInput = function addInput(options) { + var input = Input.fromOptions(options); this.inputs.push(input); return this; }; /** - * Add a coin as an input. + * Add an outpoint as an input. + * @param {Outpoint|Object} outpoint + */ + +MTX.prototype.addOutpoint = function addOutpoint(outpoint) { + var prevout = Outpoint.fromOptions(outpoint); + var input = Input.fromOutpoint(prevout); + this.inputs.push(input); + return this; +}; + +/** + * Add a coin as an input. Note that this will + * add the coin to the internal coin viewpoint. * @param {Coin} coin */ @@ -148,14 +164,15 @@ MTX.prototype.addCoin = function addCoin(coin) { input = Input.fromCoin(coin); this.inputs.push(input); - this.view.addCoin(coin); return this; }; /** - * Add a transaction as an input. + * Add a transaction as an input. Note that + * this will add the coin to the internal + * coin viewpoint. * @param {TX} tx * @param {Number} index * @param {Number?} height @@ -170,51 +187,10 @@ MTX.prototype.addTX = function addTX(tx, index, height) { height = -1; input = Input.fromTX(tx, index); - - this.inputs.push(input); - coin = Coin.fromTX(tx, index, height); - this.view.addCoin(coin); - - return this; -}; - -/** - * Add an input to the transaction. - * @example - * tx.addInput({ prevout: { hash: ... }, script: ... }); - * tx.addInput(tx, index); - * tx.addInput(new Outpoint(hash, index)); - * tx.addInput(Coin.fromTX(prev, prevIndex, -1)); - * @param {TX|Coin|Outpoint|Input|Object} coin - * @param {Number?} index - Input of output if `coin` is a TX. - * @param {Number?} height - Coin height if `coin` is a TX. - */ - -MTX.prototype.addInput = function addInput(coin, index, height) { - var input = new Input(); - - if (coin instanceof TX) { - input.fromTX(coin, index); - coin = Coin.fromTX(coin, index, height || -1); - } - - if (coin instanceof Coin) { - input.fromCoin(coin); - this.view.addCoin(coin); - this.inputs.push(input); - return this; - } - - if (coin instanceof Outpoint) { - input.prevout.fromOptions(coin); - this.inputs.push(input); - return this; - } - - input.fromOptions(coin); this.inputs.push(input); + this.view.addCoin(coin); return this; }; @@ -223,21 +199,14 @@ MTX.prototype.addInput = function addInput(coin, index, height) { * Add an output. * @example * tx.addOutput({ address: ..., value: 100000 }); - * tx.addOutput({ address: ..., value: Amount.value('0.1') }); * tx.addOutput(address, Amount.value('0.1')); - * @param {KeyRing|Base58Address|Address|Script|Output|Object} options + * @param {Address|Script|Output|Object} options * @param {Amount?} value - Only needs to be present for non-output options. */ MTX.prototype.addOutput = function addOutput(options, value) { var output; - if (options instanceof KeyRing) - options = options.getAddress(); - - if (typeof options === 'string') - options = Address.fromBase58(options); - if (options instanceof Address) options = Script.fromAddress(options); @@ -245,13 +214,12 @@ MTX.prototype.addOutput = function addOutput(options, value) { output.mutable = true; if (options instanceof Script) { - assert(util.isNumber(value)); - assert(value >= 0); + assert(util.isUInt53(value), 'Value must be a uint53.'); output.script.fromOptions(options); output.value = value; } else { output.fromOptions(options); - assert(output.value >= 0); + assert(util.isUInt53(output.value), 'Value must be a uint53.'); } this.outputs.push(output); @@ -1223,7 +1191,7 @@ MTX.prototype.fund = co(function* fund(coins, options) { // Add coins to transaction. for (i = 0; i < select.chosen.length; i++) - this.addInput(select.chosen[i]); + this.addCoin(select.chosen[i]); // Attempt to subtract fee. if (select.shouldSubtract) @@ -1717,7 +1685,7 @@ CoinSelector.prototype.fund = function fund() { if (!this.isSpendable(coin)) continue; - this.tx.addInput(coin); + this.tx.addCoin(coin); this.chosen.push(coin); if (this.selection === 'all') diff --git a/test/chain-test.js b/test/chain-test.js index 91526058..bcf19576 100644 --- a/test/chain-test.js +++ b/test/chain-test.js @@ -27,30 +27,23 @@ describe('Chain', function() { mineBlock = co(function* mineBlock(tip, tx) { var attempt = yield miner.createBlock(tip); - var redeemer; + var rtx; if (!tx) return yield attempt.mineAsync(); - redeemer = new MTX(); + rtx = new MTX(); - redeemer.addOutput({ - address: wallet.getReceive(), - value: 25 * 1e8 - }); + rtx.addTX(tx, 0); - redeemer.addOutput({ - address: wallet.getChange(), - value: 5 * 1e8 - }); + rtx.addOutput(wallet.getReceive(), 25 * 1e8); + rtx.addOutput(wallet.getChange(), 5 * 1e8); - redeemer.addInput(tx, 0); + rtx.setLocktime(chain.height); - redeemer.setLocktime(chain.height); + yield wallet.sign(rtx); - yield wallet.sign(redeemer); - - attempt.addTX(redeemer.toTX(), redeemer.view); + attempt.addTX(rtx.toTX(), rtx.view); return yield attempt.mineAsync(); }); @@ -326,7 +319,7 @@ describe('Chain', function() { value: 10 * 1e8 }); - redeemer.addInput(tx, 0); + redeemer.addTX(tx, 0); redeemer.setLocktime(chain.height); @@ -356,7 +349,7 @@ describe('Chain', function() { value: 10 * 1e8 }); - redeemer.addInput(csv, 0); + redeemer.addTX(csv, 0); redeemer.setSequence(0, 1, false); attempt = yield miner.createBlock(); @@ -382,7 +375,7 @@ describe('Chain', function() { value: 10 * 1e8 }); - redeemer.addInput(csv, 0); + redeemer.addTX(csv, 0); redeemer.setSequence(0, 1, false); attempt = yield miner.createBlock(); @@ -426,7 +419,7 @@ describe('Chain', function() { value: 10 * 1e8 }); - redeemer.addInput(csv, 0); + redeemer.addTX(csv, 0); redeemer.setSequence(0, 2, false); attempt = yield miner.createBlock(); diff --git a/test/http-test.js b/test/http-test.js index 6cd37c03..26f20975 100644 --- a/test/http-test.js +++ b/test/http-test.js @@ -5,6 +5,7 @@ var consensus = require('../lib/protocol/consensus'); var encoding = require('../lib/utils/encoding'); var co = require('../lib/utils/co'); var Amount = require('../lib/btc/amount'); +var Address = require('../lib/primitives/address'); var MTX = require('../lib/primitives/mtx'); var HTTP = require('../lib/http'); var FullNode = require('../lib/node/fullnode'); @@ -61,17 +62,18 @@ describe('HTTP', function() { assert.equal(info.id, 'test'); addr = info.account.receiveAddress; assert.equal(typeof addr, 'string'); + addr = Address.fromBase58(addr); })); it('should fill with funds', cob(function* () { var tx, balance, receive, details; // Coinbase - tx = MTX() - .addOutput(addr, 50460) - .addOutput(addr, 50460) - .addOutput(addr, 50460) - .addOutput(addr, 50460); + tx = new MTX(); + tx.addOutput(addr, 50460); + tx.addOutput(addr, 50460); + tx.addOutput(addr, 50460); + tx.addOutput(addr, 50460); tx.addInput(dummyInput); tx = tx.toTX(); @@ -116,7 +118,7 @@ describe('HTTP', function() { rate: 10000, outputs: [{ value: 10000, - address: addr + address: addr.toBase58() }] }; diff --git a/test/mempool-test.js b/test/mempool-test.js index 8326c219..ee50f6cd 100644 --- a/test/mempool-test.js +++ b/test/mempool-test.js @@ -41,31 +41,27 @@ describe('Mempool', function() { }); function dummy(prev, prevHash) { - var funding = new MTX(); - var coin, entry; + var fund, coin, entry; if (!prevHash) prevHash = encoding.ONE_HASH.toString('hex'); - coin = new Coin({ - version: 1, - height: 0, - value: 0, - script: prev, - coinbase: false, - hash: prevHash, - index: 0 - }); + coin = new Coin(); + coin.height = 0; + coin.value = 0; + coin.script = prev; + coin.hash = prevHash; + coin.index = 0; - funding.addInput(coin); + fund = new MTX(); + fund.addCoin(coin); + fund.addOutput(prev, 70000); - funding.addOutput({ value: 70000, script: prev }); + entry = MempoolEntry.fromTX(fund.toTX(), fund.view, 0); - entry = MempoolEntry.fromTX(funding.toTX(), funding.view, 0); + mempool.trackEntry(entry, fund.view); - mempool.trackEntry(entry, funding.view); - - return Coin.fromTX(funding, 0, -1); + return Coin.fromTX(fund, 0, -1); } it('should open mempool', cob(function* () { @@ -86,58 +82,58 @@ describe('Mempool', function() { var w = wallet; var t1, t2, t3, t4, f1, fake, prev, sig, balance, txs; - t1 = new MTX() - .addOutput(w.getAddress(), 50000) - .addOutput(w.getAddress(), 10000); + t1 = new MTX(); + t1.addOutput(w.getAddress(), 50000); + t1.addOutput(w.getAddress(), 10000); prev = new Script([kp.publicKey, opcodes.OP_CHECKSIG]); - t1.addInput(dummy(prev)); - sig = t1.signature(0, prev, 70000, kp.privateKey, 'all', 0); + t1.addCoin(dummy(prev)); + sig = t1.signature(0, prev, 70000, kp.privateKey, Script.hashType.ALL, 0); t1.inputs[0].script = new Script([sig]); // balance: 51000 yield w.sign(t1); t1 = t1.toTX(); - t2 = new MTX() - .addInput(t1, 0) // 50000 - .addOutput(w.getAddress(), 20000) - .addOutput(w.getAddress(), 20000); + t2 = new MTX(); + t2.addTX(t1, 0); // 50000 + t2.addOutput(w.getAddress(), 20000); + t2.addOutput(w.getAddress(), 20000); // balance: 49000 yield w.sign(t2); t2 = t2.toTX(); - t3 = new MTX() - .addInput(t1, 1) // 10000 - .addInput(t2, 0) // 20000 - .addOutput(w.getAddress(), 23000); + t3 = new MTX(); + t3.addTX(t1, 1); // 10000 + t3.addTX(t2, 0); // 20000 + t3.addOutput(w.getAddress(), 23000); // balance: 47000 yield w.sign(t3); t3 = t3.toTX(); - t4 = new MTX() - .addInput(t2, 1) // 24000 - .addInput(t3, 0) // 23000 - .addOutput(w.getAddress(), 11000) - .addOutput(w.getAddress(), 11000); + t4 = new MTX(); + t4.addTX(t2, 1); // 24000 + t4.addTX(t3, 0); // 23000 + t4.addOutput(w.getAddress(), 11000); + t4.addOutput(w.getAddress(), 11000); // balance: 22000 yield w.sign(t4); t4 = t4.toTX(); - f1 = new MTX() - .addInput(t4, 1) // 11000 - .addOutput(new Address(), 9000); + f1 = new MTX(); + f1.addTX(t4, 1); // 11000 + f1.addOutput(new Address(), 9000); // balance: 11000 yield w.sign(f1); f1 = f1.toTX(); - fake = new MTX() - .addInput(t1, 1) // 1000 (already redeemed) - .addOutput(w.getAddress(), 6000); // 6000 instead of 500 + fake = new MTX(); + fake.addTX(t1, 1); // 1000 (already redeemed) + fake.addOutput(w.getAddress(), 6000); // 6000 instead of 500 // Script inputs but do not sign yield w.template(fake); @@ -185,19 +181,19 @@ describe('Mempool', function() { var kp = KeyRing.generate(); var tx, prev, prevHash, sig; - tx = new MTX() - .addOutput(w.getAddress(), 50000) - .addOutput(w.getAddress(), 10000); + tx = new MTX(); + tx.addOutput(w.getAddress(), 50000); + tx.addOutput(w.getAddress(), 10000); prev = new Script([kp.publicKey, opcodes.OP_CHECKSIG]); prevHash = crypto.randomBytes(32).toString('hex'); - tx.addInput(dummy(prev, prevHash)); + tx.addCoin(dummy(prev, prevHash)); tx.setLocktime(200); chain.tip.height = 200; - sig = tx.signature(0, prev, 70000, kp.privateKey, 'all', 0); + sig = tx.signature(0, prev, 70000, kp.privateKey, Script.hashType.ALL, 0); tx.inputs[0].script = new Script([sig]), tx = tx.toTX(); @@ -211,18 +207,18 @@ describe('Mempool', function() { var kp = KeyRing.generate(); var tx, prev, prevHash, sig, err; - tx = new MTX() - .addOutput(w.getAddress(), 50000) - .addOutput(w.getAddress(), 10000); + tx = new MTX(); + tx.addOutput(w.getAddress(), 50000); + tx.addOutput(w.getAddress(), 10000); prev = new Script([kp.publicKey, opcodes.OP_CHECKSIG]); prevHash = crypto.randomBytes(32).toString('hex'); - tx.addInput(dummy(prev, prevHash)); + tx.addCoin(dummy(prev, prevHash)); tx.setLocktime(200); chain.tip.height = 200 - 1; - sig = tx.signature(0, prev, 70000, kp.privateKey, 'all', 0); + sig = tx.signature(0, prev, 70000, kp.privateKey, Script.hashType.ALL, 0); tx.inputs[0].script = new Script([sig]), tx = tx.toTX(); @@ -244,18 +240,18 @@ describe('Mempool', function() { kp.witness = true; - tx = new MTX() - .addOutput(w.getAddress(), 50000) - .addOutput(w.getAddress(), 10000); + tx = new MTX(); + tx.addOutput(w.getAddress(), 50000); + tx.addOutput(w.getAddress(), 10000); prev = new Script([0, kp.getKeyHash()]); prevHash = crypto.randomBytes(32).toString('hex'); - tx.addInput(dummy(prev, prevHash)); + tx.addCoin(dummy(prev, prevHash)); prevs = Script.fromPubkeyhash(kp.getKeyHash()); - sig = tx.signature(0, prevs, 70000, kp.privateKey, 'all', 1); + sig = tx.signature(0, prevs, 70000, kp.privateKey, Script.hashType.ALL, 1); sig[sig.length - 1] = 0; tx.inputs[0].witness = new Witness([sig, kp.publicKey]); @@ -276,16 +272,16 @@ describe('Mempool', function() { var kp = KeyRing.generate(); var tx, prev, prevHash, sig, err; - tx = new MTX() - .addOutput(w.getAddress(), 50000) - .addOutput(w.getAddress(), 10000); + tx = new MTX(); + tx.addOutput(w.getAddress(), 50000); + tx.addOutput(w.getAddress(), 10000); prev = new Script([kp.publicKey, opcodes.OP_CHECKSIG]); prevHash = crypto.randomBytes(32).toString('hex'); - tx.addInput(dummy(prev, prevHash)); + tx.addCoin(dummy(prev, prevHash)); - sig = tx.signature(0, prev, 70000, kp.privateKey, 'all', 0); + sig = tx.signature(0, prev, 70000, kp.privateKey, Script.hashType.ALL, 0); tx.inputs[0].script = new Script([sig]); tx.inputs[0].witness.push(new Buffer(0)); tx = tx.toTX(); @@ -307,14 +303,14 @@ describe('Mempool', function() { kp.witness = true; - tx = new MTX() - .addOutput(w.getAddress(), 50000) - .addOutput(w.getAddress(), 10000); + tx = new MTX(); + tx.addOutput(w.getAddress(), 50000); + tx.addOutput(w.getAddress(), 10000); prev = new Script([0, kp.getKeyHash()]); prevHash = crypto.randomBytes(32).toString('hex'); - tx.addInput(dummy(prev, prevHash)); + tx.addCoin(dummy(prev, prevHash)); tx = tx.toTX(); @@ -334,14 +330,14 @@ describe('Mempool', function() { var kp = KeyRing.generate(); var tx, prev, prevHash, err; - tx = new MTX() - .addOutput(w.getAddress(), 50000) - .addOutput(w.getAddress(), 10000); + tx = new MTX(); + tx.addOutput(w.getAddress(), 50000); + tx.addOutput(w.getAddress(), 10000); prev = new Script([kp.publicKey, opcodes.OP_CHECKSIG]); prevHash = crypto.randomBytes(32).toString('hex'); - tx.addInput(dummy(prev, prevHash)); + tx.addCoin(dummy(prev, prevHash)); tx = tx.toTX(); @@ -359,9 +355,10 @@ describe('Mempool', function() { it('should clear reject cache', cob(function* () { var w = wallet; - var tx, input, block; + var tx, input; - tx = new MTX().addOutput(w.getAddress(), 50000); + tx = new MTX(); + tx.addOutput(w.getAddress(), 50000); input = { prevout: { @@ -374,11 +371,8 @@ describe('Mempool', function() { tx = tx.toTX(); - block = new Block(); - block.txs.push(tx); - assert(mempool.hasReject(cached.hash())); - yield mempool.addBlock({ height: 1 }, block.txs); + yield mempool.addBlock({ height: 1 }, [tx]); assert(!mempool.hasReject(cached.hash())); })); diff --git a/test/wallet-test.js b/test/wallet-test.js index d699f58e..6cc2e353 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -12,6 +12,8 @@ var MTX = require('../lib/primitives/mtx'); var Coin = require('../lib/primitives/coin'); var KeyRing = require('../lib/primitives/keyring'); var Address = require('../lib/primitives/address'); +var Input = require('../lib/primitives/input'); +var Outpoint = require('../lib/primitives/outpoint'); var Script = require('../lib/script/script'); var HD = require('../lib/hd'); var scriptTypes = Script.types; @@ -50,18 +52,13 @@ function dummy(hash) { if (!hash) hash = crypto.randomBytes(32).toString('hex'); - return { - prevout: { - hash: hash, - index: 0 - } - }; + return Input.fromOutpoint(new Outpoint(hash, 0)); } describe('Wallet', function() { var walletdb, wallet, ewallet, ekey; var doubleSpendWallet, doubleSpend; - var p2pkh, multisig; + var testP2PKH, testMultisig; walletdb = new WalletDB({ name: 'wallet-test', @@ -107,13 +104,10 @@ describe('Wallet', function() { w2.account.accountKey.toBase58()); })); - p2pkh = co(function* p2pkh(witness, bullshitNesting) { + testP2PKH = co(function* testP2PKH(witness, bullshitNesting) { var flags = Script.flags.STANDARD_VERIFY_FLAGS; var w, addr, src, tx; - if (witness) - flags |= Script.flags.VERIFY_WITNESS; - w = yield walletdb.create({ witness: witness }); addr = Address.fromBase58(w.getAddress('base58')); @@ -123,23 +117,15 @@ describe('Wallet', function() { else assert.equal(addr.type, scriptTypes.PUBKEYHASH); - src = new MTX({ - outputs: [{ - value: 5460 * 2, - address: bullshitNesting - ? w.getNested() - : w.getAddress() - }, { - value: 5460 * 2, - address: new Address() - }] - }); - + src = new MTX(); src.addInput(dummy()); + src.addOutput(bullshitNesting ? w.getNested() : w.getAddress(), 5460 * 2); + src.addOutput(new Address(), 2 * 5460); + src = src.toTX(); - tx = new MTX() - .addInput(src, 0) - .addOutput(w.getAddress(), 5460); + tx = new MTX(); + tx.addTX(src, 0); + tx.addOutput(w.getAddress(), 5460); yield w.sign(tx); @@ -147,19 +133,19 @@ describe('Wallet', function() { }); it('should sign/verify pubkeyhash tx', cob(function* () { - yield p2pkh(false, false); + yield testP2PKH(false, false); })); it('should sign/verify witnesspubkeyhash tx', cob(function* () { - yield p2pkh(true, false); + yield testP2PKH(true, false); })); it('should sign/verify witnesspubkeyhash tx with bullshit nesting', cob(function* () { - yield p2pkh(true, true); + yield testP2PKH(true, true); })); it('should multisign/verify TX', cob(function* () { - var w, k, keys, src, tx, maxSize; + var w, k, script, src, tx, maxSize; w = yield walletdb.create({ type: 'multisig', @@ -171,27 +157,21 @@ describe('Wallet', function() { yield w.addSharedKey(k); - keys = [ + script = Script.fromMultisig(1, 2, [ w.account.receive.getPublicKey(), k.derive('m/0/0').publicKey - ]; + ]); // Input transaction (bare 1-of-2 multisig) - src = new MTX({ - outputs: [{ - value: 5460 * 2, - script: Script.fromMultisig(1, 2, keys) - }, { - value: 5460 * 2, - address: new Address() - }] - }); - + src = new MTX(); src.addInput(dummy()); + src.addOutput(script, 5460 * 2); + src.addOutput(new Address(), 5460 * 2); + src = src.toTX(); - tx = new MTX() - .addInput(src, 0) - .addOutput(w.getAddress(), 5460); + tx = new MTX(); + tx.addTX(src, 0) + tx.addOutput(w.getAddress(), 5460); maxSize = yield tx.estimateSize(); @@ -206,57 +186,54 @@ describe('Wallet', function() { var f = yield walletdb.create(); var t1, t2, t3, t4, f1, fake, balance, txs; - doubleSpendWallet = w; - // Coinbase - t1 = new MTX() - .addOutput(w.getAddress(), 50000) - .addOutput(w.getAddress(), 1000); - t1.addInput(dummy()); - t1.ts = util.now(); - // balance: 51000 - // yield w.sign(t1); + t1 = new MTX(); + t1.addInput(dummy()); + t1.addOutput(w.getAddress(), 50000); + t1.addOutput(w.getAddress(), 1000); t1 = t1.toTX(); - t2 = new MTX() - .addInput(t1, 0) // 50000 - .addOutput(w.getAddress(), 24000) - .addOutput(w.getAddress(), 24000); + t2 = new MTX(); + t2.addTX(t1, 0); // 50000 + t2.addOutput(w.getAddress(), 24000); + t2.addOutput(w.getAddress(), 24000); + // Save for later. + doubleSpendWallet = w; doubleSpend = Coin.fromTX(t1, 0, -1); // balance: 49000 yield w.sign(t2); t2 = t2.toTX(); - t3 = new MTX() - .addInput(t1, 1) // 1000 - .addInput(t2, 0) // 24000 - .addOutput(w.getAddress(), 23000); + t3 = new MTX(); + t3.addTX(t1, 1); // 1000 + t3.addTX(t2, 0); // 24000 + t3.addOutput(w.getAddress(), 23000); // balance: 47000 yield w.sign(t3); t3 = t3.toTX(); - t4 = new MTX() - .addInput(t2, 1) // 24000 - .addInput(t3, 0) // 23000 - .addOutput(w.getAddress(), 11000) - .addOutput(w.getAddress(), 11000); + t4 = new MTX(); + t4.addTX(t2, 1); // 24000 + t4.addTX(t3, 0); // 23000 + t4.addOutput(w.getAddress(), 11000); + t4.addOutput(w.getAddress(), 11000); // balance: 22000 yield w.sign(t4); t4 = t4.toTX(); - f1 = new MTX() - .addInput(t4, 1) // 11000 - .addOutput(f.getAddress(), 10000); + f1 = new MTX(); + f1.addTX(t4, 1); // 11000 + f1.addOutput(f.getAddress(), 10000); // balance: 11000 yield w.sign(f1); f1 = f1.toTX(); - fake = new MTX() - .addInput(t1, 1) // 1000 (already redeemed) - .addOutput(w.getAddress(), 500); + fake = new MTX(); + fake.addTX(t1, 1); // 1000 (already redeemed) + fake.addOutput(w.getAddress(), 500); // Script inputs but do not sign yield w.template(fake); @@ -266,26 +243,23 @@ describe('Wallet', function() { // balance: 11000 fake = fake.toTX(); - // Fake TX should temporarly change output + // Fake TX should temporarily change output. yield walletdb.addTX(fake); yield walletdb.addTX(t4); balance = yield w.getBalance(); assert.equal(balance.unconfirmed, 22500); - // assert.equal(balance.unconfirmed, 0); yield walletdb.addTX(t1); balance = yield w.getBalance(); assert.equal(balance.unconfirmed, 72500); - // assert.equal(balance.unconfirmed, 51000); yield walletdb.addTX(t2); balance = yield w.getBalance(); assert.equal(balance.unconfirmed, 46500); - // assert.equal(balance.unconfirmed, 49000); yield walletdb.addTX(t3); @@ -315,8 +289,9 @@ describe('Wallet', function() { var w = doubleSpendWallet; var tx, txs, total, balance; - tx = new MTX().addOutput(w.getAddress(), 5000); - tx.addInput(doubleSpend); + tx = new MTX(); + tx.addCoin(doubleSpend); + tx.addOutput(w.getAddress(), 5000); txs = yield w.getHistory(); assert.equal(txs.length, 5); @@ -361,51 +336,51 @@ describe('Wallet', function() { f = yield walletdb.create(); // Coinbase - t1 = new MTX() - .addOutput(w.getAddress(), 50000) - .addOutput(w.getAddress(), 1000); + t1 = new MTX(); t1.addInput(dummy()); + t1.addOutput(w.getAddress(), 50000); + t1.addOutput(w.getAddress(), 1000); // balance: 51000 // yield w.sign(t1); t1 = t1.toTX(); - t2 = new MTX() - .addInput(t1, 0) // 50000 - .addOutput(w.getAddress(), 24000) - .addOutput(w.getAddress(), 24000); + t2 = new MTX(); + t2.addTX(t1, 0); // 50000 + t2.addOutput(w.getAddress(), 24000); + t2.addOutput(w.getAddress(), 24000); // balance: 49000 yield w.sign(t2); t2 = t2.toTX(); - t3 = new MTX() - .addInput(t1, 1) // 1000 - .addInput(t2, 0) // 24000 - .addOutput(w.getAddress(), 23000); + t3 = new MTX(); + t3.addTX(t1, 1); // 1000 + t3.addTX(t2, 0); // 24000 + t3.addOutput(w.getAddress(), 23000); // balance: 47000 yield w.sign(t3); t3 = t3.toTX(); - t4 = new MTX() - .addInput(t2, 1) // 24000 - .addInput(t3, 0) // 23000 - .addOutput(w.getAddress(), 11000) - .addOutput(w.getAddress(), 11000); + t4 = new MTX(); + t4.addTX(t2, 1); // 24000 + t4.addTX(t3, 0); // 23000 + t4.addOutput(w.getAddress(), 11000); + t4.addOutput(w.getAddress(), 11000); // balance: 22000 yield w.sign(t4); t4 = t4.toTX(); - f1 = new MTX() - .addInput(t4, 1) // 11000 - .addOutput(f.getAddress(), 10000); + f1 = new MTX(); + f1.addTX(t4, 1); // 11000 + f1.addOutput(f.getAddress(), 10000); // balance: 11000 yield w.sign(f1); f1 = f1.toTX(); - // fake = new MTX() - // .addInput(t1, 1) // 1000 (already redeemed) - // .addOutput(w.getAddress(), 500); + // fake = new MTX(); + // fake.addTX(t1, 1); // 1000 (already redeemed) + // fake.addOutput(w.getAddress(), 500); // Script inputs but do not sign // yield w.template(fake); @@ -431,19 +406,16 @@ describe('Wallet', function() { yield walletdb.addTX(t2); balance = yield w.getBalance(); - //assert.equal(balance.unconfirmed, 71000); assert.equal(balance.unconfirmed, 47000); yield walletdb.addTX(t3); balance = yield w.getBalance(); - //assert.equal(balance.unconfirmed, 69000); assert.equal(balance.unconfirmed, 22000); yield walletdb.addTX(f1); balance = yield w.getBalance(); - //assert.equal(balance.unconfirmed, 58000); assert.equal(balance.unconfirmed, 11000); txs = yield w.getHistory(); @@ -481,18 +453,19 @@ describe('Wallet', function() { // Coinbase t1 = new MTX() - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460); - t1.addInput(dummy()); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1 = t1.toTX(); yield walletdb.addTX(t1); // Create new transaction - t2 = new MTX().addOutput(w2.getAddress(), 5460); + t2 = new MTX(); + t2.addOutput(w2.getAddress(), 5460); yield w1.fund(t2, { rate: 10000, round: true }); yield w1.sign(t2); view = t2.view; @@ -501,15 +474,12 @@ describe('Wallet', function() { assert(t2.verify(view)); assert.equal(t2.getInputValue(view), 16380); - - // assert.equal(t2.getOutputValue(), 5460); // minrelay=10000 - // assert.equal(t2.getFee(view), 10920); // minrelay=10000 - - assert.equal(t2.getOutputValue(), 6380); // minrelay=1000 - assert.equal(t2.getFee(view), 10000); // minrelay=1000 + assert.equal(t2.getOutputValue(), 6380); + assert.equal(t2.getFee(view), 10000); // Create new transaction - t3 = new MTX().addOutput(w2.getAddress(), 15000); + t3 = new MTX(); + t3.addOutput(w2.getAddress(), 15000); try { yield w1.fund(t3, { rate: 10000, round: true }); @@ -528,12 +498,11 @@ describe('Wallet', function() { // Coinbase t1 = new MTX() - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460); - t1.addInput(dummy(encoding.NULL_HASH)); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); t1 = t1.toTX(); yield walletdb.addTX(t1); @@ -566,7 +535,8 @@ describe('Wallet', function() { yield walletdb.addTX(t2); // Create new transaction - t3 = new MTX().addOutput(w2.getAddress(), 15000); + t3 = new MTX(); + t3.addOutput(w2.getAddress(), 15000); try { yield w1.fund(t3, { rate: 10000 }); @@ -586,23 +556,21 @@ describe('Wallet', function() { var t1, t2, tx, cost, total, coins1, coins2, left; // Coinbase - t1 = new MTX() - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460); - + t1 = new MTX(); t1.addInput(dummy()); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); t1 = t1.toTX(); // Coinbase - t2 = new MTX() - .addOutput(w2.getAddress(), 5460) - .addOutput(w2.getAddress(), 5460) - .addOutput(w2.getAddress(), 5460) - .addOutput(w2.getAddress(), 5460); - + t2 = new MTX(); t2.addInput(dummy()); + t2.addOutput(w2.getAddress(), 5460); + t2.addOutput(w2.getAddress(), 5460); + t2.addOutput(w2.getAddress(), 5460); + t2.addOutput(w2.getAddress(), 5460); t2 = t2.toTX(); yield walletdb.addTX(t1); @@ -622,9 +590,9 @@ describe('Wallet', function() { tx.addOutput(w1.getAddress(), 0); // Add our unspent inputs to sign - tx.addInput(coins1[0]); - tx.addInput(coins1[1]); - tx.addInput(coins2[0]); + tx.addCoin(coins1[0]); + tx.addCoin(coins1[1]); + tx.addCoin(coins2[0]); left = tx.getInputValue() - total; if (left === 0) @@ -642,11 +610,10 @@ describe('Wallet', function() { // Verify assert.equal(tx.verify(), true); - // Sign transaction using `inputs` and `off` params. tx.inputs.length = 0; - tx.addInput(coins1[1]); - tx.addInput(coins1[2]); - tx.addInput(coins2[1]); + tx.addCoin(coins1[1]); + tx.addCoin(coins1[2]); + tx.addCoin(coins2[1]); total = yield w1.sign(tx); assert.equal(total, 2); @@ -658,16 +625,14 @@ describe('Wallet', function() { assert.equal(tx.verify(), true); })); - multisig = co(function* multisig(witness, bullshitNesting, cb) { + testMultisig = co(function* testMultisig(witness, bullshitNesting, cb) { var flags = Script.flags.STANDARD_VERIFY_FLAGS; - var options, w1, w2, w3, receive, b58, addr, paddr, utx, send, change; var rec = bullshitNesting ? 'nested' : 'receive'; var depth = bullshitNesting ? 'nestedDepth' : 'receiveDepth'; + var options, w1, w2, w3, receive, b58; + var addr, paddr, utx, send, change; var view, block; - if (witness) - flags |= Script.flags.VERIFY_WITNESS; - // Create 3 2-of-3 wallets with our pubkeys as "shared keys" options = { witness: witness, @@ -787,15 +752,15 @@ describe('Wallet', function() { }); it('should verify 2-of-3 scripthash tx', cob(function* () { - yield multisig(false, false); + yield testMultisig(false, false); })); it('should verify 2-of-3 witnessscripthash tx', cob(function* () { - yield multisig(true, false); + yield testMultisig(true, false); })); it('should verify 2-of-3 witnessscripthash tx with bullshit nesting', cob(function* () { - yield multisig(true, true); + yield testMultisig(true, true); })); it('should fill tx with account 1', cob(function* () { @@ -813,11 +778,11 @@ describe('Wallet', function() { rec = account.receive; // Coinbase - t1 = new MTX() - .addOutput(rec.getAddress(), 5460) - .addOutput(rec.getAddress(), 5460) - .addOutput(rec.getAddress(), 5460) - .addOutput(rec.getAddress(), 5460); + t1 = new MTX(); + t1.addOutput(rec.getAddress(), 5460); + t1.addOutput(rec.getAddress(), 5460); + t1.addOutput(rec.getAddress(), 5460); + t1.addOutput(rec.getAddress(), 5460); t1.addInput(dummy()); t1 = t1.toTX(); @@ -825,22 +790,20 @@ describe('Wallet', function() { yield walletdb.addTX(t1); // Create new transaction - t2 = new MTX().addOutput(w2.getAddress(), 5460); + t2 = new MTX(); + t2.addOutput(w2.getAddress(), 5460); yield w1.fund(t2, { rate: 10000, round: true }); yield w1.sign(t2); assert(t2.verify()); assert.equal(t2.getInputValue(), 16380); - - // assert.equal(t2.getOutputValue(), 5460); // minrelay=10000 - // assert.equal(t2.getFee(), 10920); // minrelay=10000 - - assert.equal(t2.getOutputValue(), 6380); // minrelay=1000 - assert.equal(t2.getFee(), 10000); // minrelay=1000 + assert.equal(t2.getOutputValue(), 6380); + assert.equal(t2.getFee(), 10000); // Create new transaction - t3 = new MTX().addOutput(w2.getAddress(), 15000); + t3 = new MTX(); + t3.addOutput(w2.getAddress(), 15000); try { yield w1.fund(t3, { rate: 10000, round: true }); @@ -879,11 +842,11 @@ describe('Wallet', function() { w.account.receive.getAddress('base58')); // Coinbase - t1 = new MTX() - .addOutput(w.getAddress(), 5460) - .addOutput(w.getAddress(), 5460) - .addOutput(w.getAddress(), 5460) - .addOutput(account.receive.getAddress(), 5460); + t1 = new MTX(); + t1.addOutput(w.getAddress(), 5460); + t1.addOutput(w.getAddress(), 5460); + t1.addOutput(w.getAddress(), 5460); + t1.addOutput(account.receive.getAddress(), 5460); t1.addInput(dummy()); t1 = t1.toTX(); @@ -891,7 +854,8 @@ describe('Wallet', function() { yield walletdb.addTX(t1); // Should fill from `foo` and fail - t2 = new MTX().addOutput(w.getAddress(), 5460); + t2 = new MTX(); + t2.addOutput(w.getAddress(), 5460); try { yield w.fund(t2, { rate: 10000, round: true, account: 'foo' }); } catch (e) { @@ -900,22 +864,23 @@ describe('Wallet', function() { assert(err); // Should fill from whole wallet and succeed - t2 = new MTX().addOutput(w.getAddress(), 5460); + t2 = new MTX(); + t2.addOutput(w.getAddress(), 5460); yield w.fund(t2, { rate: 10000, round: true }); // Coinbase - t1 = new MTX() - .addOutput(account.receive.getAddress(), 5460) - .addOutput(account.receive.getAddress(), 5460) - .addOutput(account.receive.getAddress(), 5460); - + t1 = new MTX(); t1.addInput(dummy()); + t1.addOutput(account.receive.getAddress(), 5460); + t1.addOutput(account.receive.getAddress(), 5460); + t1.addOutput(account.receive.getAddress(), 5460); t1 = t1.toTX(); yield walletdb.addTX(t1); - t2 = new MTX().addOutput(w.getAddress(), 5460); // Should fill from `foo` and succeed + t2 = new MTX(); + t2.addOutput(w.getAddress(), 5460); yield w.fund(t2, { rate: 10000, round: true, account: 'foo' }); })); @@ -941,19 +906,19 @@ describe('Wallet', function() { w.master.key = null; // Coinbase - t1 = new MTX() - .addOutput(w.getAddress(), 5460) - .addOutput(w.getAddress(), 5460) - .addOutput(w.getAddress(), 5460) - .addOutput(w.getAddress(), 5460); - + t1 = new MTX(); t1.addInput(dummy()); + t1.addOutput(w.getAddress(), 5460); + t1.addOutput(w.getAddress(), 5460); + t1.addOutput(w.getAddress(), 5460); + t1.addOutput(w.getAddress(), 5460); t1 = t1.toTX(); yield walletdb.addTX(t1); // Create new transaction - t2 = new MTX().addOutput(w.getAddress(), 5460); + t2 = new MTX(); + t2.addOutput(w.getAddress(), 5460); yield w.fund(t2, { rate: 10000, round: true }); // Should fail @@ -977,19 +942,19 @@ describe('Wallet', function() { var t1, t2; // Coinbase - t1 = new MTX() - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460); - + t1 = new MTX(); t1.addInput(dummy()); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); t1 = t1.toTX(); yield walletdb.addTX(t1); // Create new transaction - t2 = new MTX().addOutput(w2.getAddress(), 21840); + t2 = new MTX(); + t2.addOutput(w2.getAddress(), 21840); yield w1.fund(t2, { rate: 10000, round: true, subtractFee: true }); yield w1.sign(t2); @@ -1006,13 +971,12 @@ describe('Wallet', function() { var options, t1, t2; // Coinbase - t1 = new MTX() - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460) - .addOutput(w1.getAddress(), 5460); - + t1 = new MTX(); t1.addInput(dummy()); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); + t1.addOutput(w1.getAddress(), 5460); t1 = t1.toTX(); yield walletdb.addTX(t1); @@ -1079,11 +1043,11 @@ describe('Wallet', function() { assert.equal(k.getHash('hex'), key.getHash('hex')); // Coinbase - t1 = new MTX() - .addOutput(key.getAddress(), 5460) - .addOutput(key.getAddress(), 5460) - .addOutput(key.getAddress(), 5460) - .addOutput(key.getAddress(), 5460); + t1 = new MTX(); + t1.addOutput(key.getAddress(), 5460); + t1.addOutput(key.getAddress(), 5460); + t1.addOutput(key.getAddress(), 5460); + t1.addOutput(key.getAddress(), 5460); t1.addInput(dummy()); t1 = t1.toTX(); @@ -1213,21 +1177,19 @@ describe('Wallet', function() { addr = alice.getAddress(); // Coinbase - t1 = new MTX() - .addOutput(addr, 50000); + t1 = new MTX(); t1.addInput(dummy()); - - // yield alice.sign(t1); + t1.addOutput(addr, 50000); t1 = t1.toTX(); yield alice.add(t1); yield bob.add(t1); // Bob misses this tx! - t2 = new MTX() - .addInput(t1, 0) - .addOutput(addr, 24000) - .addOutput(addr, 24000); + t2 = new MTX(); + t2.addTX(t1, 0); + t2.addOutput(addr, 24000); + t2.addOutput(addr, 24000); yield alice.sign(t2); t2 = t2.toTX(); @@ -1239,10 +1201,10 @@ describe('Wallet', function() { (yield bob.getBalance()).unconfirmed); // Bob sees this one. - t3 = new MTX() - .addInput(t2, 0) - .addInput(t2, 1) - .addOutput(addr, 30000); + t3 = new MTX(); + t3.addTX(t2, 0); + t3.addTX(t2, 1); + t3.addOutput(addr, 30000); yield alice.sign(t3); t3 = t3.toTX(); @@ -1279,21 +1241,19 @@ describe('Wallet', function() { addr = alice.getAddress(); // Coinbase - t1 = new MTX() - .addOutput(addr, 50000); + t1 = new MTX(); t1.addInput(dummy()); - - // yield alice.sign(t1); + t1.addOutput(addr, 50000); t1 = t1.toTX(); yield alice.add(t1); yield bob.add(t1); // Bob misses this tx! - t2 = new MTX() - .addInput(t1, 0) - .addOutput(addr, 24000) - .addOutput(addr, 24000); + t2 = new MTX(); + t2.addTX(t1, 0); + t2.addOutput(addr, 24000); + t2.addOutput(addr, 24000); yield alice.sign(t2); t2 = t2.toTX(); @@ -1305,10 +1265,10 @@ describe('Wallet', function() { (yield bob.getBalance()).unconfirmed); // Bob doublespends. - t2a = new MTX() - .addInput(t1, 0) - .addOutput(addr, 10000) - .addOutput(addr, 10000); + t2a = new MTX(); + t2a.addTX(t1, 0); + t2a.addOutput(addr, 10000); + t2a.addOutput(addr, 10000); yield bob.sign(t2a); t2a = t2a.toTX(); @@ -1316,10 +1276,10 @@ describe('Wallet', function() { yield bob.add(t2a); // Bob sees this one. - t3 = new MTX() - .addInput(t2, 0) - .addInput(t2, 1) - .addOutput(addr, 30000); + t3 = new MTX(); + t3.addTX(t2, 0); + t3.addTX(t2, 1); + t3.addOutput(addr, 30000); yield alice.sign(t3); t3 = t3.toTX();