Browse Source

Merge pull request #307 from isocolsky/ref/error_codes

Ref/error codes
activeAddress
Matias Alejo Garcia 10 years ago
parent
commit
789c171a4e
  1. 2
      lib/errors/clienterror.js
  2. 39
      lib/errors/errordefinitions.js
  3. 4
      lib/expressapp.js
  4. 107
      lib/server.js
  5. 91
      test/integration/server.js

2
lib/clienterror.js → lib/errors/clienterror.js

@ -1,3 +1,5 @@
'use strict';
function ClientError() { function ClientError() {
var args = Array.prototype.slice.call(arguments); var args = Array.prototype.slice.call(arguments);

39
lib/errors/errordefinitions.js

@ -0,0 +1,39 @@
'use strict';
var _ = require('lodash');
var ClientError = require('./clienterror');
var errors = {
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',
INCORRECT_ADDRESS_NETWORK: 'Incorrect address network',
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) {
return [code, new ClientError(code, msg)];
}));
errorObjects.codes = _.mapValues(errors, function(v, k) {
return k;
});
module.exports = errorObjects;

4
lib/expressapp.js

@ -69,7 +69,7 @@ ExpressApp.prototype.start = function(opts, cb) {
function returnError(err, res, req) { function returnError(err, res, req) {
if (err instanceof WalletService.ClientError) { if (err instanceof WalletService.ClientError) {
var status = (err.code == 'NOTAUTHORIZED') ? 401 : 400; var status = (err.code == 'NOT_AUTHORIZED') ? 401 : 400;
if (!opts.disableLogs) if (!opts.disableLogs)
log.info('Client Err: ' + status + ' ' + req.url + ' ' + err); log.info('Client Err: ' + status + ' ' + req.url + ' ' + err);
@ -115,7 +115,7 @@ ExpressApp.prototype.start = function(opts, cb) {
var credentials = getCredentials(req); var credentials = getCredentials(req);
if (!credentials) if (!credentials)
return returnError(new WalletService.ClientError({ return returnError(new WalletService.ClientError({
code: 'NOTAUTHORIZED' code: 'NOT_AUTHORIZED'
}), res, req); }), res, req);
var auth = { var auth = {

107
lib/server.js

@ -13,7 +13,9 @@ var PublicKey = Bitcore.PublicKey;
var HDPublicKey = Bitcore.HDPublicKey; var HDPublicKey = Bitcore.HDPublicKey;
var Address = Bitcore.Address; var Address = Bitcore.Address;
var ClientError = require('./clienterror'); var ClientError = require('./errors/clienterror');
var Errors = require('./errors/errordefinitions');
var Utils = require('./utils'); var Utils = require('./utils');
var Lock = require('./lock'); var Lock = require('./lock');
var Storage = require('./storage'); var Storage = require('./storage');
@ -159,11 +161,11 @@ WalletService.getInstanceWithAuth = function(opts, cb) {
var server = new WalletService(); var server = new WalletService();
server.storage.fetchCopayerLookup(opts.copayerId, function(err, copayer) { server.storage.fetchCopayerLookup(opts.copayerId, function(err, copayer) {
if (err) return cb(err); if (err) return cb(err);
if (!copayer) return cb(new ClientError('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); var isValid = server._verifySignature(opts.message, opts.signature, copayer.requestPubKey);
if (!isValid) if (!isValid)
return cb(new ClientError('NOTAUTHORIZED', 'Invalid signature')); return cb(new ClientError(Errors.codes.NOT_AUTHORIZED, 'Invalid signature'));
server.copayerId = opts.copayerId; server.copayerId = opts.copayerId;
server.walletId = copayer.walletId; server.walletId = copayer.walletId;
@ -217,7 +219,7 @@ WalletService.prototype.createWallet = function(opts, cb) {
return acb(); return acb();
self.storage.fetchWallet(opts.id, function(err, wallet) { self.storage.fetchWallet(opts.id, function(err, wallet) {
if (wallet) return acb(new ClientError('WEXISTS', 'Wallet already exists')); if (wallet) return acb(Errors.WALLET_ALREADY_EXISTS);
return acb(err); return acb(err);
}); });
}, },
@ -295,10 +297,10 @@ WalletService.prototype.replaceTemporaryRequestKey = function(opts, cb) {
$.checkState(oldCopayerData); $.checkState(oldCopayerData);
if (oldCopayerData.xPubKey !== opts.xPubKey || !oldCopayerData.isTemporaryRequestKey) if (oldCopayerData.xPubKey !== opts.xPubKey || !oldCopayerData.isTemporaryRequestKey)
return cb(new ClientError('CDATAMISMATCH', 'Copayer data mismatch')); return cb(Errors.COPAYER_DATA_MISMATCH);
if (wallet.copayers.length != wallet.n) if (wallet.copayers.length != wallet.n)
return cb(new ClientError('WNOTFULL', 'Replace only works on full wallets')); return cb(Errors.WALLET_NOT_COMPLETE);
wallet.updateCopayerRequestKey(self.copayerId, opts.requestPubKey, opts.copayerSignature); wallet.updateCopayerRequestKey(self.copayerId, opts.requestPubKey, opts.copayerSignature);
@ -404,10 +406,9 @@ WalletService.prototype.joinWallet = function(opts, cb) {
if (_.find(wallet.copayers, { if (_.find(wallet.copayers, {
xPubKey: opts.xPubKey xPubKey: opts.xPubKey
})) return cb(new ClientError('CINWALLET', 'Copayer already in wallet')); })) return cb(Errors.COPAYER_IN_WALLET);
if (wallet.copayers.length == wallet.n) if (wallet.copayers.length == wallet.n) return cb(Errors.WALLET_FULL);
return cb(new ClientError('WFULL', 'Wallet full'));
var copayer = Model.Copayer.create({ var copayer = Model.Copayer.create({
name: opts.name, name: opts.name,
@ -420,14 +421,12 @@ WalletService.prototype.joinWallet = function(opts, cb) {
self.storage.fetchCopayerLookup(copayer.id, function(err, res) { self.storage.fetchCopayerLookup(copayer.id, function(err, res) {
if (err) return cb(err); if (err) return cb(err);
if (res) if (res) return cb(Errors.COPAYER_REGISTERED);
return cb(new ClientError('CREGISTERED', 'Copayer ID already registered on server'));
wallet.addCopayer(copayer); wallet.addCopayer(copayer);
self.storage.storeWalletAndUpdateCopayersLookup(wallet, function(err) { self.storage.storeWalletAndUpdateCopayersLookup(wallet, function(err) {
if (err) return cb(err); if (err) return cb(err);
async.series([ async.series([
function(next) { function(next) {
@ -641,10 +640,8 @@ WalletService.prototype.getUtxos = function(cb) {
var bc = self._getBlockchainExplorer(networkName); var bc = self._getBlockchainExplorer(networkName);
bc.getUnspentUtxos(addressStrs, function(err, inutxos) { bc.getUnspentUtxos(addressStrs, function(err, inutxos) {
if (err) { if (err) return cb(err);
log.error('Could not fetch unspent outputs', err);
return cb(new ClientError('BLOCKCHAINERROR', 'Could not fetch unspent outputs'));
}
var utxos = _.map(inutxos, function(utxo) { var utxos = _.map(inutxos, function(utxo) {
var u = _.pick(utxo, ['txid', 'vout', 'address', 'scriptPubKey', 'amount', 'satoshis', 'confirmations']); var u = _.pick(utxo, ['txid', 'vout', 'address', 'scriptPubKey', 'amount', 'satoshis', 'confirmations']);
u.confirmations = u.confirmations || 0; u.confirmations = u.confirmations || 0;
@ -848,10 +845,8 @@ WalletService.prototype._selectTxInputs = function(txp, cb) {
availableAmount = balance.availableAmount; availableAmount = balance.availableAmount;
} }
if (totalAmount < txp.getTotalAmount()) if (totalAmount < txp.getTotalAmount()) return cb(Errors.INSUFFICIENT_FUNDS);
return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds')); if (availableAmount < txp.amount) return cb(Errors.LOCKED_FUNDS);
if (availableAmount < txp.amount)
return cb(new ClientError('LOCKEDFUNDS', 'Funds are locked by pending transaction proposals'));
// Prepare UTXOs list // Prepare UTXOs list
utxos = _.reject(utxos, 'locked'); utxos = _.reject(utxos, 'locked');
@ -895,12 +890,11 @@ WalletService.prototype._selectTxInputs = function(txp, cb) {
} }
} }
if (bitcoreError instanceof Bitcore.errors.Transaction.FeeError) { if (bitcoreError instanceof Bitcore.errors.Transaction.FeeError)
return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds for fee')); return cb(Errors.INSUFFICIENT_FUNDS_FOR_FEE);
}
if (bitcoreError instanceof Bitcore.errors.Transaction.DustOutputs) { if (bitcoreError instanceof Bitcore.errors.Transaction.DustOutputs)
return cb(new ClientError('DUSTAMOUNT', 'Amount below dust threshold')); return cb(Errors.DUST_AMOUNT);
}
return cb(bitcoreError || new Error('Could not select tx inputs')); return cb(bitcoreError || new Error('Could not select tx inputs'));
}); });
@ -1007,8 +1001,7 @@ WalletService.prototype.createTx = function(opts, cb) {
self._canCreateTx(self.copayerId, function(err, canCreate) { self._canCreateTx(self.copayerId, function(err, canCreate) {
if (err) return cb(err); if (err) return cb(err);
if (!canCreate) if (!canCreate) return cb(Errors.TX_CANNOT_CREATE);
return cb(new ClientError('NOTALLOWEDTOCREATETX', 'Cannot create TX proposal during backoff time'));
_.each(opts.outputs, function(output) { _.each(opts.outputs, function(output) {
output.valid = false; output.valid = false;
@ -1016,11 +1009,11 @@ WalletService.prototype.createTx = function(opts, cb) {
try { try {
toAddress = new Bitcore.Address(output.toAddress); toAddress = new Bitcore.Address(output.toAddress);
} catch (ex) { } catch (ex) {
cb(new ClientError('INVALIDADDRESS', 'Invalid address')); cb(Errors.INVALID_ADDRESS);
return false; return false;
} }
if (toAddress.network != wallet.getNetworkName()) { if (toAddress.network != wallet.getNetworkName()) {
cb(new ClientError('INVALIDADDRESS', 'Incorrect address network')); cb(Errors.INCORRECT_ADDRESS_NETWORK);
return false; return false;
} }
if (!_.isNumber(output.amount) || _.isNaN(output.amount) || output.amount <= 0) { if (!_.isNumber(output.amount) || _.isNaN(output.amount) || output.amount <= 0) {
@ -1028,7 +1021,7 @@ WalletService.prototype.createTx = function(opts, cb) {
return false; return false;
} }
if (output.amount < Bitcore.Transaction.DUST_AMOUNT) { if (output.amount < Bitcore.Transaction.DUST_AMOUNT) {
cb(new ClientError('DUSTAMOUNT', 'Amount below dust threshold')); cb(Errors.DUST_AMOUNT);
return false; return false;
} }
output.valid = true; output.valid = true;
@ -1155,14 +1148,11 @@ WalletService.prototype.removePendingTx = function(opts, cb) {
}, function(err, txp) { }, function(err, txp) {
if (err) return cb(err); if (err) return cb(err);
if (!txp.isPending()) if (!txp.isPending()) return cb(Errors.TX_NOT_PENDING);
return cb(new ClientError('TXNOTPENDING', 'Transaction proposal not pending'));
var deleteLockTime = self.getRemainingDeleteLockTime(txp); var deleteLockTime = self.getRemainingDeleteLockTime(txp);
if (deleteLockTime > 0) { if (deleteLockTime > 0) return cb(Errors.TX_CANNOT_REMOVE);
return cb(new ClientError('TXCANNOTREMOVE', 'Cannot remove this tx proposal during locktime'));
}
self.storage.removeTx(self.walletId, txp.id, function() { self.storage.removeTx(self.walletId, txp.id, function() {
self._notify('TxProposalRemoved', {}, cb); self._notify('TxProposalRemoved', {}, cb);
}); });
@ -1180,10 +1170,7 @@ WalletService.prototype._broadcastTx = function(txp, cb) {
} }
var bc = this._getBlockchainExplorer(txp.getNetworkName()); var bc = this._getBlockchainExplorer(txp.getNetworkName());
bc.broadcast(raw, function(err, txid) { bc.broadcast(raw, function(err, txid) {
if (err) { if (err) return cb(err);
log.error('Could not broadcast transaction', err);
return cb(new ClientError('BLOCKCHAINERROR', 'Could not broadcast transaction'));
}
return cb(null, txid); return cb(null, txid);
}) })
}; };
@ -1192,10 +1179,7 @@ WalletService.prototype._checkTxInBlockchain = function(txp, cb) {
var tx = txp.getBitcoreTx(); var tx = txp.getBitcoreTx();
var bc = this._getBlockchainExplorer(txp.getNetworkName()); var bc = this._getBlockchainExplorer(txp.getNetworkName());
bc.getTransaction(tx.id, function(err, tx) { bc.getTransaction(tx.id, function(err, tx) {
if (err) { if (err) return cb(err);
log.error('Could not get transaction info', err);
return cb(new ClientError('BLOCKCHAINERROR', 'Could not get transaction info'));
}
return cb(null, tx); return cb(null, tx);
}) })
}; };
@ -1223,15 +1207,13 @@ WalletService.prototype.signTx = function(opts, cb) {
var action = _.find(txp.actions, { var action = _.find(txp.actions, {
copayerId: self.copayerId copayerId: self.copayerId
}); });
if (action) if (action) return cb(Errors.COPAYER_VOTED);
return cb(new ClientError('CVOTED', 'Copayer already voted on this transaction proposal')); if (!txp.isPending()) return cb(Errors.TX_NOT_PENDING);
if (!txp.isPending())
return cb(new ClientError('TXNOTPENDING', 'The transaction proposal is not pending'));
var copayer = wallet.getCopayer(self.copayerId); var copayer = wallet.getCopayer(self.copayerId);
if (!txp.sign(self.copayerId, opts.signatures, copayer.xPubKey)) if (!txp.sign(self.copayerId, opts.signatures, copayer.xPubKey))
return cb(new ClientError('BADSIGNATURES', 'Bad signatures')); return cb(Errors.BAD_SIGNATURES);
self.storage.storeTx(self.walletId, txp, function(err) { self.storage.storeTx(self.walletId, txp, function(err) {
if (err) return cb(err); if (err) return cb(err);
@ -1296,11 +1278,8 @@ WalletService.prototype.broadcastTx = function(opts, cb) {
}, function(err, txp) { }, function(err, txp) {
if (err) return cb(err); if (err) return cb(err);
if (txp.status == 'broadcasted') if (txp.status == 'broadcasted') return cb(Errors.TX_ALREADY_BROADCASTED);
return cb(new ClientError('TXALREADYBROADCASTED', 'The transaction proposal is already broadcasted')); if (txp.status != 'accepted') return cb(Errors.TX_NOT_ACCEPTED);
if (txp.status != 'accepted')
return cb(new ClientError('TXNOTACCEPTED', 'The transaction proposal is not accepted'));
self._broadcastTx(txp, function(err, txid) { self._broadcastTx(txp, function(err, txid) {
if (err) { if (err) {
@ -1340,11 +1319,9 @@ WalletService.prototype.rejectTx = function(opts, cb) {
var action = _.find(txp.actions, { var action = _.find(txp.actions, {
copayerId: self.copayerId copayerId: self.copayerId
}); });
if (action)
return cb(new ClientError('CVOTED', 'Copayer already voted on this transaction proposal'));
if (txp.status != 'pending') if (action) return cb(Errors.COPAYER_VOTED);
return cb(new ClientError('TXNOTPENDING', 'The transaction proposal is not pending')); if (txp.status != 'pending') return cb(Errors.TX_NOT_PENDING);
txp.reject(self.copayerId, opts.reason); txp.reject(self.copayerId, opts.reason);
@ -1396,7 +1373,7 @@ WalletService.prototype.getPendingTxs = function(opts, cb) {
return _.startsWith(txp.version, '1.'); 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(Errors.codes.UPGRADE_NEEDED, 'Some spend proposals were created using a newer version of the client app'));
} }
_.each(txps, function(txp) { _.each(txps, function(txp) {
@ -1615,10 +1592,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) {
var from = opts.skip || 0; var from = opts.skip || 0;
var to = from + (_.isUndefined(opts.limit) ? 100 : opts.limit); var to = from + (_.isUndefined(opts.limit) ? 100 : opts.limit);
bc.getTransactions(addressStrs, from, to, function(err, txs) { bc.getTransactions(addressStrs, from, to, function(err, txs) {
if (err) { if (err) return cb(err);
log.error('Could not fetch transactions', err);
return next(new ClientError('BLOCKCHAINERROR', 'Could not fetch transactions'));
}
next(null, self._normalizeTxHistory(txs)); next(null, self._normalizeTxHistory(txs));
}); });
}, },
@ -1671,10 +1645,7 @@ WalletService.prototype.scan = function(opts, cb) {
if (err) return next(err); if (err) return next(err);
networkName = networkName || Bitcore.Address(addresses[0].address).toObject().network; networkName = networkName || Bitcore.Address(addresses[0].address).toObject().network;
checkActivity(_.pluck(addresses, 'address'), networkName, function(err, thereIsActivity) { checkActivity(_.pluck(addresses, 'address'), networkName, function(err, thereIsActivity) {
if (err) { if (err) return cb(err);
log.error('Could not check address activity', err);
return next(new ClientError('BLOCKCHAINERROR', 'Could not check address activity'));
}
activity = thereIsActivity; activity = thereIsActivity;
if (thereIsActivity) { if (thereIsActivity) {

91
test/integration/server.js

@ -169,10 +169,6 @@ helpers.stubBroadcast = function(txid) {
blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, null, txid); blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, null, txid);
}; };
helpers.stubBroadcastFail = function() {
blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error');
};
helpers.stubHistory = function(txs) { helpers.stubHistory = function(txs) {
blockchainExplorer.getTransactions = function(addresses, from, to, cb) { blockchainExplorer.getTransactions = function(addresses, from, to, cb) {
var MAX_BATCH_SIZE = 100; var MAX_BATCH_SIZE = 100;
@ -735,7 +731,7 @@ describe('Wallet service', function() {
message: TestData.message.text, message: TestData.message.text,
signature: TestData.message.signature, signature: TestData.message.signature,
}, function(err, server) { }, function(err, server) {
err.code.should.equal('NOTAUTHORIZED'); err.code.should.equal('NOT_AUTHORIZED');
err.message.should.contain('Copayer not found'); err.message.should.contain('Copayer not found');
done(); done();
}); });
@ -748,7 +744,7 @@ describe('Wallet service', function() {
message: 'dummy', message: 'dummy',
signature: 'dummy', signature: 'dummy',
}, function(err, server) { }, function(err, server) {
err.code.should.equal('NOTAUTHORIZED'); err.code.should.equal('NOT_AUTHORIZED');
err.message.should.contain('Invalid signature'); err.message.should.contain('Invalid signature');
done(); done();
}); });
@ -981,7 +977,7 @@ describe('Wallet service', function() {
}); });
server.joinWallet(copayerOpts, function(err) { server.joinWallet(copayerOpts, function(err) {
should.exist(err); should.exist(err);
err.code.should.equal('WFULL'); err.code.should.equal('WALLET_FULL');
err.message.should.equal('Wallet full'); err.message.should.equal('Wallet full');
done(); done();
}); });
@ -999,7 +995,7 @@ describe('Wallet service', function() {
should.not.exist(err); should.not.exist(err);
server.joinWallet(copayerOpts, function(err) { server.joinWallet(copayerOpts, function(err) {
should.exist(err); should.exist(err);
err.code.should.equal('CINWALLET'); err.code.should.equal('COPAYER_IN_WALLET');
err.message.should.equal('Copayer already in wallet'); err.message.should.equal('Copayer already in wallet');
done(); done();
}); });
@ -1032,7 +1028,7 @@ describe('Wallet service', function() {
}); });
server.joinWallet(copayerOpts, function(err) { server.joinWallet(copayerOpts, function(err) {
should.exist(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'); err.message.should.equal('Copayer ID already registered on server');
done(); done();
}); });
@ -1452,7 +1448,7 @@ describe('Wallet service', function() {
should.not.exist(err); should.not.exist(err);
server.getBalance({}, function(err, balance) { server.getBalance({}, function(err, balance) {
should.exist(err); should.exist(err);
err.code.should.equal('BLOCKCHAINERROR'); err.toString().should.equal('dummy error');
done(); done();
}); });
}); });
@ -1686,13 +1682,13 @@ describe('Wallet service', function() {
txOpts.excludeUnconfirmedUtxos = true; txOpts.excludeUnconfirmedUtxos = true;
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('INSUFFICIENTFUNDS'); err.code.should.equal('INSUFFICIENT_FUNDS');
err.message.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); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 2.5, 'some message', TestData.copayers[0].privKey_1H_0);
txOpts.excludeUnconfirmedUtxos = true; txOpts.excludeUnconfirmedUtxos = true;
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('INSUFFICIENTFUNDS'); err.code.should.equal('INSUFFICIENT_FUNDS_FOR_FEE');
err.message.should.equal('Insufficient funds for fee'); err.message.should.equal('Insufficient funds for fee');
done(); done();
}); });
@ -1716,7 +1712,7 @@ describe('Wallet service', function() {
txOpts.excludeUnconfirmedUtxos = true; txOpts.excludeUnconfirmedUtxos = true;
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('LOCKEDFUNDS'); err.code.should.equal('LOCKED_FUNDS');
done(); done();
}); });
}); });
@ -1731,7 +1727,7 @@ describe('Wallet service', function() {
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey_1H_0); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey_1H_0);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('BLOCKCHAINERROR'); err.toString().should.equal('dummy error');
done(); done();
}); });
}); });
@ -1783,7 +1779,7 @@ describe('Wallet service', function() {
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.not.exist(tx); should.not.exist(tx);
should.exist(err); should.exist(err);
err.code.should.equal('INVALIDADDRESS'); err.code.should.equal('INCORRECT_ADDRESS_NETWORK');
err.message.should.equal('Incorrect address network'); err.message.should.equal('Incorrect address network');
done(); done();
}); });
@ -1805,7 +1801,7 @@ describe('Wallet service', function() {
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 120, null, TestData.copayers[0].privKey_1H_0); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 120, null, TestData.copayers[0].privKey_1H_0);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('INSUFFICIENTFUNDS'); err.code.should.equal('INSUFFICIENT_FUNDS');
err.message.should.equal('Insufficient funds'); err.message.should.equal('Insufficient funds');
server.getPendingTxs({}, function(err, txs) { server.getPendingTxs({}, function(err, txs) {
should.not.exist(err); should.not.exist(err);
@ -1826,7 +1822,7 @@ describe('Wallet service', function() {
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.048200, null, TestData.copayers[0].privKey_1H_0); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.048200, null, TestData.copayers[0].privKey_1H_0);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('INSUFFICIENTFUNDS'); err.code.should.equal('INSUFFICIENT_FUNDS_FOR_FEE');
err.message.should.equal('Insufficient funds for fee'); err.message.should.equal('Insufficient funds for fee');
done(); done();
}); });
@ -1850,7 +1846,7 @@ describe('Wallet service', function() {
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 80000); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 80000);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('INSUFFICIENTFUNDS'); err.code.should.equal('INSUFFICIENT_FUNDS_FOR_FEE');
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 5000); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 5000);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.not.exist(err); should.not.exist(err);
@ -1876,7 +1872,7 @@ describe('Wallet service', function() {
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.00000001, null, TestData.copayers[0].privKey_1H_0); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.00000001, null, TestData.copayers[0].privKey_1H_0);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('DUSTAMOUNT'); err.code.should.equal('DUST_AMOUNT');
err.message.should.equal('Amount below dust threshold'); err.message.should.equal('Amount below dust threshold');
done(); done();
}); });
@ -1892,7 +1888,7 @@ describe('Wallet service', function() {
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount, null, TestData.copayers[0].privKey_1H_0, 10000); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount, null, TestData.copayers[0].privKey_1H_0, 10000);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('DUSTAMOUNT'); err.code.should.equal('DUST_AMOUNT');
err.message.should.equal('Amount below dust threshold'); err.message.should.equal('Amount below dust threshold');
done(); done();
}); });
@ -1911,7 +1907,7 @@ describe('Wallet service', function() {
txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 8, null, TestData.copayers[0].privKey_1H_0); txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 8, null, TestData.copayers[0].privKey_1H_0);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); 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'); err.message.should.equal('Funds are locked by pending transaction proposals');
done(); done();
}); });
@ -1987,7 +1983,7 @@ describe('Wallet service', function() {
should.exist(tx); should.exist(tx);
var txOpts2 = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 24, null, TestData.copayers[0].privKey_1H_0); var txOpts2 = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 24, null, TestData.copayers[0].privKey_1H_0);
server.createTx(txOpts2, function(err, tx) { server.createTx(txOpts2, function(err, tx) {
err.code.should.equal('LOCKEDFUNDS'); err.code.should.equal('LOCKED_FUNDS');
should.not.exist(tx); should.not.exist(tx);
server.getPendingTxs({}, function(err, txs) { server.getPendingTxs({}, function(err, txs) {
should.not.exist(err); should.not.exist(err);
@ -2192,7 +2188,7 @@ describe('Wallet service', function() {
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 1, null, TestData.copayers[0].privKey_1H_0); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 1, null, TestData.copayers[0].privKey_1H_0);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('NOTALLOWEDTOCREATETX'); err.code.should.equal('TX_CANNOT_CREATE');
next(); next();
}); });
}, },
@ -2214,7 +2210,7 @@ describe('Wallet service', function() {
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
clock.restore(); clock.restore();
should.exist(err); should.exist(err);
err.code.should.equal('NOTALLOWEDTOCREATETX'); err.code.should.equal('TX_CANNOT_CREATE');
next(); next();
}); });
}, },
@ -2306,7 +2302,7 @@ describe('Wallet service', function() {
reason: 'some other reason', reason: 'some other reason',
}, function(err) { }, function(err) {
should.exist(err); should.exist(err);
err.code.should.equal('TXNOTPENDING'); err.code.should.equal('TX_NOT_PENDING');
done(); done();
}); });
}); });
@ -2371,7 +2367,7 @@ describe('Wallet service', function() {
txProposalId: txid, txProposalId: txid,
signatures: signatures, signatures: signatures,
}, function(err) { }, function(err) {
err.code.should.contain('BADSIG'); err.code.should.equal('BAD_SIGNATURES');
done(); done();
}); });
}); });
@ -2442,7 +2438,7 @@ describe('Wallet service', function() {
server.rejectTx({ server.rejectTx({
txProposalId: txid, txProposalId: txid,
}, function(err) { }, function(err) {
err.code.should.contain('CVOTED'); err.code.should.contain('COPAYER_VOTED');
done(); done();
}); });
}); });
@ -2462,7 +2458,7 @@ describe('Wallet service', function() {
txProposalId: txid, txProposalId: txid,
signatures: signatures, signatures: signatures,
}, function(err) { }, function(err) {
err.code.should.contain('CVOTED'); err.code.should.contain('COPAYER_VOTED');
done(); done();
}); });
}); });
@ -2511,7 +2507,7 @@ describe('Wallet service', function() {
signatures: signatures, signatures: signatures,
}, function(err) { }, function(err) {
should.exist(err); should.exist(err);
err.code.should.equal('TXNOTPENDING'); err.code.should.equal('TX_NOT_PENDING');
done(); done();
}); });
}); });
@ -2579,7 +2575,7 @@ describe('Wallet service', function() {
txProposalId: txpid txProposalId: txpid
}, function(err) { }, function(err) {
should.exist(err); should.exist(err);
err.code.should.equal('TXALREADYBROADCASTED'); err.code.should.equal('TX_ALREADY_BROADCASTED');
done(); done();
}); });
}); });
@ -2595,20 +2591,20 @@ describe('Wallet service', function() {
txProposalId: txp.id txProposalId: txp.id
}, function(err) { }, function(err) {
should.exist(err); should.exist(err);
err.code.should.equal('TXNOTACCEPTED'); err.code.should.equal('TX_NOT_ACCEPTED');
done(); done();
}); });
}); });
}); });
it('should keep tx as accepted if unable to broadcast it', function(done) { 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); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, null);
server.broadcastTx({ server.broadcastTx({
txProposalId: txpid txProposalId: txpid
}, function(err) { }, function(err) {
should.exist(err); should.exist(err);
err.code.should.equal('BLOCKCHAINERROR'); err.toString().should.equal('broadcast error');
server.getTx({ server.getTx({
txProposalId: txpid txProposalId: txpid
}, function(err, txp) { }, 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) { 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, { blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, null, {
txid: '999' 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) { 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'); blockchainExplorer.getTransaction = sinon.stub().callsArgWith(1, 'bc check error');
server.broadcastTx({ server.broadcastTx({
txProposalId: txpid txProposalId: txpid
}, function(err) { }, function(err) {
should.exist(err); should.exist(err);
err.code.should.equal('BLOCKCHAINERROR'); err.toString().should.equal('bc check error');
server.getTx({ server.getTx({
txProposalId: txpid txProposalId: txpid
}, function(err, txp) { }, function(err, txp) {
@ -3085,7 +3081,7 @@ describe('Wallet service', function() {
it('should notify sign and acceptance', function(done) { it('should notify sign and acceptance', function(done) {
server.getPendingTxs({}, function(err, txs) { server.getPendingTxs({}, function(err, txs) {
helpers.stubBroadcastFail(); blockchainExplorer.broadcast = sinon.stub().callsArgWith(1, 'broadcast error');
var tx = txs[0]; var tx = txs[0];
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey); var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey);
server.signTx({ server.signTx({
@ -3379,7 +3375,7 @@ describe('Wallet service', function() {
txProposalId: txp.id txProposalId: txp.id
}, function(err) { }, function(err) {
should.exist(err); should.exist(err);
err.code.should.equal('TXNOTPENDING'); err.code.should.equal('TX_NOT_PENDING');
done(); done();
}); });
}, },
@ -3392,7 +3388,7 @@ describe('Wallet service', function() {
txProposalId: txp.id txProposalId: txp.id
}, function(err) { }, function(err) {
should.exist(err); should.exist(err);
err.code.should.contain('TXCANNOTREMOVE'); err.code.should.contain('TX_CANNOT_REMOVE');
server2.getPendingTxs({}, function(err, txs) { server2.getPendingTxs({}, function(err, txs) {
txs.length.should.equal(1); txs.length.should.equal(1);
done(); done();
@ -3412,7 +3408,7 @@ describe('Wallet service', function() {
server.removePendingTx({ server.removePendingTx({
txProposalId: txp.id txProposalId: txp.id
}, function(err) { }, function(err) {
err.code.should.equal('TXCANNOTREMOVE'); err.code.should.equal('TX_CANNOT_REMOVE');
err.message.should.contain('Cannot remove'); err.message.should.contain('Cannot remove');
done(); done();
}); });
@ -3770,7 +3766,7 @@ describe('Wallet service', function() {
blockchainExplorer.getTransactions = sinon.stub().callsArgWith(3, 'dummy error'); blockchainExplorer.getTransactions = sinon.stub().callsArgWith(3, 'dummy error');
server.getTxHistory({}, function(err, txs) { server.getTxHistory({}, function(err, txs) {
should.exist(err); should.exist(err);
err.code.should.equal('BLOCKCHAINERROR'); err.toString().should.equal('dummy error');
done(); done();
}); });
}); });
@ -3920,7 +3916,7 @@ describe('Wallet service', function() {
blockchainExplorer.getAddressActivity = sinon.stub().callsArgWith(1, 'dummy error'); blockchainExplorer.getAddressActivity = sinon.stub().callsArgWith(1, 'dummy error');
server.scan({}, function(err) { server.scan({}, function(err) {
should.exist(err); should.exist(err);
err.code.should.equal('BLOCKCHAINERROR'); err.toString().should.equal('dummy error');
server.getWallet({}, function(err, wallet) { server.getWallet({}, function(err, wallet) {
should.not.exist(err); should.not.exist(err);
wallet.scanStatus.should.equal('error'); wallet.scanStatus.should.equal('error');
@ -4117,7 +4113,7 @@ describe('Wallet service', function() {
}); });
copayerOpts.isTemporaryRequestKey = false; copayerOpts.isTemporaryRequestKey = false;
server.replaceTemporaryRequestKey(copayerOpts, function(err, wallet) { server.replaceTemporaryRequestKey(copayerOpts, function(err, wallet) {
err.code.should.equal('WNOTFULL'); err.code.should.equal('WALLET_NOT_COMPLETE');
done(); done();
}); });
}); });
@ -4149,7 +4145,7 @@ describe('Wallet service', function() {
}); });
copayerOpts.isTemporaryRequestKey = false; copayerOpts.isTemporaryRequestKey = false;
server.replaceTemporaryRequestKey(copayerOpts, function(err, wallet) { server.replaceTemporaryRequestKey(copayerOpts, function(err, wallet) {
err.code.should.equal('CDATAMISMATCH'); err.code.should.equal('COPAYER_DATA_MISMATCH');
done(); done();
}); });
}); });
@ -4192,7 +4188,7 @@ describe('Wallet service', function() {
}); });
copayerOpts.isTemporaryRequestKey = false; copayerOpts.isTemporaryRequestKey = false;
server.replaceTemporaryRequestKey(copayerOpts, function(err, wallet) { server.replaceTemporaryRequestKey(copayerOpts, function(err, wallet) {
err.code.should.equal('CDATAMISMATCH'); err.code.should.equal('COPAYER_DATA_MISMATCH');
done(); done();
}); });
}); });
@ -4309,7 +4305,8 @@ describe('Wallet service', function() {
server.getPendingTxs({}, function(err, txps) { server.getPendingTxs({}, function(err, txps) {
should.exist(err); should.exist(err);
should.not.exist(txps); should.not.exist(txps);
err.toString().should.contain('created by a newer version'); err.code.should.equal('UPGRADE_NEEDED');
err.message.should.contain('newer version');
done(); done();
}); });
}); });
@ -4367,7 +4364,7 @@ describe('Wallet service', function() {
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.exist(err); should.exist(err);
err.code.should.equal('INSUFFICIENTFUNDS'); err.code.should.equal('INSUFFICIENT_FUNDS_FOR_FEE');
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 5000); var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 5000);
server.createTx(txOpts, function(err, tx) { server.createTx(txOpts, function(err, tx) {
should.not.exist(err); should.not.exist(err);

Loading…
Cancel
Save