diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index c37b61d59ba08..2859edd5cf7e6 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -93,10 +93,11 @@ CMainSignals& GetMainSignals() { return g_signals; } - -void RegisterValidationInterface(CValidationInterface* pwalletIn) +void RegisterSharedValidationInterface(std::shared_ptr pwalletIn) { - ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn]; + // Each connection captures pwalletIn to ensure that each callback is + // executed before pwalletIn is destroyed. For more details see bitcoin #18338 + ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn.get()]; conns.AcceptedBlockHeader = g_signals.m_internals->AcceptedBlockHeader.connect(std::bind(&CValidationInterface::AcceptedBlockHeader, pwalletIn, std::placeholders::_1)); conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); conns.TransactionAddedToMempool = g_signals.m_internals->TransactionAddedToMempool.connect(std::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, std::placeholders::_1)); @@ -108,6 +109,12 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2)); conns.NotifyMasternodeListChanged = g_signals.m_internals->NotifyMasternodeListChanged.connect(std::bind(&CValidationInterface::NotifyMasternodeListChanged, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); } +void RegisterValidationInterface(CValidationInterface* pwalletIn) +{ + // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle + // is managed by the caller. + RegisterSharedValidationInterface({pwalletIn, [](CValidationInterface*) {}}); +} void UnregisterValidationInterface(CValidationInterface* pwalletIn) { @@ -116,6 +123,11 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) } } +void UnregisterSharedValidationInterface(std::shared_ptr pwalletIn) +{ + UnregisterValidationInterface(pwalletIn.get()); +} + void UnregisterAllValidationInterfaces() { if (!g_signals.m_internals) { diff --git a/src/validationinterface.h b/src/validationinterface.h index de6f7ed044ddf..18ab38356b563 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -34,6 +34,14 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn); void UnregisterValidationInterface(CValidationInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllValidationInterfaces(); + +// Alternate registration functions that release a shared_ptr after the last +// notification is sent. These are useful for race-free cleanup, since +// unregistration is nonblocking and can return before the last notification is +// processed. +void RegisterSharedValidationInterface(std::shared_ptr pwalletIn); +void UnregisterSharedValidationInterface(std::shared_ptr pwalletIn); + /** * Pushes a function to callback onto the notification queue, guaranteeing any * callbacks generated prior to now are finished when the function is called. @@ -147,7 +155,7 @@ class CValidationInterface { /** Tells listeners to broadcast their data. */ virtual void ResendWalletTransactions(CConnman* connman) {} virtual void BlockChecked(const CBlock&, const CValidationState&) {} - friend void ::RegisterValidationInterface(CValidationInterface*); + friend void ::RegisterSharedValidationInterface(std::shared_ptr); friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterAllValidationInterfaces(); /** Notifies listeners of updated deterministic masternode list */ @@ -159,7 +167,7 @@ class CMainSignals { private: std::unique_ptr m_internals; - friend void ::RegisterValidationInterface(CValidationInterface*); + friend void ::RegisterSharedValidationInterface(std::shared_ptr); friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterAllValidationInterfaces(); friend void ::CallFunctionInValidationInterfaceQueue(std::function func);