Bitcoin Core  21.99.0
P2P Digital Currency
clientmodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2020 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <qt/clientmodel.h>
6 
7 #include <qt/bantablemodel.h>
8 #include <qt/guiconstants.h>
9 #include <qt/guiutil.h>
10 #include <qt/peertablemodel.h>
11 
12 #include <clientversion.h>
13 #include <interfaces/handler.h>
14 #include <interfaces/node.h>
15 #include <net.h>
16 #include <netbase.h>
17 #include <util/system.h>
18 #include <util/threadnames.h>
19 #include <validation.h>
20 
21 #include <stdint.h>
22 #include <functional>
23 
24 #include <QDebug>
25 #include <QThread>
26 #include <QTimer>
27 
30 
31 ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QObject *parent) :
32  QObject(parent),
33  m_node(node),
34  optionsModel(_optionsModel),
35  peerTableModel(nullptr),
36  banTableModel(nullptr),
37  m_thread(new QThread(this))
38 {
42  banTableModel = new BanTableModel(m_node, this);
43 
44  QTimer* timer = new QTimer;
45  timer->setInterval(MODEL_UPDATE_DELAY);
46  connect(timer, &QTimer::timeout, [this] {
47  // no locking required at this point
48  // the following calls will acquire the required lock
51  });
52  connect(m_thread, &QThread::finished, timer, &QObject::deleteLater);
53  connect(m_thread, &QThread::started, [timer] { timer->start(); });
54  // move timer to thread so that polling doesn't disturb main event loop
55  timer->moveToThread(m_thread);
56  m_thread->start();
57  QTimer::singleShot(0, timer, []() {
58  util::ThreadRename("qt-clientmodl");
59  });
60 
62 }
63 
65 {
67 
68  m_thread->quit();
69  m_thread->wait();
70 }
71 
72 int ClientModel::getNumConnections(unsigned int flags) const
73 {
75 
76  if(flags == CONNECTIONS_IN)
77  connections = ConnectionDirection::In;
78  else if (flags == CONNECTIONS_OUT)
79  connections = ConnectionDirection::Out;
80  else if (flags == CONNECTIONS_ALL)
81  connections = ConnectionDirection::Both;
82 
83  return m_node.getNodeCount(connections);
84 }
85 
87 {
88  if (cachedBestHeaderHeight == -1) {
89  // make sure we initially populate the cache via a cs_main lock
90  // otherwise we need to wait for a tip update
91  int height;
92  int64_t blockTime;
93  if (m_node.getHeaderTip(height, blockTime)) {
94  cachedBestHeaderHeight = height;
95  cachedBestHeaderTime = blockTime;
96  }
97  }
99 }
100 
102 {
103  if (cachedBestHeaderTime == -1) {
104  int height;
105  int64_t blockTime;
106  if (m_node.getHeaderTip(height, blockTime)) {
107  cachedBestHeaderHeight = height;
108  cachedBestHeaderTime = blockTime;
109  }
110  }
111  return cachedBestHeaderTime;
112 }
113 
115 {
116  if (m_cached_num_blocks == -1) {
118  }
119  return m_cached_num_blocks;
120 }
121 
123 {
124  uint256 tip{WITH_LOCK(m_cached_tip_mutex, return m_cached_tip_blocks)};
125 
126  if (!tip.IsNull()) {
127  return tip;
128  }
129 
130  // Lock order must be: first `cs_main`, then `m_cached_tip_mutex`.
131  // The following will lock `cs_main` (and release it), so we must not
132  // own `m_cached_tip_mutex` here.
133  tip = m_node.getBestBlockHash();
134 
136  // We checked that `m_cached_tip_blocks` is not null above, but then we
137  // released the mutex `m_cached_tip_mutex`, so it could have changed in the
138  // meantime. Thus, check again.
139  if (m_cached_tip_blocks.IsNull()) {
140  m_cached_tip_blocks = tip;
141  }
142  return m_cached_tip_blocks;
143 }
144 
145 void ClientModel::updateNumConnections(int numConnections)
146 {
147  Q_EMIT numConnectionsChanged(numConnections);
148 }
149 
150 void ClientModel::updateNetworkActive(bool networkActive)
151 {
152  Q_EMIT networkActiveChanged(networkActive);
153 }
154 
156 {
158 }
159 
161 {
162  if (m_node.getReindex())
163  return BlockSource::REINDEX;
164  else if (m_node.getImporting())
165  return BlockSource::DISK;
166  else if (getNumConnections() > 0)
167  return BlockSource::NETWORK;
168 
169  return BlockSource::NONE;
170 }
171 
173 {
174  return QString::fromStdString(m_node.getWarnings().translated);
175 }
176 
178 {
179  return optionsModel;
180 }
181 
183 {
184  return peerTableModel;
185 }
186 
188 {
189  return banTableModel;
190 }
191 
193 {
194  return QString::fromStdString(FormatFullVersion());
195 }
196 
198 {
199  return QString::fromStdString(strSubVersion);
200 }
201 
203 {
205 }
206 
208 {
209  return QDateTime::fromTime_t(GetStartupTime()).toString();
210 }
211 
212 QString ClientModel::dataDir() const
213 {
215 }
216 
217 QString ClientModel::blocksDir() const
218 {
220 }
221 
223 {
225 }
226 
227 // Handlers for core signals
228 static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
229 {
230  // emits signal "showProgress"
231  bool invoked = QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
232  Q_ARG(QString, QString::fromStdString(title)),
233  Q_ARG(int, nProgress));
234  assert(invoked);
235 }
236 
237 static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
238 {
239  // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections);
240  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
241  Q_ARG(int, newNumConnections));
242  assert(invoked);
243 }
244 
245 static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkActive)
246 {
247  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNetworkActive", Qt::QueuedConnection,
248  Q_ARG(bool, networkActive));
249  assert(invoked);
250 }
251 
252 static void NotifyAlertChanged(ClientModel *clientmodel)
253 {
254  qDebug() << "NotifyAlertChanged";
255  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
256  assert(invoked);
257 }
258 
259 static void BannedListChanged(ClientModel *clientmodel)
260 {
261  qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__);
262  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
263  assert(invoked);
264 }
265 
266 static void BlockTipChanged(ClientModel* clientmodel, SynchronizationState sync_state, interfaces::BlockTip tip, double verificationProgress, bool fHeader)
267 {
268  if (fHeader) {
269  // cache best headers time and height to reduce future cs_main locks
270  clientmodel->cachedBestHeaderHeight = tip.block_height;
271  clientmodel->cachedBestHeaderTime = tip.block_time;
272  } else {
273  clientmodel->m_cached_num_blocks = tip.block_height;
274  WITH_LOCK(clientmodel->m_cached_tip_mutex, clientmodel->m_cached_tip_blocks = tip.block_hash;);
275  }
276 
277  // Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex.
278  const bool throttle = (sync_state != SynchronizationState::POST_INIT && !fHeader) || sync_state == SynchronizationState::INIT_REINDEX;
279  const int64_t now = throttle ? GetTimeMillis() : 0;
280  int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
281  if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
282  return;
283  }
284 
285  bool invoked = QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
286  Q_ARG(int, tip.block_height),
287  Q_ARG(QDateTime, QDateTime::fromTime_t(tip.block_time)),
288  Q_ARG(double, verificationProgress),
289  Q_ARG(bool, fHeader),
290  Q_ARG(SynchronizationState, sync_state));
291  assert(invoked);
292  nLastUpdateNotification = now;
293 }
294 
296 {
297  // Connect signals to client
298  m_handler_show_progress = m_node.handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
303  m_handler_notify_block_tip = m_node.handleNotifyBlockTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, false));
304  m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, true));
305 }
306 
308 {
309  // Disconnect signals from client
310  m_handler_show_progress->disconnect();
313  m_handler_notify_alert_changed->disconnect();
314  m_handler_banned_list_changed->disconnect();
315  m_handler_notify_block_tip->disconnect();
316  m_handler_notify_header_tip->disconnect();
317 }
318 
319 bool ClientModel::getProxyInfo(std::string& ip_port) const
320 {
321  proxyType ipv4, ipv6;
322  if (m_node.getProxy((Network) 1, ipv4) && m_node.getProxy((Network) 2, ipv6)) {
323  ip_port = ipv4.proxy.ToStringIPPort();
324  return true;
325  }
326  return false;
327 }
ClientModel::alertsChanged
void alertsChanged(const QString &warnings)
interfaces::BlockTip::block_hash
uint256 block_hash
Definition: node.h:235
ClientModel::subscribeToCoreSignals
void subscribeToCoreSignals()
Definition: clientmodel.cpp:295
interfaces::Node::handleShowProgress
virtual std::unique_ptr< Handler > handleShowProgress(ShowProgressFn fn)=0
CONNECTIONS_IN
@ CONNECTIONS_IN
Definition: clientmodel.h:40
GUIUtil::boostPathToQString
QString boostPathToQString(const fs::path &path)
Convert OS specific boost path to QString through UTF-8.
Definition: guiutil.cpp:645
ClientModel::m_handler_notify_alert_changed
std::unique_ptr< interfaces::Handler > m_handler_notify_alert_changed
Definition: clientmodel.h:93
interfaces::Node::getNumBlocks
virtual int getNumBlocks()=0
Get num blocks.
GetDataDir
const fs::path & GetDataDir(bool fNetSpecific)
Definition: system.cpp:770
ClientModel::numConnectionsChanged
void numConnectionsChanged(int count)
CONNECTIONS_OUT
@ CONNECTIONS_OUT
Definition: clientmodel.h:41
ClientModel::mempoolSizeChanged
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes)
ConnectionDirection::Out
@ Out
interfaces::Node::getProxy
virtual bool getProxy(Network net, proxyType &proxy_info)=0
Get proxy.
NotifyAlertChanged
static void NotifyAlertChanged(ClientModel *clientmodel)
Definition: clientmodel.cpp:252
interfaces::Node::handleNotifyNetworkActiveChanged
virtual std::unique_ptr< Handler > handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn)=0
ClientModel::getNumConnections
int getNumConnections(unsigned int flags=CONNECTIONS_ALL) const
Return number of connections, default is in- and outbound (total)
Definition: clientmodel.cpp:72
flags
int flags
Definition: bitcoin-tx.cpp:512
ClientModel::isReleaseVersion
bool isReleaseVersion() const
Definition: clientmodel.cpp:202
ShowProgress
static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
Definition: clientmodel.cpp:228
interfaces::Node::handleNotifyHeaderTip
virtual std::unique_ptr< Handler > handleNotifyHeaderTip(NotifyHeaderTipFn fn)=0
CLIENT_VERSION_IS_RELEASE
#define CLIENT_VERSION_IS_RELEASE
Definition: bitcoin-config.h:18
interfaces::Node::handleNotifyBlockTip
virtual std::unique_ptr< Handler > handleNotifyBlockTip(NotifyBlockTipFn fn)=0
interfaces::Node::getReindex
virtual bool getReindex()=0
Get reindex.
ConnectionDirection::Both
@ Both
ClientModel::getBlockSource
enum BlockSource getBlockSource() const
Returns enum BlockSource of the current importing/syncing state.
Definition: clientmodel.cpp:160
handler.h
GetStartupTime
int64_t GetStartupTime()
Definition: system.cpp:1354
ClientModel::blocksDir
QString blocksDir() const
Definition: clientmodel.cpp:217
ClientModel::m_handler_notify_num_connections_changed
std::unique_ptr< interfaces::Handler > m_handler_notify_num_connections_changed
Definition: clientmodel.h:91
BlockSource::DISK
@ DISK
WITH_LOCK
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:276
interfaces::Node::handleNotifyAlertChanged
virtual std::unique_ptr< Handler > handleNotifyAlertChanged(NotifyAlertChangedFn fn)=0
clientversion.h
interfaces::Node::getNodeCount
virtual size_t getNodeCount(ConnectionDirection flags)=0
Get number of connections.
CONNECTIONS_ALL
@ CONNECTIONS_ALL
Definition: clientmodel.h:42
ClientModel::getStatusBarWarnings
QString getStatusBarWarnings() const
Return warnings to be displayed in status bar.
Definition: clientmodel.cpp:172
Network
Network
A network type.
Definition: netaddress.h:43
BanTableModel
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call.
Definition: bantablemodel.h:42
ClientModel::banTableModel
BanTableModel * banTableModel
Definition: clientmodel.h:99
interfaces::Node::handleBannedListChanged
virtual std::unique_ptr< Handler > handleBannedListChanged(BannedListChangedFn fn)=0
proxyType
Definition: netbase.h:48
CService::ToStringIPPort
std::string ToStringIPPort() const
Definition: netaddress.cpp:1019
ClientModel::updateNetworkActive
void updateNetworkActive(bool networkActive)
Definition: clientmodel.cpp:150
ClientModel::m_handler_notify_block_tip
std::unique_ptr< interfaces::Handler > m_handler_notify_block_tip
Definition: clientmodel.h:95
interfaces::BlockTip::block_time
int64_t block_time
Definition: node.h:234
nLastHeaderTipUpdateNotification
static int64_t nLastHeaderTipUpdateNotification
Definition: clientmodel.cpp:28
OptionsModel
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:39
ClientModel::getOptionsModel
OptionsModel * getOptionsModel()
Definition: clientmodel.cpp:177
ConnectionDirection::In
@ In
interfaces::Node::getHeaderTip
virtual bool getHeaderTip(int &height, int64_t &block_time)=0
Get header tip height and time.
ClientModel::unsubscribeFromCoreSignals
void unsubscribeFromCoreSignals()
Definition: clientmodel.cpp:307
ClientModel::m_handler_notify_network_active_changed
std::unique_ptr< interfaces::Handler > m_handler_notify_network_active_changed
Definition: clientmodel.h:92
ClientModel::getPeerTableModel
PeerTableModel * getPeerTableModel()
Definition: clientmodel.cpp:182
BlockSource::REINDEX
@ REINDEX
interfaces::BlockTip::block_height
int block_height
Definition: node.h:233
ClientModel::getHeaderTipHeight
int getHeaderTipHeight() const
Definition: clientmodel.cpp:86
ClientModel::getProxyInfo
bool getProxyInfo(std::string &ip_port) const
Definition: clientmodel.cpp:319
node.h
ClientModel::bytesChanged
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut)
util::ThreadRename
void ThreadRename(std::string &&)
Rename a thread both in terms of an internal (in-memory) name as well as its system thread name.
Definition: threadnames.cpp:57
BlockSource::NETWORK
@ NETWORK
ClientModel::ClientModel
ClientModel(interfaces::Node &node, OptionsModel *optionsModel, QObject *parent=nullptr)
Definition: clientmodel.cpp:31
BannedListChanged
static void BannedListChanged(ClientModel *clientmodel)
Definition: clientmodel.cpp:259
SynchronizationState::INIT_REINDEX
@ INIT_REINDEX
ClientModel::getNumBlocks
int getNumBlocks() const
Definition: clientmodel.cpp:114
guiutil.h
ClientModel::formatFullVersion
QString formatFullVersion() const
Definition: clientmodel.cpp:192
ClientModel::cachedBestHeaderTime
std::atomic< int64_t > cachedBestHeaderTime
Definition: clientmodel.h:82
interfaces::Node::handleNotifyNumConnectionsChanged
virtual std::unique_ptr< Handler > handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn)=0
bilingual_str::translated
std::string translated
Definition: translation.h:18
m_node
NodeContext & m_node
Definition: interfaces.cpp:712
uint256
256-bit opaque blob.
Definition: uint256.h:124
ClientModel::peerTableModel
PeerTableModel * peerTableModel
Definition: clientmodel.h:98
ClientModel::optionsModel
OptionsModel * optionsModel
Definition: clientmodel.h:97
BlockSource::NONE
@ NONE
ClientModel::m_node
interfaces::Node & m_node
Definition: clientmodel.h:86
PeerTableModel
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call.
Definition: peertablemodel.h:49
ClientModel::updateNumConnections
void updateNumConnections(int numConnections)
Definition: clientmodel.cpp:145
interfaces::Node
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:53
ClientModel::updateBanlist
void updateBanlist()
Definition: clientmodel.cpp:222
system.h
ClientModel
Model for Bitcoin network client.
Definition: clientmodel.h:46
BlockTipChanged
static void BlockTipChanged(ClientModel *clientmodel, SynchronizationState sync_state, interfaces::BlockTip tip, double verificationProgress, bool fHeader)
Definition: clientmodel.cpp:266
strSubVersion
std::string strSubVersion
Subversion as sent to the P2P network in version messages.
Definition: net.cpp:110
guiconstants.h
nLastBlockTipUpdateNotification
static int64_t nLastBlockTipUpdateNotification
Definition: clientmodel.cpp:29
ClientModel::formatSubVersion
QString formatSubVersion() const
Definition: clientmodel.cpp:197
ClientModel::m_handler_show_progress
std::unique_ptr< interfaces::Handler > m_handler_show_progress
Definition: clientmodel.h:90
LOCK
#define LOCK(cs)
Definition: sync.h:232
ClientModel::m_handler_notify_header_tip
std::unique_ptr< interfaces::Handler > m_handler_notify_header_tip
Definition: clientmodel.h:96
interfaces::Node::getMempoolDynamicUsage
virtual size_t getMempoolDynamicUsage()=0
Get mempool dynamic usage.
ClientModel::cachedBestHeaderHeight
std::atomic< int > cachedBestHeaderHeight
Definition: clientmodel.h:81
ClientModel::formatClientStartupTime
QString formatClientStartupTime() const
Definition: clientmodel.cpp:207
NotifyNumConnectionsChanged
static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
Definition: clientmodel.cpp:237
ClientModel::~ClientModel
~ClientModel()
Definition: clientmodel.cpp:64
ClientModel::m_cached_num_blocks
std::atomic< int > m_cached_num_blocks
Definition: clientmodel.h:83
interfaces::Node::getWarnings
virtual bilingual_str getWarnings()=0
Get warnings.
GetBlocksDir
const fs::path & GetBlocksDir()
Definition: system.cpp:744
ClientModel::dataDir
QString dataDir() const
Definition: clientmodel.cpp:212
node
Definition: interfaces.cpp:66
SynchronizationState
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:104
bantablemodel.h
netbase.h
interfaces::Node::getImporting
virtual bool getImporting()=0
Get importing.
BlockSource
BlockSource
Definition: clientmodel.h:31
FormatFullVersion
std::string FormatFullVersion()
Definition: clientversion.cpp:50
ConnectionDirection::None
@ None
ConnectionDirection
ConnectionDirection
Definition: netbase.h:32
peertablemodel.h
interfaces::Node::getTotalBytesRecv
virtual int64_t getTotalBytesRecv()=0
Get total bytes recv.
net.h
interfaces::Node::getBestBlockHash
virtual uint256 getBestBlockHash()=0
Get best block hash.
interfaces::Node::getMempoolSize
virtual size_t getMempoolSize()=0
Get mempool size.
ClientModel::m_thread
QThread *const m_thread
A thread to interact with m_node asynchronously.
Definition: clientmodel.h:102
ClientModel::getBestBlockHash
uint256 getBestBlockHash()
Definition: clientmodel.cpp:122
threadnames.h
ClientModel::m_cached_tip_mutex
Mutex m_cached_tip_mutex
Definition: clientmodel.h:85
ClientModel::m_handler_banned_list_changed
std::unique_ptr< interfaces::Handler > m_handler_banned_list_changed
Definition: clientmodel.h:94
assert
assert(std::addressof(::ChainstateActive().CoinsTip())==std::addressof(coins_cache))
NotifyNetworkActiveChanged
static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkActive)
Definition: clientmodel.cpp:245
interfaces::BlockTip
Block tip (could be a header or not, depends on the subscribed signal).
Definition: node.h:232
interfaces::Node::getTotalBytesSent
virtual int64_t getTotalBytesSent()=0
Get total bytes sent.
BanTableModel::refresh
void refresh()
Definition: bantablemodel.cpp:166
GetTimeMillis
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: time.cpp:117
SynchronizationState::POST_INIT
@ POST_INIT
ClientModel::networkActiveChanged
void networkActiveChanged(bool networkActive)
clientmodel.h
ClientModel::updateAlert
void updateAlert()
Definition: clientmodel.cpp:155
proxyType::proxy
CService proxy
Definition: netbase.h:56
MODEL_UPDATE_DELAY
static const int MODEL_UPDATE_DELAY
Definition: guiconstants.h:11
ClientModel::getHeaderTipTime
int64_t getHeaderTipTime() const
Definition: clientmodel.cpp:101
ClientModel::getBanTableModel
BanTableModel * getBanTableModel()
Definition: clientmodel.cpp:187