aboutsummaryrefslogtreecommitdiff
path: root/src/wallet.cpp
diff options
context:
space:
mode:
authorChris Moore <dooglus@gmail.com>2012-02-27 04:19:32 -0800
committerLuke Dashjr <luke-jr+git@utopios.org>2012-06-04 16:36:34 +0000
commit9b0369c773c1d350a05435d8d3ec4e954828fb82 (patch)
tree43b695e7dd82200c0bcd407b40613ee4501ac2eb /src/wallet.cpp
parent882ba0e7524b54be861b379366b5845a3978b256 (diff)
downloadbitcoin-9b0369c773c1d350a05435d8d3ec4e954828fb82.tar.xz
Refactor SelectCoinsMinConf() and add unit tests.
AvailableCoins() makes a vector of available outputs which is then passed to SelectCoinsMinConf(). This allows unit tests to test the coin selection algorithm without having the whole blockchain available.
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r--src/wallet.cpp102
1 files changed, 55 insertions, 47 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 4e3b559f6a..f7e931dbbb 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -889,7 +889,32 @@ int64 CWallet::GetImmatureBalance() const
return nTotal;
}
-bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
+// populate vCoins with vector of spendable (age, (value, (transaction, output_number))) outputs
+void CWallet::AvailableCoins(vector<COutput>& vCoins) const
+{
+ vCoins.clear();
+
+ {
+ LOCK(cs_wallet);
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+
+ if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ continue;
+
+ if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
+ continue;
+
+ for (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()));
+ }
+ }
+}
+
+bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
+ set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
{
setCoinsRet.clear();
nValueRet = 0;
@@ -901,54 +926,32 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
int64 nTotalLower = 0;
+ BOOST_FOREACH(COutput output, vCoins)
{
- LOCK(cs_wallet);
- vector<const CWalletTx*> vCoins;
- vCoins.reserve(mapWallet.size());
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
- vCoins.push_back(&(*it).second);
- random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
-
- BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
- {
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
- continue;
-
- if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
- continue;
+ const CWalletTx *pcoin = output.tx;
- int nDepth = pcoin->GetDepthInMainChain();
- if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
- continue;
-
- for (unsigned int i = 0; i < pcoin->vout.size(); i++)
- {
- if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
- continue;
-
- int64 n = pcoin->vout[i].nValue;
+ if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
+ continue;
- if (n <= 0)
- continue;
+ 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));
+ 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;
- }
- }
+ 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;
}
}
@@ -1023,12 +1026,14 @@ 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;
@@ -1036,9 +1041,12 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
{
- return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
+ vector<COutput> vCoins;
+ AvailableCoins(vCoins);
+
+ return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) ||
+ SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) ||
+ SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet));
}