Merge #16033: Hold cs_main when reading chainActive via getTipLocator(). Remove assumeLocked().

9402ef0739 Remove temporary method assumeLocked(). Remove LockingStateImpl. Remove redundant cs_main locks. (practicalswift)
593a8e8a2c wallet: Use chain.lock() instead of temporary chain.assumeLocked() (practicalswift)

Pull request description:

  Fixes #16028.

  Problem description:

  `LockAnnotation lock(::cs_main)` is a guarantee to the compiler thread analysis that `::cs_main` is locked (when it couldn't be determined otherwise).

  Despite being annotated with the locking guarantee ...

  65526fc866/src/interfaces/chain.cpp (L134-L138)

  ... `getTipLocator()` reads `chainActive` (via `::ChainActive()`) without holding `cs_main`.

  This can be verified by adding the following `AssertLockHeld(cs_main)`:

  ```
  $ git diff
  diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
  index 59623284d..9fc693a0f 100644
  --- a/src/interfaces/chain.cpp
  +++ b/src/interfaces/chain.cpp
  @@ -134,6 +134,7 @@ class LockImpl : public Chain::Lock
       CBlockLocator getTipLocator() override
       {
           LockAnnotation lock(::cs_main);
  +        AssertLockHeld(::cs_main);
           return ::ChainActive().GetLocator();
       }
       Optional<int> findLocatorFork(const CBlockLocator& locator) override
  $ make check
  ../build-aux/test-driver: line 107: 12881 Aborted                 "$@" > $log_file 2>&1
  FAIL: qt/test/test_bitcoin-qt
  ```

ACKs for commit 9402ef:
  MarcoFalke:
    utACK 9402ef0739
  ryanofsky:
    utACK 9402ef0739. Changes are consolidating commits and removing redundant lock2 cs_main calls

Tree-SHA512: 0a030bf0c07eb53194ecc246f973ef389dd42a0979f51932bf94bdf7e90c52473ae03be49718ee1629582b05dd8e0dc020b5a210318c93378ea4ace90c0f9f72
pull/764/head
MarcoFalke 6 years ago
commit f3d27d126b
No known key found for this signature in database
GPG Key ID: D2EA4850E7528B25

@ -37,7 +37,7 @@
namespace interfaces { namespace interfaces {
namespace { namespace {
class LockImpl : public Chain::Lock class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection>
{ {
Optional<int> getHeight() override Optional<int> getHeight() override
{ {
@ -155,10 +155,7 @@ class LockImpl : public Chain::Lock
return AcceptToMemoryPool(::mempool, state, tx, nullptr /* missing inputs */, nullptr /* txn replaced */, return AcceptToMemoryPool(::mempool, state, tx, nullptr /* missing inputs */, nullptr /* txn replaced */,
false /* bypass limits */, absurd_fee); false /* bypass limits */, absurd_fee);
} }
};
class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
{
using UniqueLock::UniqueLock; using UniqueLock::UniqueLock;
}; };
@ -249,13 +246,12 @@ class ChainImpl : public Chain
public: public:
std::unique_ptr<Chain::Lock> lock(bool try_lock) override std::unique_ptr<Chain::Lock> lock(bool try_lock) override
{ {
auto result = MakeUnique<LockingStateImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock); auto result = MakeUnique<LockImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
if (try_lock && result && !*result) return {}; if (try_lock && result && !*result) return {};
// std::move necessary on some compilers due to conversion from // std::move necessary on some compilers due to conversion from
// LockingStateImpl to Lock pointer // LockImpl to Lock pointer
return std::move(result); return std::move(result);
} }
std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); }
bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override
{ {
CBlockIndex* index; CBlockIndex* index;

@ -138,11 +138,6 @@ public:
//! unlocked when the returned interface is freed. //! unlocked when the returned interface is freed.
virtual std::unique_ptr<Lock> lock(bool try_lock = false) = 0; virtual std::unique_ptr<Lock> lock(bool try_lock = false) = 0;
//! Return Lock interface assuming chain is already locked. This
//! method is temporary and is only used in a few places to avoid changing
//! behavior while code is transitioned to use the Chain::Lock interface.
virtual std::unique_ptr<Lock> assumeLocked() = 0;
//! Return whether node has the block and optionally return block metadata //! Return whether node has the block and optionally return block metadata
//! or contents. //! or contents.
//! //!

@ -368,7 +368,10 @@ public:
int changePos = -1; int changePos = -1;
std::string error; std::string error;
CCoinControl dummy; CCoinControl dummy;
BOOST_CHECK(wallet->CreateTransaction(*m_locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy)); {
auto locked_chain = m_chain->lock();
BOOST_CHECK(wallet->CreateTransaction(*locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy));
}
CValidationState state; CValidationState state;
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, state)); BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, state));
CMutableTransaction blocktx; CMutableTransaction blocktx;
@ -387,7 +390,6 @@ public:
} }
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain(); std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
std::unique_ptr<interfaces::Chain::Lock> m_locked_chain = m_chain->assumeLocked(); // Temporary. Removed in upcoming lock cleanup
std::unique_ptr<CWallet> wallet; std::unique_ptr<CWallet> wallet;
}; };
@ -399,8 +401,9 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
// address. // address.
std::map<CTxDestination, std::vector<COutput>> list; std::map<CTxDestination, std::vector<COutput>> list;
{ {
LOCK2(cs_main, wallet->cs_wallet); auto locked_chain = m_chain->lock();
list = wallet->ListCoins(*m_locked_chain); LOCK(wallet->cs_wallet);
list = wallet->ListCoins(*locked_chain);
} }
BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
@ -415,8 +418,9 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
// pubkey. // pubkey.
AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */}); AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */});
{ {
LOCK2(cs_main, wallet->cs_wallet); auto locked_chain = m_chain->lock();
list = wallet->ListCoins(*m_locked_chain); LOCK(wallet->cs_wallet);
list = wallet->ListCoins(*locked_chain);
} }
BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
@ -424,9 +428,10 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
// 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); auto locked_chain = m_chain->lock();
LOCK(wallet->cs_wallet);
std::vector<COutput> available; std::vector<COutput> available;
wallet->AvailableCoins(*m_locked_chain, available); wallet->AvailableCoins(*locked_chain, available);
BOOST_CHECK_EQUAL(available.size(), 2U); BOOST_CHECK_EQUAL(available.size(), 2U);
} }
for (const auto& group : list) { for (const auto& group : list) {
@ -436,16 +441,18 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
} }
} }
{ {
LOCK2(cs_main, wallet->cs_wallet); auto locked_chain = m_chain->lock();
LOCK(wallet->cs_wallet);
std::vector<COutput> available; std::vector<COutput> available;
wallet->AvailableCoins(*m_locked_chain, available); wallet->AvailableCoins(*locked_chain, available);
BOOST_CHECK_EQUAL(available.size(), 0U); BOOST_CHECK_EQUAL(available.size(), 0U);
} }
// Confirm ListCoins still returns same result as before, despite coins // Confirm ListCoins still returns same result as before, despite coins
// being locked. // being locked.
{ {
LOCK2(cs_main, wallet->cs_wallet); auto locked_chain = m_chain->lock();
list = wallet->ListCoins(*m_locked_chain); LOCK(wallet->cs_wallet);
list = wallet->ListCoins(*locked_chain);
} }
BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);

@ -4074,7 +4074,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
return nullptr; return nullptr;
} }
auto locked_chain = chain.assumeLocked(); // Temporary. Removed in upcoming lock cleanup auto locked_chain = chain.lock();
walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); walletInstance->ChainStateFlushed(locked_chain->getTipLocator());
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
// Make it impossible to disable private keys after creation // Make it impossible to disable private keys after creation

Loading…
Cancel
Save