Skip to content
This repository has been archived by the owner on Jan 12, 2022. It is now read-only.

Commit

Permalink
fix: simple transaction do not have any 4 inputs limitation (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex-Werner authored Jun 30, 2020
1 parent e5c807e commit 11d8d01
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 270 deletions.
4 changes: 2 additions & 2 deletions src/CONSTANTS.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ const CONSTANTS = {
UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR: 5,
MAX_STANDARD_TX_SIZE: 100000,
MAX_P2SH_SIGOPS: 15,
MAX_INPUTS_FOR_AUTO_IX: 4,
UTXO_MAX_INPUTS_PER_TX: 25,
// limit to how many times an unconfirmed input in a new tx can be respent
UTXO_CHAINED_SPENDING_LIMIT_FOR_TX: 25,
FEES: {
DUST_RELAY_TX_FEE: 1000,
ZERO: 0,
Expand Down
4 changes: 2 additions & 2 deletions src/types/Account/Account.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { WALLET_TYPES } = require('../../CONSTANTS');
const { is } = require('../../utils');
const EVENTS = require('../../EVENTS');
const Wallet = require('../Wallet/Wallet.js');
const { simpleTransactionOptimizedAccumulator } = require('../../utils/coinSelections/strategies');
const { simpleDescendingAccumulator } = require('../../utils/coinSelections/strategies');

function getNextUnusedAccountIndexForWallet(wallet) {
if (wallet && wallet.accounts) {
Expand Down Expand Up @@ -35,7 +35,7 @@ const defaultOptions = {
plugins: [],
injectDefaultPlugins: true,
debug: false,
strategy: simpleTransactionOptimizedAccumulator,
strategy: simpleDescendingAccumulator,
};

/* eslint-disable no-underscore-dangle */
Expand Down
47 changes: 46 additions & 1 deletion src/utils/coinSelection.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const {Transaction, Address, Script} = require('@dashevo/dashcore-lib');
const coinSelection = require('./coinSelection');
const {utxosList} = require('../../fixtures/crackspice');
const STRATEGIES = require('./coinSelections/strategies');
const TransactionEstimator = require('./coinSelections/TransactionEstimator')

const utxosListAsUnspentOutput = utxosList.map((utxo)=> Transaction.UnspentOutput(utxo));
const outputs = {
Expand Down Expand Up @@ -56,7 +57,6 @@ describe('Utils - coinSelection', function suite() {
it('should require a outputsList with at least one output', () => {
expect(() => coinSelection(utxosList, [])).to.throw('outputsList must contains at least 1 output');
});

it('should require a outputsList with valid outputs', () => {
expect(() => coinSelection(utxosListAsUnspentOutput, [{toto: true}])).to.throw('data parameter supplied is not a string.');
});
Expand Down Expand Up @@ -317,6 +317,51 @@ describe('Utils - coinSelection', function suite() {

expect(result).to.deep.equal(expectedResult);
});
it('should handle externally crafted strategy', function () {
// A dummy strategy that takes a random selection of utxo
const externalStrategy = (utxosList, outputsList, deductFee = false, feeCategory = 'normal') => {
const copiedUtxos = [...utxosList];
const txEstimator = new TransactionEstimator(feeCategory);

txEstimator.addOutputs(outputsList);

let inputValue = 0;
let outputValue = txEstimator.getOutValue();
const randomlySelectedUtxos = [];

while(inputValue<outputValue){
if(copiedUtxos.length === 0){
throw new Error('Not enought UTXOs');
}
// Take a random item and add it to selection
const utxo = copiedUtxos.splice(Math.floor(Math.random() * copiedUtxos.length),1)[0];
inputValue+=utxo.satoshis;
randomlySelectedUtxos.push(utxo);
}

txEstimator.addInputs(randomlySelectedUtxos);

return {
utxos: txEstimator.getInputs(),
outputs: txEstimator.getOutputs(),
feeCategory,
estimatedFee: txEstimator.getFeeEstimate(),
utxosValue: txEstimator.getInValue(),
};
}
const result = coinSelection(
utxosListAsUnspentOutput,
[outputs.FOURTY_FIVE_DASH],
false,
'normal',
externalStrategy);

expect(result).to.exist;
expect(result.feeCategory).to.equal('normal');
expect(result.utxosValue).to.gte(4500000000);
expect(result.outputs).to.deep.equal([outputs.FOURTY_FIVE_DASH]);
expect(result.utxos.length).to.gte(0);
});
// Note : Removed, kept in case of fallback needed
// it('should return an error in not any utxo has been found', () => {
// const utxo = utxosList[15];
Expand Down
2 changes: 1 addition & 1 deletion src/utils/coinSelections/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const InvalidUTXO = require('../../errors/InvalidUTXO');
const InvalidOutput = require('../../errors/InvalidOutput');
const CoinSelectionUnsufficientUTXOS = require('../../errors/CoinSelectionUnsufficientUTXOS');

module.exports = function coinSelection(utxosList, outputsList, deductFee = false, feeCategory = 'normal', strategy = STRATEGIES.simpleTransactionOptimizedAccumulator) {
module.exports = function coinSelection(utxosList, outputsList, deductFee = false, feeCategory = 'normal', strategy = STRATEGIES.simpleDescendingAccumulator) {
if (!utxosList) { throw new Error('A utxosList is required'); }
if (utxosList.constructor.name !== Array.name) { throw new Error('UtxosList is expected to be an array of utxos'); }
if (utxosList.length < 1) { throw new Error('utxosList must contain at least 1 utxo'); }
Expand Down
2 changes: 0 additions & 2 deletions src/utils/coinSelections/strategies/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
const simpleAscendingAccumulator = require('./simpleAscendingAccumulator');
const simpleDescendingAccumulator = require('./simpleDescendingAccumulator');
const simpleTransactionOptimizedAccumulator = require('./simpleTransactionOptimizedAccumulator');

const STRATEGIES = {
simpleDescendingAccumulator,
simpleAscendingAccumulator,
simpleTransactionOptimizedAccumulator,
};
module.exports = STRATEGIES;

This file was deleted.

This file was deleted.

0 comments on commit 11d8d01

Please sign in to comment.