Fix coin selection to only include change when it's necessary.
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user