From 36f170d87924e50d0ff9be2a1b0f2a8f13950a9b Mon Sep 17 00:00:00 2001 From: glozow Date: Fri, 29 Sep 2023 13:58:16 +0100 Subject: [PATCH] add ValidationInterface::ActiveTipChange This is a synchronous callback notifying clients of all tip changes. It allows clients to respond to a new block immediately after it is connected. The synchronicity is important for things like m_recent_rejects, in which a transaction's validity can change (rejected vs accepted) when this event is processed. For example, the transaction might have a timelock condition that has just been met. This is distinct from something like m_recent_confirmed_transactions, in which the validation outcome is the same (valid vs already-have), so it does not need to be reset immediately. --- src/validation.cpp | 14 +++++++++++++- src/validationinterface.cpp | 6 ++++++ src/validationinterface.h | 5 +++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 988df3802a1..52bff9bac26 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3488,6 +3488,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< { LOCK(cs_main); + { // Lock transaction pool for at least as long as it takes for connectTrace to be consumed LOCK(MempoolMutex()); const bool was_in_ibd = m_chainman.IsInitialBlockDownload(); @@ -3564,7 +3565,12 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< break; } } - } + } // release MempoolMutex + // Notify external listeners about the new tip, even if pindexFork == pindexNewTip. + if (m_chainman.m_options.signals && this == &m_chainman.ActiveChainstate()) { + m_chainman.m_options.signals->ActiveTipChange(pindexNewTip, m_chainman.IsInitialBlockDownload()); + } + } // release cs_main // When we reach this point, we switched to a new tip (stored in pindexNewTip). if (exited_ibd) { @@ -3783,6 +3789,12 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde // distinguish user-initiated invalidateblock changes from other // changes. (void)m_chainman.GetNotifications().blockTip(GetSynchronizationState(m_chainman.IsInitialBlockDownload(), m_chainman.m_blockman.m_blockfiles_indexed), *to_mark_failed->pprev); + + // Fire ActiveTipChange now for the current chain tip to make sure clients are notified. + // ActivateBestChain may call this as well, but not necessarily. + if (m_chainman.m_options.signals) { + m_chainman.m_options.signals->ActiveTipChange(m_chain.Tip(), m_chainman.IsInitialBlockDownload()); + } } return true; } diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 579444a065a..f5baa16c99b 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -183,6 +183,12 @@ void ValidationSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlo fInitialDownload); } +void ValidationSignals::ActiveTipChange(const CBlockIndex *new_tip, bool is_ibd) +{ + LOG_EVENT("%s: new block hash=%s block height=%d", __func__, new_tip->GetBlockHash().ToString(), new_tip->nHeight); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ActiveTipChange(new_tip, is_ibd); }); +} + void ValidationSignals::TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t mempool_sequence) { auto event = [tx, mempool_sequence, this] { diff --git a/src/validationinterface.h b/src/validationinterface.h index 6f49a73c93c..3cc3566a605 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -61,6 +61,10 @@ protected: * Called on a background thread. Only called for the active chainstate. */ virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {} + /** + * Notifies listeners any time the block chain tip changes, synchronously. + */ + virtual void ActiveTipChange(const CBlockIndex* new_tip, bool is_ibd) {}; /** * Notifies listeners of a transaction having been added to mempool. * @@ -214,6 +218,7 @@ public: void SyncWithValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main); void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload); + void ActiveTipChange(const CBlockIndex*, bool); void TransactionAddedToMempool(const NewMempoolTransactionInfo&, uint64_t mempool_sequence); void TransactionRemovedFromMempool(const CTransactionRef&, MemPoolRemovalReason, uint64_t mempool_sequence); void MempoolTransactionsRemovedForBlock(const std::vector&, unsigned int nBlockHeight);