Merge #12333: Make CWallet::ListCoins atomic

2f960b5 [wallet] Indent only change of CWallet::AvailableCoins (João Barbosa)
1beea7a [wallet] Make CWallet::ListCoins atomic (João Barbosa)

Pull request description:

  Fix a potencial race in `CWallet::ListCoins`.

  Replaces `cs_main` and `cs_wallet` locks by assertions in `CWallet::AvailableCoins`.

Tree-SHA512: 09109f44a08b4b53f7605d950ab506d3f748490ab9aed474aa200e93f7b0b9f96f9bf60abe1c5f658240fd13d9e3267c0dd43fd3c1695d82384198ce1da8109f
This commit is contained in:
Wladimir J. van der Laan 2018-02-08 19:44:52 +01:00
commit d405beea26
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
2 changed files with 93 additions and 89 deletions

View file

@ -676,18 +676,24 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
BOOST_CHECK_EQUAL(list.begin()->second.size(), 2); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2);
// Lock both coins. Confirm number of available coins drops to 0. // Lock both coins. Confirm number of available coins drops to 0.
{
LOCK2(cs_main, wallet->cs_wallet);
std::vector<COutput> available; std::vector<COutput> available;
wallet->AvailableCoins(available); wallet->AvailableCoins(available);
BOOST_CHECK_EQUAL(available.size(), 2); BOOST_CHECK_EQUAL(available.size(), 2);
}
for (const auto& group : list) { for (const auto& group : list) {
for (const auto& coin : group.second) { for (const auto& coin : group.second) {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
wallet->LockCoin(COutPoint(coin.tx->GetHash(), coin.i)); wallet->LockCoin(COutPoint(coin.tx->GetHash(), coin.i));
} }
} }
{
LOCK2(cs_main, wallet->cs_wallet);
std::vector<COutput> available;
wallet->AvailableCoins(available); wallet->AvailableCoins(available);
BOOST_CHECK_EQUAL(available.size(), 0); BOOST_CHECK_EQUAL(available.size(), 0);
}
// Confirm ListCoins still returns same result as before, despite coins // Confirm ListCoins still returns same result as before, despite coins
// being locked. // being locked.
list = wallet->ListCoins(); list = wallet->ListCoins();

View file

@ -2198,11 +2198,10 @@ CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const
void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const int nMinDepth, const int nMaxDepth) const void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const int nMinDepth, const int nMaxDepth) const
{ {
AssertLockHeld(cs_main);
AssertLockHeld(cs_wallet);
vCoins.clear(); vCoins.clear();
{
LOCK2(cs_main, cs_wallet);
CAmount nTotal = 0; CAmount nTotal = 0;
for (const auto& entry : mapWallet) for (const auto& entry : mapWallet)
@ -2305,7 +2304,6 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
} }
} }
} }
}
std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const
{ {
@ -2320,11 +2318,11 @@ std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const
// avoid adding some extra complexity to the Qt code. // avoid adding some extra complexity to the Qt code.
std::map<CTxDestination, std::vector<COutput>> result; std::map<CTxDestination, std::vector<COutput>> result;
std::vector<COutput> availableCoins; std::vector<COutput> availableCoins;
AvailableCoins(availableCoins);
LOCK2(cs_main, cs_wallet); LOCK2(cs_main, cs_wallet);
AvailableCoins(availableCoins);
for (auto& coin : availableCoins) { for (auto& coin : availableCoins) {
CTxDestination address; CTxDestination address;
if (coin.fSpendable && if (coin.fSpendable &&