mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 14:38:29 +01:00
Fix wallet unload race condition
Currently it's possible for ReleaseWallet to delete the CWallet pointer while it is processing BlockConnected, etc chain notifications. To fix this, unregister from notifications earlier in UnloadWallet instead of ReleaseWallet, and use a new RegisterSharedValidationInterface function to prevent the CValidationInterface shared_ptr from being deleted until the last notification is actually finished.
This commit is contained in:
committed by
João Barbosa
parent
3e50fdbe4e
commit
ab31b9d6fe
@@ -148,22 +148,12 @@ class LockImpl : public Chain::Lock, public UniqueLock<RecursiveMutex>
|
||||
using UniqueLock::UniqueLock;
|
||||
};
|
||||
|
||||
class NotificationsHandlerImpl : public Handler, CValidationInterface
|
||||
class NotificationsProxy : public CValidationInterface
|
||||
{
|
||||
public:
|
||||
explicit NotificationsHandlerImpl(Chain& chain, Chain::Notifications& notifications)
|
||||
: m_chain(chain), m_notifications(¬ifications)
|
||||
{
|
||||
RegisterValidationInterface(this);
|
||||
}
|
||||
~NotificationsHandlerImpl() override { disconnect(); }
|
||||
void disconnect() override
|
||||
{
|
||||
if (m_notifications) {
|
||||
m_notifications = nullptr;
|
||||
UnregisterValidationInterface(this);
|
||||
}
|
||||
}
|
||||
explicit NotificationsProxy(std::shared_ptr<Chain::Notifications> notifications)
|
||||
: m_notifications(std::move(notifications)) {}
|
||||
virtual ~NotificationsProxy() = default;
|
||||
void TransactionAddedToMempool(const CTransactionRef& tx) override
|
||||
{
|
||||
m_notifications->transactionAddedToMempool(tx);
|
||||
@@ -185,8 +175,26 @@ public:
|
||||
m_notifications->updatedBlockTip();
|
||||
}
|
||||
void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->chainStateFlushed(locator); }
|
||||
Chain& m_chain;
|
||||
Chain::Notifications* m_notifications;
|
||||
std::shared_ptr<Chain::Notifications> m_notifications;
|
||||
};
|
||||
|
||||
class NotificationsHandlerImpl : public Handler
|
||||
{
|
||||
public:
|
||||
explicit NotificationsHandlerImpl(std::shared_ptr<Chain::Notifications> notifications)
|
||||
: m_proxy(std::make_shared<NotificationsProxy>(std::move(notifications)))
|
||||
{
|
||||
RegisterSharedValidationInterface(m_proxy);
|
||||
}
|
||||
~NotificationsHandlerImpl() override { disconnect(); }
|
||||
void disconnect() override
|
||||
{
|
||||
if (m_proxy) {
|
||||
UnregisterSharedValidationInterface(m_proxy);
|
||||
m_proxy.reset();
|
||||
}
|
||||
}
|
||||
std::shared_ptr<NotificationsProxy> m_proxy;
|
||||
};
|
||||
|
||||
class RpcHandlerImpl : public Handler
|
||||
@@ -343,9 +351,9 @@ public:
|
||||
{
|
||||
::uiInterface.ShowProgress(title, progress, resume_possible);
|
||||
}
|
||||
std::unique_ptr<Handler> handleNotifications(Notifications& notifications) override
|
||||
std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) override
|
||||
{
|
||||
return MakeUnique<NotificationsHandlerImpl>(*this, notifications);
|
||||
return MakeUnique<NotificationsHandlerImpl>(std::move(notifications));
|
||||
}
|
||||
void waitForNotificationsIfTipChanged(const uint256& old_tip) override
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user