simplify validations on createTx

This commit is contained in:
Ivan Socolsky 2015-06-25 11:43:47 -03:00
parent 3851428a57
commit 48e0709607
4 changed files with 36 additions and 61 deletions

View File

@ -35,7 +35,9 @@ TxProposal._create.simple = function(txp, opts) {
TxProposal._create.undefined = TxProposal._create.simple;
TxProposal._create.multiple_outputs = function(txp, opts) {
txp.outputs = opts.outputs;
txp.outputs = _.map(opts.outputs, function(output) {
return _.pick(output, ['amount', 'toAddress', 'message']);
});
txp.outputOrder = _.shuffle(_.range(txp.outputs.length + 1));
try {
txp.network = Bitcore.Address(txp.outputs[0].toAddress).toObject().network;

View File

@ -827,41 +827,28 @@ WalletService.prototype._canCreateTx = function(copayerId, cb) {
WalletService.prototype.createTx = function(opts, cb) {
var self = this;
if (!Utils.checkRequired(opts, ['proposalSignature']))
if (!opts.outputs) {
opts.outputs = _.pick(opts, ['amount', 'toAddress', 'message']);
}
opts.outputs = [].concat(opts.outputs);
if (!Utils.checkRequired(opts, ['outputs', 'proposalSignature']))
return cb(new ClientError('Required argument missing'));
opts.type = opts.type || Model.TxProposal.Types.SIMPLE;
if (!Model.TxProposal.isTypeSupported(opts.type))
return cb(new ClientError('Invalid proposal type'));
if (opts.type == Model.TxProposal.Types.MULTIPLEOUTPUTS) {
if (!Utils.checkRequired(opts, ['outputs']))
return cb(new ClientError('Required argument missing'));
_.each(opts.outputs, function(o) {
o.valid = true;
if (!Utils.checkRequired(o, ['toAddress', 'amount'])) {
o.valid = false;
cb(new ClientError('Required outputs argument missing'));
return false;
}
_.each(_.keys(o), function(key) {
if (!_.contains(['toAddress', 'amount', 'message', 'valid'], key)) {
o.valid = false;
cb(new ClientError('Invalid outputs argument found'));
return false;
}
});
if (!o.valid) return false;
});
if (_.any(opts.outputs, 'valid', false)) return;
_.each(opts.outputs, function(o) {
delete o.valid;
});
} else {
if (!Utils.checkRequired(opts, ['toAddress', 'amount']))
return cb(new ClientError('Required argument missing'));
}
_.each(opts.outputs, function(output) {
if (!Utils.checkRequired(output, ['toAddress', 'amount'])) {
output.valid = false;
cb(new ClientError('Required outputs argument missing'));
return false;
}
});
if (_.any(opts.outputs, {
valid: false
})) return;
var feePerKb = opts.feePerKb || 10000;
if (feePerKb < WalletUtils.MIN_FEE_PER_KB || feePerKb > WalletUtils.MAX_FEE_PER_KB)
@ -878,17 +865,7 @@ WalletService.prototype.createTx = function(opts, cb) {
if (!canCreate)
return cb(new ClientError('NOTALLOWEDTOCREATETX', 'Cannot create TX proposal during backoff time'));
var copayer = wallet.getCopayer(self.copayerId);
var proposalHeader = Model.TxProposal.create(opts).getHeader();
var hash = WalletUtils.getProposalHash(proposalHeader);
if (!self._verifySignature(hash, opts.proposalSignature, copayer.requestPubKey))
return cb(new ClientError('Invalid proposal signature'));
var outputs = (opts.type == Model.TxProposal.Types.MULTIPLEOUTPUTS) ? opts.outputs : [{
toAddress: opts.toAddress,
amount: opts.amount
}];
_.each(outputs, function(output) {
_.each(opts.outputs, function(output) {
output.valid = false;
var toAddress = {};
try {
@ -901,7 +878,7 @@ WalletService.prototype.createTx = function(opts, cb) {
cb(new ClientError('INVALIDADDRESS', 'Incorrect address network'));
return false;
}
if (output.amount <= 0) {
if (!_.isNumber(output.amount) || _.isNaN(output.amount) || output.amount <= 0) {
cb(new ClientError('Invalid amount'));
return false;
}
@ -911,9 +888,9 @@ WalletService.prototype.createTx = function(opts, cb) {
}
output.valid = true;
});
if (_.any(outputs, 'valid', false)) return;
var changeAddress = wallet.createAddress(true);
if (_.any(opts.outputs, {
valid: false
})) return;
var txp = Model.TxProposal.create({
type: opts.type,
@ -926,18 +903,23 @@ WalletService.prototype.createTx = function(opts, cb) {
proposalSignature: opts.proposalSignature,
feePerKb: feePerKb,
payProUrl: opts.payProUrl,
changeAddress: changeAddress,
requiredSignatures: wallet.m,
requiredRejections: Math.min(wallet.m, wallet.n - wallet.m + 1),
});
var copayer = wallet.getCopayer(self.copayerId);
var hash = WalletUtils.getProposalHash(txp.getHeader());
if (!self._verifySignature(hash, opts.proposalSignature, copayer.requestPubKey))
return cb(new ClientError('Invalid proposal signature'));
txp.changeAddress = wallet.createAddress(true);
self._selectTxInputs(txp, function(err) {
if (err) return cb(err);
$.checkState(txp.inputs);
self.storage.storeAddressAndWallet(wallet, changeAddress, function(err) {
self.storage.storeAddressAndWallet(wallet, txp.changeAddress, function(err) {
if (err) return cb(err);
self.storage.storeTx(wallet.id, txp, function(err) {

View File

@ -137,7 +137,7 @@ helpers.toSatoshi = function(btc) {
helpers.stubUtxos = function(server, wallet, amounts, cb) {
var amounts = [].concat(amounts);
async.map(_.range(1, Math.ceil(amounts.length / 2) + 1), function(i, next) {
async.mapSeries(_.range(1, Math.ceil(amounts.length / 2) + 1), function(i, next) {
server.createAddress({}, function(err, address) {
next(err, address);
});
@ -248,7 +248,7 @@ helpers.createAddresses = function(server, wallet, main, change, cb) {
var storage, blockchainExplorer;
var useMongo = false;
var useMongo = true;
function initStorage(cb) {
function getDb(cb) {
@ -1685,13 +1685,11 @@ describe('Wallet service', function() {
});
});
it('should fail to create tx for type multiple_outputs with invalid output argument', function(done) {
it('should fail to create tx for type multiple_outputs with missing output argument', function(done) {
helpers.stubUtxos(server, wallet, [100, 200], function() {
var outputs = [{
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: 80,
message: 'message #1',
foo: 'bar'
}, {
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: 90,
@ -1700,7 +1698,7 @@ describe('Wallet service', function() {
var txOpts = helpers.createProposalOptsByType(Model.TxProposal.Types.MULTIPLEOUTPUTS, outputs, 'some message', TestData.copayers[0].privKey_1H_0);
server.createTx(txOpts, function(err, tx) {
should.exist(err);
err.message.should.contain('Invalid outputs argument');
err.message.should.contain('outputs argument missing');
done();
});
});

View File

@ -64,18 +64,11 @@ describe('TXProposal', function() {
});
describe('#getHeader', function() {
it('should be compatible with simple proposal legacy header', function() {
var x = TxProposal.fromObj(aTXP());
var proposalHeader = x.getHeader();
var pH = WalletUtils.getProposalHash.apply(WalletUtils, proposalHeader);
var uH = WalletUtils.getProposalHash(x.toAddress, x.amount, x.message, x.payProUrl);
pH.should.equal(uH);
});
it('should handle multiple-outputs', function() {
var x = TxProposal.fromObj(aTXP(TxProposal.Types.MULTIPLEOUTPUTS));
var proposalHeader = x.getHeader();
should.exist(proposalHeader);
var pH = WalletUtils.getProposalHash.apply(WalletUtils, proposalHeader);
var pH = WalletUtils.getProposalHash(proposalHeader);
should.exist(pH);
});
});