LCOV - code coverage report
Current view: top level - src - validationinterface.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 96 122 78.7 %
Date: 2023-09-26 12:08:55 Functions: 58 88 65.9 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2022 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           1 :     explicit MainSignalsImpl(CScheduler& scheduler LIFETIMEBOUND) : m_schedulerClient(scheduler) {}
      49             : 
      50        7872 :     void Register(std::shared_ptr<CValidationInterface> callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
      51             :     {
      52        7872 :         LOCK(m_mutex);
      53        7872 :         auto inserted = m_map.emplace(callbacks.get(), m_list.end());
      54        7872 :         if (inserted.second) inserted.first->second = m_list.emplace(m_list.end());
      55        7872 :         inserted.first->second->callbacks = std::move(callbacks);
      56        7872 :     }
      57             : 
      58        7872 :     void Unregister(CValidationInterface* callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
      59             :     {
      60        7872 :         LOCK(m_mutex);
      61        7872 :         auto it = m_map.find(callbacks);
      62        7872 :         if (it != m_map.end()) {
      63        7872 :             if (!--it->second->count) m_list.erase(it->second);
      64        7872 :             m_map.erase(it);
      65        7872 :         }
      66        7872 :     }
      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           0 :     void Clear() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
      73             :     {
      74           2 :         LOCK(m_mutex);
      75           0 :         for (const auto& entry : m_map) {
      76           0 :             if (!--entry.second->count) m_list.erase(entry.second);
      77             :         }
      78           0 :         m_map.clear();
      79           0 :     }
      80             : 
      81        3108 :     template<typename F> void Iterate(F&& f) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
      82             :     {
      83        3108 :         WAIT_LOCK(m_mutex, lock);
      84        6158 :         for (auto it = m_list.begin(); it != m_list.end();) {
      85        3050 :             ++it->count;
      86             :             {
      87        3050 :                 REVERSE_LOCK(lock);
      88        3050 :                 f(*it->callbacks);
      89        3050 :             }
      90        3050 :             it = --it->count ? std::next(it) : m_list.erase(it);
      91             :         }
      92        3108 :     }
      93             : };
      94             : 
      95             : static CMainSignals g_signals;
      96             : 
      97           1 : void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler)
      98             : {
      99           1 :     assert(!m_internals);
     100           1 :     m_internals = std::make_unique<MainSignalsImpl>(scheduler);
     101           1 : }
     102             : 
     103           1 : void CMainSignals::UnregisterBackgroundSignalScheduler()
     104             : {
     105           1 :     m_internals.reset(nullptr);
     106           1 : }
     107             : 
     108           1 : void CMainSignals::FlushBackgroundCallbacks()
     109             : {
     110           1 :     if (m_internals) {
     111           1 :         m_internals->m_schedulerClient.EmptyQueue();
     112           1 :     }
     113           1 : }
     114             : 
     115         201 : size_t CMainSignals::CallbacksPending()
     116             : {
     117         201 :     if (!m_internals) return 0;
     118         201 :     return m_internals->m_schedulerClient.CallbacksPending();
     119         201 : }
     120             : 
     121        3312 : CMainSignals& GetMainSignals()
     122             : {
     123        3312 :     return g_signals;
     124             : }
     125             : 
     126        7872 : 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        7872 :     g_signals.m_internals->Register(std::move(callbacks));
     131        7872 : }
     132             : 
     133         200 : void RegisterValidationInterface(CValidationInterface* callbacks)
     134             : {
     135             :     // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle
     136             :     // is managed by the caller.
     137         400 :     RegisterSharedValidationInterface({callbacks, [](CValidationInterface*){}});
     138         200 : }
     139             : 
     140        7672 : void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
     141             : {
     142        7672 :     UnregisterValidationInterface(callbacks.get());
     143        7672 : }
     144             : 
     145        7872 : void UnregisterValidationInterface(CValidationInterface* callbacks)
     146             : {
     147        7872 :     if (g_signals.m_internals) {
     148        7872 :         g_signals.m_internals->Unregister(callbacks);
     149        7872 :     }
     150        7872 : }
     151             : 
     152           0 : void UnregisterAllValidationInterfaces()
     153             : {
     154           0 :     if (!g_signals.m_internals) {
     155           0 :         return;
     156             :     }
     157           0 :     g_signals.m_internals->Clear();
     158           0 : }
     159             : 
     160       12732 : void CallFunctionInValidationInterfaceQueue(std::function<void()> func)
     161             : {
     162       12732 :     g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
     163       12732 : }
     164             : 
     165       12732 : void SyncWithValidationInterfaceQueue()
     166             : {
     167       12732 :     AssertLockNotHeld(cs_main);
     168             :     // Block until the validation queue drains
     169       12732 :     std::promise<void> promise;
     170       25464 :     CallFunctionInValidationInterfaceQueue([&promise] {
     171       12732 :         promise.set_value();
     172       12732 :     });
     173       12732 :     promise.get_future().wait();
     174       12732 : }
     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         201 : 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         402 :     auto event = [pindexNew, pindexFork, fInitialDownload, this] {
     199         369 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
     200         201 :     };
     201         402 :     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         201 : }
     206             : 
     207        2196 : void CMainSignals::TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {
     208        4392 :     auto event = [tx, mempool_sequence, this] {
     209        4392 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx, mempool_sequence); });
     210        2196 :     };
     211        4392 :     ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
     212             :                           tx->GetHash().ToString(),
     213             :                           tx->GetWitnessHash().ToString());
     214        2196 : }
     215             : 
     216         309 : void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {
     217         618 :     auto event = [tx, reason, mempool_sequence, this] {
     218         618 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(tx, reason, mempool_sequence); });
     219         309 :     };
     220         618 :     ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s reason=%s", __func__,
     221             :                           tx->GetHash().ToString(),
     222             :                           tx->GetWitnessHash().ToString(),
     223             :                           RemovalReasonToString(reason));
     224         309 : }
     225             : 
     226         201 : void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
     227         402 :     auto event = [pblock, pindex, this] {
     228         378 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(pblock, pindex); });
     229         201 :     };
     230         402 :     ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
     231             :                           pblock->GetHash().ToString(),
     232             :                           pindex->nHeight);
     233         201 : }
     234             : 
     235           0 : void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
     236             : {
     237           0 :     auto event = [pblock, pindex, this] {
     238           0 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockDisconnected(pblock, pindex); });
     239           0 :     };
     240           0 :     ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
     241             :                           pblock->GetHash().ToString(),
     242             :                           pindex->nHeight);
     243           0 : }
     244             : 
     245           0 : void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
     246           0 :     auto event = [locator, this] {
     247           0 :         m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(locator); });
     248           0 :     };
     249           0 :     ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
     250             :                           locator.IsNull() ? "null" : locator.vHave.front().ToString());
     251           0 : }
     252             : 
     253         201 : void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
     254         201 :     LOG_EVENT("%s: block hash=%s state=%s", __func__,
     255             :               block.GetHash().ToString(), state.ToString());
     256         401 :     m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); });
     257         201 : }
     258             : 
     259           0 : void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
     260           0 :     LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
     261           0 :     m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NewPoWValidBlock(pindex, block); });
     262           0 : }

Generated by: LCOV version 1.14