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 : }
|