simplify validations on createTx
This commit is contained in:
parent
3851428a57
commit
48e0709607
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue