diff options
author | Chris Moore <dooglus@gmail.com> | 2012-04-12 16:22:15 -0700 |
---|---|---|
committer | Luke Dashjr <luke-jr+git@utopios.org> | 2012-06-04 16:49:10 +0000 |
commit | 831f59ce8b179bd3180a73499da9b1dc1d5ecaeb (patch) | |
tree | a7310330f320bd919e2817f2ae120bc613a10e1d /src/wallet.cpp | |
parent | d650f96d5f48a9cc458af9ef644f57973ca7f48b (diff) |
Fix coin selection to only include change when it's necessary.
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r-- | src/wallet.cpp | 93 |
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; |