Bitcoin ABC  0.22.13
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 <validation.h>
20 
21 #include <QDebug>
22 #include <QThread>
23 #include <QTimer>
24 
25 #include <cstdint>
26 
29 
31  QObject *parent)
32  : QObject(parent), m_node(node), optionsModel(_optionsModel),
33  peerTableModel(nullptr), banTableModel(nullptr),
34  m_thread(new QThread(this)) {
38  banTableModel = new BanTableModel(m_node, this);
39 
40  QTimer *timer = new QTimer;
41  timer->setInterval(MODEL_UPDATE_DELAY);
42  connect(timer, &QTimer::timeout, [this] {
43  // no locking required at this point
44  // the following calls will acquire the required lock
49  });
50  connect(m_thread, &QThread::finished, timer, &QObject::deleteLater);
51  connect(m_thread, &QThread::started, [timer] { timer->start(); });
52  // move timer to thread so that polling doesn't disturb main event loop
53  timer->moveToThread(m_thread);
54  m_thread->start();
55 
57 }
58 
61 
62  m_thread->quit();
63  m_thread->wait();
64 }
65 
68 
69  if (flags == CONNECTIONS_IN) {
70  connections = CConnman::CONNECTIONS_IN;
71  } else if (flags == CONNECTIONS_OUT) {
72  connections = CConnman::CONNECTIONS_OUT;
73  } else if (flags == CONNECTIONS_ALL) {
74  connections = CConnman::CONNECTIONS_ALL;
75  }
76 
77  return m_node.getNodeCount(connections);
78 }
79 
81  if (cachedBestHeaderHeight == -1) {
82  // make sure we initially populate the cache via a cs_main lock
83  // otherwise we need to wait for a tip update
84  int height;
85  int64_t blockTime;
86  if (m_node.getHeaderTip(height, blockTime)) {
87  cachedBestHeaderHeight = height;
88  cachedBestHeaderTime = blockTime;
89  }
90  }
92 }
93 
95  if (cachedBestHeaderTime == -1) {
96  int height;
97  int64_t blockTime;
98  if (m_node.getHeaderTip(height, blockTime)) {
99  cachedBestHeaderHeight = height;
100  cachedBestHeaderTime = blockTime;
101  }
102  }
103  return cachedBestHeaderTime;
104 }
105 
107  if (m_cached_num_blocks == -1) {
109  }
110  return m_cached_num_blocks;
111 }
112 
113 void ClientModel::updateNumConnections(int numConnections) {
114  Q_EMIT numConnectionsChanged(numConnections);
115 }
116 
117 void ClientModel::updateNetworkActive(bool networkActive) {
118  Q_EMIT networkActiveChanged(networkActive);
119 }
120 
123 }
124 
126  if (m_node.getReindex()) {
127  return BlockSource::REINDEX;
128  } else if (m_node.getImporting()) {
129  return BlockSource::DISK;
130  } else if (getNumConnections() > 0) {
131  return BlockSource::NETWORK;
132  }
133 
134  return BlockSource::NONE;
135 }
136 
138  return QString::fromStdString(m_node.getWarnings());
139 }
140 
142  return optionsModel;
143 }
144 
146  return peerTableModel;
147 }
148 
150  return banTableModel;
151 }
152 
154  return QString::fromStdString(FormatFullVersion());
155 }
156 
158  return QString::fromStdString(userAgent(GetConfig()));
159 }
160 
162  return CLIENT_VERSION_IS_RELEASE;
163 }
164 
166  return QDateTime::fromTime_t(GetStartupTime()).toString();
167 }
168 
169 QString ClientModel::dataDir() const {
171 }
172 
173 QString ClientModel::blocksDir() const {
175 }
176 
179 }
180 
181 // Handlers for core signals
182 static void ShowProgress(ClientModel *clientmodel, const std::string &title,
183  int nProgress) {
184  // emits signal "showProgress"
185  bool invoked = QMetaObject::invokeMethod(
186  clientmodel, "showProgress", Qt::QueuedConnection,
187  Q_ARG(QString, QString::fromStdString(title)), Q_ARG(int, nProgress));
188  assert(invoked);
189 }
190 
191 static void NotifyNumConnectionsChanged(ClientModel *clientmodel,
192  int newNumConnections) {
193  // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " +
194  // QString::number(newNumConnections);
195  bool invoked = QMetaObject::invokeMethod(
196  clientmodel, "updateNumConnections", Qt::QueuedConnection,
197  Q_ARG(int, newNumConnections));
198  assert(invoked);
199 }
200 
201 static void NotifyNetworkActiveChanged(ClientModel *clientmodel,
202  bool networkActive) {
203  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNetworkActive",
204  Qt::QueuedConnection,
205  Q_ARG(bool, networkActive));
206  assert(invoked);
207 }
208 
209 static void NotifyAlertChanged(ClientModel *clientmodel) {
210  qDebug() << "NotifyAlertChanged";
211  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateAlert",
212  Qt::QueuedConnection);
213  assert(invoked);
214 }
215 
216 static void BannedListChanged(ClientModel *clientmodel) {
217  qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__);
218  bool invoked = QMetaObject::invokeMethod(clientmodel, "updateBanlist",
219  Qt::QueuedConnection);
220  assert(invoked);
221 }
222 
223 static void BlockTipChanged(ClientModel *clientmodel,
224  SynchronizationState sync_state, int height,
225  int64_t blockTime, double verificationProgress,
226  bool fHeader) {
227  if (fHeader) {
228  // cache best headers time and height to reduce future cs_main locks
229  clientmodel->cachedBestHeaderHeight = height;
230  clientmodel->cachedBestHeaderTime = blockTime;
231  } else {
232  clientmodel->m_cached_num_blocks = height;
233  }
234 
235  // Throttle GUI notifications about (a) blocks during initial sync, and (b)
236  // both blocks and headers during reindex.
237  const bool throttle =
238  (sync_state != SynchronizationState::POST_INIT && !fHeader) ||
240  const int64_t now = throttle ? GetTimeMillis() : 0;
241  int64_t &nLastUpdateNotification = fHeader
244  if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
245  return;
246  }
247 
248  bool invoked = QMetaObject::invokeMethod(
249  clientmodel, "numBlocksChanged", Qt::QueuedConnection,
250  Q_ARG(int, height), Q_ARG(QDateTime, QDateTime::fromTime_t(blockTime)),
251  Q_ARG(double, verificationProgress), Q_ARG(bool, fHeader),
252  Q_ARG(SynchronizationState, sync_state));
253  assert(invoked);
254  nLastUpdateNotification = now;
255 }
256 
258  // Connect signals to client
260  ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
263  NotifyNumConnectionsChanged, this, std::placeholders::_1));
266  std::bind(NotifyNetworkActiveChanged, this, std::placeholders::_1));
272  BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2,
273  std::placeholders::_3, std::placeholders::_4, false));
275  BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2,
276  std::placeholders::_3, std::placeholders::_4, true));
277 }
278 
280  // Disconnect signals from client
281  m_handler_show_progress->disconnect();
284  m_handler_notify_alert_changed->disconnect();
285  m_handler_banned_list_changed->disconnect();
286  m_handler_notify_block_tip->disconnect();
287  m_handler_notify_header_tip->disconnect();
288 }
289 
290 bool ClientModel::getProxyInfo(std::string &ip_port) const {
291  proxyType ipv4, ipv6;
292  if (m_node.getProxy((Network)1, ipv4) &&
293  m_node.getProxy((Network)2, ipv6)) {
294  ip_port = ipv4.proxy.ToStringIPPort();
295  return true;
296  }
297  return false;
298 }
virtual std::unique_ptr< Handler > handleNotifyHeaderTip(NotifyHeaderTipFn fn)=0
QString formatClientStartupTime() const
PeerTableModel * peerTableModel
Definition: clientmodel.h:91
void updateNetworkActive(bool networkActive)
QString formatSubVersion() const
int getNumConnections(NumConnections flags=CONNECTIONS_ALL) const
Return number of connections, default is in- and outbound (total)
Definition: clientmodel.cpp:66
static void NotifyAlertChanged(ClientModel *clientmodel)
interfaces::Node & m_node
Definition: clientmodel.h:80
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:128
bool isReleaseVersion() const
std::atomic< int64_t > cachedBestHeaderTime
Definition: clientmodel.h:76
void updateBanlist()
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: time.cpp:59
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:95
NodeContext & m_node
Definition: chain.cpp:442
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:92
ClientModel(interfaces::Node &node, OptionsModel *optionsModel, QObject *parent=nullptr)
Definition: clientmodel.cpp:30
std::unique_ptr< interfaces::Handler > m_handler_show_progress
Definition: clientmodel.h:81
OptionsModel * getOptionsModel()
const fs::path & GetBlocksDir()
Definition: system.cpp:734
std::atomic< int > cachedBestHeaderHeight
Definition: clientmodel.h:75
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:88
virtual std::unique_ptr< Handler > handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn)=0
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut)
static int64_t nLastHeaderTipUpdateNotification
Definition: clientmodel.cpp:27
std::atomic< int > m_cached_num_blocks
Definition: clientmodel.h:77
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:31
const fs::path & GetDataDir(bool fNetSpecific)
Definition: system.cpp:760
void unsubscribeFromCoreSignals()
virtual std::unique_ptr< Handler > handleShowProgress(ShowProgressFn fn)=0
BanTableModel * getBanTableModel()
void subscribeToCoreSignals()
Network
Definition: netaddress.h:19
const Config & GetConfig()
Definition: config.cpp:34
std::unique_ptr< interfaces::Handler > m_handler_banned_list_changed
Definition: clientmodel.h:87
NumConnections
Definition: net.h:167
virtual std::unique_ptr< Handler > handleBannedListChanged(BannedListChangedFn fn)=0
Model for Bitcoin network client.
Definition: clientmodel.h:34
std::unique_ptr< interfaces::Handler > m_handler_notify_header_tip
Definition: clientmodel.h:89
std::string FormatFullVersion()
static const int MODEL_UPDATE_DELAY
Definition: guiconstants.h:11
int flags
Definition: bitcoin-tx.cpp:529
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:37
int64_t GetStartupTime()
Server/client environment: argument handling, config file parsing, thread wrappers, startup time.
Definition: system.cpp:1348
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:48
static int64_t nLastBlockTipUpdateNotification
Definition: clientmodel.cpp:28
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call...
Definition: bantablemodel.h:41
std::string ToStringIPPort() const
Definition: netaddress.cpp:772
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:90
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes)
QString dataDir() const
virtual int getNumBlocks()=0
Get num blocks.
virtual std::unique_ptr< Handler > handleNotifyAlertChanged(NotifyAlertChangedFn fn)=0
std::unique_ptr< interfaces::Handler > m_handler_notify_network_active_changed
Definition: clientmodel.h:85
int getNumBlocks() const
void updateNumConnections(int numConnections)
std::string userAgent(const Config &config)
Definition: net.cpp:3164
virtual std::string getWarnings()=0
Get warnings.
int getHeaderTipHeight() const
Definition: clientmodel.cpp:80
QString boostPathToQString(const fs::path &path)
Definition: guiutil.cpp:747
std::unique_ptr< interfaces::Handler > m_handler_notify_alert_changed
Definition: clientmodel.h:86
virtual std::unique_ptr< Handler > handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn)=0
static void BlockTipChanged(ClientModel *clientmodel, SynchronizationState sync_state, int height, int64_t blockTime, double verificationProgress, bool fHeader)
static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
virtual int64_t getTotalBytesSent()=0
Get total bytes sent.
int64_t getHeaderTipTime() const
Definition: clientmodel.cpp:94
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:45
virtual size_t getNodeCount(CConnman::NumConnections flags)=0
Get number of connections.
QString formatFullVersion() const
bool getProxyInfo(std::string &ip_port) const