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