From 2558dcbbbdc6836e9852ade12f0149fc048e5a83 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Wed, 29 Jul 2015 17:45:25 -0300 Subject: [PATCH] support legacy clients + tests --- lib/model/txproposal.js | 2 +- lib/server.js | 35 ++++++++++--- package.json | 4 +- test/integration/server.js | 103 +++++++++++++++++++++++++++++++++++++ test/models/txproposal.js | 12 +---- 5 files changed, 135 insertions(+), 21 deletions(-) diff --git a/lib/model/txproposal.js b/lib/model/txproposal.js index 5a05b00..73b6c63 100644 --- a/lib/model/txproposal.js +++ b/lib/model/txproposal.js @@ -9,7 +9,7 @@ var Address = Bitcore.Address; var TxProposalAction = require('./txproposalaction'); function TxProposal() { - this.version = '1.0.1'; + this.version = '2.0.0'; }; TxProposal.Types = { diff --git a/lib/server.js b/lib/server.js index 24b8468..d4cdb3f 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1052,6 +1052,10 @@ WalletService.prototype.createTx = function(opts, cb) { excludeUnconfirmedUtxos: !!opts.excludeUnconfirmedUtxos, }); + if (!self.clientVersion || _.startsWith(self.clientVersion, 'bwc-0.0.')) { + txp.version = '1.0.1'; + } + self._selectTxInputs(txp, function(err) { if (err) return cb(err); @@ -1384,6 +1388,14 @@ WalletService.prototype.getPendingTxs = function(opts, cb) { self.storage.fetchPendingTxs(self.walletId, function(err, txps) { if (err) return cb(err); + if (_.startsWith(self.clientVersion, 'bwc-0.0.')) { + var allLegacy = _.all(txps, function(txp) { + return _.startsWith(txp.version, '1.'); + }); + + if (!allLegacy) return cb(new Error('Some transaction proposals were created using a newer version. Please upgrade your client app.')) + } + _.each(txps, function(txp) { txp.deleteLockTime = self.getRemainingDeleteLockTime(txp); }); @@ -1534,7 +1546,12 @@ WalletService.prototype.getTxHistory = function(opts, cb) { amount = 0; } - function outputMap(o) { return { amount: o.amount, address: o.address } }; + function outputMap(o) { + return { + amount: o.amount, + address: o.address + } + }; var newTx = { txid: tx.txid, action: action, @@ -1542,7 +1559,9 @@ WalletService.prototype.getTxHistory = function(opts, cb) { fees: tx.fees, time: tx.time, addressTo: addressTo, - outputs: _.map(_.filter(outputs, { isChange: false }), outputMap), + outputs: _.map(_.filter(outputs, { + isChange: false + }), outputMap), confirmations: tx.confirmations, }; @@ -1556,11 +1575,13 @@ WalletService.prototype.getTxHistory = function(opts, cb) { return _.pick(action, ['createdOn', 'type', 'copayerId', 'copayerName', 'comment']); }); _.each(newTx.outputs, function(output) { - var query = { toAddress: output.address, amount: output.amount }; - var txpOut = _.find(proposal.outputs, query); - output.message = txpOut ? txpOut.message : null; - } - ); + var query = { + toAddress: output.address, + amount: output.amount + }; + var txpOut = _.find(proposal.outputs, query); + output.message = txpOut ? txpOut.message : null; + }); // newTx.sentTs = proposal.sentTs; // newTx.merchant = proposal.merchant; //newTx.paymentAckMemo = proposal.paymentAckMemo; diff --git a/package.json b/package.json index 00ae69c..5fe297f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "bitcore-wallet-service", "description": "A service for Mutisig HD Bitcoin Wallets", "author": "BitPay Inc", - "version": "0.0.47", + "version": "0.1.0", "keywords": [ "bitcoin", "copay", @@ -20,7 +20,7 @@ "dependencies": { "async": "^0.9.0", "bitcore": "^0.12.9", - "bitcore-wallet-utils": "^0.0.23", + "bitcore-wallet-utils": "^0.1.0", "body-parser": "^1.11.0", "coveralls": "^2.11.2", "email-validator": "^1.0.1", diff --git a/test/integration/server.js b/test/integration/server.js index fdd3d05..83a1cac 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -35,6 +35,7 @@ helpers.getAuthServer = function(copayerId, cb) { copayerId: copayerId, message: 'dummy', signature: 'dummy', + clientVersion: 'bwc-0.1.0', }, function(err, server) { verifyStub.restore(); if (err || !server) throw new Error('Could not login as copayerId ' + copayerId); @@ -4249,4 +4250,106 @@ describe('Wallet service', function() { }); }); }); + + + describe('Legacy', function() { + describe('Fees', function() { + var server, wallet; + beforeEach(function(done) { + helpers.createAndJoinWallet(2, 3, function(s, w) { + server = s; + wallet = w; + done(); + }); + }); + + it('should create a tx from legacy (bwc-0.0.*) client', function(done) { + helpers.stubUtxos(server, wallet, [100, 200], function() { + var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey_1H_0); + + var verifyStub = sinon.stub(WalletService.prototype, '_verifySignature'); + verifyStub.returns(true); + WalletService.getInstanceWithAuth({ + copayerId: wallet.copayers[0].id, + message: 'dummy', + signature: 'dummy', + clientVersion: 'bwc-0.0.40', + }, function(err, server) { + should.not.exist(err); + should.exist(server); + verifyStub.restore(); + server.createTx(txOpts, function(err, tx) { + should.not.exist(err); + should.exist(tx); + tx.amount.should.equal(helpers.toSatoshi(80)); + tx.fee.should.equal(WalletUtils.DEFAULT_FEE_PER_KB); + done(); + }); + }); + }); + }); + it('should return error when fetching new txps from legacy (bwc-0.0.*) client', function(done) { + helpers.stubUtxos(server, wallet, [100, 200], function() { + var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey_1H_0); + server.createTx(txOpts, function(err, tx) { + should.not.exist(err); + should.exist(tx); + + var verifyStub = sinon.stub(WalletService.prototype, '_verifySignature'); + verifyStub.returns(true); + WalletService.getInstanceWithAuth({ + copayerId: wallet.copayers[0].id, + message: 'dummy', + signature: 'dummy', + clientVersion: 'bwc-0.0.40', + }, function(err, server) { + should.not.exist(err); + should.exist(server); + verifyStub.restore(); + server.getPendingTxs({}, function(err, txps) { + should.exist(err); + should.not.exist(txps); + err.toString().should.contain('created by a newer version'); + done(); + }); + }); + }); + }); + }); + it('should create a tx from legacy (bwc-0.0.*) client and sign it from newer client', function(done) { + helpers.stubUtxos(server, wallet, [100, 200], function() { + var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey_1H_0); + + var verifyStub = sinon.stub(WalletService.prototype, '_verifySignature'); + verifyStub.returns(true); + WalletService.getInstanceWithAuth({ + copayerId: wallet.copayers[0].id, + message: 'dummy', + signature: 'dummy', + clientVersion: 'bwc-0.0.40', + }, function(err, server) { + should.not.exist(err); + should.exist(server); + verifyStub.restore(); + server.createTx(txOpts, function(err, tx) { + should.not.exist(err); + should.exist(tx); + tx.amount.should.equal(helpers.toSatoshi(80)); + tx.fee.should.equal(WalletUtils.DEFAULT_FEE_PER_KB); + helpers.getAuthServer(wallet.copayers[0].id, function(server) { + var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey); + server.signTx({ + txProposalId: tx.id, + signatures: signatures, + }, function(err) { + should.not.exist(err); + done(); + }); + }); + }); + }); + }); + }); + }); + }); }); diff --git a/test/models/txproposal.js b/test/models/txproposal.js index 9de4a3a..bc9cf14 100644 --- a/test/models/txproposal.js +++ b/test/models/txproposal.js @@ -153,18 +153,8 @@ var aTxpOpts = function(type) { }; var aTXP = function(type) { - var version; - switch (type) { - case TxProposal.Types.MULTIPLEOUTPUTS: - version = '1.0.1'; - break; - default: - version = '1.0.0'; - break - } - var txp = { - "version": version, + "version": '2.0.0', "type": type, "createdOn": 1423146231, "id": "75c34f49-1ed6-255f-e9fd-0c71ae75ed1e",