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 1252 : 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 1005876 : 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 1252 : explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
44 :
45 251469 : void Register(std::shared_ptr<CValidationInterface> callbacks)
46 : {
47 251469 : LOCK(m_mutex);
48 251469 : auto inserted = m_map.emplace(callbacks.get(), m_list.end());
49 251469 : if (inserted.second) inserted.first->second = m_list.emplace(m_list.end());
50 251469 : inserted.first->second->callbacks = std::move(callbacks);
51 251469 : }
52 :
53 251480 : void Unregister(CValidationInterface* callbacks)
54 : {
55 251480 : LOCK(m_mutex);
56 251480 : auto it = m_map.find(callbacks);
57 251480 : if (it != m_map.end()) {
58 251468 : if (!--it->second->count) m_list.erase(it->second);
59 251468 : m_map.erase(it);
60 251468 : }
61 251480 : }
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 529 : void Clear()
68 : {
69 529 : LOCK(m_mutex);
70 530 : for (const auto& entry : m_map) {
71 1 : if (!--entry.second->count) m_list.erase(entry.second);
72 0 : }
73 529 : m_map.clear();
74 529 : }
75 :
76 220756 : template<typename F> void Iterate(F&& f)
77 : {
78 220756 : WAIT_LOCK(m_mutex, lock);
79 616161 : for (auto it = m_list.begin(); it != m_list.end();) {
80 395405 : ++it->count;
81 : {
82 395405 : REVERSE_LOCK(lock);
83 395405 : f(*it->callbacks);
84 395405 : }
85 395405 : it = --it->count ? std::next(it) : m_list.erase(it);
86 : }
87 220756 : }
88 : };
89 :
90 640 : static CMainSignals g_signals;
91 :
92 626 : void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler)
93 : {
94 626 : assert(!m_internals);
95 626 : m_internals.reset(new MainSignalsInstance(&scheduler));
96 626 : }
97 :
98 628 : void CMainSignals::UnregisterBackgroundSignalScheduler()
99 : {
100 628 : m_internals.reset(nullptr);
101 628 : }
102 :
103 628 : void CMainSignals::FlushBackgroundCallbacks()
104 : {
105 628 : if (m_internals) {
106 626 : m_internals->m_schedulerClient.EmptyQueue();
107 626 : }
108 628 : }
109 :
110 58987 : size_t CMainSignals::CallbacksPending()
111 : {
112 58987 : if (!m_internals) return 0;
113 58987 : return m_internals->m_schedulerClient.CallbacksPending();
114 58987 : }
115 :
116 282123 : CMainSignals& GetMainSignals()
117 : {
118 282123 : return g_signals;
119 : }
120 :
121 251469 : void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
122 : {
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 251469 : g_signals.m_internals->Register(std::move(callbacks));
126 251469 : }
127 :
128 521 : void RegisterValidationInterface(CValidationInterface* callbacks)
129 : {
130 : // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle
131 : // is managed by the caller.
132 1042 : RegisterSharedValidationInterface({callbacks, [](CValidationInterface*){}});
133 521 : }
134 :
135 250947 : void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
136 : {
137 250947 : UnregisterValidationInterface(callbacks.get());
138 250947 : }
139 :
140 251483 : void UnregisterValidationInterface(CValidationInterface* callbacks)
141 : {
142 251483 : if (g_signals.m_internals) {
143 251480 : g_signals.m_internals->Unregister(callbacks);
144 251480 : }
145 251483 : }
146 :
147 531 : void UnregisterAllValidationInterfaces()
148 : {
149 531 : if (!g_signals.m_internals) {
150 : return;
151 : }
152 529 : g_signals.m_internals->Clear();
153 531 : }
154 :
155 9456 : void CallFunctionInValidationInterfaceQueue(std::function<void()> func)
156 : {
157 9456 : g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
158 9456 : }
159 :
160 1726 : void SyncWithValidationInterfaceQueue()
161 : {
162 1726 : AssertLockNotHeld(cs_main);
163 : // Block until the validation queue drains
164 1726 : std::promise<void> promise;
165 3452 : CallFunctionInValidationInterfaceQueue([&promise] {
166 1726 : promise.set_value();
167 1726 : });
168 1726 : promise.get_future().wait();
169 1726 : }
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 : do { \
177 : auto local_name = (name); \
178 : LOG_EVENT("Enqueuing " fmt, local_name, __VA_ARGS__); \
179 : m_internals->m_schedulerClient.AddToProcessQueue([=] { \
180 : LOG_EVENT(fmt, local_name, __VA_ARGS__); \
181 : event(); \
182 : }); \
183 : } while (0)
184 :
185 : #define LOG_EVENT(fmt, ...) \
186 : LogPrint(BCLog::VALIDATION, fmt "\n", __VA_ARGS__)
187 :
188 43834 : 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 87668 : auto event = [pindexNew, pindexFork, fInitialDownload, this] {
194 131152 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
195 43834 : };
196 87668 : ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s fork block hash=%s (in IBD=%s)", __func__,
197 : pindexNew->GetBlockHash().ToString(),
198 : pindexFork ? pindexFork->GetBlockHash().ToString() : "null",
199 : fInitialDownload);
200 43834 : }
201 :
202 18825 : void CMainSignals::TransactionAddedToMempool(const CTransactionRef& tx) {
203 225900 : auto event = [tx, this] {
204 56283 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx); });
205 18825 : };
206 150600 : ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
207 : tx->GetHash().ToString(),
208 : tx->GetWitnessHash().ToString());
209 18825 : }
210 :
211 10515 : void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {
212 126180 : auto event = [tx, reason, this] {
213 11410 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(tx, reason); });
214 10515 : };
215 84120 : ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
216 : tx->GetHash().ToString(),
217 : tx->GetWitnessHash().ToString());
218 10515 : }
219 :
220 46544 : void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
221 558528 : auto event = [pblock, pindex, this] {
222 137533 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(pblock, pindex); });
223 46544 : };
224 372352 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
225 : pblock->GetHash().ToString(),
226 : pindex->nHeight);
227 46544 : }
228 :
229 3284 : void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
230 : {
231 39408 : auto event = [pblock, pindex, this] {
232 8954 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockDisconnected(pblock, pindex); });
233 3284 : };
234 26272 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
235 : pblock->GetHash().ToString(),
236 : pindex->nHeight);
237 3284 : }
238 :
239 1350 : void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
240 15702 : auto event = [locator, this] {
241 1830 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(locator); });
242 852 : };
243 10302 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
244 : locator.IsNull() ? "null" : locator.vHave.front().ToString());
245 1350 : }
246 :
247 59882 : void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
248 59882 : LOG_EVENT("%s: block hash=%s state=%s", __func__,
249 : block.GetHash().ToString(), state.ToString());
250 155652 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); });
251 59882 : }
252 :
253 37020 : void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
254 37020 : LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
255 113347 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NewPoWValidBlock(pindex, block); });
256 37020 : }
|