From a5e44070b9de37451b866e7605796b1b7a7fd2ff Mon Sep 17 00:00:00 2001 From: Kosta Korenkov <7r0ggy@gmail.com> Date: Fri, 7 Aug 2015 17:15:01 +0300 Subject: [PATCH 1/2] Allow to exclude certain UTXO from coin selection Optional array of lockedUtxos (in ``txid:vout`` form) can be passed with tx proposal options. When selecting inputs for proposal, these UTXOs will not be used. --- lib/server.js | 10 ++++++++-- test/integration/server.js | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/server.js b/lib/server.js index aa1ff39..df018f3 100644 --- a/lib/server.js +++ b/lib/server.js @@ -917,7 +917,7 @@ WalletService.prototype.getFeeLevels = function(opts, cb) { }); }; -WalletService.prototype._selectTxInputs = function(txp, cb) { +WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { var self = this; function sortUtxos(utxos) { @@ -941,6 +941,12 @@ WalletService.prototype._selectTxInputs = function(txp, cb) { self.getUtxos({}, function(err, utxos) { if (err) return cb(err); + var excludeIndex = _.reduce(utxosToExclude, function(res, val) { res[val] = val; return res; }, {}); + + utxos = _.reject(utxos, function(utxo) { + return excludeIndex[utxo.txid + ":" + utxo.vout]; + }); + var totalAmount; var availableAmount; @@ -1167,7 +1173,7 @@ WalletService.prototype.createTx = function(opts, cb) { txp.version = '1.0.1'; } - self._selectTxInputs(txp, function(err) { + self._selectTxInputs(txp, opts.utxosToExclude, function(err) { if (err) return cb(err); $.checkState(txp.inputs); diff --git a/test/integration/server.js b/test/integration/server.js index 80aab2f..9e1f004 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -2429,6 +2429,18 @@ describe('Wallet service', function() { }); }); }); + it('should not use UTXO provided in utxosToExclude option', function(done) { + helpers.stubUtxos(server, wallet, [1, 2, 3], function(utxos) { + var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 4.5, 'some message', TestData.copayers[0].privKey_1H_0); + txOpts.utxosToExclude = [ utxos[1].txid + ':' + utxos[1].vout ]; + server.createTx(txOpts, function(err, tx) { + should.exist(err); + err.code.should.equal('INSUFFICIENT_FUNDS'); + err.message.should.equal('Insufficient funds'); + done(); + }); + }); + }); }); describe('#createTx backoff time', function(done) { From 1a047ff2a0f4ab15056021ce36f03a037b3c9a4d Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Wed, 26 Aug 2015 11:23:13 -0300 Subject: [PATCH 2/2] restore previous test --- test/integration/server.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/integration/server.js b/test/integration/server.js index 9e1f004..5900fb7 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -2432,7 +2432,7 @@ describe('Wallet service', function() { it('should not use UTXO provided in utxosToExclude option', function(done) { helpers.stubUtxos(server, wallet, [1, 2, 3], function(utxos) { var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 4.5, 'some message', TestData.copayers[0].privKey_1H_0); - txOpts.utxosToExclude = [ utxos[1].txid + ':' + utxos[1].vout ]; + txOpts.utxosToExclude = [utxos[1].txid + ':' + utxos[1].vout]; server.createTx(txOpts, function(err, tx) { should.exist(err); err.code.should.equal('INSUFFICIENT_FUNDS'); @@ -2441,6 +2441,19 @@ describe('Wallet service', function() { }); }); }); + it('should use non-excluded UTXOs', function(done) { + helpers.stubUtxos(server, wallet, [1, 2], function(utxos) { + var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.5, 'some message', TestData.copayers[0].privKey_1H_0); + txOpts.utxosToExclude = [utxos[0].txid + ':' + utxos[0].vout]; + server.createTx(txOpts, function(err, tx) { + should.not.exist(err); + tx.inputs.length.should.equal(1); + tx.inputs[0].txid.should.equal(utxos[1].txid); + tx.inputs[0].vout.should.equal(utxos[1].vout); + done(); + }); + }); + }); }); describe('#createTx backoff time', function(done) {