Skip to content

Commit 200d97f

Browse files
committed
Merge bitcoin/bitcoin#22868: wallet: Call load handlers without cs_wallet locked
f13a22a 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 1c7e25d to satisfy TSAN. With 44c430f 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 f13a22a ryanofsky: Code review ACK f13a22a. Only change since last review is adding a lock order comment jonatack: ACK f13a22a Tree-SHA512: d51976c3aae4bebc2d1997c88edff712d21fc5523801f5614062a10f826e164579973aeb1981bb1cbc243ecff6af3250362f544c02a79e5d135cbbca1704be62
2 parents 111c3e0 + f13a22a commit 200d97f

File tree

3 files changed

+5
-9
lines changed

3 files changed

+5
-9
lines changed

src/wallet/context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ using LoadWalletFn = std::function<void(std::unique_ptr<interfaces::Wallet> wall
3434
struct WalletContext {
3535
interfaces::Chain* chain{nullptr};
3636
ArgsManager* args{nullptr}; // Currently a raw pointer because the memory is not managed by this struct
37+
// It is unsafe to lock this after locking a CWallet::cs_wallet mutex because
38+
// this could introduce inconsistent lock ordering and cause deadlocks.
3739
Mutex wallets_mutex;
3840
std::vector<std::shared_ptr<CWallet>> wallets GUARDED_BY(wallets_mutex);
3941
std::list<LoadWalletFn> wallet_load_fns GUARDED_BY(wallets_mutex);

src/wallet/test/wallet_tests.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -779,18 +779,14 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
779779
// deadlock during the sync and simulates a new block notification happening
780780
// as soon as possible.
781781
addtx_count = 0;
782-
auto handler = HandleLoadWallet(context, [&](std::unique_ptr<interfaces::Wallet> wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet->wallet()->cs_wallet, context.wallets_mutex) {
782+
auto handler = HandleLoadWallet(context, [&](std::unique_ptr<interfaces::Wallet> wallet) {
783783
BOOST_CHECK(rescan_completed);
784784
m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
785785
block_tx = TestSimpleSpend(*m_coinbase_txns[2], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
786786
m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
787787
mempool_tx = TestSimpleSpend(*m_coinbase_txns[3], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
788788
BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error));
789-
LEAVE_CRITICAL_SECTION(context.wallets_mutex);
790-
LEAVE_CRITICAL_SECTION(wallet->wallet()->cs_wallet);
791789
SyncWithValidationInterfaceQueue();
792-
ENTER_CRITICAL_SECTION(wallet->wallet()->cs_wallet);
793-
ENTER_CRITICAL_SECTION(context.wallets_mutex);
794790
});
795791
wallet = TestLoadWallet(context);
796792
BOOST_CHECK_EQUAL(addtx_count, 4);

src/wallet/wallet.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2763,8 +2763,6 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
27632763
// Try to top up keypool. No-op if the wallet is locked.
27642764
walletInstance->TopUpKeyPool();
27652765

2766-
LOCK(walletInstance->cs_wallet);
2767-
27682766
if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) {
27692767
return nullptr;
27702768
}
@@ -2776,9 +2774,9 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
27762774
}
27772775
}
27782776

2779-
walletInstance->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
2780-
27812777
{
2778+
LOCK(walletInstance->cs_wallet);
2779+
walletInstance->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
27822780
walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
27832781
walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size());
27842782
walletInstance->WalletLogPrintf("m_address_book.size() = %u\n", walletInstance->m_address_book.size());

0 commit comments

Comments
 (0)