diff options
author | Chris Moore <dooglus@gmail.com> | 2012-02-27 04:19:32 -0800 |
---|---|---|
committer | Luke Dashjr <luke-jr+git@utopios.org> | 2012-06-04 16:36:34 +0000 |
commit | 9b0369c773c1d350a05435d8d3ec4e954828fb82 (patch) | |
tree | 43b695e7dd82200c0bcd407b40613ee4501ac2eb /src/wallet.cpp | |
parent | 882ba0e7524b54be861b379366b5845a3978b256 (diff) |
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.cpp | 102 |
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)); } |