@@ -73,6 +73,12 @@ struct CompareValueOnly {
7373 }
7474};
7575
76+ enum class CWallet ::CoinSelectStrategy
77+ {
78+ random,
79+ descentByAmount,
80+ };
81+
7682std::string COutput::ToString () const
7783{
7884 return strprintf (" COutput(%s, %d, %d) [%s]" , tx->GetHash ().ToString (), i, nDepth, FormatMoney (tx->vout [i].nValue ));
@@ -2138,7 +2144,7 @@ bool CWallet::MintableCoins()
21382144 return false ;
21392145}
21402146
2141- bool CWallet::SelectCoinsMinConf (const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins, set<pair<const CWalletTx*, unsigned int > >& setCoinsRet, CAmount& nValueRet) const
2147+ bool CWallet::SelectCoinsMinConf (const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins, set<pair<const CWalletTx*, unsigned int > >& setCoinsRet, CAmount& nValueRet, CoinSelectStrategy coinSelectStrategy ) const
21422148{
21432149 setCoinsRet.clear ();
21442150 nValueRet = 0 ;
@@ -2150,7 +2156,18 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
21502156 vector<pair<CAmount, pair<const CWalletTx*, unsigned int > > > vValue;
21512157 CAmount nTotalLower = 0 ;
21522158
2153- random_shuffle (vCoins.begin (), vCoins.end (), GetRandInt);
2159+ switch (coinSelectStrategy) {
2160+ case CoinSelectStrategy::descentByAmount:
2161+ std::sort (vCoins.begin (), vCoins.end (), [](const COutput & a, const COutput & b) -> bool {
2162+ return a.Value () > b.Value ();
2163+ });
2164+ break ;
2165+
2166+ case CoinSelectStrategy::random:
2167+ default :
2168+ random_shuffle (vCoins.begin (), vCoins.end (), GetRandInt);
2169+ break ;
2170+ }
21542171
21552172 // move denoms down on the list
21562173 sort (vCoins.begin (), vCoins.end (), less_then_denom);
@@ -2245,7 +2262,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
22452262 return true ;
22462263}
22472264
2248- bool CWallet::SelectCoins (const CAmount& nTargetValue, set<pair<const CWalletTx*, unsigned int > >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX) const
2265+ bool CWallet::SelectCoins (const CAmount& nTargetValue, set<pair<const CWalletTx*, unsigned int > >& setCoinsRet, CAmount& nValueRet, CoinSelectStrategy coinSelectStrategy, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX) const
22492266{
22502267 // Note: this function should never be used for "always free" tx types like dstx
22512268
@@ -2291,9 +2308,9 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*
22912308 return (nValueRet >= nTargetValue);
22922309 }
22932310
2294- return (SelectCoinsMinConf (nTargetValue, 1 , 6 , vCoins, setCoinsRet, nValueRet) ||
2295- SelectCoinsMinConf (nTargetValue, 1 , 1 , vCoins, setCoinsRet, nValueRet) ||
2296- (bSpendZeroConfChange && SelectCoinsMinConf (nTargetValue, 0 , 1 , vCoins, setCoinsRet, nValueRet)));
2311+ return (SelectCoinsMinConf (nTargetValue, 1 , 6 , vCoins, setCoinsRet, nValueRet, coinSelectStrategy ) ||
2312+ SelectCoinsMinConf (nTargetValue, 1 , 1 , vCoins, setCoinsRet, nValueRet, coinSelectStrategy ) ||
2313+ (bSpendZeroConfChange && SelectCoinsMinConf (nTargetValue, 0 , 1 , vCoins, setCoinsRet, nValueRet, coinSelectStrategy )));
22972314}
22982315
22992316struct CompareByPriority {
@@ -2621,6 +2638,18 @@ bool CWallet::ConvertList(std::vector<CTxIn> vCoins, std::vector<CAmount>& vecAm
26212638 return true ;
26222639}
26232640
2641+ enum class ErrorOfCreateTransaction
2642+ {
2643+ other,
2644+ transactionSizeTooLarge,
2645+ };
2646+
2647+ struct CWallet ::ParamForCreateTransaction
2648+ {
2649+ CoinSelectStrategy coinSelectStrategy;
2650+ ErrorOfCreateTransaction error;
2651+ };
2652+
26242653bool CWallet::CreateTransaction (const vector<pair<CScript, CAmount> >& vecSend,
26252654 CWalletTx& wtxNew,
26262655 CReserveKey& reservekey,
@@ -2630,6 +2659,57 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
26302659 AvailableCoinsType coin_type,
26312660 bool useIX,
26322661 CAmount nFeePay)
2662+ {
2663+ ParamForCreateTransaction param = {};
2664+
2665+ param.coinSelectStrategy = CoinSelectStrategy::random;
2666+ param.error = ErrorOfCreateTransaction::other;
2667+ bool result = CreateTransactionHelper (
2668+ vecSend,
2669+ wtxNew,
2670+ reservekey,
2671+ nFeeRet,
2672+ strFailReason,
2673+ coinControl,
2674+ coin_type,
2675+ useIX,
2676+ nFeePay,
2677+ ¶m
2678+ );
2679+ if (result) {
2680+ return result;
2681+ }
2682+ if (param.error == ErrorOfCreateTransaction::transactionSizeTooLarge) {
2683+ // If the transaction is too large for the maximum fee, let's try to use different strategy to select coins.
2684+ param.coinSelectStrategy = CoinSelectStrategy::descentByAmount;
2685+ param.error = ErrorOfCreateTransaction::other;
2686+ result = CreateTransactionHelper (
2687+ vecSend,
2688+ wtxNew,
2689+ reservekey,
2690+ nFeeRet,
2691+ strFailReason,
2692+ coinControl,
2693+ coin_type,
2694+ useIX,
2695+ nFeePay,
2696+ ¶m
2697+ );
2698+ }
2699+
2700+ return result;
2701+ }
2702+
2703+ bool CWallet::CreateTransactionHelper (const std::vector<std::pair<CScript, CAmount> >& vecSend,
2704+ CWalletTx& wtxNew,
2705+ CReserveKey& reservekey,
2706+ CAmount& nFeeRet,
2707+ std::string& strFailReason,
2708+ const CCoinControl* coinControl,
2709+ AvailableCoinsType coin_type,
2710+ bool useIX,
2711+ CAmount nFeePay,
2712+ ParamForCreateTransaction * param)
26332713{
26342714 if (useIX && nFeePay < CENT) nFeePay = CENT;
26352715
@@ -2701,7 +2781,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
27012781 set<pair<const CWalletTx*, unsigned int > > setCoins;
27022782 CAmount nValueIn = 0 ;
27032783
2704- if (!SelectCoins (nTotalValue, setCoins, nValueIn, coinControl, coin_type, useIX)) {
2784+ if (!SelectCoins (nTotalValue, setCoins, nValueIn, param-> coinSelectStrategy , coinControl, coin_type, useIX)) {
27052785 if (coin_type == ALL_COINS) {
27062786 strFailReason = _ (" Insufficient funds." );
27072787 } else if (coin_type == ONLY_NOT10000IFMN) {
@@ -2831,6 +2911,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
28312911 // Limit size
28322912 if (GetTransactionCost (txNew) >= MAX_STANDARD_TX_COST) {
28332913 strFailReason = _ (" Transaction too large" );
2914+ param->error = ErrorOfCreateTransaction::transactionSizeTooLarge;
28342915 return false ;
28352916 }
28362917 unsigned int nBytes = GetVirtualTransactionSize (txNew);
@@ -4620,7 +4701,7 @@ bool CWallet::CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransa
46204701 nValueIn = nValue;
46214702 } else {
46224703 // select UTXO's to use
4623- if (!SelectCoins (nTotalValue, setCoins, nValueIn, coinControl)) {
4704+ if (!SelectCoins (nTotalValue, setCoins, nValueIn, CoinSelectStrategy::random, coinControl)) {
46244705 strFailReason = _ (" Insufficient or insufficient confirmed funds, you might need to wait a few minutes and try again." );
46254706 return false ;
46264707 }
0 commit comments