Bitcoin Core  0.19.99
P2P Digital Currency
clientmodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2019 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 
19 #include <stdint.h>
20 
21 #include <QDebug>
22 #include <QThread>
23 #include <QTimer>
24 
27 
28 ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QObject *parent) :
29  QObject(parent),
30  m_node(node),
31  optionsModel(_optionsModel),
32  peerTableModel(nullptr),
33  banTableModel(nullptr),
34  m_thread(new QThread(this))
35 {
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
48  });
49  connect(m_thread, &QThread::finished, timer, &QObject::deleteLater);
50  connect(m_thread, &QThread::started, [timer] { timer->start(); });
51  // move timer to thread so that polling doesn't disturb main event loop
52  timer->moveToThread(m_thread);
53  m_thread->start();
54 
56 }
57 
59 {
61 
62  m_thread->quit();
63  m_thread->wait();
64 }
65 
66 int ClientModel::getNumConnections(unsigned int flags) const
67 {
69 
70  if(flags == CONNECTIONS_IN)
71  connections = CConnman::CONNECTIONS_IN;
72  else if (flags == CONNECTIONS_OUT)
73  connections = CConnman::CONNECTIONS_OUT;
74  else if (flags == CONNECTIONS_ALL)
75  connections = CConnman::CONNECTIONS_ALL;
76 
77  return m_node.getNodeCount(connections);
78 }
79 
81 {
82  if (cachedBestHeaderHeight == -1) {
83  // make sure we initially populate the cache via a cs_main lock
84  // otherwise we need to wait for a tip update
85  int height;
86  int64_t blockTime;
87  if (m_node.getHeaderTip(height, blockTime)) {
88  cachedBestHeaderHeight = height;
89  cachedBestHeaderTime = blockTime;
90  }
91  }
93 }
94 
96 {
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 
108 void ClientModel::updateNumConnections(int numConnections)
109 {
110  Q_EMIT numConnectionsChanged(numConnections);
111 }
112 
113 void ClientModel::updateNetworkActive(bool networkActive)
114 {
115  Q_EMIT networkActiveChanged(networkActive);
116 }
117 
119 {
121 }
122 
124 {
125  if (m_node.getReindex())
126  return BlockSource::REINDEX;
127  else if (m_node.getImporting())
128  return BlockSource::DISK;
129  else if (getNumConnections() > 0)
130  return BlockSource::NETWORK;
131 
132  return BlockSource::NONE;
133 }
134 
136 {
137  return QString::fromStdString(m_node.getWarnings());
138 }
139 
141 {
142  return optionsModel;
143 }
144 
146 {
147  return peerTableModel;
148 }
149 
151 {
152  return banTableModel;
153 }
154 
156 {
157  return QString::fromStdString(FormatFullVersion());
158 }
159 
161 {
162  return QString::fromStdString(strSubVersion);
163 }
164 
166 {
168 }
169 
171 {
172  return QDateTime::fromTime_t(GetStartupTime()).toString();
173 }
174 
175 QString ClientModel::dataDir() const
176 {
178 }
179 
180 QString ClientModel::blocksDir() const
181 {
183 }
184 
186 {
188 }
189 
190 // Handlers for core signals
191 static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
192 {
193  // emits signal "showProgress"
194  bool invoked = QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
195  Q_ARG(QString, QString::fromStdString(title)),
196  Q_ARG(int, nProgress));
197  assert(invoked);
198 }
199 
200 static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
201 {
202  // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections);
203  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
204  Q_ARG(int, newNumConnections));
205  assert(invoked);
206 }
207 
208 static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkActive)
209 {
210  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNetworkActive", Qt::QueuedConnection,
211  Q_ARG(bool, networkActive));
212  assert(invoked);
213 }
214 
215 static void NotifyAlertChanged(ClientModel *clientmodel)
216 {
217  qDebug() << "NotifyAlertChanged";
218  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
219  assert(invoked);
220 }
221 
222 static void BannedListChanged(ClientModel *clientmodel)
223 {
224  qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__);
225  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
226  assert(invoked);
227 }
228 
229 static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int height, int64_t blockTime, double verificationProgress, bool fHeader)
230 {
231  // lock free async UI updates in case we have a new block tip
232  // during initial sync, only update the UI if the last update
233  // was > 250ms (MODEL_UPDATE_DELAY) ago
234  int64_t now = 0;
235  if (initialSync)
236  now = GetTimeMillis();
237 
238  int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
239 
240  if (fHeader) {
241  // cache best headers time and height to reduce future cs_main locks
242  clientmodel->cachedBestHeaderHeight = height;
243  clientmodel->cachedBestHeaderTime = blockTime;
244  }
245 
246  // During initial sync, block notifications, and header notifications from reindexing are both throttled.
247  if (!initialSync || (fHeader && !clientmodel->node().getReindex()) || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
248  //pass an async signal to the UI thread
249  bool invoked = QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
250  Q_ARG(int, height),
251  Q_ARG(QDateTime, QDateTime::fromTime_t(blockTime)),
252  Q_ARG(double, verificationProgress),
253  Q_ARG(bool, fHeader));
254  assert(invoked);
255  nLastUpdateNotification = now;
256  }
257 }
258 
260 {
261  // Connect signals to client
262  m_handler_show_progress = m_node.handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
267  m_handler_notify_block_tip = m_node.handleNotifyBlockTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, false));
268  m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, true));
269 }
270 
272 {
273  // Disconnect signals from client
274  m_handler_show_progress->disconnect();
277  m_handler_notify_alert_changed->disconnect();
278  m_handler_banned_list_changed->disconnect();
279  m_handler_notify_block_tip->disconnect();
280  m_handler_notify_header_tip->disconnect();
281 }
282 
283 bool ClientModel::getProxyInfo(std::string& ip_port) const
284 {
285  proxyType ipv4, ipv6;
286  if (m_node.getProxy((Network) 1, ipv4) && m_node.getProxy((Network) 2, ipv6)) {
287  ip_port = ipv4.proxy.ToStringIPPort();
288  return true;
289  }
290  return false;
291 }
virtual std::unique_ptr< Handler > handleNotifyHeaderTip(NotifyHeaderTipFn fn)=0
QString formatClientStartupTime() const
PeerTableModel * peerTableModel
Definition: clientmodel.h:90
void updateNetworkActive(bool networkActive)
QString formatSubVersion() const
static void NotifyAlertChanged(ClientModel *clientmodel)
interfaces::Node & m_node
Definition: clientmodel.h:81
bool isReleaseVersion() const
std::atomic< int64_t > cachedBestHeaderTime
Definition: clientmodel.h:78
void updateBanlist()
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: time.cpp:57
QString blocksDir() const
virtual size_t getMempoolDynamicUsage()=0
Get mempool dynamic usage.
virtual bool getProxy(Network net, proxyType &proxy_info)=0
Get proxy.
QThread *const m_thread
A thread to interact with m_node asynchronously.
Definition: clientmodel.h:94
NodeContext & m_node
Definition: chain.cpp:382
virtual int64_t getTotalBytesRecv()=0
Get total bytes recv.
virtual bool getImporting()=0
Get importing.
virtual size_t getMempoolSize()=0
Get mempool size.
static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
void networkActiveChanged(bool networkActive)
BanTableModel * banTableModel
Definition: clientmodel.h:91
ClientModel(interfaces::Node &node, OptionsModel *optionsModel, QObject *parent=nullptr)
Definition: clientmodel.cpp:28
std::unique_ptr< interfaces::Handler > m_handler_show_progress
Definition: clientmodel.h:82
static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int height, int64_t blockTime, double verificationProgress, bool fHeader)
OptionsModel * getOptionsModel()
const fs::path & GetBlocksDir()
Definition: system.cpp:587
std::atomic< int > cachedBestHeaderHeight
Definition: clientmodel.h:77
PeerTableModel * getPeerTableModel()
virtual std::unique_ptr< Handler > handleNotifyBlockTip(NotifyBlockTipFn fn)=0
void numConnectionsChanged(int count)
QString getStatusBarWarnings() const
Return warnings to be displayed in status bar.
void alertsChanged(const QString &warnings)
std::unique_ptr< interfaces::Handler > m_handler_notify_block_tip
Definition: clientmodel.h:87
virtual std::unique_ptr< Handler > handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn)=0
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut)
#define CLIENT_VERSION_IS_RELEASE
static int64_t nLastHeaderTipUpdateNotification
Definition: clientmodel.cpp:25
int getNumConnections(unsigned int flags=CONNECTIONS_ALL) const
Return number of connections, default is in- and outbound (total)
Definition: clientmodel.cpp:66
enum BlockSource getBlockSource() const
Returns enum BlockSource of the current importing/syncing state.
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call...
BlockSource
Definition: clientmodel.h:29
const fs::path & GetDataDir(bool fNetSpecific)
Definition: system.cpp:612
void unsubscribeFromCoreSignals()
virtual std::unique_ptr< Handler > handleShowProgress(ShowProgressFn fn)=0
BanTableModel * getBanTableModel()
interfaces::Node & node() const
Definition: clientmodel.h:52
void subscribeToCoreSignals()
Network
Definition: netaddress.h:19
std::unique_ptr< interfaces::Handler > m_handler_banned_list_changed
Definition: clientmodel.h:86
NumConnections
Definition: net.h:125
virtual std::unique_ptr< Handler > handleBannedListChanged(BannedListChangedFn fn)=0
std::string strSubVersion
Subversion as sent to the P2P network in version messages.
Definition: net.cpp:91
Model for Bitcoin network client.
Definition: clientmodel.h:44
std::unique_ptr< interfaces::Handler > m_handler_notify_header_tip
Definition: clientmodel.h:88
std::string FormatFullVersion()
static const int MODEL_UPDATE_DELAY
Definition: guiconstants.h:11
int flags
Definition: bitcoin-tx.cpp:509
static void BannedListChanged(ClientModel *clientmodel)
virtual bool getReindex()=0
Get reindex.
void updateAlert()
std::unique_ptr< interfaces::Handler > m_handler_notify_num_connections_changed
Definition: clientmodel.h:83
CService proxy
Definition: netbase.h:36
int64_t GetStartupTime()
Server/client environment: argument handling, config file parsing, thread wrappers, startup time.
Definition: system.cpp:1141
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:36
static int64_t nLastBlockTipUpdateNotification
Definition: clientmodel.cpp:26
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call...
Definition: bantablemodel.h:42
std::string ToStringIPPort() const
Definition: netaddress.cpp:741
virtual bool getHeaderTip(int &height, int64_t &block_time)=0
Get header tip height and time.
static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkActive)
OptionsModel * optionsModel
Definition: clientmodel.h:89
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes)
QString dataDir() const
virtual std::unique_ptr< Handler > handleNotifyAlertChanged(NotifyAlertChangedFn fn)=0
std::unique_ptr< interfaces::Handler > m_handler_notify_network_active_changed
Definition: clientmodel.h:84
void updateNumConnections(int numConnections)
virtual std::string getWarnings()=0
Get warnings.
int getHeaderTipHeight() const
Definition: clientmodel.cpp:80
QString boostPathToQString(const fs::path &path)
Definition: guiutil.cpp:715
std::unique_ptr< interfaces::Handler > m_handler_notify_alert_changed
Definition: clientmodel.h:85
virtual std::unique_ptr< Handler > handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn)=0
static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
virtual int64_t getTotalBytesSent()=0
Get total bytes sent.
int64_t getHeaderTipTime() const
Definition: clientmodel.cpp:95
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:39
virtual size_t getNodeCount(CConnman::NumConnections flags)=0
Get number of connections.
QString formatFullVersion() const
bool getProxyInfo(std::string &ip_port) const