LCOV - code coverage report
Current view: top level - src - validationinterface.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 136 176 77.3 %
Date: 2026-06-25 07:23:51 Functions: 123 238 51.7 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2020 The Bitcoin Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include <validationinterface.h>
       7             : 
       8             : #include <attributes.h>
       9             : #include <chain.h>
      10             : #include <consensus/validation.h>
      11             : #include <logging.h>
      12             : #include <primitives/block.h>
      13             : #include <primitives/transaction.h>
      14             : #include <scheduler.h>
      15             : 
      16             : #include <future>
      17             : #include <unordered_map>
      18             : #include <utility>
      19             : 
      20             : std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept;
      21             : 
      22             : /**
      23             :  * MainSignalsImpl manages a list of shared_ptr<CValidationInterface> callbacks.
      24             :  *
      25             :  * A std::unordered_map is used to track what callbacks are currently
      26             :  * registered, and a std::list is used to store the callbacks that are
      27             :  * currently registered as well as any callbacks that are just unregistered
      28             :  * and about to be deleted when they are done executing.
      29             :  */
      30             : class MainSignalsImpl
      31             : {
      32             : private:
      33             :     Mutex m_mutex;
      34             :     //! List entries consist of a callback pointer and reference count. The
      35             :     //! count is equal to the number of current executions of that entry, plus 1
      36             :     //! if it's registered. It cannot be 0 because that would imply it is
      37             :     //! unregistered and also not being executed (so shouldn't exist).
      38             :     struct ListEntry { std::shared_ptr<CValidationInterface> callbacks; int count = 1; };
      39             :     std::list<ListEntry> m_list GUARDED_BY(m_mutex);
      40             :     std::unordered_map<CValidationInterface*, std::list<ListEntry>::iterator> m_map GUARDED_BY(m_mutex);
      41             : 
      42             : public:
      43             :     // We are not allowed to assume the scheduler only runs in one thread,
      44             :     // but must ensure all callbacks happen in-order, so we end up creating
      45             :     // our own queue here :(
      46             :     SingleThreadedSchedulerClient m_schedulerClient;
      47             : 
      48         368 :     explicit MainSignalsImpl(CScheduler& scheduler LIFETIMEBOUND) : m_schedulerClient(scheduler) {}
      49             : 
      50      250093 :     void Register(std::shared_ptr<CValidationInterface> callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
      51             :     {
      52      250093 :         LOCK(m_mutex);
      53      250093 :         auto inserted = m_map.emplace(callbacks.get(), m_list.end());
      54      250093 :         if (inserted.second) inserted.first->second = m_list.emplace(m_list.end());
      55      250093 :         inserted.first->second->callbacks = std::move(callbacks);
      56      250093 :     }
      57             : 
      58      250165 :     void Unregister(CValidationInterface* callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
      59             :     {
      60      250165 :         LOCK(m_mutex);
      61      250165 :         auto it = m_map.find(callbacks);
      62      250165 :         if (it != m_map.end()) {
      63      250092 :             if (!--it->second->count) m_list.erase(it->second);
      64      250092 :             m_map.erase(it);
      65      250092 :         }
      66      250165 :     }
      67             : 
      68             :     //! Clear unregisters every previously registered callback, erasing every
      69             :     //! map entry. After this call, the list may still contain callbacks that
      70             :     //! are currently executing, but it will be cleared when they are done
      71             :     //! executing.
      72           2 :     void Clear() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
      73             :     {
      74           2 :         LOCK(m_mutex);
      75           3 :         for (const auto& entry : m_map) {
      76           1 :             if (!--entry.second->count) m_list.erase(entry.second);
      77             :         }
      78           2 :         m_map.clear();
      79           2 :     }
      80             : 
      81      177379 :     template<typename F> void Iterate(F&& f) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
      82             :     {
      83      177379 :         WAIT_LOCK(m_mutex, lock);
      84      268326 :         for (auto it = m_list.begin(); it != m_list.end();) {
      85       90947 :             ++it->count;
      86             :             {
      87       90947 :                 REVERSE_LOCK(lock);
      88       90947 :                 f(*it->callbacks);
      89       90947 :             }
      90       90947 :             it = --it->count ? std::next(it) : m_list.erase(it);
      91             :         }
      92      177379 :     }
      93             : };
      94             : 
      95             : static CMainSignals g_signals;
      96             : 
      97         184 : void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler)
      98             : {
      99         184 :     assert(!m_internals);
     100         184 :     m_internals = std::make_unique<MainSignalsImpl>(scheduler);
     101         184 : }
     102             : 
     103         184 : void CMainSignals::UnregisterBackgroundSignalScheduler()
     104             : {
     105         184 :     m_internals.reset(nullptr);
     106         184 : }
     107             : 
     108         184 : void CMainSignals::FlushBackgroundCallbacks()
     109             : {
     110         184 :     if (m_internals) {
     111         184 :         m_internals->m_schedulerClient.EmptyQueue();
     112         184 :     }
     113         184 : }
     114             : 
     115       35090 : size_t CMainSignals::CallbacksPending()
     116             : {
     117       35090 :     if (!m_internals) return 0;
     118       35090 :     return m_internals->m_schedulerClient.CallbacksPending();
     119       35090 : }
     120             : 
     121      213021 : CMainSignals& GetMainSignals()
     122             : {
     123      213021 :     return g_signals;
     124             : }
     125             : 
     126      250093 : void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
     127             : {
     128             :     // Each connection captures the shared_ptr to ensure that each callback is
     129             :     // executed before the subscriber is destroyed. For more details see #18338.
     130      250093 :     g_signals.m_internals->Register(std::move(callbacks));
     131      250093 : }
     132             : 
     133          73 : void RegisterValidationInterface(CValidationInterface* callbacks)
     134             : {
     135             :     // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle
     136             :     // is managed by the caller.
     137         146 :     RegisterSharedValidationInterface({callbacks, [](CValidationInterface*){}});
     138          73 : }
     139             : 
     140      250019 : void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
     141             : {
     142      250019 :     UnregisterValidationInterface(callbacks.get());
     143      250019 : }
     144             : 
     145      250168 : void UnregisterValidationInterface(CValidationInterface* callbacks)
     146             : {
     147      250168 :     if (g_signals.m_internals) {
     148      250165 :         g_signals.m_internals->Unregister(callbacks);
     149      250165 :     }
     150      250168 : }
     151             : 
     152           2 : void UnregisterAllValidationInterfaces()
     153             : {
     154           2 :     if (!g_signals.m_internals) {
     155           0 :         return;
     156             :     }
     157           2 :     g_signals.m_internals->Clear();
     158           2 : }
     159             : 
     160         166 : void CallFunctionInValidationInterfaceQueue(std::function<void()> func)
     161             : {
     162         166 :     g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
     163         166 : }
     164             : 
     165         165 : void SyncWithValidationInterfaceQueue()
     166             : {
     167         165 :     AssertLockNotHeld(cs_main);
     168             :     // Block until the validation queue drains
     169         165 :     std::promise<void> promise;
     170         330 :     CallFunctionInValidationInterfaceQueue([&promise] {
     171         165 :         promise.set_value();
     172         165 :     });
     173         165 :     promise.get_future().wait();
     174         165 : }
     175             : 
     176             : // Use a macro instead of a function for conditional logging to prevent
     177             : // evaluating arguments when logging is not enabled.
     178             : //
     179             : // NOTE: The lambda captures all local variables by value.
     180             : #define ENQUEUE_AND_LOG_EVENT(event, fmt, name, ...)           \
     181             :     do {                                                       \
     182             :         auto local_name = (name);                              \
     183             :         LOG_EVENT("Enqueuing " fmt, local_name, __VA_ARGS__);  \
     184             :         m_internals->m_schedulerClient.AddToProcessQueue([=] { \
     185             :             LOG_EVENT(fmt, local_name, __VA_ARGS__);           \
     186             :             event();                                           \
     187             :         });                                                    \
     188             :     } while (0)
     189             : 
     190             : #define LOG_EVENT(fmt, ...) \
     191             :     LogPrint(BCLog::VALIDATION, fmt "\n", __VA_ARGS__)
     192             : 
     193       24308 : void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
     194             :     // Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which
     195             :     // the chain actually updates. One way to ensure this is for the caller to invoke this signal
     196             :     // in the same critical section where the chain is updated
     197             : 
     198       48616 :     auto event = [pindexNew, pindexFork, fInitialDownload, this] {
     199       36850 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
     200       24308 :     };
     201       48616 :     ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s fork block hash=%s (in IBD=%s)", __func__,
     202             :                           pindexNew->GetBlockHash().ToString(),
     203             :                           pindexFork ? pindexFork->GetBlockHash().ToString() : "null",
     204             :                           fInitialDownload);
     205       24308 : }
     206             : 
     207           0 : void CMainSignals::InitializeCurrentBlockTip(const CBlockIndex* tip, bool ibd) {
     208           0 :     m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.InitializeCurrentBlockTip(tip, ibd); });
     209           0 : }
     210             : 
     211       24308 : void CMainSignals::SynchronousUpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
     212       36842 :     m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.SynchronousUpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
     213       24308 : }
     214             : 
     215          78 : void CMainSignals::TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime, uint64_t mempool_sequence) {
     216         156 :     auto event = [tx, nAcceptTime, mempool_sequence, this] {
     217          92 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx, nAcceptTime, mempool_sequence); });
     218          78 :     };
     219         156 :     ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__,
     220             :                           tx->GetHash().ToString());
     221          78 : }
     222             : 
     223          99 : void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {
     224         198 :     auto event = [tx, reason, mempool_sequence, this] {
     225         104 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(tx, reason, mempool_sequence); });
     226          99 :     };
     227         198 :     ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s reason=%s", __func__,
     228             :                           tx->GetHash().ToString(),
     229             :                           RemovalReasonToString(reason));
     230          99 : }
     231             : 
     232       24673 : void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
     233       49346 :     auto event = [pblock, pindex, this] {
     234       37223 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(pblock, pindex); });
     235       24673 :     };
     236       49346 :     ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
     237             :                           pblock->GetHash().ToString(),
     238             :                           pindex->nHeight);
     239       24673 : }
     240             : 
     241         387 : void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex* pindex) {
     242         774 :     auto event = [pblock, pindex, this] {
     243         409 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockDisconnected(pblock, pindex); });
     244         387 :     };
     245         774 :     ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
     246             :                           pblock->GetHash().ToString(),
     247             :                           pindex->nHeight);
     248         387 : }
     249             : 
     250          23 : void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
     251          46 :     auto event = [locator, this] {
     252          41 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(locator); });
     253          23 :     };
     254          69 :     ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
     255             :                           locator.IsNull() ? "null" : locator.vHave.front().ToString());
     256          23 : }
     257             : 
     258       29295 : void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
     259       29295 :     LOG_EVENT("%s: block hash=%s state=%s", __func__,
     260             :               block.GetHash().ToString(), state.ToString());
     261       43030 :     m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); });
     262       29295 : }
     263             : 
     264       23523 : void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
     265       23523 :     LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
     266       36009 :     m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NewPoWValidBlock(pindex, block); });
     267       23523 : }
     268             : 
     269       24536 : void CMainSignals::AcceptedBlockHeader(const CBlockIndex *pindexNew) {
     270       24536 :     LOG_EVENT("%s: accepted block header hash=%s", __func__, pindexNew->GetBlockHash().ToString());
     271       37058 :     m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.AcceptedBlockHeader(pindexNew); });
     272       24536 : }
     273             : 
     274       24130 : void CMainSignals::NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload) {
     275       24130 :     LOG_EVENT("%s: accepted block header hash=%s initial=%d", __func__, pindexNew->GetBlockHash().ToString(), fInitialDownload);
     276       36630 :     m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyHeaderTip(pindexNew, fInitialDownload); });
     277       24130 : }
     278             : 
     279           0 : void CMainSignals::NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const instantsend::InstantSendLock>& islock) {
     280           0 :     auto event = [tx, islock, this] {
     281           0 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyTransactionLock(tx, islock); });
     282           0 :     };
     283           0 :     ENQUEUE_AND_LOG_EVENT(event, "%s: transaction lock txid=%s", __func__,
     284             :                           tx->GetHash().ToString());
     285           0 : }
     286             : 
     287           0 : void CMainSignals::NotifyChainLock(const CBlockIndex* pindex, const std::shared_ptr<const chainlock::ChainLockSig>& clsig, const std::string& id) {
     288           0 :     auto event = [pindex, clsig, this] {
     289           0 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyChainLock(pindex, clsig); });
     290           0 :     };
     291           0 :     ENQUEUE_AND_LOG_EVENT(event, "%s: notify chainlock at block=%s cl=%s", __func__,
     292             :             pindex->GetBlockHash().ToString(),
     293             :             id);
     294           0 : }
     295             : 
     296           0 : void CMainSignals::NotifyGovernanceVote(const std::shared_ptr<CDeterministicMNList>& tip_mn_list, const std::shared_ptr<const CGovernanceVote>& vote, const std::string& id) {
     297           0 :     auto event = [vote, tip_mn_list, this] {
     298           0 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyGovernanceVote(tip_mn_list, vote); });
     299           0 :     };
     300           0 :     ENQUEUE_AND_LOG_EVENT(event, "%s: notify governance vote: %s", __func__, id);
     301           0 : }
     302             : 
     303           0 : void CMainSignals::NotifyGovernanceObject(const std::shared_ptr<const Governance::Object>& object, const std::string& id) {
     304           0 :     auto event = [object, this] {
     305           0 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyGovernanceObject(object); });
     306           0 :     };
     307           0 :     ENQUEUE_AND_LOG_EVENT(event, "%s: notify governance object: %s", __func__, id);
     308           0 : }
     309             : 
     310           0 : void CMainSignals::NotifyInstantSendDoubleSpendAttempt(const CTransactionRef& currentTx, const CTransactionRef& previousTx) {
     311           0 :     auto event = [currentTx, previousTx, this] {
     312           0 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyInstantSendDoubleSpendAttempt(currentTx, previousTx); });
     313           0 :     };
     314           0 :     ENQUEUE_AND_LOG_EVENT(event, "%s: notify instant doublespendattempt currenttxid=%s previoustxid=%s", __func__,
     315             :             currentTx->GetHash().ToString(),
     316             :             previousTx->GetHash().ToString());
     317           0 : }
     318             : 
     319           0 : void CMainSignals::NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig>& sig, const std::string& id, bool proactive_relay) {
     320           0 :     auto event = [sig, proactive_relay, this] {
     321           0 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyRecoveredSig(sig, proactive_relay); });
     322           0 :     };
     323           0 :     ENQUEUE_AND_LOG_EVENT(event, "%s: notify recoveredsig=%s", __func__,
     324             :             id);
     325           0 : }
     326             : 
     327        2019 : void CMainSignals::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff) {
     328        2019 :     LOG_EVENT("%s: notify mn list changed undo=%d", __func__, undo);
     329        4038 :     m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyMasternodeListChanged(undo, oldMNList, diff); });
     330        2019 : }

Generated by: LCOV version 1.16