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