Acquire cs_main lock before cs_wallet during wallet initialization

CWallet::MarkConflicted may acquire the cs_main lock after
CWalletDB::LoadWallet acquires the cs_wallet lock during wallet initialization.
(CWalletDB::LoadWallet calls ReadKeyValue which calls CWallet::LoadToWallet
which calls CWallet::MarkConflicted). This is the opposite order that cs_main
and cs_wallet locks are acquired in the rest of the code, and so leads to
POTENTIAL DEADLOCK DETECTED errors if bitcoin is built with -DDEBUG_LOCKORDER.

This commit changes CWallet::LoadWallet (which calls CWalletDB::LoadWallet) to
acquire both locks in the standard order. It also fixes some tests that were
acquiring wallet and main locks out of order and failed with the new locking in
CWallet::LoadWallet.

Error was reported by Luke Dashjr <luke-jr@utopios.org> in
https://botbot.me/freenode/bitcoin-core-dev/msg/90244330/
This commit is contained in:
Russell Yanofsky
2017-08-24 14:12:21 -04:00
parent 41496e20f3
commit de9a1db2ed
2 changed files with 12 additions and 8 deletions

View File

@@ -3107,13 +3107,14 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_c
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{
LOCK2(cs_main, cs_wallet);
fFirstRunRet = false;
DBErrors nLoadWalletRet = CWalletDB(*dbw,"cr+").LoadWallet(this);
if (nLoadWalletRet == DB_NEED_REWRITE)
{
if (dbw->Rewrite("\x04pool"))
{
LOCK(cs_wallet);
setInternalKeyPool.clear();
setExternalKeyPool.clear();
m_pool_key_to_index.clear();