Browse Source

use predefined errors

activeAddress
Ivan Socolsky 10 years ago
parent
commit
e474c71a1e
  1. 2
      lib/errors/clienterror.js
  2. 39
      lib/errors/errordefinitions.js
  3. 91
      lib/server.js

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

@ -1,3 +1,5 @@
'use strict';
function ClientError() {
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 = {
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;

91
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;

Loading…
Cancel
Save