/ src / validationinterface.cpp
validationinterface.cpp
  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 <chain.h>
  9  #include <consensus/validation.h>
 10  #include <kernel/chain.h>
 11  #include <kernel/mempool_entry.h>
 12  #include <logging.h>
 13  #include <primitives/block.h>
 14  #include <primitives/transaction.h>
 15  #include <util/check.h>
 16  #include <util/task_runner.h>
 17  
 18  #include <future>
 19  #include <unordered_map>
 20  #include <utility>
 21  
 22  std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept;
 23  
 24  /**
 25   * ValidationSignalsImpl manages a list of shared_ptr<CValidationInterface> callbacks.
 26   *
 27   * A std::unordered_map is used to track what callbacks are currently
 28   * registered, and a std::list is used to store the callbacks that are
 29   * currently registered as well as any callbacks that are just unregistered
 30   * and about to be deleted when they are done executing.
 31   */
 32  class ValidationSignalsImpl
 33  {
 34  private:
 35      Mutex m_mutex;
 36      //! List entries consist of a callback pointer and reference count. The
 37      //! count is equal to the number of current executions of that entry, plus 1
 38      //! if it's registered. It cannot be 0 because that would imply it is
 39      //! unregistered and also not being executed (so shouldn't exist).
 40      struct ListEntry { std::shared_ptr<CValidationInterface> callbacks; int count = 1; };
 41      std::list<ListEntry> m_list GUARDED_BY(m_mutex);
 42      std::unordered_map<CValidationInterface*, std::list<ListEntry>::iterator> m_map GUARDED_BY(m_mutex);
 43  
 44  public:
 45      std::unique_ptr<util::TaskRunnerInterface> m_task_runner;
 46  
 47      explicit ValidationSignalsImpl(std::unique_ptr<util::TaskRunnerInterface> task_runner)
 48          : m_task_runner{std::move(Assert(task_runner))} {}
 49  
 50      void Register(std::shared_ptr<CValidationInterface> callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
 51      {
 52          LOCK(m_mutex);
 53          auto inserted = m_map.emplace(callbacks.get(), m_list.end());
 54          if (inserted.second) inserted.first->second = m_list.emplace(m_list.end());
 55          inserted.first->second->callbacks = std::move(callbacks);
 56      }
 57  
 58      void Unregister(CValidationInterface* callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
 59      {
 60          LOCK(m_mutex);
 61          auto it = m_map.find(callbacks);
 62          if (it != m_map.end()) {
 63              if (!--it->second->count) m_list.erase(it->second);
 64              m_map.erase(it);
 65          }
 66      }
 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      void Clear() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
 73      {
 74          LOCK(m_mutex);
 75          for (const auto& entry : m_map) {
 76              if (!--entry.second->count) m_list.erase(entry.second);
 77          }
 78          m_map.clear();
 79      }
 80  
 81      template<typename F> void Iterate(F&& f) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
 82      {
 83          WAIT_LOCK(m_mutex, lock);
 84          for (auto it = m_list.begin(); it != m_list.end();) {
 85              ++it->count;
 86              {
 87                  REVERSE_LOCK(lock);
 88                  f(*it->callbacks);
 89              }
 90              it = --it->count ? std::next(it) : m_list.erase(it);
 91          }
 92      }
 93  };
 94  
 95  ValidationSignals::ValidationSignals(std::unique_ptr<util::TaskRunnerInterface> task_runner)
 96      : m_internals{std::make_unique<ValidationSignalsImpl>(std::move(task_runner))} {}
 97  
 98  ValidationSignals::~ValidationSignals() {}
 99  
100  void ValidationSignals::FlushBackgroundCallbacks()
101  {
102      m_internals->m_task_runner->flush();
103  }
104  
105  size_t ValidationSignals::CallbacksPending()
106  {
107      return m_internals->m_task_runner->size();
108  }
109  
110  void ValidationSignals::RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
111  {
112      // Each connection captures the shared_ptr to ensure that each callback is
113      // executed before the subscriber is destroyed. For more details see #18338.
114      m_internals->Register(std::move(callbacks));
115  }
116  
117  void ValidationSignals::RegisterValidationInterface(CValidationInterface* callbacks)
118  {
119      // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle
120      // is managed by the caller.
121      RegisterSharedValidationInterface({callbacks, [](CValidationInterface*){}});
122  }
123  
124  void ValidationSignals::UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
125  {
126      UnregisterValidationInterface(callbacks.get());
127  }
128  
129  void ValidationSignals::UnregisterValidationInterface(CValidationInterface* callbacks)
130  {
131      m_internals->Unregister(callbacks);
132  }
133  
134  void ValidationSignals::UnregisterAllValidationInterfaces()
135  {
136      m_internals->Clear();
137  }
138  
139  void ValidationSignals::CallFunctionInValidationInterfaceQueue(std::function<void()> func)
140  {
141      m_internals->m_task_runner->insert(std::move(func));
142  }
143  
144  void ValidationSignals::SyncWithValidationInterfaceQueue()
145  {
146      AssertLockNotHeld(cs_main);
147      // Block until the validation queue drains
148      std::promise<void> promise;
149      CallFunctionInValidationInterfaceQueue([&promise] {
150          promise.set_value();
151      });
152      promise.get_future().wait();
153  }
154  
155  // Use a macro instead of a function for conditional logging to prevent
156  // evaluating arguments when logging is not enabled.
157  //
158  // NOTE: The lambda captures all local variables by value.
159  #define ENQUEUE_AND_LOG_EVENT(event, fmt, name, ...)           \
160      do {                                                       \
161          auto local_name = (name);                              \
162          LOG_EVENT("Enqueuing " fmt, local_name, __VA_ARGS__);  \
163          m_internals->m_task_runner->insert([=] { \
164              LOG_EVENT(fmt, local_name, __VA_ARGS__);           \
165              event();                                           \
166          });                                                    \
167      } while (0)
168  
169  #define LOG_EVENT(fmt, ...) \
170      LogPrint(BCLog::VALIDATION, fmt "\n", __VA_ARGS__)
171  
172  void ValidationSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
173      // Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which
174      // the chain actually updates. One way to ensure this is for the caller to invoke this signal
175      // in the same critical section where the chain is updated
176  
177      auto event = [pindexNew, pindexFork, fInitialDownload, this] {
178          m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
179      };
180      ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s fork block hash=%s (in IBD=%s)", __func__,
181                            pindexNew->GetBlockHash().ToString(),
182                            pindexFork ? pindexFork->GetBlockHash().ToString() : "null",
183                            fInitialDownload);
184  }
185  
186  void ValidationSignals::TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t mempool_sequence)
187  {
188      auto event = [tx, mempool_sequence, this] {
189          m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx, mempool_sequence); });
190      };
191      ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
192                            tx.info.m_tx->GetHash().ToString(),
193                            tx.info.m_tx->GetWitnessHash().ToString());
194  }
195  
196  void ValidationSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {
197      auto event = [tx, reason, mempool_sequence, this] {
198          m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(tx, reason, mempool_sequence); });
199      };
200      ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s reason=%s", __func__,
201                            tx->GetHash().ToString(),
202                            tx->GetWitnessHash().ToString(),
203                            RemovalReasonToString(reason));
204  }
205  
206  void ValidationSignals::BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
207      auto event = [role, pblock, pindex, this] {
208          m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(role, pblock, pindex); });
209      };
210      ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
211                            pblock->GetHash().ToString(),
212                            pindex->nHeight);
213  }
214  
215  void ValidationSignals::MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block, unsigned int nBlockHeight)
216  {
217      auto event = [txs_removed_for_block, nBlockHeight, this] {
218          m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.MempoolTransactionsRemovedForBlock(txs_removed_for_block, nBlockHeight); });
219      };
220      ENQUEUE_AND_LOG_EVENT(event, "%s: block height=%s txs removed=%s", __func__,
221                            nBlockHeight,
222                            txs_removed_for_block.size());
223  }
224  
225  void ValidationSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
226  {
227      auto event = [pblock, pindex, this] {
228          m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockDisconnected(pblock, pindex); });
229      };
230      ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
231                            pblock->GetHash().ToString(),
232                            pindex->nHeight);
233  }
234  
235  void ValidationSignals::ChainStateFlushed(ChainstateRole role, const CBlockLocator &locator) {
236      auto event = [role, locator, this] {
237          m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(role, locator); });
238      };
239      ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
240                            locator.IsNull() ? "null" : locator.vHave.front().ToString());
241  }
242  
243  void ValidationSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
244      LOG_EVENT("%s: block hash=%s state=%s", __func__,
245                block.GetHash().ToString(), state.ToString());
246      m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); });
247  }
248  
249  void ValidationSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
250      LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
251      m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NewPoWValidBlock(pindex, block); });
252  }