handle lots of small inputs causing the total balance after fees to decrease
This commit is contained in:
parent
680516da70
commit
cbde3233df
|
@ -1273,6 +1273,12 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) {
|
||||||
return cb(self._checkTxAndEstimateFee(txp));
|
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) {
|
function excludeUtxos(utxos) {
|
||||||
var excludeIndex = _.reduce(utxosToExclude, function(res, val) {
|
var excludeIndex = _.reduce(utxosToExclude, function(res, val) {
|
||||||
res[val] = 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) {
|
function partitionUtxos(utxos) {
|
||||||
return _.groupBy(utxos, function(utxo) {
|
return _.groupBy(utxos, function(utxo) {
|
||||||
if (utxo.confirmations == 0) return '0'
|
if (utxo.confirmations == 0) return '0'
|
||||||
|
@ -1293,14 +1308,9 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) {
|
||||||
};
|
};
|
||||||
|
|
||||||
function select(utxos, 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 totalValueInUtxos = _.sum(utxos, 'satoshis');
|
||||||
var netValueInUtxos = totalValueInUtxos - baseTxpFee - (utxos.length * feePerInput);
|
var netValueInUtxos = totalValueInUtxos - baseTxpFee - (utxos.length * feePerInput);
|
||||||
|
|
||||||
if (totalValueInUtxos < txpAmount) {
|
if (totalValueInUtxos < txpAmount) {
|
||||||
log.debug('Total value in all utxos (' + Utils.formatAmountInBtc(totalValueInUtxos) + ') is insufficient to cover for txp amount (' + Utils.formatAmountInBtc(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);
|
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 (totalAmount < txp.getTotalAmount()) return cb(Errors.INSUFFICIENT_FUNDS);
|
||||||
if (availableAmount < txp.getTotalAmount()) return cb(Errors.LOCKED_FUNDS);
|
if (availableAmount < txp.getTotalAmount()) return cb(Errors.LOCKED_FUNDS);
|
||||||
|
|
||||||
// Prepare UTXOs list
|
utxos = sanitizeUtxos(utxos);
|
||||||
utxos = _.reject(utxos, 'locked');
|
|
||||||
if (txp.excludeUnconfirmedUtxos) {
|
|
||||||
utxos = _.filter(utxos, 'confirmations');
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug('Considering ' + utxos.length + ' utxos (' + Utils.formatUtxos(utxos) + ')');
|
log.debug('Considering ' + utxos.length + ' utxos (' + Utils.formatUtxos(utxos) + ')');
|
||||||
|
|
||||||
|
|
|
@ -3412,8 +3412,6 @@ describe('Wallet service', function() {
|
||||||
feePerKb: 100e2,
|
feePerKb: 100e2,
|
||||||
};
|
};
|
||||||
server.createTx(txOpts, function(err, txp) {
|
server.createTx(txOpts, function(err, txp) {
|
||||||
console.log('*** [server.js ln3417] err:', err); // TODO
|
|
||||||
|
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
should.exist(txp);
|
should.exist(txp);
|
||||||
txp.inputs.length.should.equal(1);
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue