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