Simplify and fix notifier removal on error.

This factors out the common logic to run over all ZMQ notifiers, call a
function on them, and remove them from the list if the function fails is
extracted to a helper method.

Note that this also fixes a potential memory leak:  When a notifier was
removed previously after its callback returned false, it would just be
removed from the list without destructing the object.  This is now done
correctly by std::unique_ptr behind the scenes.
pull/764/head
Daniel Kraft 4 years ago
parent e15b1cfc31
commit b93b9d5456

@ -114,45 +114,43 @@ void CZMQNotificationInterface::Shutdown()
} }
} }
void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) namespace {
{
if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones
return;
for (auto i = notifiers.begin(); i!=notifiers.end(); ) template <typename Function>
{ void TryForEachAndRemoveFailed(std::list<std::unique_ptr<CZMQAbstractNotifier>>& notifiers, const Function& func)
CZMQAbstractNotifier *notifier = i->get(); {
if (notifier->NotifyBlock(pindexNew)) for (auto i = notifiers.begin(); i != notifiers.end(); ) {
{ CZMQAbstractNotifier* notifier = i->get();
i++; if (func(notifier)) {
} ++i;
else } else {
{
notifier->Shutdown(); notifier->Shutdown();
i = notifiers.erase(i); i = notifiers.erase(i);
} }
} }
} }
} // anonymous namespace
void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
{
if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones
return;
TryForEachAndRemoveFailed(notifiers, [pindexNew](CZMQAbstractNotifier* notifier) {
return notifier->NotifyBlock(pindexNew);
});
}
void CZMQNotificationInterface::TransactionAddedToMempool(const CTransactionRef& ptx) void CZMQNotificationInterface::TransactionAddedToMempool(const CTransactionRef& ptx)
{ {
// Used by BlockConnected and BlockDisconnected as well, because they're // Used by BlockConnected and BlockDisconnected as well, because they're
// all the same external callback. // all the same external callback.
const CTransaction& tx = *ptx; const CTransaction& tx = *ptx;
for (auto i = notifiers.begin(); i!=notifiers.end(); ) TryForEachAndRemoveFailed(notifiers, [&tx](CZMQAbstractNotifier* notifier) {
{ return notifier->NotifyTransaction(tx);
CZMQAbstractNotifier *notifier = i->get(); });
if (notifier->NotifyTransaction(tx))
{
i++;
}
else
{
notifier->Shutdown();
i = notifiers.erase(i);
}
}
} }
void CZMQNotificationInterface::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) void CZMQNotificationInterface::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected)

Loading…
Cancel
Save