aboutsummaryrefslogtreecommitdiff
path: root/src/wallet.cpp
diff options
context:
space:
mode:
authorChris Moore <dooglus@gmail.com>2012-04-12 16:22:15 -0700
committerLuke Dashjr <luke-jr+git@utopios.org>2012-06-04 16:49:10 +0000
commit831f59ce8b179bd3180a73499da9b1dc1d5ecaeb (patch)
treea7310330f320bd919e2817f2ae120bc613a10e1d /src/wallet.cpp
parentd650f96d5f48a9cc458af9ef644f57973ca7f48b (diff)
Fix coin selection to only include change when it's necessary.
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r--src/wallet.cpp93
1 files changed, 51 insertions, 42 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp
index d190ad9242..127d580803 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -898,7 +898,7 @@ int64 CWallet::GetImmatureBalance() const
return nTotal;
}
-// populate vCoins with vector of spendable (age, (value, (transaction, output_number))) outputs
+// populate vCoins with vector of spendable COutputs
void CWallet::AvailableCoins(vector<COutput>& vCoins) const
{
vCoins.clear();
@@ -915,13 +915,51 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins) const
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;
- for (int i = 0; i < pcoin->vout.size(); i++)
+ for (unsigned int i = 0; i < pcoin->vout.size(); i++)
if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue > 0)
vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain()));
}
}
}
+static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsigned int> > >vValue, int64 nTotalLower, int64 nTargetValue,
+ vector<char>& vfBest, int64& nBest, int iterations = 1000)
+{
+ vector<char> vfIncluded;
+
+ vfBest.assign(vValue.size(), true);
+ nBest = nTotalLower;
+
+ for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
+ {
+ vfIncluded.assign(vValue.size(), false);
+ int64 nTotal = 0;
+ bool fReachedTarget = false;
+ for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
+ {
+ for (unsigned int i = 0; i < vValue.size(); i++)
+ {
+ if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
+ {
+ nTotal += vValue[i].first;
+ vfIncluded[i] = true;
+ if (nTotal >= nTargetValue)
+ {
+ fReachedTarget = true;
+ if (nTotal < nBest)
+ {
+ nBest = nTotal;
+ vfBest = vfIncluded;
+ }
+ nTotal -= vValue[i].first;
+ vfIncluded[i] = false;
+ }
+ }
+ }
+ }
+ }
+}
+
bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
{
@@ -966,7 +1004,7 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
}
}
- if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
+ if (nTotalLower == nTargetValue)
{
for (unsigned int i = 0; i < vValue.size(); ++i)
{
@@ -976,7 +1014,7 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
return true;
}
- if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
+ if (nTotalLower < nTargetValue)
{
if (coinLowestLarger.second.first == NULL)
return false;
@@ -985,46 +1023,19 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
return true;
}
- if (nTotalLower >= nTargetValue + CENT)
- nTargetValue += CENT;
-
// Solve subset sum by stochastic approximation
sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
- vector<char> vfIncluded;
- vector<char> vfBest(vValue.size(), true);
- int64 nBest = nTotalLower;
+ vector<char> vfBest;
+ int64 nBest;
- for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
- {
- vfIncluded.assign(vValue.size(), false);
- int64 nTotal = 0;
- bool fReachedTarget = false;
- for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
- {
- for (unsigned int i = 0; i < vValue.size(); i++)
- {
- if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
- {
- nTotal += vValue[i].first;
- vfIncluded[i] = true;
- if (nTotal >= nTargetValue)
- {
- fReachedTarget = true;
- if (nTotal < nBest)
- {
- nBest = nTotal;
- vfBest = vfIncluded;
- }
- nTotal -= vValue[i].first;
- vfIncluded[i] = false;
- }
- }
- }
- }
- }
+ ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, 1000);
+ if (nBest != nTargetValue && nTotalLower >= nTargetValue + CENT)
+ ApproximateBestSubset(vValue, nTotalLower, nTargetValue + CENT, vfBest, nBest, 1000);
- // If the next larger is still closer, return it
- if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
+ // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
+ // or the next bigger coin is closer), return the bigger coin
+ if (coinLowestLarger.second.first &&
+ ((nBest != nTargetValue && nBest < nTargetValue + CENT) || coinLowestLarger.first <= nBest))
{
setCoinsRet.insert(coinLowestLarger.second);
nValueRet += coinLowestLarger.first;
@@ -1037,14 +1048,12 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
nValueRet += vValue[i].first;
}
-#ifdef DEBUG
//// debug print
printf("SelectCoins() best subset: ");
for (unsigned int i = 0; i < vValue.size(); i++)
if (vfBest[i])
printf("%s ", FormatMoney(vValue[i].first).c_str());
printf("total %s\n", FormatMoney(nBest).c_str());
-#endif
}
return true;