handle lots of small inputs causing the total balance after fees to decrease

This commit is contained in:
Ivan Socolsky 2016-03-07 15:18:32 -03:00
parent 680516da70
commit cbde3233df
2 changed files with 36 additions and 13 deletions

View File

@ -1273,6 +1273,12 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) {
return cb(self._checkTxAndEstimateFee(txp));
}
var txpAmount = txp.getTotalAmount();
var baseTxpSize = txp.getEstimatedSize();
var baseTxpFee = baseTxpSize * txp.feePerKb / 1000.;
var sizePerInput = txp.getEstimatedSizeForSingleInput();
var feePerInput = sizePerInput * txp.feePerKb / 1000.;
function excludeUtxos(utxos) {
var excludeIndex = _.reduce(utxosToExclude, function(res, val) {
res[val] = val;
@ -1284,6 +1290,15 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) {
});
};
function sanitizeUtxos(utxos) {
return _.filter(utxos, function(utxo) {
if (utxo.locked) return false;
if (utxo.satoshis <= feePerInput) return false;
if (txp.excludeUnconfirmedUtxos && !utxo.confirmations) return false;
return true;
});
};
function partitionUtxos(utxos) {
return _.groupBy(utxos, function(utxo) {
if (utxo.confirmations == 0) return '0'
@ -1293,14 +1308,9 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) {
};
function select(utxos, cb) {
var txpAmount = txp.getTotalAmount();
var baseTxpSize = txp.getEstimatedSize();
var baseTxpFee = baseTxpSize * txp.feePerKb / 1000.;
var sizePerInput = txp.getEstimatedSizeForSingleInput();
var feePerInput = sizePerInput * txp.feePerKb / 1000.;
var totalValueInUtxos = _.sum(utxos, 'satoshis');
var netValueInUtxos = totalValueInUtxos - baseTxpFee - (utxos.length * feePerInput);
if (totalValueInUtxos < txpAmount) {
log.debug('Total value in all utxos (' + Utils.formatAmountInBtc(totalValueInUtxos) + ') is insufficient to cover for txp amount (' + Utils.formatAmountInBtc(txpAmount) + ')');
return cb(Errors.INSUFFICIENT_FUNDS);
@ -1422,11 +1432,7 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) {
if (totalAmount < txp.getTotalAmount()) return cb(Errors.INSUFFICIENT_FUNDS);
if (availableAmount < txp.getTotalAmount()) return cb(Errors.LOCKED_FUNDS);
// Prepare UTXOs list
utxos = _.reject(utxos, 'locked');
if (txp.excludeUnconfirmedUtxos) {
utxos = _.filter(utxos, 'confirmations');
}
utxos = sanitizeUtxos(utxos);
log.debug('Considering ' + utxos.length + ' utxos (' + Utils.formatUtxos(utxos) + ')');

View File

@ -3412,8 +3412,6 @@ describe('Wallet service', function() {
feePerKb: 100e2,
};
server.createTx(txOpts, function(err, txp) {
console.log('*** [server.js ln3417] err:', err); // TODO
should.not.exist(err);
should.exist(txp);
txp.inputs.length.should.equal(1);
@ -3422,6 +3420,25 @@ describe('Wallet service', function() {
});
});
});
it('should ignore utxos too small to pay for fee', function(done) {
helpers.stubUtxos(server, wallet, ['1c200bit', '200bit'].concat(_.times(20, function() {
return '1bit';
})), function() {
var txOpts = {
outputs: [{
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
amount: 200e2,
}],
feePerKb: 90e2,
};
server.createTx(txOpts, function(err, txp) {
should.not.exist(err);
should.exist(txp);
txp.inputs.length.should.equal(2);
done();
});
});
});
});
});