From 1aa6da9d36064dee46a1320da2d5578e70fc56e2 Mon Sep 17 00:00:00 2001
From: UdjinM6 <UdjinM6@users.noreply.github.com>
Date: Mon, 15 Dec 2014 06:17:54 +0300
Subject: [PATCH 1/2] when no Darksend is unchecked select nondenom inputs
 first

---
 src/wallet.cpp | 99 ++++++++++++++++++++++++++++++++------------------
 1 file changed, 64 insertions(+), 35 deletions(-)

diff --git a/src/wallet.cpp b/src/wallet.cpp
index 741bb74c061f..2cb154b6beda 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -253,7 +253,6 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
     nStartTime = GetTimeMillis();
     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
     kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
-
     if (kMasterKey.nDeriveIterations < 25000)
         kMasterKey.nDeriveIterations = 25000;
 
@@ -1216,52 +1215,82 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
 
     random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
 
-    BOOST_FOREACH(COutput output, vCoins)
+    // try to find nondenom first to prevent unneeded spending of mixed coins
+    for (unsigned int tryDenom = 0; tryDenom < 2; tryDenom++)
     {
-        const CWalletTx *pcoin = output.tx;
+        if (fDebug) LogPrintf("tryDenom: %d\n", tryDenom);
+        setCoinsRet.clear();
+        nValueRet = 0;
+        nTotalLower = 0;
 
-        if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
-            continue;
+        BOOST_FOREACH(COutput output, vCoins)
+        {
+            const CWalletTx *pcoin = output.tx;
 
-        int i = output.i;
-        int64 n = pcoin->vout[i].nValue;
+            if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
+                continue;
 
-        pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
+            if (tryDenom == 0) {
+                CTxIn vin = CTxIn(output.tx->GetHash(), output.i);
+                int rounds = GetInputDarksendRounds(vin);
+                if(rounds >= 0) {
+                    if (fDebug) LogPrintf("REJECT tryDenom %d rounds %d value %s\n", tryDenom, rounds, FormatMoney(pcoin->vout[output.i].nValue).c_str());
+                    continue;
+                }
+                if (fDebug) LogPrintf("ACCEPT tryDenom %d rounds %d value %s\n", tryDenom, rounds, FormatMoney(pcoin->vout[output.i].nValue).c_str());
+            }
 
-        if (n == nTargetValue)
-        {
-            setCoinsRet.insert(coin.second);
-            nValueRet += coin.first;
-            return true;
-        }
-        else if (n < nTargetValue + CENT)
-        {
-            vValue.push_back(coin);
-            nTotalLower += n;
+            int i = output.i;
+            int64 n = pcoin->vout[i].nValue;
+
+            pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
+
+            if (n == nTargetValue)
+            {
+                setCoinsRet.insert(coin.second);
+                nValueRet += coin.first;
+                return true;
+            }
+            else if (n < nTargetValue + CENT)
+            {
+                vValue.push_back(coin);
+                nTotalLower += n;
+            }
+            else if (n < coinLowestLarger.first)
+            {
+                coinLowestLarger = coin;
+            }
         }
-        else if (n < coinLowestLarger.first)
+
+        if (nTotalLower == nTargetValue)
         {
-            coinLowestLarger = coin;
+            for (unsigned int i = 0; i < vValue.size(); ++i)
+            {
+                setCoinsRet.insert(vValue[i].second);
+                nValueRet += vValue[i].first;
+            }
+            return true;
         }
-    }
 
-    if (nTotalLower == nTargetValue)
-    {
-        for (unsigned int i = 0; i < vValue.size(); ++i)
+        if (nTotalLower < nTargetValue)
         {
-            setCoinsRet.insert(vValue[i].second);
-            nValueRet += vValue[i].first;
+            if (coinLowestLarger.second.first == NULL) // there is no input larger than nTargetValue
+            {
+                if (tryDenom == 0)
+                    // we didn't look at denom yet, let's do it
+                    continue;
+                else
+                    // we looked at everything possible and didn't find anything, no luck
+                    return false;
+            }
+            setCoinsRet.insert(coinLowestLarger.second);
+            nValueRet += coinLowestLarger.first;
+            return true;
         }
-        return true;
-    }
 
-    if (nTotalLower < nTargetValue)
-    {
-        if (coinLowestLarger.second.first == NULL)
-            return false;
-        setCoinsRet.insert(coinLowestLarger.second);
-        nValueRet += coinLowestLarger.first;
-        return true;
+        // nTotalLower > nTargetValue
+        break;
+
     }
 
     // Solve subset sum by stochastic approximation

From 94074a59f273dfbe9d0b9310455afd49ab7014ef Mon Sep 17 00:00:00 2001
From: UdjinM6 <UdjinM6@users.noreply.github.com>
Date: Sat, 20 Dec 2014 09:13:51 +0300
Subject: [PATCH 2/2] no more rounds calculations / move denoms down on the
 list

---
 src/wallet.cpp | 40 ++++++++++++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/src/wallet.cpp b/src/wallet.cpp
index 2cb154b6beda..7b37452ea393 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -1200,6 +1200,23 @@ static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsig
     }
 }
 
+// TODO: find appropriate place for this sort function
+// move denoms down
+bool less_then_denom (const COutput& out1, const COutput& out2)
+{
+    const CWalletTx *pcoin1 = out1.tx;
+    const CWalletTx *pcoin2 = out2.tx;
+
+    bool found1 = false;
+    bool found2 = false;
+    BOOST_FOREACH(int64 d, darkSendDenominations) // loop through predefined denoms
+    {
+        if(pcoin1->vout[out1.i].nValue == d) found1 = true;
+        if(pcoin2->vout[out2.i].nValue == d) found2 = true;
+    }
+    return (!found1 && found2);
+}
+
 bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
                                  set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
 {
@@ -1215,6 +1232,9 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
 
     random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
 
+    // move denoms down on the list
+    sort(vCoins.begin(), vCoins.end(), less_then_denom);
+
     // try to find nondenom first to prevent unneeded spending of mixed coins
     for (unsigned int tryDenom = 0; tryDenom < 2; tryDenom++)
     {
@@ -1227,22 +1247,22 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
         {
             const CWalletTx *pcoin = output.tx;
 
+//            if (fDebug) LogPrintf("value %s confirms %d\n", FormatMoney(pcoin->vout[output.i].nValue).c_str(), output.nDepth);
             if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
                 continue;
 
-            if (tryDenom == 0) {
-                CTxIn vin = CTxIn(output.tx->GetHash(), output.i);
-                int rounds = GetInputDarksendRounds(vin);
-                if(rounds >= 0) {
-                    if (fDebug) LogPrintf("REJECT tryDenom %d rounds %d value %s\n", tryDenom, rounds, FormatMoney(pcoin->vout[output.i].nValue).c_str());
-                    continue;
-                }
-                if (fDebug) LogPrintf("ACCEPT tryDenom %d rounds %d value %s\n", tryDenom, rounds, FormatMoney(pcoin->vout[output.i].nValue).c_str());
-            }
-
             int i = output.i;
             int64 n = pcoin->vout[i].nValue;
 
+            if (tryDenom == 0) // first run?
+            {
+                bool found = false;
+                BOOST_FOREACH(int64 d, darkSendDenominations) // loop through predefined denoms
+                    if(n == d)
+                        found = true;
+                if (found) continue; // we don't want denom values on first run
+            }
+
             pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
 
             if (n == nTargetValue)
