Bitcoin Core  0.19.99
P2P Digital Currency
validationinterface.cpp
Go to the documentation of this file.
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 #include <boost/signals2/signal.hpp>
20 
22  boost::signals2::scoped_connection UpdatedBlockTip;
23  boost::signals2::scoped_connection TransactionAddedToMempool;
24  boost::signals2::scoped_connection BlockConnected;
25  boost::signals2::scoped_connection BlockDisconnected;
26  boost::signals2::scoped_connection TransactionRemovedFromMempool;
27  boost::signals2::scoped_connection ChainStateFlushed;
28  boost::signals2::scoped_connection BlockChecked;
29  boost::signals2::scoped_connection NewPoWValidBlock;
30 };
31 
33  boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
34  boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
35  boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex)> BlockConnected;
36  boost::signals2::signal<void (const std::shared_ptr<const CBlock>&, const CBlockIndex* pindex)> BlockDisconnected;
37  boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
38  boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
39  boost::signals2::signal<void (const CBlock&, const BlockValidationState&)> BlockChecked;
40  boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
41 
42  // We are not allowed to assume the scheduler only runs in one thread,
43  // but must ensure all callbacks happen in-order, so we end up creating
44  // our own queue here :(
46  std::unordered_map<CValidationInterface*, ValidationInterfaceConnections> m_connMainSignals;
47 
48  explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
49 };
50 
52 
54  assert(!m_internals);
55  m_internals.reset(new MainSignalsInstance(&scheduler));
56 }
57 
59  m_internals.reset(nullptr);
60 }
61 
63  if (m_internals) {
64  m_internals->m_schedulerClient.EmptyQueue();
65  }
66 }
67 
69  if (!m_internals) return 0;
70  return m_internals->m_schedulerClient.CallbacksPending();
71 }
72 
74 {
75  return g_signals;
76 }
77 
79  ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn];
80  conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
81  conns.TransactionAddedToMempool = g_signals.m_internals->TransactionAddedToMempool.connect(std::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, std::placeholders::_1));
82  conns.BlockConnected = g_signals.m_internals->BlockConnected.connect(std::bind(&CValidationInterface::BlockConnected, pwalletIn, std::placeholders::_1, std::placeholders::_2));
83  conns.BlockDisconnected = g_signals.m_internals->BlockDisconnected.connect(std::bind(&CValidationInterface::BlockDisconnected, pwalletIn, std::placeholders::_1, std::placeholders::_2));
84  conns.TransactionRemovedFromMempool = g_signals.m_internals->TransactionRemovedFromMempool.connect(std::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, std::placeholders::_1));
85  conns.ChainStateFlushed = g_signals.m_internals->ChainStateFlushed.connect(std::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, std::placeholders::_1));
86  conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2));
87  conns.NewPoWValidBlock = g_signals.m_internals->NewPoWValidBlock.connect(std::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, std::placeholders::_1, std::placeholders::_2));
88 }
89 
91  if (g_signals.m_internals) {
92  g_signals.m_internals->m_connMainSignals.erase(pwalletIn);
93  }
94 }
95 
97  if (!g_signals.m_internals) {
98  return;
99  }
100  g_signals.m_internals->m_connMainSignals.clear();
101 }
102 
103 void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
104  g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
105 }
106 
109  // Block until the validation queue drains
110  std::promise<void> promise;
112  promise.set_value();
113  });
114  promise.get_future().wait();
115 }
116 
117 // Use a macro instead of a function for conditional logging to prevent
118 // evaluating arguments when logging is not enabled.
119 //
120 // NOTE: The lambda captures all local variables by value.
121 #define ENQUEUE_AND_LOG_EVENT(event, fmt, name, ...) \
122  do { \
123  auto local_name = (name); \
124  LOG_EVENT("Enqueuing " fmt, local_name, __VA_ARGS__); \
125  m_internals->m_schedulerClient.AddToProcessQueue([=] { \
126  LOG_EVENT(fmt, local_name, __VA_ARGS__); \
127  event(); \
128  }); \
129  } while (0)
130 
131 #define LOG_EVENT(fmt, ...) \
132  LogPrint(BCLog::VALIDATION, fmt "\n", __VA_ARGS__)
133 
134 void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
135  // Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which
136  // the chain actually updates. One way to ensure this is for the caller to invoke this signal
137  // in the same critical section where the chain is updated
138 
139  auto event = [pindexNew, pindexFork, fInitialDownload, this] {
140  m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
141  };
142  ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s fork block hash=%s (in IBD=%s)", __func__,
143  pindexNew->GetBlockHash().ToString(),
144  pindexFork ? pindexFork->GetBlockHash().ToString() : "null",
145  fInitialDownload);
146 }
147 
149  auto event = [ptx, this] {
150  m_internals->TransactionAddedToMempool(ptx);
151  };
152  ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
153  ptx->GetHash().ToString(),
154  ptx->GetWitnessHash().ToString());
155 }
156 
158  auto event = [ptx, this] {
159  m_internals->TransactionRemovedFromMempool(ptx);
160  };
161  ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
162  ptx->GetHash().ToString(),
163  ptx->GetWitnessHash().ToString());
164 }
165 
166 void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
167  auto event = [pblock, pindex, this] {
168  m_internals->BlockConnected(pblock, pindex);
169  };
170  ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
171  pblock->GetHash().ToString(),
172  pindex->nHeight);
173 }
174 
175 void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
176 {
177  auto event = [pblock, pindex, this] {
178  m_internals->BlockDisconnected(pblock, pindex);
179  };
180  ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
181  pblock->GetHash().ToString(),
182  pindex->nHeight);
183 }
184 
186  auto event = [locator, this] {
187  m_internals->ChainStateFlushed(locator);
188  };
189  ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
190  locator.IsNull() ? "null" : locator.vHave.front().ToString());
191 }
192 
193 void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
194  LOG_EVENT("%s: block hash=%s state=%s", __func__,
195  block.GetHash().ToString(), state.ToString());
196  m_internals->BlockChecked(block, state);
197 }
198 
199 void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
200  LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
201  m_internals->NewPoWValidBlock(pindex, block);
202 }
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:408
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)
Class used by CScheduler clients which may schedule multiple jobs which are required to be run serial...
Definition: scheduler.h:109
boost::signals2::signal< void(const CTransactionRef &)> TransactionAddedToMempool
std::unique_ptr< MainSignalsInstance > m_internals
virtual void ChainStateFlushed(const CBlockLocator &locator)
Notifies listeners of the new active block chain on-disk.
void SyncWithValidationInterfaceQueue()
This is a synonym for the following, which asserts certain locks are not held: std::promise<void> pro...
Describes a place in the block chain to another node such that if the other node doesn&#39;t have the sam...
Definition: block.h:126
virtual void BlockDisconnected(const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being disconnected.
boost::signals2::scoped_connection BlockChecked
void BlockDisconnected(const std::shared_ptr< const CBlock > &, const CBlockIndex *pindex)
Definition: block.h:72
boost::signals2::signal< void(const CBlock &, const BlockValidationState &)> BlockChecked
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr< const CBlock > &block)
Notifies listeners that a block which builds directly on our current tip has been received and connec...
void UnregisterBackgroundSignalScheduler()
Unregister a CScheduler to give callbacks which should run in the background - these callbacks will n...
void TransactionRemovedFromMempool(const CTransactionRef &)
void UnregisterAllValidationInterfaces()
Unregister all wallets from core.
bool IsNull() const
Definition: block.h:149
void UnregisterValidationInterface(CValidationInterface *pwalletIn)
Unregister a wallet from core.
boost::signals2::scoped_connection NewPoWValidBlock
boost::signals2::scoped_connection BlockDisconnected
virtual void BlockChecked(const CBlock &, const BlockValidationState &)
Notifies listeners of a block validation result.
Implement this to subscribe to events generated in validation.
virtual void BlockConnected(const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being connected.
uint256 GetBlockHash() const
Definition: chain.h:233
static CMainSignals g_signals
boost::signals2::scoped_connection UpdatedBlockTip
#define LOG_EVENT(fmt,...)
std::unordered_map< CValidationInterface *, ValidationInterfaceConnections > m_connMainSignals
boost::signals2::scoped_connection ChainStateFlushed
std::string ToString() const
Definition: validation.h:112
SingleThreadedSchedulerClient m_schedulerClient
MainSignalsInstance(CScheduler *pscheduler)
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: validation.cpp:105
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
Notifies listeners when the block chain tip advances.
CMainSignals & GetMainSignals()
void CallFunctionInValidationInterfaceQueue(std::function< void()> func)
Pushes a function to callback onto the notification queue, guaranteeing any callbacks generated prior...
std::string ToString() const
Definition: uint256.cpp:60
std::vector< uint256 > vHave
Definition: block.h:128
void ChainStateFlushed(const CBlockLocator &)
boost::signals2::scoped_connection TransactionAddedToMempool
boost::signals2::scoped_connection TransactionRemovedFromMempool
void RegisterValidationInterface(CValidationInterface *pwalletIn)
Register a wallet to receive updates from core.
uint256 GetHash() const
Definition: block.cpp:11
void RegisterBackgroundSignalScheduler(CScheduler &scheduler)
Register a CScheduler to give callbacks which should run in the background (may only be called once) ...
#define ENQUEUE_AND_LOG_EVENT(event, fmt, name,...)
boost::signals2::scoped_connection BlockConnected
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:137
void FlushBackgroundCallbacks()
Call any remaining callbacks on the calling thread.
virtual void TransactionRemovedFromMempool(const CTransactionRef &ptx)
Notifies listeners of a transaction leaving mempool.
#define AssertLockNotHeld(cs)
Definition: sync.h:74
virtual void TransactionAddedToMempool(const CTransactionRef &ptxn)
Notifies listeners of a transaction having been added to mempool.
boost::signals2::signal< void(const CBlockLocator &)> ChainStateFlushed
boost::signals2::signal< void(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr< const CBlock > &)
void BlockChecked(const CBlock &, const BlockValidationState &)
void BlockConnected(const std::shared_ptr< const CBlock > &, const CBlockIndex *pindex)
boost::signals2::signal< void(const CTransactionRef &)> TransactionRemovedFromMempool
void TransactionAddedToMempool(const CTransactionRef &)