From 9b327cd45813b2b385041d5a1dffbb1c0baa7a9d Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Sun, 23 Nov 2014 17:41:34 -0300 Subject: [PATCH] tests again! --- js/models/TxProposal.js | 36 ++++++++++--------- js/models/Wallet.js | 33 +++++++---------- test/TxProposal.js | 2 +- test/Wallet.js | 75 +++++++++++++++++++++------------------ test/mocks/FakeBuilder.js | 7 +++- 5 files changed, 79 insertions(+), 74 deletions(-) diff --git a/js/models/TxProposal.js b/js/models/TxProposal.js index a65bed269..7c986cd0a 100644 --- a/js/models/TxProposal.js +++ b/js/models/TxProposal.js @@ -11,6 +11,7 @@ var Key = bitcore.Key; var buffertools = bitcore.buffertools; var preconditions = require('preconditions').instance(); +var TX_MAX_SIZE_KB = 50; var VERSION = 1; var CORE_FIELDS = ['builderObj', 'inputChainPaths', 'version', 'comment', 'paymentProtocolURL']; @@ -44,10 +45,14 @@ function TxProposal(opts) { var me = {}; me[opts.creator] = now; - this.signedBy = me; - this.signedBy = _.clone(me); + this.seenBy = me; + this.signedBy = {}; this.creator = opts.creator; this.createdTs = now; + if (opts.signWith) { + if (!this.sign(opts.signWith, opts.creator)) + throw new Error('Could not sign generated tx'); + } } this._sync(); @@ -99,8 +104,6 @@ TxProposal.prototype.sign = function(keys, signerId) { return signaturesAdded; }; - - TxProposal.prototype._check = function() { if (this.builder.signhash && this.builder.signhash !== Transaction.SIGHASH_ALL) { @@ -108,6 +111,11 @@ TxProposal.prototype._check = function() { } var tx = this.builder.build(); + + var txSize = tx.getSize(); + if (txSize / 1024 > TX_MAX_SIZE_KB) + throw new Error('BIG: Invalid TX proposal. Too big: ' + txSize + ' bytes'); + if (!tx.ins.length) throw new Error('Invalid tx proposal: no ins'); @@ -301,17 +309,6 @@ TxProposal._infoFromRedeemScript = function(s) { }; }; -TxProposal.prototype.mergeBuilder = function(incoming) { - var b0 = this.builder; - var b1 = incoming.builder; - - var before = JSON.stringify(b0.toObj()); - b0.merge(b1); - var after = JSON.stringify(b0.toObj()); - return after !== before; -}; - - TxProposal.prototype.getSeen = function(copayerId) { return this.seenBy[copayerId]; }; @@ -421,9 +418,14 @@ TxProposal.prototype.setCopayers = function(senderId, keyMap, readOnlyPeers) { // merge will not merge any metadata. TxProposal.prototype.merge = function(incoming) { - var hasChanged = this.mergeBuilder(incoming); + // Note that all inputs must have the same number of signatures, so checking + // one (0) is OK. + var before = this._inputSigners[0].length; + this.builder.merge(incoming.builder); this._sync(); - return hasChanged; + + var after = this._inputSigners[0].length; + return after !== before; }; //This should be on bitcore / Transaction diff --git a/js/models/Wallet.js b/js/models/Wallet.js index 8369e53b8..361407b69 100644 --- a/js/models/Wallet.js +++ b/js/models/Wallet.js @@ -31,7 +31,6 @@ var Async = require('./Async'); var Insight = module.exports.Insight = require('./Insight'); var copayConfig = require('../../config'); -var TX_MAX_SIZE_KB = 50; var TX_MAX_INS = 70; @@ -527,7 +526,6 @@ Wallet.prototype._onTxProposal = function(senderId, data) { var self = this; var m; -console.log('[Wallet.js.533]a', this.txProposals.txps); //TODO try { m = this.txProposals.merge(data.txProposal, Wallet.builderOpts); var keyMap = this._getKeyMap(m.txp); @@ -538,7 +536,6 @@ console.log('[Wallet.js.533]a', this.txProposals.txps); //TODO this.txProposals.deleteOne(m.ntxid); m = null; } -console.log('[Wallet.js.533]a', this.txProposals.txps); //TODO this._processIncomingTxProposal(m, function(err) { if (err) { @@ -546,6 +543,9 @@ console.log('[Wallet.js.533]a', this.txProposals.txps); //TODO if (m && m.ntxid) self.txProposals.deleteOne(m.ntxid); m = null; + } else { + if (m && m.hasChanged) + self.sendTxProposal(m.ntxid); } self._processProposalEvents(senderId, m); }); @@ -1166,7 +1166,7 @@ Wallet.fromObj = function(o, readOpts) { Wallet.prototype._sendToPeers = function(recipients, obj) { if (!this.isShared()) return; - log.info('Wallet:' + this.getName() + ' ### SENDING ' + obj.type); + log.info('Wallet:' + this.getName() + ' ### Sending ' + obj.type); log.debug('Sending obj', obj); this.network.send(recipients, obj); @@ -2086,7 +2086,7 @@ Wallet.prototype.spend = function(opts, cb) { opts.merchantData = merchantData; opts.toAddress = merchantData.outs[0].address; opts.amountSat = parseInt(merchantData.outs[0].amountSatStr); - return self.createTx(opts, cb); + return self.spend(opts, cb); }); }; preconditions.checkArgument(amountSat, 'no amount'); @@ -2095,7 +2095,7 @@ Wallet.prototype.spend = function(opts, cb) { this.getUnspent(function(err, safeUnspent) { if (err) { log.info(err); - return cb(new Error('CreateTx: Could not get list of UTXOs')); + return cb(new Error('Spend: Could not get list of UTXOs')); } var ntxid, txp; @@ -2212,28 +2212,21 @@ Wallet.prototype._createTxProposal = function(toAddress, amountSat, comment, utx var inputChainPaths = selectedUtxos.map(function(utxo) { return pkr.pathForAddress(utxo.address); }); - b.setHashToScriptMap(pkr.getRedeemScriptMap(inputChainPaths)); - var keys = priv.getForPaths(inputChainPaths); - b.sign(keys); - var tx = b.build(); - if (!tx.countInputSignatures(0)) - throw new Error('Could not sign generated tx'); - - var txSize = tx.getSize(); - if (txSize / - 1024 > TX_MAX_SIZE_KB) - throw new Error('BIG: Resulting TX is too big ' + txSize + ' bytes. Aborting'); - - return new TxProposal({ + var myId = this.getMyCopayerId(); + var keys = priv.getForPaths(inputChainPaths); + return new TxProposal({ inputChainPaths: inputChainPaths, comment: comment, builder: b, - creator: this.getMyCopayerId(), + creator: myId, + signWith: keys, }); + + return txp; }; diff --git a/test/TxProposal.js b/test/TxProposal.js index e2a106df3..881677f34 100644 --- a/test/TxProposal.js +++ b/test/TxProposal.js @@ -371,7 +371,7 @@ describe('TxProposal', function() { it('with less signatures', function() { var backup = txp.builder.vanilla.scriptSig[0]; txp.builder.merge = function() { - // 2 signatures. + // Only one signatures. this.vanilla.scriptSig = ['0048304502207d8e832bd576c93300e53ab6cbd68641961bec60690c358fd42d8e42b7d7d687022100a1daa89923efdb4c9b615d065058d9e1644f67000694a7d0806759afa7bef19b014cad532103197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d210380a29968851f93af55e581c43d9ef9294577a439a3ca9fc2bc47d1ca2b3e9127210392dccb2ed470a45984811d6402fdca613c175f8f3e4eb8e2306e8ccd7d0aed032103a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e32103e085eb6fa1f20b2722c16161144314070a2c316a9cae2489fd52ce5f63fff6e455ae']; this.tx.ins[0].s = new Buffer(this.vanilla.scriptSig[0], 'hex'); }; diff --git a/test/Wallet.js b/test/Wallet.js index 17580551f..d3738e0c5 100644 --- a/test/Wallet.js +++ b/test/Wallet.js @@ -234,7 +234,7 @@ describe('Wallet model', function() { unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(1, true); var f = function() { - var ntxid = w.createTxProposal( + var ntxid = w._createTxProposal( '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt', '123456789', null, @@ -250,7 +250,7 @@ describe('Wallet model', function() { var w = cachedCreateW2(); unspentTest[0].address = w.publicKeyRing.getAddress(1, true, w.publicKey).toString(); unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(1, true, w.publicKey); - var txp = w.createTxProposal( + var txp = w._createTxProposal( 'mgGJEugdPnvhmRuFdbdQcFfoFLc1XXeB79', '123456789', null, @@ -269,7 +269,7 @@ describe('Wallet model', function() { unspentTest[0].address = w.publicKeyRing.getAddress(1, true, w.publicKey).toString(); unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(1, true, w.publicKey); - var txp = w.createTxProposal( + var txp = w._createTxProposal( 'mgGJEugdPnvhmRuFdbdQcFfoFLc1XXeB79', '123456789', null, @@ -282,6 +282,7 @@ describe('Wallet model', function() { chai.expect(txp.comment).to.be.null; tx.isComplete().should.equal(false); Object.keys(txp.seenBy).length.should.equal(1); + Object.keys(txp.signedBy).length.should.equal(1); }); it('#create with comment', function() { @@ -292,7 +293,7 @@ describe('Wallet model', function() { unspentTest[0].address = w.publicKeyRing.getAddress(1, true, w.publicKey).toString(); unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(1, true, w.publicKey); - var txp = w.createTxProposal( + var txp = w._createTxProposal( 'mgGJEugdPnvhmRuFdbdQcFfoFLc1XXeB79', '123456789', comment, @@ -313,7 +314,7 @@ describe('Wallet model', function() { unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(1, true, w.publicKey); (function() { - w.createTxProposal( + w._createTxProposal( 'mgGJEugdPnvhmRuFdbdQcFfoFLc1XXeB79', '123456789', comment, @@ -342,7 +343,7 @@ describe('Wallet model', function() { for (var index = 0; index < 3; index++) { unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange, w.publicKey).toString(); unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(index, isChange, w.publicKey); - var txp = w.createTxProposal( + var txp = w._createTxProposal( 'mgGJEugdPnvhmRuFdbdQcFfoFLc1XXeB79', '123456789', null, @@ -778,7 +779,7 @@ describe('Wallet model', function() { var w = cachedCreateW2(); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx({ + w.spend({ toAddress: toAddress, amountSat: amountSatStr, }, function(err, ntxid) { @@ -795,7 +796,7 @@ describe('Wallet model', function() { var w = createW2([k2]); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx({ + w.spend({ toAddress: toAddress, amountSat: amountSatStr, }, function(err, ntxid) { @@ -812,7 +813,7 @@ describe('Wallet model', function() { var w = cachedCreateW2(); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx({ + w.spend({ toAddress: toAddress, amountSat: amountSatStr, }, function(err, ntxid) { @@ -827,7 +828,7 @@ describe('Wallet model', function() { var oldK = w.privateKey; var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx({ + w.spend({ toAddress: toAddress, amountSat: amountSatStr, }, function(err, ntxid) { @@ -844,12 +845,14 @@ describe('Wallet model', function() { var w = createW2(null, 1); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx({ + w.spend({ toAddress: toAddress, amountSat: amountSatStr, }, function(err, ntxid) { - w.sendTx(ntxid, function(txid) { + w.broadcastTx(ntxid, function(err, txid, status) { + should.not.exist(err); txid.length.should.equal(64); + status.should.equal(Wallet.TX_BROADCASTED); done(); }); }); @@ -858,7 +861,7 @@ describe('Wallet model', function() { var w = createW2(null, 1); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx({ + w.spend({ toAddress: toAddress, amountSat: amountSatStr, }, function(err, ntxid) { @@ -871,7 +874,7 @@ describe('Wallet model', function() { } }); (function() { - w.sendTx(ntxid); + w.broadcastTx(ntxid); }).should.throw('Tx is not complete. Can not broadcast'); done(); }); @@ -880,7 +883,7 @@ describe('Wallet model', function() { var w = createW2(null, 1); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx({ + w.spend({ toAddress: toAddress, amountSat: amountSatStr, }, function(err, ntxid) { @@ -888,7 +891,7 @@ describe('Wallet model', function() { statusCode: 303 }); var spyCheckSentTx = sinon.spy(w, '_checkSentTx'); - w.sendTx(ntxid, function() {}); + w.broadcastTx(ntxid, function() {}); chai.expect(spyCheckSentTx.calledOnce).to.be.true; done(); }); @@ -897,7 +900,7 @@ describe('Wallet model', function() { var w = cachedCreateW2(); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx({ + w.spend({ toAddress: toAddress, amountSat: amountSatStr, }, function(err, ntxid) { @@ -913,7 +916,7 @@ describe('Wallet model', function() { var w = cachedCreateW2(); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx({ + w.spend({ toAddress: toAddress, amountSat: amountSatStr, }, function(err, ntxid) { @@ -994,12 +997,12 @@ describe('Wallet model', function() { }); }); - describe('#createTx', function() { + describe('#spend', function() { it('should fail if insight server is down', function(done) { var w = cachedCreateW2(); var utxo = createUTXO(w); sinon.stub(w, 'getUnspent').yields('error', null); - w.createTx({ + w.spend({ toAddress: toAddress, amountSat: amountSatStr, }, function(err, ntxid) { @@ -1014,7 +1017,7 @@ describe('Wallet model', function() { var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); sinon.stub(w, 'fetchPaymentRequest').yields('error'); - w.createTx({ + w.spend({ url: 'test', }, function(err, ntxid) { should.exist(err); @@ -1038,7 +1041,7 @@ describe('Wallet model', function() { }, total: '123400', }); - w.createTx({ + w.spend({ url: 'test', }, function(err, ntxid) { should.not.exist(err); @@ -1150,12 +1153,12 @@ describe('Wallet model', function() { - describe('#send', function() { + describe('#_sendToPeers', function() { it('should call this.network.send', function() { var w = cachedCreateW2(); var save = w.network.send; w.network.send = sinon.spy(); - w.send(); + w._sendToPeers(null, {type:'hola'}); w.network.send.calledOnce.should.equal(true); w.network.send = save; }); @@ -1607,7 +1610,7 @@ describe('Wallet model', function() { spy.called.should.be.true; }); - it('should handle new', function(done) { + it('should handle new 1', function(done) { var data = { txProposal: { dummy: 1, @@ -1643,11 +1646,13 @@ describe('Wallet model', function() { }); w._onTxProposal('senderID', data); + spy1.called.should.be.true; spy2.called.should.be.true; txp.setSeen.calledOnce.should.be.true; - w.sendSeen.calledOnce.should.be.true; - w.sendTxProposal.calledOnce.should.be.true; + w.sendSeen.calledOnce.should.equal(true); + w.sendTxProposal.calledOnce.should.equal(true); + }); it('should handle signed', function(done) { @@ -1715,14 +1720,14 @@ describe('Wallet model', function() { ntxid: 1, txp: txp, new: false, - hasChanged: true, + hasChanged: false, }); w._checkSentTx = sinon.stub().yields('123'); w._onTxProposal('senderID', data); - txp.setSent.calledOnce.should.be.true; - txp.setSent.calledWith('123').should.be.true; - w.sendTxProposal.called.should.be.false; + txp.setSent.calledOnce.should.equal(true); + txp.setSent.calledWith('123').should.equal(true); + w.sendTxProposal.called.should.equal(false); done(); }); @@ -1749,14 +1754,14 @@ describe('Wallet model', function() { ntxid: 1, txp: txp, new: false, - hasChanged: true, + hasChanged: false, }); w._checkSentTx = sinon.stub().yields(false); w._onTxProposal('senderID', data); - txp.setSent.called.should.be.false; - txp.setSent.calledWith(1).should.be.false; - w.sendTxProposal.called.should.be.false; + txp.setSent.called.should.equal(false); + txp.setSent.calledWith(1).should.equal(false); + w.sendTxProposal.called.should.equal(false); done(); }); diff --git a/test/mocks/FakeBuilder.js b/test/mocks/FakeBuilder.js index f066ceec2..63d247d06 100644 --- a/test/mocks/FakeBuilder.js +++ b/test/mocks/FakeBuilder.js @@ -10,6 +10,11 @@ function Tx() { }]; }; + +Tx.prototype.getSize = function() { + return 1; +}; + Tx.prototype.getHashType = function() { return 1; }; @@ -38,7 +43,7 @@ function FakeBuilder() { address: '2NDJbzwzsmRgD2o5HHXPhuq5g6tkKTjYkd6', amountSatStr: '123', }]), - + } }