replace old utxo selection algo
This commit is contained in:
parent
504b52d695
commit
680516da70
123
lib/server.js
123
lib/server.js
|
@ -1267,90 +1267,6 @@ WalletService.prototype._checkTxAndEstimateFee = function(txp) {
|
||||||
|
|
||||||
WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) {
|
WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
//todo: check inputs are ours and has enough value
|
|
||||||
if (txp.inputs && txp.inputs.length > 0) {
|
|
||||||
return cb(self._checkTxAndEstimateFee(txp));
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortUtxos(utxos) {
|
|
||||||
var list = _.map(utxos, function(utxo) {
|
|
||||||
var order;
|
|
||||||
if (utxo.confirmations == 0) {
|
|
||||||
order = 0;
|
|
||||||
} else if (utxo.confirmations < 6) {
|
|
||||||
order = -1;
|
|
||||||
} else {
|
|
||||||
order = -2;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
order: order,
|
|
||||||
utxo: utxo
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return _.pluck(_.sortBy(list, 'order'), 'utxo');
|
|
||||||
};
|
|
||||||
|
|
||||||
self._getUtxosForCurrentWallet(null, 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;
|
|
||||||
|
|
||||||
var balance = self._totalizeUtxos(utxos);
|
|
||||||
if (txp.excludeUnconfirmedUtxos) {
|
|
||||||
totalAmount = balance.totalConfirmedAmount;
|
|
||||||
availableAmount = balance.availableConfirmedAmount;
|
|
||||||
} else {
|
|
||||||
totalAmount = balance.totalAmount;
|
|
||||||
availableAmount = balance.availableAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
var total = 0;
|
|
||||||
var selected = [];
|
|
||||||
var inputs = sortUtxos(utxos);
|
|
||||||
|
|
||||||
var bitcoreTx, bitcoreError;
|
|
||||||
|
|
||||||
function select() {
|
|
||||||
if (i >= inputs.length) return cb(bitcoreError || new Error('Could not select tx inputs'));
|
|
||||||
|
|
||||||
var input = inputs[i++];
|
|
||||||
selected.push(input);
|
|
||||||
total += input.satoshis;
|
|
||||||
if (total >= txp.getTotalAmount()) {
|
|
||||||
txp.setInputs(selected);
|
|
||||||
bitcoreError = self._checkTxAndEstimateFee(txp);
|
|
||||||
if (!bitcoreError) return cb();
|
|
||||||
}
|
|
||||||
setTimeout(select, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
select();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
//todo: check inputs are ours and has enough value
|
//todo: check inputs are ours and has enough value
|
||||||
if (txp.inputs && txp.inputs.length > 0) {
|
if (txp.inputs && txp.inputs.length > 0) {
|
||||||
|
@ -1796,22 +1712,6 @@ WalletService.prototype.createTxLegacy = function(opts, cb) {
|
||||||
WalletService.prototype.createTx = function(opts, cb) {
|
WalletService.prototype.createTx = function(opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
function logStatistics(prefix, txp) {
|
|
||||||
var totalAmount = txp.getTotalAmount();
|
|
||||||
var inputs = _.sortBy(_.map(txp.inputs, function(input) {
|
|
||||||
return _.pick(input, 'satoshis', 'confirmations');
|
|
||||||
}), 'satoshis');
|
|
||||||
var totalLocked = _.sum(inputs, 'satoshis');
|
|
||||||
var overhead = totalLocked - totalAmount;
|
|
||||||
|
|
||||||
log.info(prefix, 'TXP ID: ' + txp.id);
|
|
||||||
log.info(prefix, 'Total amount: ' + Utils.formatAmountInBtc(totalAmount));
|
|
||||||
log.info(prefix, 'Fee: ' + Utils.formatAmountInBtc(txp.fee) + ' (per KB: ' + Utils.formatAmountInBtc(txp.feePerKb) + ')');
|
|
||||||
log.info(prefix, 'Exclude unconfirmed: ' + txp.excludeUnconfirmedUtxos);
|
|
||||||
log.info(prefix, 'Total locked: ' + Utils.formatAmountInBtc(totalLocked) + ', Overhead: ' + Utils.formatAmountInBtc(overhead) + ' (' + Utils.formatRatio(overhead / totalAmount) + ')');
|
|
||||||
log.info(prefix, 'Inputs: ', Utils.formatUtxos(inputs));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!Utils.checkRequired(opts, ['outputs', 'feePerKb']))
|
if (!Utils.checkRequired(opts, ['outputs', 'feePerKb']))
|
||||||
return cb(new ClientError('Required argument missing'));
|
return cb(new ClientError('Required argument missing'));
|
||||||
|
|
||||||
|
@ -1853,28 +1753,15 @@ WalletService.prototype.createTx = function(opts, cb) {
|
||||||
|
|
||||||
var txp = Model.TxProposal.create(txOpts);
|
var txp = Model.TxProposal.create(txOpts);
|
||||||
|
|
||||||
self._selectTxInputs2(txp, opts.utxosToExclude, function(err) {
|
self._selectTxInputs(txp, opts.utxosToExclude, function(err) {
|
||||||
if (err) {
|
if (err) return cb(err);
|
||||||
log.error('Could not select inputs using new algorithm', err);
|
|
||||||
} else {
|
|
||||||
logStatistics('NEW_UTXO_SEL', txp);
|
|
||||||
}
|
|
||||||
|
|
||||||
txp.setInputs([]);
|
self.storage.storeAddressAndWallet(wallet, txp.changeAddress, function(err) {
|
||||||
txp.fee = null;
|
|
||||||
|
|
||||||
self._selectTxInputs(txp, opts.utxosToExclude, function(err) {
|
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
logStatistics('OLD_UTXO_SEL', txp);
|
self.storage.storeTx(wallet.id, txp, function(err) {
|
||||||
|
|
||||||
self.storage.storeAddressAndWallet(wallet, txp.changeAddress, function(err) {
|
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
return cb(null, txp);
|
||||||
self.storage.storeTx(wallet.id, txp, function(err) {
|
|
||||||
if (err) return cb(err);
|
|
||||||
return cb(null, txp);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3169,7 +3169,7 @@ describe('Wallet service', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.skip('UTXO Selection', function() {
|
describe('UTXO Selection', function() {
|
||||||
var server, wallet;
|
var server, wallet;
|
||||||
beforeEach(function(done) {
|
beforeEach(function(done) {
|
||||||
helpers.createAndJoinWallet(2, 3, function(s, w) {
|
helpers.createAndJoinWallet(2, 3, function(s, w) {
|
||||||
|
|
Loading…
Reference in New Issue