Branch data 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 <chain.h>
# 9 : : #include <consensus/validation.h>
# 10 : : #include <logging.h>
# 11 : : #include <primitives/block.h>
# 12 : : #include <primitives/transaction.h>
# 13 : : #include <scheduler.h>
# 14 : :
# 15 : : #include <future>
# 16 : : #include <unordered_map>
# 17 : : #include <utility>
# 18 : :
# 19 : : //! The MainSignalsInstance manages a list of shared_ptr<CValidationInterface>
# 20 : : //! callbacks.
# 21 : : //!
# 22 : : //! A std::unordered_map is used to track what callbacks are currently
# 23 : : //! registered, and a std::list is to used to store the callbacks that are
# 24 : : //! currently registered as well as any callbacks that are just unregistered
# 25 : : //! and about to be deleted when they are done executing.
# 26 : : struct MainSignalsInstance {
# 27 : : private:
# 28 : : Mutex m_mutex;
# 29 : : //! List entries consist of a callback pointer and reference count. The
# 30 : : //! count is equal to the number of current executions of that entry, plus 1
# 31 : : //! if it's registered. It cannot be 0 because that would imply it is
# 32 : : //! unregistered and also not being executed (so shouldn't exist).
# 33 : : struct ListEntry { std::shared_ptr<CValidationInterface> callbacks; int count = 1; };
# 34 : : std::list<ListEntry> m_list GUARDED_BY(m_mutex);
# 35 : : std::unordered_map<CValidationInterface*, std::list<ListEntry>::iterator> m_map GUARDED_BY(m_mutex);
# 36 : :
# 37 : : public:
# 38 : : // We are not allowed to assume the scheduler only runs in one thread,
# 39 : : // but must ensure all callbacks happen in-order, so we end up creating
# 40 : : // our own queue here :(
# 41 : : SingleThreadedSchedulerClient m_schedulerClient;
# 42 : :
# 43 : 818 : explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
# 44 : :
# 45 : : void Register(std::shared_ptr<CValidationInterface> callbacks)
# 46 : 255519 : {
# 47 : 255519 : LOCK(m_mutex);
# 48 : 255519 : auto inserted = m_map.emplace(callbacks.get(), m_list.end());
# 49 [ + - ]: 255519 : if (inserted.second) inserted.first->second = m_list.emplace(m_list.end());
# 50 : 255519 : inserted.first->second->callbacks = std::move(callbacks);
# 51 : 255519 : }
# 52 : :
# 53 : : void Unregister(CValidationInterface* callbacks)
# 54 : 255544 : {
# 55 : 255544 : LOCK(m_mutex);
# 56 : 255544 : auto it = m_map.find(callbacks);
# 57 [ + + ]: 255544 : if (it != m_map.end()) {
# 58 [ + + ]: 255518 : if (!--it->second->count) m_list.erase(it->second);
# 59 : 255518 : m_map.erase(it);
# 60 : 255518 : }
# 61 : 255544 : }
# 62 : :
# 63 : : //! Clear unregisters every previously registered callback, erasing every
# 64 : : //! map entry. After this call, the list may still contain callbacks that
# 65 : : //! are currently executing, but it will be cleared when they are done
# 66 : : //! executing.
# 67 : : void Clear()
# 68 : 663 : {
# 69 : 663 : LOCK(m_mutex);
# 70 [ + + ]: 663 : for (const auto& entry : m_map) {
# 71 [ - + ]: 1 : if (!--entry.second->count) m_list.erase(entry.second);
# 72 : 1 : }
# 73 : 663 : m_map.clear();
# 74 : 663 : }
# 75 : :
# 76 : : template<typename F> void Iterate(F&& f)
# 77 : 294483 : {
# 78 : 294483 : WAIT_LOCK(m_mutex, lock);
# 79 [ + + ][ + + ]: 799067 : for (auto it = m_list.begin(); it != m_list.end();) {
# [ + + ][ + + ]
# [ + + ][ + + ]
# [ + + ][ + + ]
# 80 : 504584 : ++it->count;
# 81 : 504584 : {
# 82 : 504584 : REVERSE_LOCK(lock);
# 83 : 504584 : f(*it->callbacks);
# 84 : 504584 : }
# 85 [ + - ][ + + ]: 504584 : it = --it->count ? std::next(it) : m_list.erase(it);
# [ + - ][ + - ]
# [ + - ][ + + ]
# [ + - ][ + - ]
# 86 : 504584 : }
# 87 : 294483 : }
# 88 : : };
# 89 : :
# 90 : : static CMainSignals g_signals;
# 91 : :
# 92 : : void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler)
# 93 : 818 : {
# 94 : 818 : assert(!m_internals);
# 95 : 818 : m_internals.reset(new MainSignalsInstance(&scheduler));
# 96 : 818 : }
# 97 : :
# 98 : : void CMainSignals::UnregisterBackgroundSignalScheduler()
# 99 : 820 : {
# 100 : 820 : m_internals.reset(nullptr);
# 101 : 820 : }
# 102 : :
# 103 : : void CMainSignals::FlushBackgroundCallbacks()
# 104 : 820 : {
# 105 [ + + ]: 820 : if (m_internals) {
# 106 : 818 : m_internals->m_schedulerClient.EmptyQueue();
# 107 : 818 : }
# 108 : 820 : }
# 109 : :
# 110 : : size_t CMainSignals::CallbacksPending()
# 111 : 85370 : {
# 112 [ - + ]: 85370 : if (!m_internals) return 0;
# 113 : 85370 : return m_internals->m_schedulerClient.CallbacksPending();
# 114 : 85370 : }
# 115 : :
# 116 : : CMainSignals& GetMainSignals()
# 117 : 382937 : {
# 118 : 382937 : return g_signals;
# 119 : 382937 : }
# 120 : :
# 121 : : void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
# 122 : 255519 : {
# 123 : : // Each connection captures the shared_ptr to ensure that each callback is
# 124 : : // executed before the subscriber is destroyed. For more details see #18338.
# 125 : 255519 : g_signals.m_internals->Register(std::move(callbacks));
# 126 : 255519 : }
# 127 : :
# 128 : : void RegisterValidationInterface(CValidationInterface* callbacks)
# 129 : 661 : {
# 130 : : // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle
# 131 : : // is managed by the caller.
# 132 : 661 : RegisterSharedValidationInterface({callbacks, [](CValidationInterface*){}});
# 133 : 661 : }
# 134 : :
# 135 : : void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
# 136 : 254857 : {
# 137 : 254857 : UnregisterValidationInterface(callbacks.get());
# 138 : 254857 : }
# 139 : :
# 140 : : void UnregisterValidationInterface(CValidationInterface* callbacks)
# 141 : 255550 : {
# 142 [ + + ]: 255550 : if (g_signals.m_internals) {
# 143 : 255544 : g_signals.m_internals->Unregister(callbacks);
# 144 : 255544 : }
# 145 : 255550 : }
# 146 : :
# 147 : : void UnregisterAllValidationInterfaces()
# 148 : 665 : {
# 149 [ + + ]: 665 : if (!g_signals.m_internals) {
# 150 : 2 : return;
# 151 : 2 : }
# 152 : 663 : g_signals.m_internals->Clear();
# 153 : 663 : }
# 154 : :
# 155 : : void CallFunctionInValidationInterfaceQueue(std::function<void()> func)
# 156 : 9745 : {
# 157 : 9745 : g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
# 158 : 9745 : }
# 159 : :
# 160 : : void SyncWithValidationInterfaceQueue()
# 161 : 1994 : {
# 162 : 1994 : AssertLockNotHeld(cs_main);
# 163 : : // Block until the validation queue drains
# 164 : 1994 : std::promise<void> promise;
# 165 : 1994 : CallFunctionInValidationInterfaceQueue([&promise] {
# 166 : 1994 : promise.set_value();
# 167 : 1994 : });
# 168 : 1994 : promise.get_future().wait();
# 169 : 1994 : }
# 170 : :
# 171 : : // Use a macro instead of a function for conditional logging to prevent
# 172 : : // evaluating arguments when logging is not enabled.
# 173 : : //
# 174 : : // NOTE: The lambda captures all local variables by value.
# 175 : : #define ENQUEUE_AND_LOG_EVENT(event, fmt, name, ...) \
# 176 : 159230 : do { \
# 177 : 159230 : auto local_name = (name); \
# 178 : 159230 : LOG_EVENT("Enqueuing " fmt, local_name, __VA_ARGS__); \
# 179 : 159230 : m_internals->m_schedulerClient.AddToProcessQueue([=] { \
# 180 [ + - ][ + - ]: 158604 : LOG_EVENT(fmt, local_name, __VA_ARGS__); \
# [ + - ][ + - ]
# [ + - ][ + - ]
# [ + + ][ + + ]
# 181 : 158604 : event(); \
# 182 : 158604 : }); \
# 183 : 159230 : } while (0)
# 184 : :
# 185 : : #define LOG_EVENT(fmt, ...) \
# 186 : 453713 : LogPrint(BCLog::VALIDATION, fmt "\n", __VA_ARGS__)
# 187 : :
# 188 : 64007 : void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
# 189 : : // Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which
# 190 : : // the chain actually updates. One way to ensure this is for the caller to invoke this signal
# 191 : : // in the same critical section where the chain is updated
# 192 : :
# 193 : 64007 : auto event = [pindexNew, pindexFork, fInitialDownload, this] {
# 194 : 108193 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
# 195 : 64007 : };
# 196 [ + - ][ + + ]: 64007 : ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s fork block hash=%s (in IBD=%s)", __func__,
# 197 : 64007 : pindexNew->GetBlockHash().ToString(),
# 198 : 64007 : pindexFork ? pindexFork->GetBlockHash().ToString() : "null",
# 199 : 64007 : fInitialDownload);
# 200 : 64007 : }
# 201 : :
# 202 : 20131 : void CMainSignals::TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {
# 203 : 20131 : auto event = [tx, mempool_sequence, this] {
# 204 : 40063 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx, mempool_sequence); });
# 205 : 20131 : };
# 206 [ + - ]: 20131 : ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
# 207 : 20131 : tx->GetHash().ToString(),
# 208 : 20131 : tx->GetWitnessHash().ToString());
# 209 : 20131 : }
# 210 : :
# 211 : 635 : void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {
# 212 : 635 : auto event = [tx, reason, mempool_sequence, this] {
# 213 : 994 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(tx, reason, mempool_sequence); });
# 214 : 635 : };
# 215 [ + - ]: 635 : ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
# 216 : 635 : tx->GetHash().ToString(),
# 217 : 635 : tx->GetWitnessHash().ToString());
# 218 : 635 : }
# 219 : :
# 220 : 68162 : void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
# 221 : 68162 : auto event = [pblock, pindex, this] {
# 222 : 113493 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(pblock, pindex); });
# 223 : 68162 : };
# 224 [ + - ]: 68162 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
# 225 : 68162 : pblock->GetHash().ToString(),
# 226 : 68162 : pindex->nHeight);
# 227 : 68162 : }
# 228 : :
# 229 : : void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
# 230 : 4716 : {
# 231 : 4716 : auto event = [pblock, pindex, this] {
# 232 : 6101 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockDisconnected(pblock, pindex); });
# 233 : 4716 : };
# 234 [ + - ]: 4716 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
# 235 : 4716 : pblock->GetHash().ToString(),
# 236 : 4716 : pindex->nHeight);
# 237 : 4716 : }
# 238 : :
# 239 : 1579 : void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
# 240 : 1579 : auto event = [locator, this] {
# 241 : 1406 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(locator); });
# 242 : 953 : };
# 243 [ + - ][ + + ]: 1579 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
# 244 : 1579 : locator.IsNull() ? "null" : locator.vHave.front().ToString());
# 245 : 1579 : }
# 246 : :
# 247 : 76922 : void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
# 248 [ + - ]: 76922 : LOG_EVENT("%s: block hash=%s state=%s", __func__,
# 249 : 76922 : block.GetHash().ToString(), state.ToString());
# 250 : 127061 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); });
# 251 : 76922 : }
# 252 : :
# 253 : 58957 : void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
# 254 [ + - ]: 58957 : LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
# 255 : 107273 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NewPoWValidBlock(pindex, block); });
# 256 : 58957 : }
|