From 98e8af4bb991fd8edeb15c0fb8afa66bff6b5cac Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Fri, 20 Feb 2026 14:23:51 -0800 Subject: [PATCH] wallet: Drain validation interface queue after notifications disconnect When unloading a wallet, there may be unexecuted callbacks in the validation interface queue that can still execute after we have completed all of the other wallet shutdown tasks. Instead of letting these run in the background, once the notifications are disconnected, wait for the queue to drain before continuing with wallet shutdown. --- src/wallet/wallet.cpp | 16 +++++++++++++--- src/wallet/wallet.h | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 63dab29972d..1e7ad3fc6b8 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -169,7 +169,7 @@ bool RemoveWallet(WalletContext& context, const std::shared_ptr& wallet WITH_LOCK(wallet->cs_wallet, wallet->WriteBestBlock()); // Unregister with the validation interface which also drops shared pointers. - wallet->m_chain_notifications_handler.reset(); + wallet->DisconnectChainNotifications(); { LOCK(context.wallets_mutex); std::vector>::iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet); @@ -3117,7 +3117,7 @@ std::shared_ptr CWallet::CreateNew(WalletContext& context, const std::s walletInstance->TopUpKeyPool(); if (chain && !AttachChain(walletInstance, *chain, /*rescan_required=*/false, error, warnings)) { - walletInstance->m_chain_notifications_handler.reset(); // Reset this pointer so that the wallet will actually be unloaded + walletInstance->DisconnectChainNotifications(); return nullptr; } @@ -3158,7 +3158,7 @@ std::shared_ptr CWallet::LoadExisting(WalletContext& context, const std walletInstance->TopUpKeyPool(); if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) { - walletInstance->m_chain_notifications_handler.reset(); // Reset this pointer so that the wallet will actually be unloaded + walletInstance->DisconnectChainNotifications(); return nullptr; } @@ -4577,4 +4577,14 @@ std::optional CWallet::GetTXO(const COutPoint& outpoint) const } return it->second; } + +void CWallet::DisconnectChainNotifications() +{ + if (m_chain_notifications_handler) { + m_chain_notifications_handler->disconnect(); + chain().waitForNotifications(); + m_chain_notifications_handler.reset(); + } +} + } // namespace wallet diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index e3d362360c4..fd4b368d781 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1072,6 +1072,9 @@ public: //! Find the private key for the given key id from the wallet's descriptors, if available //! Returns nullopt when no descriptor has the key or if the wallet is locked. std::optional GetKey(const CKeyID& keyid) const; + + //! Disconnect chain notifications and wait for all notifications to be processed + void DisconnectChainNotifications(); }; /**