From a8cd4fe2c69dad862febb6d37e831119b9f5dfcb Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Wed, 2 Mar 2016 11:26:07 -0300 Subject: [PATCH] improve test cases --- lib/common/defaults.js | 5 +++ lib/server.js | 67 ++++++++++++++++++++++++++------------ test/integration/server.js | 54 ++++++++++++++++++++++++++---- 3 files changed, 100 insertions(+), 26 deletions(-) diff --git a/lib/common/defaults.js b/lib/common/defaults.js index 362363b..a2f5f85 100644 --- a/lib/common/defaults.js +++ b/lib/common/defaults.js @@ -49,4 +49,9 @@ Defaults.FIAT_RATE_MAX_LOOK_BACK_TIME = 120; // In minutes Defaults.HISTORY_LIMIT = 100; +Defaults.UTXO_SELECTION_MAX_SINGLE_UTXO_FACTOR = 2; +Defaults.UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR = 5; +Defaults.UTXO_SELECTION_MAX_TX_AMOUNT_VS_FEE_FACTOR = 0.002; +Defaults.UTXO_SELECTION_MIN_TX_AMOUNT_VS_UTXO_FACTOR = 0.1; + module.exports = Defaults; diff --git a/lib/server.js b/lib/server.js index 88a1c41..2c9a822 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1348,10 +1348,6 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) { }; -var UTXO_SELECTION_MAX_SINGLE_UTXO_FACTOR = 2; -var UTXO_SELECTION_MAX_FEE_FACTOR_FOR_SMALL_UTXOS = 2; -var UTXO_SELECTION_MAX_TX_AMOUNT_VS_FEE_FACTOR_FOR_SMALL_UTXOS = 0.002; - WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) { var self = this; @@ -1388,13 +1384,15 @@ WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) { console.log('*** [server.js ln1362] ----------------------- select for amount of:', txpAmount); // TODO // TODO: fix for when fee is specified instead of feePerKb - var baseTxpFee = txp.getEstimatedSize() * txp.feePerKb / 1000.; - var feePerInput = txp.getEstimatedSizeForSingleInput() * txp.feePerKb / 1000.; + var baseTxpSize = txp.getEstimatedSize(); + var baseTxpFee = baseTxpSize * txp.feePerKb / 1000.; + var sizePerInput = txp.getEstimatedSizeForSingleInput(); + var feePerInput = sizePerInput * txp.feePerKb / 1000.; console.log('*** [server.js ln1375] feePerInput:', feePerInput); // TODO var partitions = _.partition(utxos, function(utxo) { - return utxo.satoshis > txpAmount * UTXO_SELECTION_MAX_SINGLE_UTXO_FACTOR; + return utxo.satoshis > txpAmount * Defaults.UTXO_SELECTION_MAX_SINGLE_UTXO_FACTOR; }); var bigInputs = _.sortBy(partitions[0], 'satoshis'); @@ -1406,40 +1404,69 @@ WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) { console.log('*** [server.js ln1386] smallInputs:', _.pluck(smallInputs, 'satoshis')); // TODO - _.each(smallInputs, function(input) { + _.each(smallInputs, function(input, i) { + console.log('****************************** [server.js ln1395] INPUT #', i); // TODO + if (input.satoshis < feePerInput) return false; + + var inputAmount = input.satoshis - feePerInput; + console.log('*** [server.js ln1398] inputAmount:', inputAmount); // TODO + selected.push(input); - var txpFee = baseTxpFee + (feePerInput * selected.length); + var txpSize = baseTxpSize + selected.length * sizePerInput; + var txpFee = baseTxpFee + selected.length * feePerInput; var amountVsFeeRatio = txpFee / txpAmount; var singleInputFeeVsFeeRatio = txpFee / (baseTxpFee + feePerInput); + var amountVsUtxoRatio = inputAmount / txpAmount; - console.log('*** [server.js ln1402] txpFee, amountVsFeeRatio, singleInputFeeVsFeeRatio:', txpFee, amountVsFeeRatio, singleInputFeeVsFeeRatio); // TODO + console.log('*** [server.js ln1402] txpSize, txpFee', txpSize, txpFee); // TODO + console.log('*** [server.js ln1403] amountVsFeeRatio, singleInputFeeVsFeeRatio, amountVsUtxoRatio:', amountVsFeeRatio, singleInputFeeVsFeeRatio, amountVsUtxoRatio); // TODO + if (!_.isEmpty(bigInputs)) { + if ((amountVsFeeRatio > Defaults.UTXO_SELECTION_MAX_TX_AMOUNT_VS_FEE_FACTOR && + singleInputFeeVsFeeRatio > Defaults.UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR)) { + console.log('*** [server.js ln1413] breaking because fee exceeded fee/amount ratio and fee is too expensive compared to single input tx'); // TODO + return false; + } - if (amountVsFeeRatio > UTXO_SELECTION_MAX_TX_AMOUNT_VS_FEE_FACTOR_FOR_SMALL_UTXOS && - (_.isEmpty(bigInputs) || (singleInputFeeVsFeeRatio > UTXO_SELECTION_MAX_FEE_FACTOR_FOR_SMALL_UTXOS))) - return false; + if (amountVsUtxoRatio < Defaults.UTXO_SELECTION_MIN_TX_AMOUNT_VS_UTXO_FACTOR) { + console.log('*** [server.js ln1418] breaking because utxo is too small compared to tx amount'); // TODO + return false; + } + + if (txpSize / 1000. > Defaults.MAX_TX_SIZE_IN_KB) { + console.log('*** [server.js ln1423] breaking because tx size is too big'); // TODO + + return false; + } + } console.log('*** [server.js ln1380] input:', input.satoshis, ' aporta:', input.satoshis - feePerInput); // TODO - total += input.satoshis - feePerInput; + total += inputAmount; + console.log('*** [server.js ln1421] total:', total); // TODO + if (total >= txpAmount) return false; }); - console.log('*** [server.js ln1400] total, txpAmount:', total, txpAmount); // TODO - if (total < txpAmount) { - console.log('*** [server.js ln1401] no alcanzó:'); // TODO + console.log('*** [server.js ln1401] could not reach txp total, still missing:', txpAmount - total); // TODO selected = []; if (!_.isEmpty(bigInputs)) { - console.log('*** [server.js ln1405] pero hay bigInputs!:', _.first(bigInputs).satoshis); // TODO - - selected = [_.first(bigInputs)]; + console.log('*** [server.js ln1405] using big inputs!:', _.first(bigInputs).satoshis); // TODO + var input = _.first(bigInputs); + total = input.satoshis; + selected = [input]; } } + + if (!_.isEmpty(selected)) { + console.log('*** [server.js ln1400] SUCCESS! locked overhead:', total - txpAmount, ' ratio to txp:', (total - txpAmount) / txpAmount); // TODO + } + return selected; }; diff --git a/test/integration/server.js b/test/integration/server.js index 94529f8..0039270 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -5761,14 +5761,14 @@ describe('Wallet service', function() { }); }); - it('should select smaller utxos if within max fee constraints', function(done) { - helpers.stubUtxos(server, wallet, [1, '100bit', '100bit', '100bit'], function() { + it('should select smaller utxos if within fee constraints', function(done) { + helpers.stubUtxos(server, wallet, [1, '800bit', '800bit', '800bit'], function() { var txOpts = { outputs: [{ toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', - amount: 20000, + amount: 2000e2, }], - feePerKb: 1000, + feePerKb: 10e2, }; server.createTx(txOpts, function(err, txp) { should.not.exist(err); @@ -5799,7 +5799,7 @@ describe('Wallet service', function() { }); }); }); - it.only('should select smallest big utxo if small utxos exceed maximum fee', function(done) { + it('should select smallest big utxo if small utxos exceed maximum fee', function(done) { helpers.stubUtxos(server, wallet, [3, 1, 2].concat(_.times(20, function() { return '1000bit'; })), function() { @@ -5824,7 +5824,49 @@ describe('Wallet service', function() { }); }); }); - it.skip('should not fail with tx exceeded max size if there is at least 1 big input', function(done) {}); + it('should select smallest big utxo if small utxos are below accepted ratio of txp amount', function(done) { + helpers.stubUtxos(server, wallet, [9, 1, 1, 0.5, 0.2, 0.2, 0.2], function() { + var txOpts = { + outputs: [{ + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 3e8, + }], + feePerKb: 10e2, + }; + server.createTx(txOpts, function(err, txp) { + should.not.exist(err); + should.exist(txp); + txp.inputs.length.should.equal(1); + txp.inputs[0].satoshis.should.equal(9e8); + done(); + }); + }); + }); + it('should not fail with tx exceeded max size if there is at least 1 big input', function(done) { + var _old1 = Defaults.UTXO_SELECTION_MIN_TX_AMOUNT_VS_UTXO_FACTOR; + var _old2 = Defaults.MAX_TX_SIZE_IN_KB; + Defaults.UTXO_SELECTION_MIN_TX_AMOUNT_VS_UTXO_FACTOR = 0.0001; + Defaults.MAX_TX_SIZE_IN_KB = 3; + + helpers.stubUtxos(server, wallet, [100].concat(_.range(1, 20, 0)), function() { + var txOpts = { + outputs: [{ + toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', + amount: 15e8, + }], + feePerKb: 120e2, + }; + server.createTx(txOpts, function(err, txp) { + should.not.exist(err); + should.exist(txp); + txp.inputs.length.should.equal(1); + txp.inputs[0].satoshis.should.equal(100e8); + Defaults.UTXO_SELECTION_MIN_TX_AMOUNT_VS_UTXO_FACTOR = _old1; + Defaults.MAX_TX_SIZE_IN_KB = _old2; + done(); + }); + }); + }); it('should ignore utxos not contributing enough to cover increase in fee', function(done) { helpers.stubUtxos(server, wallet, ['100bit', '100bit', '100bit'], function() { var txOpts = {