From b659333c942b4fd2931eb7524bc3b651dd1747d4 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky <jungans@gmail.com> Date: Thu, 30 Jul 2015 14:55:35 -0300 Subject: [PATCH 1/6] differentiate INSUFFICIENTFUNDS from INSUFFICIENTFUNDSFORFEE --- lib/server.js | 2 +- test/integration/server.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/server.js b/lib/server.js index 1d03ecf..b508368 100644 --- a/lib/server.js +++ b/lib/server.js @@ -896,7 +896,7 @@ WalletService.prototype._selectTxInputs = function(txp, cb) { } if (bitcoreError instanceof Bitcore.errors.Transaction.FeeError) { - return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds for fee')); + return cb(new ClientError('INSUFFICIENTFUNDSFORFEE', 'Insufficient funds for fee')); } if (bitcoreError instanceof Bitcore.errors.Transaction.DustOutputs) { return cb(new ClientError('DUSTAMOUNT', 'Amount below dust threshold')); diff --git a/test/integration/server.js b/test/integration/server.js index e255205..1df33a5 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -1692,7 +1692,7 @@ describe('Wallet service', function() { txOpts.excludeUnconfirmedUtxos = true; server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('INSUFFICIENTFUNDS'); + err.code.should.equal('INSUFFICIENTFUNDSFORFEE'); err.message.should.equal('Insufficient funds for fee'); done(); }); @@ -1826,7 +1826,7 @@ describe('Wallet service', function() { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.048200, null, TestData.copayers[0].privKey_1H_0); server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('INSUFFICIENTFUNDS'); + err.code.should.equal('INSUFFICIENTFUNDSFORFEE'); err.message.should.equal('Insufficient funds for fee'); done(); }); @@ -1850,7 +1850,7 @@ describe('Wallet service', function() { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 80000); server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('INSUFFICIENTFUNDS'); + err.code.should.equal('INSUFFICIENTFUNDSFORFEE'); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 5000); server.createTx(txOpts, function(err, tx) { should.not.exist(err); @@ -4367,7 +4367,7 @@ describe('Wallet service', function() { server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('INSUFFICIENTFUNDS'); + err.code.should.equal('INSUFFICIENTFUNDSFORFEE'); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 5000); server.createTx(txOpts, function(err, tx) { should.not.exist(err); From 86779303a9535c238ca838c1180e1f0baa45dc11 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky <jungans@gmail.com> Date: Thu, 30 Jul 2015 16:08:17 -0300 Subject: [PATCH 2/6] add UPGRADENEEDED error code --- lib/server.js | 2 +- test/integration/server.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/server.js b/lib/server.js index b508368..0488241 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1396,7 +1396,7 @@ WalletService.prototype.getPendingTxs = function(opts, cb) { return _.startsWith(txp.version, '1.'); }); - if (!allLegacy) return cb(new Error('Some spend proposals were created using a newer version. Please upgrade your client app.')) + if (!allLegacy) return cb(new ClientError('UPGRADENEEDED', 'Some spend proposals were created using a newer version of the client app')); } _.each(txps, function(txp) { diff --git a/test/integration/server.js b/test/integration/server.js index 1df33a5..70e89eb 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -4309,7 +4309,8 @@ describe('Wallet service', function() { server.getPendingTxs({}, function(err, txps) { should.exist(err); should.not.exist(txps); - err.toString().should.contain('created by a newer version'); + err.code.should.equal('UPGRADENEEDED'); + err.message.should.contain('newer version'); done(); }); }); From e474c71a1ea8ce5d537233d743e36702a6e735b0 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky <jungans@gmail.com> Date: Fri, 31 Jul 2015 12:16:18 -0300 Subject: [PATCH 3/6] use predefined errors --- lib/{ => errors}/clienterror.js | 2 + lib/errors/errordefinitions.js | 39 ++++++++++++++ lib/server.js | 91 ++++++++++++++------------------- 3 files changed, 79 insertions(+), 53 deletions(-) rename lib/{ => errors}/clienterror.js (97%) create mode 100644 lib/errors/errordefinitions.js diff --git a/lib/clienterror.js b/lib/errors/clienterror.js similarity index 97% rename from lib/clienterror.js rename to lib/errors/clienterror.js index f0f4015..98f264b 100644 --- a/lib/clienterror.js +++ b/lib/errors/clienterror.js @@ -1,3 +1,5 @@ +'use strict'; + function ClientError() { var args = Array.prototype.slice.call(arguments); diff --git a/lib/errors/errordefinitions.js b/lib/errors/errordefinitions.js new file mode 100644 index 0000000..d88d701 --- /dev/null +++ b/lib/errors/errordefinitions.js @@ -0,0 +1,39 @@ +'use strict'; + +var _ = require('lodash'); + +var ClientError = require('./clienterror'); + +var errors = { + BADSIGNATURES: 'Bad signatures', + BLOCKCHAINERROR: 'An error ocurred while trying to interact with the blockchain explorer', + CDATAMISMATCH: 'Copayer data mismatch', + CINWALLET: 'Copayer already in wallet', + CREGISTERED: 'Copayer ID already registered on server', + CVOTED: 'Copayer already voted on this transaction proposal', + DUSTAMOUNT: 'Amount below dust threshold', + INSUFFICIENTFUNDS: 'Insufficient funds', + INSUFFICIENTFUNDSFORFEE: 'Insufficient funds for fee', + INVALIDADDRESS: 'Invalid address', + LOCKEDFUNDS: 'Funds are locked by pending transaction proposals', + NOTALLOWEDTOCREATETX: 'Cannot create TX proposal during backoff time', + NOTAUTHORIZED: 'Not authorized', + TXALREADYBROADCASTED: 'The transaction proposal is already broadcasted', + TXCANNOTREMOVE: 'Cannot remove this tx proposal during locktime', + TXNOTACCEPTED: 'The transaction proposal is not accepted', + TXNOTPENDING: 'The transaction proposal is not pending', + UPGRADENEEDED: 'Client app needs to be upgraded', + WEXISTS: 'Wallet already exists', + WFULL: 'Wallet full', + WNOTFULL: 'Replace only works on full wallets', +}; + +var errorObjects = _.zipObject(_.map(errors, function(msg, code) { + return [code, new ClientError(code, msg)]; +})); + +errorObjects.codes = _.mapValues(errors, function(v, k) { + return k; +}); + +module.exports = errorObjects; diff --git a/lib/server.js b/lib/server.js index 0488241..d60b146 100644 --- a/lib/server.js +++ b/lib/server.js @@ -13,7 +13,9 @@ var PublicKey = Bitcore.PublicKey; var HDPublicKey = Bitcore.HDPublicKey; var Address = Bitcore.Address; -var ClientError = require('./clienterror'); +var ClientError = require('./errors/clienterror'); +var Errors = require('./errors/errordefinitions'); + var Utils = require('./utils'); var Lock = require('./lock'); var Storage = require('./storage'); @@ -159,11 +161,11 @@ WalletService.getInstanceWithAuth = function(opts, cb) { var server = new WalletService(); server.storage.fetchCopayerLookup(opts.copayerId, function(err, copayer) { if (err) return cb(err); - if (!copayer) return cb(new ClientError('NOTAUTHORIZED', 'Copayer not found')); + if (!copayer) return cb(new ClientError(Errors.codes.NOTAUTHORIZED, 'Copayer not found')); var isValid = server._verifySignature(opts.message, opts.signature, copayer.requestPubKey); if (!isValid) - return cb(new ClientError('NOTAUTHORIZED', 'Invalid signature')); + return cb(new ClientError(Errors.codes.NOTAUTHORIZED, 'Invalid signature')); server.copayerId = opts.copayerId; server.walletId = copayer.walletId; @@ -217,7 +219,7 @@ WalletService.prototype.createWallet = function(opts, cb) { return acb(); self.storage.fetchWallet(opts.id, function(err, wallet) { - if (wallet) return acb(new ClientError('WEXISTS', 'Wallet already exists')); + if (wallet) return acb(Errors.WEXISTS); return acb(err); }); }, @@ -295,10 +297,10 @@ WalletService.prototype.replaceTemporaryRequestKey = function(opts, cb) { $.checkState(oldCopayerData); if (oldCopayerData.xPubKey !== opts.xPubKey || !oldCopayerData.isTemporaryRequestKey) - return cb(new ClientError('CDATAMISMATCH', 'Copayer data mismatch')); + return cb(Errors.CDATAMISMATCH); if (wallet.copayers.length != wallet.n) - return cb(new ClientError('WNOTFULL', 'Replace only works on full wallets')); + return cb(Errors.WNOTFULL); wallet.updateCopayerRequestKey(self.copayerId, opts.requestPubKey, opts.copayerSignature); @@ -404,10 +406,9 @@ WalletService.prototype.joinWallet = function(opts, cb) { if (_.find(wallet.copayers, { xPubKey: opts.xPubKey - })) return cb(new ClientError('CINWALLET', 'Copayer already in wallet')); + })) return cb(Errors.CINWALLET); - if (wallet.copayers.length == wallet.n) - return cb(new ClientError('WFULL', 'Wallet full')); + if (wallet.copayers.length == wallet.n) return cb(Errors.WFULL); var copayer = Model.Copayer.create({ name: opts.name, @@ -420,14 +421,12 @@ WalletService.prototype.joinWallet = function(opts, cb) { self.storage.fetchCopayerLookup(copayer.id, function(err, res) { if (err) return cb(err); - if (res) - return cb(new ClientError('CREGISTERED', 'Copayer ID already registered on server')); + if (res) return cb(Errors.CREGISTERED); wallet.addCopayer(copayer); self.storage.storeWalletAndUpdateCopayersLookup(wallet, function(err) { if (err) return cb(err); - async.series([ function(next) { @@ -643,7 +642,7 @@ WalletService.prototype.getUtxos = function(cb) { bc.getUnspentUtxos(addressStrs, function(err, inutxos) { if (err) { log.error('Could not fetch unspent outputs', err); - return cb(new ClientError('BLOCKCHAINERROR', 'Could not fetch unspent outputs')); + return cb(new ClientError(Errors.codes.BLOCKCHAINERROR, 'Could not fetch unspent outputs')); } var utxos = _.map(inutxos, function(utxo) { var u = _.pick(utxo, ['txid', 'vout', 'address', 'scriptPubKey', 'amount', 'satoshis', 'confirmations']); @@ -848,10 +847,8 @@ WalletService.prototype._selectTxInputs = function(txp, cb) { availableAmount = balance.availableAmount; } - if (totalAmount < txp.getTotalAmount()) - return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds')); - if (availableAmount < txp.amount) - return cb(new ClientError('LOCKEDFUNDS', 'Funds are locked by pending transaction proposals')); + if (totalAmount < txp.getTotalAmount()) return cb(Errors.INSUFFICIENTFUNDS); + if (availableAmount < txp.amount) return cb(Errors.LOCKEDFUNDS); // Prepare UTXOs list utxos = _.reject(utxos, 'locked'); @@ -895,12 +892,11 @@ WalletService.prototype._selectTxInputs = function(txp, cb) { } } - if (bitcoreError instanceof Bitcore.errors.Transaction.FeeError) { - return cb(new ClientError('INSUFFICIENTFUNDSFORFEE', 'Insufficient funds for fee')); - } - if (bitcoreError instanceof Bitcore.errors.Transaction.DustOutputs) { - return cb(new ClientError('DUSTAMOUNT', 'Amount below dust threshold')); - } + if (bitcoreError instanceof Bitcore.errors.Transaction.FeeError) + return cb(Errors.INSUFFICIENTFUNDSFORFEE); + + if (bitcoreError instanceof Bitcore.errors.Transaction.DustOutputs) + return cb(Errors.DUSTAMOUNT); return cb(bitcoreError || new Error('Could not select tx inputs')); }); @@ -1007,8 +1003,7 @@ WalletService.prototype.createTx = function(opts, cb) { self._canCreateTx(self.copayerId, function(err, canCreate) { if (err) return cb(err); - if (!canCreate) - return cb(new ClientError('NOTALLOWEDTOCREATETX', 'Cannot create TX proposal during backoff time')); + if (!canCreate) return cb(Errors.NOTALLOWEDTOCREATETX); _.each(opts.outputs, function(output) { output.valid = false; @@ -1016,11 +1011,11 @@ WalletService.prototype.createTx = function(opts, cb) { try { toAddress = new Bitcore.Address(output.toAddress); } catch (ex) { - cb(new ClientError('INVALIDADDRESS', 'Invalid address')); + cb(new ClientError(Errors.codes.INVALIDADDRESS, 'Invalid address')); return false; } if (toAddress.network != wallet.getNetworkName()) { - cb(new ClientError('INVALIDADDRESS', 'Incorrect address network')); + cb(new ClientError(Errors.codes.INVALIDADDRESS, 'Incorrect address network')); return false; } if (!_.isNumber(output.amount) || _.isNaN(output.amount) || output.amount <= 0) { @@ -1028,7 +1023,7 @@ WalletService.prototype.createTx = function(opts, cb) { return false; } if (output.amount < Bitcore.Transaction.DUST_AMOUNT) { - cb(new ClientError('DUSTAMOUNT', 'Amount below dust threshold')); + cb(Errors.DUSTAMOUNT); return false; } output.valid = true; @@ -1155,14 +1150,11 @@ WalletService.prototype.removePendingTx = function(opts, cb) { }, function(err, txp) { if (err) return cb(err); - if (!txp.isPending()) - return cb(new ClientError('TXNOTPENDING', 'Transaction proposal not pending')); - + if (!txp.isPending()) return cb(Errors.TXNOTPENDING); var deleteLockTime = self.getRemainingDeleteLockTime(txp); - if (deleteLockTime > 0) { - return cb(new ClientError('TXCANNOTREMOVE', 'Cannot remove this tx proposal during locktime')); - } + if (deleteLockTime > 0) return cb(Errors.TXCANNOTREMOVE); + self.storage.removeTx(self.walletId, txp.id, function() { self._notify('TxProposalRemoved', {}, cb); }); @@ -1182,7 +1174,7 @@ WalletService.prototype._broadcastTx = function(txp, cb) { bc.broadcast(raw, function(err, txid) { if (err) { log.error('Could not broadcast transaction', err); - return cb(new ClientError('BLOCKCHAINERROR', 'Could not broadcast transaction')); + return cb(new ClientError(Errors.codes.BLOCKCHAINERROR, 'Could not broadcast transaction')); } return cb(null, txid); }) @@ -1194,7 +1186,7 @@ WalletService.prototype._checkTxInBlockchain = function(txp, cb) { bc.getTransaction(tx.id, function(err, tx) { if (err) { log.error('Could not get transaction info', err); - return cb(new ClientError('BLOCKCHAINERROR', 'Could not get transaction info')); + return cb(new ClientError(Errors.codes.BLOCKCHAINERROR, 'Could not get transaction info')); } return cb(null, tx); }) @@ -1223,15 +1215,13 @@ WalletService.prototype.signTx = function(opts, cb) { var action = _.find(txp.actions, { copayerId: self.copayerId }); - if (action) - return cb(new ClientError('CVOTED', 'Copayer already voted on this transaction proposal')); - if (!txp.isPending()) - return cb(new ClientError('TXNOTPENDING', 'The transaction proposal is not pending')); + if (action) return cb(Errors.CVOTED); + if (!txp.isPending()) return cb(Errors.TXNOTPENDING); var copayer = wallet.getCopayer(self.copayerId); if (!txp.sign(self.copayerId, opts.signatures, copayer.xPubKey)) - return cb(new ClientError('BADSIGNATURES', 'Bad signatures')); + return cb(Errors.BADSIGNATURES); self.storage.storeTx(self.walletId, txp, function(err) { if (err) return cb(err); @@ -1296,11 +1286,8 @@ WalletService.prototype.broadcastTx = function(opts, cb) { }, function(err, txp) { if (err) return cb(err); - if (txp.status == 'broadcasted') - return cb(new ClientError('TXALREADYBROADCASTED', 'The transaction proposal is already broadcasted')); - - if (txp.status != 'accepted') - return cb(new ClientError('TXNOTACCEPTED', 'The transaction proposal is not accepted')); + if (txp.status == 'broadcasted') return cb(Errors.TXALREADYBROADCASTED); + if (txp.status != 'accepted') return cb(Errors.TXNOTACCEPTED); self._broadcastTx(txp, function(err, txid) { if (err) { @@ -1340,11 +1327,9 @@ WalletService.prototype.rejectTx = function(opts, cb) { var action = _.find(txp.actions, { copayerId: self.copayerId }); - if (action) - return cb(new ClientError('CVOTED', 'Copayer already voted on this transaction proposal')); - if (txp.status != 'pending') - return cb(new ClientError('TXNOTPENDING', 'The transaction proposal is not pending')); + if (action) return cb(Errors.CVOTED); + if (txp.status != 'pending') return cb(Errors.TXNOTPENDING); txp.reject(self.copayerId, opts.reason); @@ -1396,7 +1381,7 @@ WalletService.prototype.getPendingTxs = function(opts, cb) { return _.startsWith(txp.version, '1.'); }); - if (!allLegacy) return cb(new ClientError('UPGRADENEEDED', 'Some spend proposals were created using a newer version of the client app')); + if (!allLegacy) return cb(new ClientError(Errors.codes.UPGRADENEEDED, 'Some spend proposals were created using a newer version of the client app')); } _.each(txps, function(txp) { @@ -1617,7 +1602,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { bc.getTransactions(addressStrs, from, to, function(err, txs) { if (err) { log.error('Could not fetch transactions', err); - return next(new ClientError('BLOCKCHAINERROR', 'Could not fetch transactions')); + return next(new ClientError(Errors.codes.BLOCKCHAINERROR, 'Could not fetch transactions')); } next(null, self._normalizeTxHistory(txs)); }); @@ -1673,7 +1658,7 @@ WalletService.prototype.scan = function(opts, cb) { checkActivity(_.pluck(addresses, 'address'), networkName, function(err, thereIsActivity) { if (err) { log.error('Could not check address activity', err); - return next(new ClientError('BLOCKCHAINERROR', 'Could not check address activity')); + return next(new ClientError(Errors.codes.BLOCKCHAINERROR, 'Could not check address activity')); } activity = thereIsActivity; From 602bc9a9a390e5730041739cfb1a89a7635d9852 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky <jungans@gmail.com> Date: Sun, 2 Aug 2015 19:48:18 -0300 Subject: [PATCH 4/6] rm BLOCKCHAINERROR error code --- lib/errors/errordefinitions.js | 1 - lib/server.js | 26 ++++++-------------------- test/integration/server.js | 24 ++++++++++-------------- 3 files changed, 16 insertions(+), 35 deletions(-) diff --git a/lib/errors/errordefinitions.js b/lib/errors/errordefinitions.js index d88d701..aa33e98 100644 --- a/lib/errors/errordefinitions.js +++ b/lib/errors/errordefinitions.js @@ -6,7 +6,6 @@ var ClientError = require('./clienterror'); var errors = { BADSIGNATURES: 'Bad signatures', - BLOCKCHAINERROR: 'An error ocurred while trying to interact with the blockchain explorer', CDATAMISMATCH: 'Copayer data mismatch', CINWALLET: 'Copayer already in wallet', CREGISTERED: 'Copayer ID already registered on server', diff --git a/lib/server.js b/lib/server.js index d60b146..11144b9 100644 --- a/lib/server.js +++ b/lib/server.js @@ -640,10 +640,8 @@ WalletService.prototype.getUtxos = function(cb) { var bc = self._getBlockchainExplorer(networkName); bc.getUnspentUtxos(addressStrs, function(err, inutxos) { - if (err) { - log.error('Could not fetch unspent outputs', err); - return cb(new ClientError(Errors.codes.BLOCKCHAINERROR, 'Could not fetch unspent outputs')); - } + if (err) return cb(err); + var utxos = _.map(inutxos, function(utxo) { var u = _.pick(utxo, ['txid', 'vout', 'address', 'scriptPubKey', 'amount', 'satoshis', 'confirmations']); u.confirmations = u.confirmations || 0; @@ -1172,10 +1170,7 @@ WalletService.prototype._broadcastTx = function(txp, cb) { } var bc = this._getBlockchainExplorer(txp.getNetworkName()); bc.broadcast(raw, function(err, txid) { - if (err) { - log.error('Could not broadcast transaction', err); - return cb(new ClientError(Errors.codes.BLOCKCHAINERROR, 'Could not broadcast transaction')); - } + if (err) return cb(err); return cb(null, txid); }) }; @@ -1184,10 +1179,7 @@ WalletService.prototype._checkTxInBlockchain = function(txp, cb) { var tx = txp.getBitcoreTx(); var bc = this._getBlockchainExplorer(txp.getNetworkName()); bc.getTransaction(tx.id, function(err, tx) { - if (err) { - log.error('Could not get transaction info', err); - return cb(new ClientError(Errors.codes.BLOCKCHAINERROR, 'Could not get transaction info')); - } + if (err) return cb(err); return cb(null, tx); }) }; @@ -1600,10 +1592,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) { var from = opts.skip || 0; var to = from + (_.isUndefined(opts.limit) ? 100 : opts.limit); bc.getTransactions(addressStrs, from, to, function(err, txs) { - if (err) { - log.error('Could not fetch transactions', err); - return next(new ClientError(Errors.codes.BLOCKCHAINERROR, 'Could not fetch transactions')); - } + if (err) return cb(err); next(null, self._normalizeTxHistory(txs)); }); }, @@ -1656,10 +1645,7 @@ WalletService.prototype.scan = function(opts, cb) { if (err) return next(err); networkName = networkName || Bitcore.Address(addresses[0].address).toObject().network; checkActivity(_.pluck(addresses, 'address'), networkName, function(err, thereIsActivity) { - if (err) { - log.error('Could not check address activity', err); - return next(new ClientError(Errors.codes.BLOCKCHAINERROR, 'Could not check address activity')); - } + if (err) return cb(err); activity = thereIsActivity; if (thereIsActivity) { diff --git a/test/integration/server.js b/test/integration/server.js index 70e89eb..ed796d9 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -169,10 +169,6 @@ helpers.stubBroadcast = function(txid) { blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, null, txid); }; -helpers.stubBroadcastFail = function() { - blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error'); -}; - helpers.stubHistory = function(txs) { blockchainExplorer.getTransactions = function(addresses, from, to, cb) { var MAX_BATCH_SIZE = 100; @@ -1452,7 +1448,7 @@ describe('Wallet service', function() { should.not.exist(err); server.getBalance({}, function(err, balance) { should.exist(err); - err.code.should.equal('BLOCKCHAINERROR'); + err.toString().should.equal('dummy error'); done(); }); }); @@ -1731,7 +1727,7 @@ describe('Wallet service', function() { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey_1H_0); server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('BLOCKCHAINERROR'); + err.toString().should.equal('dummy error'); done(); }); }); @@ -2602,13 +2598,13 @@ describe('Wallet service', function() { }); it('should keep tx as accepted if unable to broadcast it', function(done) { - helpers.stubBroadcastFail(); + blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error'); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, null); server.broadcastTx({ txProposalId: txpid }, function(err) { should.exist(err); - err.code.should.equal('BLOCKCHAINERROR'); + err.toString().should.equal('broadcast error'); server.getTx({ txProposalId: txpid }, function(err, txp) { @@ -2623,7 +2619,7 @@ describe('Wallet service', function() { }); it('should mark tx as broadcasted if accepted but already in blockchain', function(done) { - helpers.stubBroadcastFail(); + blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error'); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, { txid: '999' }); @@ -2645,13 +2641,13 @@ describe('Wallet service', function() { }); it('should keep tx as accepted if broadcast fails and cannot check tx in blockchain', function(done) { - helpers.stubBroadcastFail(); + blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error'); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, 'bc check error'); server.broadcastTx({ txProposalId: txpid }, function(err) { should.exist(err); - err.code.should.equal('BLOCKCHAINERROR'); + err.toString().should.equal('bc check error'); server.getTx({ txProposalId: txpid }, function(err, txp) { @@ -3085,7 +3081,7 @@ describe('Wallet service', function() { it('should notify sign and acceptance', function(done) { server.getPendingTxs({}, function(err, txs) { - helpers.stubBroadcastFail(); + blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error'); var tx = txs[0]; var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey); server.signTx({ @@ -3770,7 +3766,7 @@ describe('Wallet service', function() { blockchainExplorer.getTransactions = sinon.stub().callsArgWith(3, 'dummy error'); server.getTxHistory({}, function(err, txs) { should.exist(err); - err.code.should.equal('BLOCKCHAINERROR'); + err.toString().should.equal('dummy error'); done(); }); }); @@ -3920,7 +3916,7 @@ describe('Wallet service', function() { blockchainExplorer.getAddressActivity = sinon.stub().callsArgWith(1, 'dummy error'); server.scan({}, function(err) { should.exist(err); - err.code.should.equal('BLOCKCHAINERROR'); + err.toString().should.equal('dummy error'); server.getWallet({}, function(err, wallet) { should.not.exist(err); wallet.scanStatus.should.equal('error'); From e1fac88a8e7850001f5e4878396deb0da4d40a04 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky <jungans@gmail.com> Date: Mon, 3 Aug 2015 16:11:09 -0300 Subject: [PATCH 5/6] improve error codes --- lib/errors/errordefinitions.js | 40 ++++++++++----------- lib/expressapp.js | 4 +-- lib/server.js | 52 +++++++++++++-------------- test/integration/server.js | 66 +++++++++++++++++----------------- 4 files changed, 81 insertions(+), 81 deletions(-) diff --git a/lib/errors/errordefinitions.js b/lib/errors/errordefinitions.js index aa33e98..72f7f10 100644 --- a/lib/errors/errordefinitions.js +++ b/lib/errors/errordefinitions.js @@ -5,26 +5,26 @@ var _ = require('lodash'); var ClientError = require('./clienterror'); var errors = { - BADSIGNATURES: 'Bad signatures', - CDATAMISMATCH: 'Copayer data mismatch', - CINWALLET: 'Copayer already in wallet', - CREGISTERED: 'Copayer ID already registered on server', - CVOTED: 'Copayer already voted on this transaction proposal', - DUSTAMOUNT: 'Amount below dust threshold', - INSUFFICIENTFUNDS: 'Insufficient funds', - INSUFFICIENTFUNDSFORFEE: 'Insufficient funds for fee', - INVALIDADDRESS: 'Invalid address', - LOCKEDFUNDS: 'Funds are locked by pending transaction proposals', - NOTALLOWEDTOCREATETX: 'Cannot create TX proposal during backoff time', - NOTAUTHORIZED: 'Not authorized', - TXALREADYBROADCASTED: 'The transaction proposal is already broadcasted', - TXCANNOTREMOVE: 'Cannot remove this tx proposal during locktime', - TXNOTACCEPTED: 'The transaction proposal is not accepted', - TXNOTPENDING: 'The transaction proposal is not pending', - UPGRADENEEDED: 'Client app needs to be upgraded', - WEXISTS: 'Wallet already exists', - WFULL: 'Wallet full', - WNOTFULL: 'Replace only works on full wallets', + BAD_SIGNATURES: 'Bad signatures', + COPAYER_DATA_MISMATCH: 'Copayer data mismatch', + COPAYER_IN_WALLET: 'Copayer already in wallet', + COPAYER_REGISTERED: 'Copayer ID already registered on server', + COPAYER_VOTED: 'Copayer already voted on this transaction proposal', + DUST_AMOUNT: 'Amount below dust threshold', + INSUFFICIENT_FUNDS: 'Insufficient funds', + INSUFFICIENT_FUNDS_FOR_FEE: 'Insufficient funds for fee', + INVALID_ADDRESS: 'Invalid address', + LOCKED_FUNDS: 'Funds are locked by pending transaction proposals', + NOT_AUTHORIZED: 'Not authorized', + TX_ALREADY_BROADCASTED: 'The transaction proposal is already broadcasted', + TX_CANNOT_CREATE: 'Cannot create TX proposal during backoff time', + TX_CANNOT_REMOVE: 'Cannot remove this tx proposal during locktime', + TX_NOT_ACCEPTED: 'The transaction proposal is not accepted', + TX_NOT_PENDING: 'The transaction proposal is not pending', + UPGRADE_NEEDED: 'Client app needs to be upgraded', + WALLET_ALREADY_EXISTS: 'Wallet already exists', + WALLET_FULL: 'Wallet full', + WALLET_NOT_COMPLETE: 'Replace only works on complete wallets', }; var errorObjects = _.zipObject(_.map(errors, function(msg, code) { diff --git a/lib/expressapp.js b/lib/expressapp.js index 56a1c2a..7642079 100644 --- a/lib/expressapp.js +++ b/lib/expressapp.js @@ -69,7 +69,7 @@ ExpressApp.prototype.start = function(opts, cb) { function returnError(err, res, req) { if (err instanceof WalletService.ClientError) { - var status = (err.code == 'NOTAUTHORIZED') ? 401 : 400; + var status = (err.code == 'NOT_AUTHORIZED') ? 401 : 400; if (!opts.disableLogs) log.info('Client Err: ' + status + ' ' + req.url + ' ' + err); @@ -115,7 +115,7 @@ ExpressApp.prototype.start = function(opts, cb) { var credentials = getCredentials(req); if (!credentials) return returnError(new WalletService.ClientError({ - code: 'NOTAUTHORIZED' + code: 'NOT_AUTHORIZED' }), res, req); var auth = { diff --git a/lib/server.js b/lib/server.js index 11144b9..c558b34 100644 --- a/lib/server.js +++ b/lib/server.js @@ -161,11 +161,11 @@ WalletService.getInstanceWithAuth = function(opts, cb) { var server = new WalletService(); server.storage.fetchCopayerLookup(opts.copayerId, function(err, copayer) { if (err) return cb(err); - if (!copayer) return cb(new ClientError(Errors.codes.NOTAUTHORIZED, 'Copayer not found')); + if (!copayer) return cb(new ClientError(Errors.codes.NOT_AUTHORIZED, 'Copayer not found')); var isValid = server._verifySignature(opts.message, opts.signature, copayer.requestPubKey); if (!isValid) - return cb(new ClientError(Errors.codes.NOTAUTHORIZED, 'Invalid signature')); + return cb(new ClientError(Errors.codes.NOT_AUTHORIZED, 'Invalid signature')); server.copayerId = opts.copayerId; server.walletId = copayer.walletId; @@ -219,7 +219,7 @@ WalletService.prototype.createWallet = function(opts, cb) { return acb(); self.storage.fetchWallet(opts.id, function(err, wallet) { - if (wallet) return acb(Errors.WEXISTS); + if (wallet) return acb(Errors.WALLET_ALREADY_EXISTS); return acb(err); }); }, @@ -297,10 +297,10 @@ WalletService.prototype.replaceTemporaryRequestKey = function(opts, cb) { $.checkState(oldCopayerData); if (oldCopayerData.xPubKey !== opts.xPubKey || !oldCopayerData.isTemporaryRequestKey) - return cb(Errors.CDATAMISMATCH); + return cb(Errors.COPAYER_DATA_MISMATCH); if (wallet.copayers.length != wallet.n) - return cb(Errors.WNOTFULL); + return cb(Errors.WALLET_NOT_COMPLETE); wallet.updateCopayerRequestKey(self.copayerId, opts.requestPubKey, opts.copayerSignature); @@ -406,9 +406,9 @@ WalletService.prototype.joinWallet = function(opts, cb) { if (_.find(wallet.copayers, { xPubKey: opts.xPubKey - })) return cb(Errors.CINWALLET); + })) return cb(Errors.COPAYER_IN_WALLET); - if (wallet.copayers.length == wallet.n) return cb(Errors.WFULL); + if (wallet.copayers.length == wallet.n) return cb(Errors.WALLET_FULL); var copayer = Model.Copayer.create({ name: opts.name, @@ -421,7 +421,7 @@ WalletService.prototype.joinWallet = function(opts, cb) { self.storage.fetchCopayerLookup(copayer.id, function(err, res) { if (err) return cb(err); - if (res) return cb(Errors.CREGISTERED); + if (res) return cb(Errors.COPAYER_REGISTERED); wallet.addCopayer(copayer); self.storage.storeWalletAndUpdateCopayersLookup(wallet, function(err) { @@ -845,8 +845,8 @@ WalletService.prototype._selectTxInputs = function(txp, cb) { availableAmount = balance.availableAmount; } - if (totalAmount < txp.getTotalAmount()) return cb(Errors.INSUFFICIENTFUNDS); - if (availableAmount < txp.amount) return cb(Errors.LOCKEDFUNDS); + if (totalAmount < txp.getTotalAmount()) return cb(Errors.INSUFFICIENT_FUNDS); + if (availableAmount < txp.amount) return cb(Errors.LOCKED_FUNDS); // Prepare UTXOs list utxos = _.reject(utxos, 'locked'); @@ -891,10 +891,10 @@ WalletService.prototype._selectTxInputs = function(txp, cb) { } if (bitcoreError instanceof Bitcore.errors.Transaction.FeeError) - return cb(Errors.INSUFFICIENTFUNDSFORFEE); + return cb(Errors.INSUFFICIENT_FUNDS_FOR_FEE); if (bitcoreError instanceof Bitcore.errors.Transaction.DustOutputs) - return cb(Errors.DUSTAMOUNT); + return cb(Errors.DUST_AMOUNT); return cb(bitcoreError || new Error('Could not select tx inputs')); }); @@ -1001,7 +1001,7 @@ WalletService.prototype.createTx = function(opts, cb) { self._canCreateTx(self.copayerId, function(err, canCreate) { if (err) return cb(err); - if (!canCreate) return cb(Errors.NOTALLOWEDTOCREATETX); + if (!canCreate) return cb(Errors.TX_CANNOT_CREATE); _.each(opts.outputs, function(output) { output.valid = false; @@ -1009,11 +1009,11 @@ WalletService.prototype.createTx = function(opts, cb) { try { toAddress = new Bitcore.Address(output.toAddress); } catch (ex) { - cb(new ClientError(Errors.codes.INVALIDADDRESS, 'Invalid address')); + cb(new ClientError(Errors.codes.INVALID_ADDRESS, 'Invalid address')); return false; } if (toAddress.network != wallet.getNetworkName()) { - cb(new ClientError(Errors.codes.INVALIDADDRESS, 'Incorrect address network')); + cb(new ClientError(Errors.codes.INVALID_ADDRESS, 'Incorrect address network')); return false; } if (!_.isNumber(output.amount) || _.isNaN(output.amount) || output.amount <= 0) { @@ -1021,7 +1021,7 @@ WalletService.prototype.createTx = function(opts, cb) { return false; } if (output.amount < Bitcore.Transaction.DUST_AMOUNT) { - cb(Errors.DUSTAMOUNT); + cb(Errors.DUST_AMOUNT); return false; } output.valid = true; @@ -1148,10 +1148,10 @@ WalletService.prototype.removePendingTx = function(opts, cb) { }, function(err, txp) { if (err) return cb(err); - if (!txp.isPending()) return cb(Errors.TXNOTPENDING); + if (!txp.isPending()) return cb(Errors.TX_NOT_PENDING); var deleteLockTime = self.getRemainingDeleteLockTime(txp); - if (deleteLockTime > 0) return cb(Errors.TXCANNOTREMOVE); + if (deleteLockTime > 0) return cb(Errors.TX_CANNOT_REMOVE); self.storage.removeTx(self.walletId, txp.id, function() { self._notify('TxProposalRemoved', {}, cb); @@ -1207,13 +1207,13 @@ WalletService.prototype.signTx = function(opts, cb) { var action = _.find(txp.actions, { copayerId: self.copayerId }); - if (action) return cb(Errors.CVOTED); - if (!txp.isPending()) return cb(Errors.TXNOTPENDING); + if (action) return cb(Errors.COPAYER_VOTED); + if (!txp.isPending()) return cb(Errors.TX_NOT_PENDING); var copayer = wallet.getCopayer(self.copayerId); if (!txp.sign(self.copayerId, opts.signatures, copayer.xPubKey)) - return cb(Errors.BADSIGNATURES); + return cb(Errors.BAD_SIGNATURES); self.storage.storeTx(self.walletId, txp, function(err) { if (err) return cb(err); @@ -1278,8 +1278,8 @@ WalletService.prototype.broadcastTx = function(opts, cb) { }, function(err, txp) { if (err) return cb(err); - if (txp.status == 'broadcasted') return cb(Errors.TXALREADYBROADCASTED); - if (txp.status != 'accepted') return cb(Errors.TXNOTACCEPTED); + if (txp.status == 'broadcasted') return cb(Errors.TX_ALREADY_BROADCASTED); + if (txp.status != 'accepted') return cb(Errors.TX_NOT_ACCEPTED); self._broadcastTx(txp, function(err, txid) { if (err) { @@ -1320,8 +1320,8 @@ WalletService.prototype.rejectTx = function(opts, cb) { copayerId: self.copayerId }); - if (action) return cb(Errors.CVOTED); - if (txp.status != 'pending') return cb(Errors.TXNOTPENDING); + if (action) return cb(Errors.COPAYER_VOTED); + if (txp.status != 'pending') return cb(Errors.TX_NOT_PENDING); txp.reject(self.copayerId, opts.reason); @@ -1373,7 +1373,7 @@ WalletService.prototype.getPendingTxs = function(opts, cb) { return _.startsWith(txp.version, '1.'); }); - if (!allLegacy) return cb(new ClientError(Errors.codes.UPGRADENEEDED, 'Some spend proposals were created using a newer version of the client app')); + if (!allLegacy) return cb(new ClientError(Errors.codes.UPGRADE_NEEDED, 'Some spend proposals were created using a newer version of the client app')); } _.each(txps, function(txp) { diff --git a/test/integration/server.js b/test/integration/server.js index ed796d9..3f68f96 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -731,7 +731,7 @@ describe('Wallet service', function() { message: TestData.message.text, signature: TestData.message.signature, }, function(err, server) { - err.code.should.equal('NOTAUTHORIZED'); + err.code.should.equal('NOT_AUTHORIZED'); err.message.should.contain('Copayer not found'); done(); }); @@ -744,7 +744,7 @@ describe('Wallet service', function() { message: 'dummy', signature: 'dummy', }, function(err, server) { - err.code.should.equal('NOTAUTHORIZED'); + err.code.should.equal('NOT_AUTHORIZED'); err.message.should.contain('Invalid signature'); done(); }); @@ -977,7 +977,7 @@ describe('Wallet service', function() { }); server.joinWallet(copayerOpts, function(err) { should.exist(err); - err.code.should.equal('WFULL'); + err.code.should.equal('WALLET_FULL'); err.message.should.equal('Wallet full'); done(); }); @@ -995,7 +995,7 @@ describe('Wallet service', function() { should.not.exist(err); server.joinWallet(copayerOpts, function(err) { should.exist(err); - err.code.should.equal('CINWALLET'); + err.code.should.equal('COPAYER_IN_WALLET'); err.message.should.equal('Copayer already in wallet'); done(); }); @@ -1028,7 +1028,7 @@ describe('Wallet service', function() { }); server.joinWallet(copayerOpts, function(err) { should.exist(err); - err.code.should.equal('CREGISTERED'); + err.code.should.equal('COPAYER_REGISTERED'); err.message.should.equal('Copayer ID already registered on server'); done(); }); @@ -1682,13 +1682,13 @@ describe('Wallet service', function() { txOpts.excludeUnconfirmedUtxos = true; server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('INSUFFICIENTFUNDS'); + err.code.should.equal('INSUFFICIENT_FUNDS'); err.message.should.equal('Insufficient funds'); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 2.5, 'some message', TestData.copayers[0].privKey_1H_0); txOpts.excludeUnconfirmedUtxos = true; server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('INSUFFICIENTFUNDSFORFEE'); + err.code.should.equal('INSUFFICIENT_FUNDS_FOR_FEE'); err.message.should.equal('Insufficient funds for fee'); done(); }); @@ -1712,7 +1712,7 @@ describe('Wallet service', function() { txOpts.excludeUnconfirmedUtxos = true; server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('LOCKEDFUNDS'); + err.code.should.equal('LOCKED_FUNDS'); done(); }); }); @@ -1779,7 +1779,7 @@ describe('Wallet service', function() { server.createTx(txOpts, function(err, tx) { should.not.exist(tx); should.exist(err); - err.code.should.equal('INVALIDADDRESS'); + err.code.should.equal('INVALID_ADDRESS'); err.message.should.equal('Incorrect address network'); done(); }); @@ -1801,7 +1801,7 @@ describe('Wallet service', function() { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 120, null, TestData.copayers[0].privKey_1H_0); server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('INSUFFICIENTFUNDS'); + err.code.should.equal('INSUFFICIENT_FUNDS'); err.message.should.equal('Insufficient funds'); server.getPendingTxs({}, function(err, txs) { should.not.exist(err); @@ -1822,7 +1822,7 @@ describe('Wallet service', function() { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.048200, null, TestData.copayers[0].privKey_1H_0); server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('INSUFFICIENTFUNDSFORFEE'); + err.code.should.equal('INSUFFICIENT_FUNDS_FOR_FEE'); err.message.should.equal('Insufficient funds for fee'); done(); }); @@ -1846,7 +1846,7 @@ describe('Wallet service', function() { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 80000); server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('INSUFFICIENTFUNDSFORFEE'); + err.code.should.equal('INSUFFICIENT_FUNDS_FOR_FEE'); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 5000); server.createTx(txOpts, function(err, tx) { should.not.exist(err); @@ -1872,7 +1872,7 @@ describe('Wallet service', function() { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.00000001, null, TestData.copayers[0].privKey_1H_0); server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('DUSTAMOUNT'); + err.code.should.equal('DUST_AMOUNT'); err.message.should.equal('Amount below dust threshold'); done(); }); @@ -1888,7 +1888,7 @@ describe('Wallet service', function() { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount, null, TestData.copayers[0].privKey_1H_0, 10000); server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('DUSTAMOUNT'); + err.code.should.equal('DUST_AMOUNT'); err.message.should.equal('Amount below dust threshold'); done(); }); @@ -1907,7 +1907,7 @@ describe('Wallet service', function() { txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 8, null, TestData.copayers[0].privKey_1H_0); server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('LOCKEDFUNDS'); + err.code.should.equal('LOCKED_FUNDS'); err.message.should.equal('Funds are locked by pending transaction proposals'); done(); }); @@ -1983,7 +1983,7 @@ describe('Wallet service', function() { should.exist(tx); var txOpts2 = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 24, null, TestData.copayers[0].privKey_1H_0); server.createTx(txOpts2, function(err, tx) { - err.code.should.equal('LOCKEDFUNDS'); + err.code.should.equal('LOCKED_FUNDS'); should.not.exist(tx); server.getPendingTxs({}, function(err, txs) { should.not.exist(err); @@ -2188,7 +2188,7 @@ describe('Wallet service', function() { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 1, null, TestData.copayers[0].privKey_1H_0); server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('NOTALLOWEDTOCREATETX'); + err.code.should.equal('TX_CANNOT_CREATE'); next(); }); }, @@ -2210,7 +2210,7 @@ describe('Wallet service', function() { server.createTx(txOpts, function(err, tx) { clock.restore(); should.exist(err); - err.code.should.equal('NOTALLOWEDTOCREATETX'); + err.code.should.equal('TX_CANNOT_CREATE'); next(); }); }, @@ -2302,7 +2302,7 @@ describe('Wallet service', function() { reason: 'some other reason', }, function(err) { should.exist(err); - err.code.should.equal('TXNOTPENDING'); + err.code.should.equal('TX_NOT_PENDING'); done(); }); }); @@ -2367,7 +2367,7 @@ describe('Wallet service', function() { txProposalId: txid, signatures: signatures, }, function(err) { - err.code.should.contain('BADSIG'); + err.code.should.equal('BAD_SIGNATURES'); done(); }); }); @@ -2438,7 +2438,7 @@ describe('Wallet service', function() { server.rejectTx({ txProposalId: txid, }, function(err) { - err.code.should.contain('CVOTED'); + err.code.should.contain('COPAYER_VOTED'); done(); }); }); @@ -2458,7 +2458,7 @@ describe('Wallet service', function() { txProposalId: txid, signatures: signatures, }, function(err) { - err.code.should.contain('CVOTED'); + err.code.should.contain('COPAYER_VOTED'); done(); }); }); @@ -2507,7 +2507,7 @@ describe('Wallet service', function() { signatures: signatures, }, function(err) { should.exist(err); - err.code.should.equal('TXNOTPENDING'); + err.code.should.equal('TX_NOT_PENDING'); done(); }); }); @@ -2575,7 +2575,7 @@ describe('Wallet service', function() { txProposalId: txpid }, function(err) { should.exist(err); - err.code.should.equal('TXALREADYBROADCASTED'); + err.code.should.equal('TX_ALREADY_BROADCASTED'); done(); }); }); @@ -2591,7 +2591,7 @@ describe('Wallet service', function() { txProposalId: txp.id }, function(err) { should.exist(err); - err.code.should.equal('TXNOTACCEPTED'); + err.code.should.equal('TX_NOT_ACCEPTED'); done(); }); }); @@ -3375,7 +3375,7 @@ describe('Wallet service', function() { txProposalId: txp.id }, function(err) { should.exist(err); - err.code.should.equal('TXNOTPENDING'); + err.code.should.equal('TX_NOT_PENDING'); done(); }); }, @@ -3388,7 +3388,7 @@ describe('Wallet service', function() { txProposalId: txp.id }, function(err) { should.exist(err); - err.code.should.contain('TXCANNOTREMOVE'); + err.code.should.contain('TX_CANNOT_REMOVE'); server2.getPendingTxs({}, function(err, txs) { txs.length.should.equal(1); done(); @@ -3408,7 +3408,7 @@ describe('Wallet service', function() { server.removePendingTx({ txProposalId: txp.id }, function(err) { - err.code.should.equal('TXCANNOTREMOVE'); + err.code.should.equal('TX_CANNOT_REMOVE'); err.message.should.contain('Cannot remove'); done(); }); @@ -4113,7 +4113,7 @@ describe('Wallet service', function() { }); copayerOpts.isTemporaryRequestKey = false; server.replaceTemporaryRequestKey(copayerOpts, function(err, wallet) { - err.code.should.equal('WNOTFULL'); + err.code.should.equal('WALLET_NOT_COMPLETE'); done(); }); }); @@ -4145,7 +4145,7 @@ describe('Wallet service', function() { }); copayerOpts.isTemporaryRequestKey = false; server.replaceTemporaryRequestKey(copayerOpts, function(err, wallet) { - err.code.should.equal('CDATAMISMATCH'); + err.code.should.equal('COPAYER_DATA_MISMATCH'); done(); }); }); @@ -4188,7 +4188,7 @@ describe('Wallet service', function() { }); copayerOpts.isTemporaryRequestKey = false; server.replaceTemporaryRequestKey(copayerOpts, function(err, wallet) { - err.code.should.equal('CDATAMISMATCH'); + err.code.should.equal('COPAYER_DATA_MISMATCH'); done(); }); }); @@ -4305,7 +4305,7 @@ describe('Wallet service', function() { server.getPendingTxs({}, function(err, txps) { should.exist(err); should.not.exist(txps); - err.code.should.equal('UPGRADENEEDED'); + err.code.should.equal('UPGRADE_NEEDED'); err.message.should.contain('newer version'); done(); }); @@ -4364,7 +4364,7 @@ describe('Wallet service', function() { server.createTx(txOpts, function(err, tx) { should.exist(err); - err.code.should.equal('INSUFFICIENTFUNDSFORFEE'); + err.code.should.equal('INSUFFICIENT_FUNDS_FOR_FEE'); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 5000); server.createTx(txOpts, function(err, tx) { should.not.exist(err); From 90dfc17ab5c5c5b1b313cd1f25afba06f55cefbe Mon Sep 17 00:00:00 2001 From: Ivan Socolsky <jungans@gmail.com> Date: Tue, 4 Aug 2015 12:07:25 -0300 Subject: [PATCH 6/6] new error for address network mismatch --- lib/errors/errordefinitions.js | 1 + lib/server.js | 4 ++-- test/integration/server.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/errors/errordefinitions.js b/lib/errors/errordefinitions.js index 72f7f10..877be20 100644 --- a/lib/errors/errordefinitions.js +++ b/lib/errors/errordefinitions.js @@ -11,6 +11,7 @@ var errors = { COPAYER_REGISTERED: 'Copayer ID already registered on server', COPAYER_VOTED: 'Copayer already voted on this transaction proposal', DUST_AMOUNT: 'Amount below dust threshold', + INCORRECT_ADDRESS_NETWORK: 'Incorrect address network', INSUFFICIENT_FUNDS: 'Insufficient funds', INSUFFICIENT_FUNDS_FOR_FEE: 'Insufficient funds for fee', INVALID_ADDRESS: 'Invalid address', diff --git a/lib/server.js b/lib/server.js index c558b34..9f6da6f 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1009,11 +1009,11 @@ WalletService.prototype.createTx = function(opts, cb) { try { toAddress = new Bitcore.Address(output.toAddress); } catch (ex) { - cb(new ClientError(Errors.codes.INVALID_ADDRESS, 'Invalid address')); + cb(Errors.INVALID_ADDRESS); return false; } if (toAddress.network != wallet.getNetworkName()) { - cb(new ClientError(Errors.codes.INVALID_ADDRESS, 'Incorrect address network')); + cb(Errors.INCORRECT_ADDRESS_NETWORK); return false; } if (!_.isNumber(output.amount) || _.isNaN(output.amount) || output.amount <= 0) { diff --git a/test/integration/server.js b/test/integration/server.js index 3f68f96..4b5e217 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -1779,7 +1779,7 @@ describe('Wallet service', function() { server.createTx(txOpts, function(err, tx) { should.not.exist(tx); should.exist(err); - err.code.should.equal('INVALID_ADDRESS'); + err.code.should.equal('INCORRECT_ADDRESS_NETWORK'); err.message.should.equal('Incorrect address network'); done(); });