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 <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 1 : explicit MainSignalsImpl(CScheduler& scheduler LIFETIMEBOUND) : m_schedulerClient(scheduler) {}
49 :
50 7872 : void Register(std::shared_ptr<CValidationInterface> callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
51 : {
52 7872 : LOCK(m_mutex);
53 7872 : auto inserted = m_map.emplace(callbacks.get(), m_list.end());
54 7872 : if (inserted.second) inserted.first->second = m_list.emplace(m_list.end());
55 7872 : inserted.first->second->callbacks = std::move(callbacks);
56 7872 : }
57 :
58 7872 : void Unregister(CValidationInterface* callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
59 : {
60 7872 : LOCK(m_mutex);
61 7872 : auto it = m_map.find(callbacks);
62 7872 : if (it != m_map.end()) {
63 7872 : if (!--it->second->count) m_list.erase(it->second);
64 7872 : m_map.erase(it);
65 7872 : }
66 7872 : }
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 0 : void Clear() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
73 : {
74 2 : LOCK(m_mutex);
75 0 : for (const auto& entry : m_map) {
76 0 : if (!--entry.second->count) m_list.erase(entry.second);
77 : }
78 0 : m_map.clear();
79 0 : }
80 :
81 3108 : template<typename F> void Iterate(F&& f) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
82 : {
83 3108 : WAIT_LOCK(m_mutex, lock);
84 6158 : for (auto it = m_list.begin(); it != m_list.end();) {
85 3050 : ++it->count;
86 : {
87 3050 : REVERSE_LOCK(lock);
88 3050 : f(*it->callbacks);
89 3050 : }
90 3050 : it = --it->count ? std::next(it) : m_list.erase(it);
91 : }
92 3108 : }
93 : };
94 :
95 : static CMainSignals g_signals;
96 :
97 1 : void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler)
98 : {
99 1 : assert(!m_internals);
100 1 : m_internals = std::make_unique<MainSignalsImpl>(scheduler);
101 1 : }
102 :
103 1 : void CMainSignals::UnregisterBackgroundSignalScheduler()
104 : {
105 1 : m_internals.reset(nullptr);
106 1 : }
107 :
108 1 : void CMainSignals::FlushBackgroundCallbacks()
109 : {
110 1 : if (m_internals) {
111 1 : m_internals->m_schedulerClient.EmptyQueue();
112 1 : }
113 1 : }
114 :
115 201 : size_t CMainSignals::CallbacksPending()
116 : {
117 201 : if (!m_internals) return 0;
118 201 : return m_internals->m_schedulerClient.CallbacksPending();
119 201 : }
120 :
121 3312 : CMainSignals& GetMainSignals()
122 : {
123 3312 : return g_signals;
124 : }
125 :
126 7872 : 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 7872 : g_signals.m_internals->Register(std::move(callbacks));
131 7872 : }
132 :
133 200 : void RegisterValidationInterface(CValidationInterface* callbacks)
134 : {
135 : // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle
136 : // is managed by the caller.
137 400 : RegisterSharedValidationInterface({callbacks, [](CValidationInterface*){}});
138 200 : }
139 :
140 7672 : void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
141 : {
142 7672 : UnregisterValidationInterface(callbacks.get());
143 7672 : }
144 :
145 7872 : void UnregisterValidationInterface(CValidationInterface* callbacks)
146 : {
147 7872 : if (g_signals.m_internals) {
148 7872 : g_signals.m_internals->Unregister(callbacks);
149 7872 : }
150 7872 : }
151 :
152 0 : void UnregisterAllValidationInterfaces()
153 : {
154 0 : if (!g_signals.m_internals) {
155 0 : return;
156 : }
157 0 : g_signals.m_internals->Clear();
158 0 : }
159 :
160 12732 : void CallFunctionInValidationInterfaceQueue(std::function<void()> func)
161 : {
162 12732 : g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
163 12732 : }
164 :
165 12732 : void SyncWithValidationInterfaceQueue()
166 : {
167 12732 : AssertLockNotHeld(cs_main);
168 : // Block until the validation queue drains
169 12732 : std::promise<void> promise;
170 25464 : CallFunctionInValidationInterfaceQueue([&promise] {
171 12732 : promise.set_value();
172 12732 : });
173 12732 : promise.get_future().wait();
174 12732 : }
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 201 : 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 402 : auto event = [pindexNew, pindexFork, fInitialDownload, this] {
199 369 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
200 201 : };
201 402 : 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 201 : }
206 :
207 2196 : void CMainSignals::TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {
208 4392 : auto event = [tx, mempool_sequence, this] {
209 4392 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx, mempool_sequence); });
210 2196 : };
211 4392 : ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
212 : tx->GetHash().ToString(),
213 : tx->GetWitnessHash().ToString());
214 2196 : }
215 :
216 309 : void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {
217 618 : auto event = [tx, reason, mempool_sequence, this] {
218 618 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(tx, reason, mempool_sequence); });
219 309 : };
220 618 : ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s reason=%s", __func__,
221 : tx->GetHash().ToString(),
222 : tx->GetWitnessHash().ToString(),
223 : RemovalReasonToString(reason));
224 309 : }
225 :
226 201 : void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
227 402 : auto event = [pblock, pindex, this] {
228 378 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(pblock, pindex); });
229 201 : };
230 402 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
231 : pblock->GetHash().ToString(),
232 : pindex->nHeight);
233 201 : }
234 :
235 0 : void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
236 : {
237 0 : auto event = [pblock, pindex, this] {
238 0 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockDisconnected(pblock, pindex); });
239 0 : };
240 0 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
241 : pblock->GetHash().ToString(),
242 : pindex->nHeight);
243 0 : }
244 :
245 0 : void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
246 0 : auto event = [locator, this] {
247 0 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(locator); });
248 0 : };
249 0 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
250 : locator.IsNull() ? "null" : locator.vHave.front().ToString());
251 0 : }
252 :
253 201 : void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
254 201 : LOG_EVENT("%s: block hash=%s state=%s", __func__,
255 : block.GetHash().ToString(), state.ToString());
256 401 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); });
257 201 : }
258 :
259 0 : void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
260 0 : LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
261 0 : m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NewPoWValidBlock(pindex, block); });
262 0 : }
|