diff options
author | Samuel Dobson <dobsonsa68@gmail.com> | 2021-11-27 21:46:21 +1300 |
---|---|---|
committer | Samuel Dobson <dobsonsa68@gmail.com> | 2021-11-27 22:30:46 +1300 |
commit | 200d97faf2ed0bd0cbef93dd4bbbe77cf8fe5d13 (patch) | |
tree | e64061a766d92aeb6a8549ea2db007bf4f07029f /src/wallet | |
parent | 111c3e06b35b7867f2e0f740e988f648ac6c325d (diff) | |
parent | f13a22a631efe01e1fbae4ae78a4901d14ebda3c (diff) |
Merge bitcoin/bitcoin#22868: wallet: Call load handlers without cs_wallet locked
f13a22a631efe01e1fbae4ae78a4901d14ebda3c wallet: Call load handlers without cs_wallet locked (João Barbosa)
Pull request description:
Don't have `cs_wallet` locked while calling each `context.wallet_load_fns`. A load handler can always lock `cs_wallet` if needed.
The lock was added in 1c7e25db0c to satisfy TSAN. With 44c430ffac most of the code requiring the lock is in `CWallet::AttachChain`. A comment is added to warn about wallets_mutex and cs_wallet lock ordering.
ACKs for top commit:
meshcollider:
re-utACK f13a22a631efe01e1fbae4ae78a4901d14ebda3c
ryanofsky:
Code review ACK f13a22a631efe01e1fbae4ae78a4901d14ebda3c. Only change since last review is adding a lock order comment
jonatack:
ACK f13a22a631efe01e1fbae4ae78a4901d14ebda3c
Tree-SHA512: d51976c3aae4bebc2d1997c88edff712d21fc5523801f5614062a10f826e164579973aeb1981bb1cbc243ecff6af3250362f544c02a79e5d135cbbca1704be62
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/context.h | 2 | ||||
-rw-r--r-- | src/wallet/test/wallet_tests.cpp | 6 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 6 |
3 files changed, 5 insertions, 9 deletions
diff --git a/src/wallet/context.h b/src/wallet/context.h index a382fb9021..dbd172e88e 100644 --- a/src/wallet/context.h +++ b/src/wallet/context.h @@ -34,6 +34,8 @@ using LoadWalletFn = std::function<void(std::unique_ptr<interfaces::Wallet> wall struct WalletContext { interfaces::Chain* chain{nullptr}; ArgsManager* args{nullptr}; // Currently a raw pointer because the memory is not managed by this struct + // It is unsafe to lock this after locking a CWallet::cs_wallet mutex because + // this could introduce inconsistent lock ordering and cause deadlocks. Mutex wallets_mutex; std::vector<std::shared_ptr<CWallet>> wallets GUARDED_BY(wallets_mutex); std::list<LoadWalletFn> wallet_load_fns GUARDED_BY(wallets_mutex); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 9a1398e970..9842089cf8 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -779,18 +779,14 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup) // deadlock during the sync and simulates a new block notification happening // as soon as possible. addtx_count = 0; - auto handler = HandleLoadWallet(context, [&](std::unique_ptr<interfaces::Wallet> wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet->wallet()->cs_wallet, context.wallets_mutex) { + auto handler = HandleLoadWallet(context, [&](std::unique_ptr<interfaces::Wallet> wallet) { BOOST_CHECK(rescan_completed); m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); block_tx = TestSimpleSpend(*m_coinbase_txns[2], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); mempool_tx = TestSimpleSpend(*m_coinbase_txns[3], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error)); - LEAVE_CRITICAL_SECTION(context.wallets_mutex); - LEAVE_CRITICAL_SECTION(wallet->wallet()->cs_wallet); SyncWithValidationInterfaceQueue(); - ENTER_CRITICAL_SECTION(wallet->wallet()->cs_wallet); - ENTER_CRITICAL_SECTION(context.wallets_mutex); }); wallet = TestLoadWallet(context); BOOST_CHECK_EQUAL(addtx_count, 4); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 96b18ef51a..2382ac268d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2763,8 +2763,6 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri // Try to top up keypool. No-op if the wallet is locked. walletInstance->TopUpKeyPool(); - LOCK(walletInstance->cs_wallet); - if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) { return nullptr; } @@ -2776,9 +2774,9 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri } } - walletInstance->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); - { + LOCK(walletInstance->cs_wallet); + walletInstance->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize()); walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size()); walletInstance->WalletLogPrintf("m_address_book.size() = %u\n", walletInstance->m_address_book.size()); |