Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2014 The Bitcoin Core developers
3 : // Copyright (c) 2017-2021 The PIVX Core developers
4 : // Distributed under the MIT software license, see the accompanying
5 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 :
7 : #include "validationinterface.h"
8 :
9 : #include "chain.h"
10 : #include "consensus/validation.h"
11 : #include "evo/deterministicmns.h"
12 : #include "logging.h"
13 : #include "scheduler.h"
14 : #include "util/validation.h"
15 : #include "validation.h" // cs_main
16 :
17 : #include <future>
18 : #include <list>
19 : #include <unordered_map>
20 : #include <boost/signals2/signal.hpp>
21 :
22 5461 : struct ValidationInterfaceConnections {
23 : boost::signals2::scoped_connection AcceptedBlockHeader;
24 : boost::signals2::scoped_connection UpdatedBlockTip;
25 : boost::signals2::scoped_connection TransactionAddedToMempool;
26 : boost::signals2::scoped_connection BlockConnected;
27 : boost::signals2::scoped_connection BlockDisconnected;
28 : boost::signals2::scoped_connection TransactionRemovedFromMempool;
29 : boost::signals2::scoped_connection SetBestChain;
30 : boost::signals2::scoped_connection Broadcast;
31 : boost::signals2::scoped_connection BlockChecked;
32 : boost::signals2::scoped_connection NotifyMasternodeListChanged;
33 : };
34 :
35 : struct MainSignalsInstance {
36 : /** Notifies listeners of accepted block header */
37 : boost::signals2::signal<void(const CBlockIndex*)> AcceptedBlockHeader;
38 : /** Notifies listeners of updated block chain tip */
39 : boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
40 : /** Notifies listeners of a transaction having been added to mempool. */
41 : boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
42 : /**
43 : * Notifies listeners of a block being connected.
44 : * Provides a vector of transactions evicted from the mempool as a result.
45 : */
46 : boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex)> BlockConnected;
47 : /** Notifies listeners of a block being disconnected */
48 : boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const uint256& blockHash, int nBlockHeight, int64_t blockTime)> BlockDisconnected;
49 : /** Notifies listeners of a transaction removal from the mempool */
50 : boost::signals2::signal<void (const CTransactionRef &, MemPoolRemovalReason reason)> TransactionRemovedFromMempool;
51 : /** Notifies listeners of a new active block chain. */
52 : boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
53 : /** Tells listeners to broadcast their data. */
54 : boost::signals2::signal<void (CConnman* connman)> Broadcast;
55 : /** Notifies listeners of a block validation result */
56 : boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
57 : /** Notifies listeners of updated deterministic masternode list */
58 : boost::signals2::signal<void (bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff)> NotifyMasternodeListChanged;
59 :
60 : std::unordered_map<CValidationInterface*, ValidationInterfaceConnections> m_connMainSignals;
61 :
62 : // We are not allowed to assume the scheduler only runs in one thread,
63 : // but must ensure all callbacks happen in-order, so we end up creating
64 : // our own queue here :(
65 : SingleThreadedSchedulerClient m_schedulerClient;
66 :
67 494 : explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
68 : };
69 :
70 : static CMainSignals g_signals;
71 :
72 494 : void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler) {
73 494 : assert(!m_internals);
74 494 : m_internals.reset(new MainSignalsInstance(&scheduler));
75 494 : }
76 :
77 496 : void CMainSignals::UnregisterBackgroundSignalScheduler() {
78 496 : m_internals.reset(nullptr);
79 496 : }
80 :
81 496 : void CMainSignals::FlushBackgroundCallbacks() {
82 496 : if (m_internals) {
83 494 : m_internals->m_schedulerClient.EmptyQueue();
84 : }
85 496 : }
86 :
87 45528 : size_t CMainSignals::CallbacksPending() {
88 45528 : if (!m_internals) return 0;
89 45528 : return m_internals->m_schedulerClient.CallbacksPending();
90 : }
91 :
92 2189752 : CMainSignals& GetMainSignals()
93 : {
94 2189752 : return g_signals;
95 : }
96 5461 : void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> pwalletIn)
97 : {
98 : // Each connection captures pwalletIn to ensure that each callback is
99 : // executed before pwalletIn is destroyed. For more details see bitcoin #18338
100 5461 : ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn.get()];
101 10922 : conns.AcceptedBlockHeader = g_signals.m_internals->AcceptedBlockHeader.connect(std::bind(&CValidationInterface::AcceptedBlockHeader, pwalletIn, std::placeholders::_1));
102 10922 : conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
103 10922 : conns.TransactionAddedToMempool = g_signals.m_internals->TransactionAddedToMempool.connect(std::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, std::placeholders::_1));
104 10922 : conns.BlockConnected = g_signals.m_internals->BlockConnected.connect(std::bind(&CValidationInterface::BlockConnected, pwalletIn, std::placeholders::_1, std::placeholders::_2));
105 10922 : conns.BlockDisconnected = g_signals.m_internals->BlockDisconnected.connect(std::bind(&CValidationInterface::BlockDisconnected, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
106 10922 : conns.TransactionRemovedFromMempool = g_signals.m_internals->TransactionRemovedFromMempool.connect(std::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, std::placeholders::_1, std::placeholders::_2));
107 10922 : conns.SetBestChain = g_signals.m_internals->SetBestChain.connect(std::bind(&CValidationInterface::SetBestChain, pwalletIn, std::placeholders::_1));
108 10922 : conns.Broadcast = g_signals.m_internals->Broadcast.connect(std::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, std::placeholders::_1));
109 10922 : conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2));
110 10922 : conns.NotifyMasternodeListChanged = g_signals.m_internals->NotifyMasternodeListChanged.connect(std::bind(&CValidationInterface::NotifyMasternodeListChanged, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
111 5461 : }
112 1994 : void RegisterValidationInterface(CValidationInterface* pwalletIn)
113 : {
114 : // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle
115 : // is managed by the caller.
116 1994 : RegisterSharedValidationInterface({pwalletIn, [](CValidationInterface*) {}});
117 1994 : }
118 :
119 4271 : void UnregisterValidationInterface(CValidationInterface* pwalletIn)
120 : {
121 4271 : if (g_signals.m_internals) {
122 4271 : g_signals.m_internals->m_connMainSignals.erase(pwalletIn);
123 : }
124 4271 : }
125 :
126 3467 : void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> pwalletIn)
127 : {
128 3467 : UnregisterValidationInterface(pwalletIn.get());
129 3467 : }
130 :
131 496 : void UnregisterAllValidationInterfaces()
132 : {
133 496 : if (!g_signals.m_internals) {
134 : return;
135 : }
136 494 : g_signals.m_internals->m_connMainSignals.clear();
137 : }
138 :
139 109876 : void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
140 109876 : g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
141 109876 : }
142 :
143 3533 : void SyncWithValidationInterfaceQueue() {
144 3533 : AssertLockNotHeld(cs_main);
145 : // if queue is empty, do not wait for nothing.s
146 3533 : if (g_signals.CallbacksPending() == 0) return;
147 :
148 : // Block until the validation queue drains
149 1268 : std::promise<void> promise;
150 1268 : CallFunctionInValidationInterfaceQueue([&promise] {
151 1268 : promise.set_value();
152 : });
153 3804 : promise.get_future().wait();
154 : }
155 :
156 : // Use a macro instead of a function for conditional logging to prevent
157 : // evaluating arguments when logging is not enabled.
158 : //
159 : // NOTE: The lambda captures all local variables by value.
160 : #define ENQUEUE_AND_LOG_EVENT(event, fmt, name, ...) \
161 : do { \
162 : auto local_name = (name); \
163 : LOG_EVENT("Enqueuing " fmt, local_name, __VA_ARGS__); \
164 : m_internals->m_schedulerClient.AddToProcessQueue([=] { \
165 : LOG_EVENT(fmt, local_name, __VA_ARGS__); \
166 : event(); \
167 : }); \
168 : } while (0)
169 :
170 : #define LOG_EVENT(fmt, ...) \
171 : LogPrint(BCLog::VALIDATION, fmt "\n", __VA_ARGS__)
172 :
173 41186 : void CMainSignals::AcceptedBlockHeader(const CBlockIndex* pindexNew)
174 : {
175 82372 : auto event = [pindexNew, this] {
176 41186 : m_internals->AcceptedBlockHeader(pindexNew);
177 41186 : };
178 157932 : ENQUEUE_AND_LOG_EVENT(event, "%s: new block header=%s", __func__, pindexNew->GetBlockHash().ToString());
179 41186 : }
180 :
181 41471 : void CMainSignals::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) {
182 : // Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which
183 : // the chain actually updates. One way to ensure this is for the caller to invoke this signal
184 : // in the same critical section where the chain is updated
185 :
186 82942 : auto event = [pindexNew, pindexFork, fInitialDownload, this] {
187 41471 : m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
188 41471 : };
189 234510 : ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s, fork block hash=%s (in IBD=%s)", __func__,
190 : pindexNew->GetBlockHash().ToString(),
191 : pindexFork ? pindexFork->GetBlockHash().ToString() : "null",
192 : fInitialDownload);
193 41471 : }
194 :
195 171129 : void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
196 171129 : auto event = [ptx, this] {
197 171129 : m_internals->TransactionAddedToMempool(ptx);
198 342258 : };
199 855605 : ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__, ptx->GetHash().ToString());
200 171129 : }
201 :
202 1432 : void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& ptx, MemPoolRemovalReason reason) {
203 1432 : auto event = [ptx, reason, this] {
204 1432 : m_internals->TransactionRemovedFromMempool(ptx, reason);
205 2864 : };
206 7106 : ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__, ptx->GetHash().ToString());
207 1432 : }
208 :
209 41568 : void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
210 41568 : auto event = [pblock, pindex, this] {
211 41568 : m_internals->BlockConnected(pblock, pindex);
212 83136 : };
213 200864 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s, block height=%d", __func__,
214 : pblock->GetHash().ToString(), pindex->nHeight);
215 41568 : }
216 :
217 329 : void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock, const uint256& blockHash, int nBlockHeight, int64_t blockTime) {
218 658 : auto event = [pblock, blockHash, nBlockHeight, blockTime, this] {
219 329 : m_internals->BlockDisconnected(pblock, blockHash, nBlockHeight, blockTime);
220 658 : };
221 2618 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s, block height=%d, block time=%d", __func__,
222 : blockHash.ToString(), nBlockHeight, blockTime);
223 329 : }
224 :
225 0 : void CMainSignals::SetBestChain(const CBlockLocator& locator) {
226 0 : auto event = [locator, this] {
227 0 : m_internals->SetBestChain(locator);
228 0 : };
229 0 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
230 : locator.IsNull() ? "null" : locator.vHave.front().ToString());
231 0 : }
232 :
233 1789460 : void CMainSignals::Broadcast(CConnman* connman) {
234 1789460 : m_internals->Broadcast(connman);
235 1789460 : }
236 :
237 52445 : void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) {
238 52445 : m_internals->BlockChecked(block, state);
239 90633 : LOG_EVENT("%s: block hash=%s (state=%s)", __func__,
240 : block.GetHash().ToString(), FormatStateMessage(state));
241 52445 : }
242 :
243 7251 : void CMainSignals::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff) {
244 7251 : m_internals->NotifyMasternodeListChanged(undo, oldMNList, diff);
245 14332 : LOG_EVENT("%s: (undo=%d) old list for=%s, added=%d, updated=%d, removed=%d", __func__,
246 : undo,
247 : oldMNList.GetBlockHash().ToString(),
248 : diff.addedMNs.size(),
249 : diff.updatedMNs.size(),
250 : diff.removedMns.size());
251 7251 : }
|