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 6481 : 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 433 : explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
68 : };
69 :
70 : static CMainSignals g_signals;
71 :
72 433 : void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler) {
73 433 : assert(!m_internals);
74 433 : m_internals.reset(new MainSignalsInstance(&scheduler));
75 433 : }
76 :
77 433 : void CMainSignals::UnregisterBackgroundSignalScheduler() {
78 433 : m_internals.reset(nullptr);
79 433 : }
80 :
81 433 : void CMainSignals::FlushBackgroundCallbacks() {
82 433 : if (m_internals) {
83 433 : m_internals->m_schedulerClient.EmptyQueue();
84 : }
85 433 : }
86 :
87 28782 : size_t CMainSignals::CallbacksPending() {
88 28782 : if (!m_internals) return 0;
89 28782 : return m_internals->m_schedulerClient.CallbacksPending();
90 : }
91 :
92 510479 : CMainSignals& GetMainSignals()
93 : {
94 510479 : return g_signals;
95 : }
96 6481 : 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 6481 : ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn.get()];
101 12962 : conns.AcceptedBlockHeader = g_signals.m_internals->AcceptedBlockHeader.connect(std::bind(&CValidationInterface::AcceptedBlockHeader, pwalletIn, std::placeholders::_1));
102 12962 : conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
103 12962 : conns.TransactionAddedToMempool = g_signals.m_internals->TransactionAddedToMempool.connect(std::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, std::placeholders::_1));
104 12962 : conns.BlockConnected = g_signals.m_internals->BlockConnected.connect(std::bind(&CValidationInterface::BlockConnected, pwalletIn, std::placeholders::_1, std::placeholders::_2));
105 12962 : 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 12962 : conns.TransactionRemovedFromMempool = g_signals.m_internals->TransactionRemovedFromMempool.connect(std::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, std::placeholders::_1, std::placeholders::_2));
107 12962 : conns.SetBestChain = g_signals.m_internals->SetBestChain.connect(std::bind(&CValidationInterface::SetBestChain, pwalletIn, std::placeholders::_1));
108 12962 : conns.Broadcast = g_signals.m_internals->Broadcast.connect(std::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, std::placeholders::_1));
109 12962 : conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2));
110 12962 : conns.NotifyMasternodeListChanged = g_signals.m_internals->NotifyMasternodeListChanged.connect(std::bind(&CValidationInterface::NotifyMasternodeListChanged, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
111 6481 : }
112 1650 : void RegisterValidationInterface(CValidationInterface* pwalletIn)
113 : {
114 : // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle
115 : // is managed by the caller.
116 1650 : RegisterSharedValidationInterface({pwalletIn, [](CValidationInterface*) {}});
117 1650 : }
118 :
119 5477 : void UnregisterValidationInterface(CValidationInterface* pwalletIn)
120 : {
121 5477 : if (g_signals.m_internals) {
122 5477 : g_signals.m_internals->m_connMainSignals.erase(pwalletIn);
123 : }
124 5477 : }
125 :
126 4831 : void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> pwalletIn)
127 : {
128 4831 : UnregisterValidationInterface(pwalletIn.get());
129 4831 : }
130 :
131 433 : void UnregisterAllValidationInterfaces()
132 : {
133 433 : if (!g_signals.m_internals) {
134 : return;
135 : }
136 433 : g_signals.m_internals->m_connMainSignals.clear();
137 : }
138 :
139 8721 : void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
140 8721 : g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
141 8721 : }
142 :
143 3465 : void SyncWithValidationInterfaceQueue() {
144 3465 : AssertLockNotHeld(cs_main);
145 : // if queue is empty, do not wait for nothing.s
146 3465 : if (g_signals.CallbacksPending() == 0) return;
147 :
148 : // Block until the validation queue drains
149 2448 : std::promise<void> promise;
150 2448 : CallFunctionInValidationInterfaceQueue([&promise] {
151 2448 : promise.set_value();
152 : });
153 7344 : 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 24511 : void CMainSignals::AcceptedBlockHeader(const CBlockIndex* pindexNew)
174 : {
175 49022 : auto event = [pindexNew, this] {
176 24511 : m_internals->AcceptedBlockHeader(pindexNew);
177 24511 : };
178 91236 : ENQUEUE_AND_LOG_EVENT(event, "%s: new block header=%s", __func__, pindexNew->GetBlockHash().ToString());
179 24511 : }
180 :
181 24761 : 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 49522 : auto event = [pindexNew, pindexFork, fInitialDownload, this] {
187 24761 : m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
188 24761 : };
189 134360 : 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 24761 : }
194 :
195 16157 : void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
196 16157 : auto event = [ptx, this] {
197 16157 : m_internals->TransactionAddedToMempool(ptx);
198 32314 : };
199 80745 : ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__, ptx->GetHash().ToString());
200 16157 : }
201 :
202 3836 : void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& ptx, MemPoolRemovalReason reason) {
203 3836 : auto event = [ptx, reason, this] {
204 3836 : m_internals->TransactionRemovedFromMempool(ptx, reason);
205 7672 : };
206 19126 : ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__, ptx->GetHash().ToString());
207 3836 : }
208 :
209 24852 : void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
210 24852 : auto event = [pblock, pindex, this] {
211 24852 : m_internals->BlockConnected(pblock, pindex);
212 49704 : };
213 117284 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s, block height=%d", __func__,
214 : pblock->GetHash().ToString(), pindex->nHeight);
215 24852 : }
216 :
217 274 : void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock, const uint256& blockHash, int nBlockHeight, int64_t blockTime) {
218 548 : auto event = [pblock, blockHash, nBlockHeight, blockTime, this] {
219 274 : m_internals->BlockDisconnected(pblock, blockHash, nBlockHeight, blockTime);
220 548 : };
221 2178 : ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s, block height=%d, block time=%d", __func__,
222 : blockHash.ToString(), nBlockHeight, blockTime);
223 274 : }
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 353699 : void CMainSignals::Broadcast(CConnman* connman) {
234 353699 : m_internals->Broadcast(connman);
235 353699 : }
236 :
237 35366 : void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) {
238 35366 : m_internals->BlockChecked(block, state);
239 56823 : LOG_EVENT("%s: block hash=%s (state=%s)", __func__,
240 : block.GetHash().ToString(), FormatStateMessage(state));
241 35366 : }
242 :
243 407 : void CMainSignals::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff) {
244 407 : m_internals->NotifyMasternodeListChanged(undo, oldMNList, diff);
245 644 : 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 407 : }
|