Bitcoin ABC  0.26.3
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 <clientversion.h>
8 #include <common/args.h>
9 #include <common/system.h>
10 #include <config.h>
11 #include <interfaces/handler.h>
12 #include <interfaces/node.h>
13 #include <net.h>
14 #include <netbase.h>
15 #include <qt/bantablemodel.h>
16 #include <qt/guiconstants.h>
17 #include <qt/guiutil.h>
18 #include <qt/peertablemodel.h>
19 #include <util/threadnames.h>
20 #include <validation.h>
21 
22 #include <QDebug>
23 #include <QMetaObject>
24 #include <QThread>
25 #include <QTimer>
26 
27 #include <cstdint>
28 
31 
33  QObject *parent)
34  : QObject(parent), m_node(node), optionsModel(_optionsModel),
35  peerTableModel(nullptr), banTableModel(nullptr),
36  m_thread(new QThread(this)) {
40  banTableModel = new BanTableModel(m_node, this);
41 
42  QTimer *timer = new QTimer;
43  timer->setInterval(MODEL_UPDATE_DELAY);
44  connect(timer, &QTimer::timeout, [this] {
45  // no locking required at this point
46  // 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, []() { util::ThreadRename("qt-clientmodl"); });
58 
60 }
61 
64 
65  m_thread->quit();
66  m_thread->wait();
67 }
68 
71 
72  if (flags == CONNECTIONS_IN) {
73  connections = CConnman::CONNECTIONS_IN;
74  } else if (flags == CONNECTIONS_OUT) {
75  connections = CConnman::CONNECTIONS_OUT;
76  } else if (flags == CONNECTIONS_ALL) {
77  connections = CConnman::CONNECTIONS_ALL;
78  }
79 
80  return m_node.getNodeCount(connections);
81 }
82 
84  if (cachedBestHeaderHeight == -1) {
85  // make sure we initially populate the cache via a cs_main lock
86  // otherwise we need to wait for a tip update
87  int height;
88  int64_t blockTime;
89  if (m_node.getHeaderTip(height, blockTime)) {
90  cachedBestHeaderHeight = height;
91  cachedBestHeaderTime = blockTime;
92  }
93  }
95 }
96 
98  if (cachedBestHeaderTime == -1) {
99  int height;
100  int64_t blockTime;
101  if (m_node.getHeaderTip(height, blockTime)) {
102  cachedBestHeaderHeight = height;
103  cachedBestHeaderTime = blockTime;
104  }
105  }
106  return cachedBestHeaderTime;
107 }
108 
110  if (m_cached_num_blocks == -1) {
112  }
113  return m_cached_num_blocks;
114 }
115 
117  BlockHash tip{WITH_LOCK(m_cached_tip_mutex, return m_cached_tip_blocks)};
118 
119  if (!tip.IsNull()) {
120  return tip;
121  }
122 
123  // Lock order must be: first `cs_main`, then `m_cached_tip_mutex`.
124  // The following will lock `cs_main` (and release it), so we must not
125  // own `m_cached_tip_mutex` here.
126  tip = m_node.getBestBlockHash();
127 
129  // We checked that `m_cached_tip_blocks` is not null above, but then we
130  // released the mutex `m_cached_tip_mutex`, so it could have changed in the
131  // meantime. Thus, check again.
132  if (m_cached_tip_blocks.IsNull()) {
133  m_cached_tip_blocks = tip;
134  }
135  return m_cached_tip_blocks;
136 }
137 
139  if (m_node.isLoadingBlocks()) {
140  return BlockSource::DISK;
141  }
142  if (getNumConnections() > 0) {
143  return BlockSource::NETWORK;
144  }
145  return BlockSource::NONE;
146 }
147 
149  return QString::fromStdString(m_node.getWarnings().translated);
150 }
151 
153  return optionsModel;
154 }
155 
157  return peerTableModel;
158 }
159 
161  return banTableModel;
162 }
163 
165  return QString::fromStdString(FormatFullVersion());
166 }
167 
169  return QString::fromStdString(userAgent(GetConfig()));
170 }
171 
173  return CLIENT_VERSION_IS_RELEASE;
174 }
175 
177  return QDateTime::fromTime_t(GetStartupTime()).toString();
178 }
179 
180 QString ClientModel::dataDir() const {
182 }
183 
184 QString ClientModel::blocksDir() const {
186 }
187 
190  double verification_progress, SyncType synctype)
191  EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex) {
192  if (synctype == SyncType::HEADER_SYNC) {
193  // cache best headers time and height to reduce future cs_main locks
194  cachedBestHeaderHeight = tip.block_height;
195  cachedBestHeaderTime = tip.block_time;
196  } else if (synctype == SyncType::BLOCK_SYNC) {
197  m_cached_num_blocks = tip.block_height;
198  WITH_LOCK(m_cached_tip_mutex, m_cached_tip_blocks = tip.block_hash;);
199  }
200 
201  // Throttle GUI notifications about (a) blocks during initial sync, and (b)
202  // both blocks and headers during reindex.
203  const bool throttle = (sync_state != SynchronizationState::POST_INIT &&
204  synctype == SyncType::BLOCK_SYNC) ||
206  const int64_t now = throttle ? GetTimeMillis() : 0;
207  int64_t &nLastUpdateNotification = synctype != SyncType::BLOCK_SYNC
210  if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
211  return;
212  }
213 
214  Q_EMIT numBlocksChanged(tip.block_height,
215  QDateTime::fromSecsSinceEpoch(tip.block_time),
216  verification_progress, synctype, sync_state);
217  nLastUpdateNotification = now;
218 }
219 
222  [this](const std::string &title, int progress,
223  [[maybe_unused]] bool resume_possible) {
224  Q_EMIT showProgress(QString::fromStdString(title), progress);
225  });
228  [this](int new_num_connections) {
229  Q_EMIT numConnectionsChanged(new_num_connections);
230  });
232  m_node.handleNotifyNetworkActiveChanged([this](bool network_active) {
233  Q_EMIT networkActiveChanged(network_active);
234  });
236  qDebug() << "ClientModel: NotifyAlertChanged";
238  });
240  qDebug() << "ClienModel: Requesting update for peer banlist";
241  QMetaObject::invokeMethod(banTableModel,
242  [this] { banTableModel->refresh(); });
243  });
245  [this](SynchronizationState sync_state, interfaces::BlockTip tip,
246  double verification_progress) {
247  TipChanged(sync_state, tip, verification_progress,
249  });
251  [this](SynchronizationState sync_state, interfaces::BlockTip tip,
252  bool presync) {
253  TipChanged(sync_state, tip, /*verification_progress=*/0.0,
254  presync ? SyncType::HEADER_PRESYNC
256  });
257 }
258 
260  m_handler_show_progress->disconnect();
263  m_handler_notify_alert_changed->disconnect();
264  m_handler_banned_list_changed->disconnect();
265  m_handler_notify_block_tip->disconnect();
266  m_handler_notify_header_tip->disconnect();
267 }
268 
269 bool ClientModel::getProxyInfo(std::string &ip_port) const {
270  proxyType ipv4, ipv6;
271  if (m_node.getProxy((Network)1, ipv4) &&
272  m_node.getProxy((Network)2, ipv6)) {
273  ip_port = ipv4.proxy.ToStringIPPort();
274  return true;
275  }
276  return false;
277 }
ArgsManager gArgs
Definition: args.cpp:38
int flags
Definition: bitcoin-tx.cpp:543
const fs::path & GetBlocksDirPath() const
Get blocks directory path.
Definition: args.cpp:289
const fs::path & GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:215
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call.
Definition: bantablemodel.h:42
NumConnections
Definition: net.h:847
@ CONNECTIONS_IN
Definition: net.h:849
@ CONNECTIONS_NONE
Definition: net.h:848
@ CONNECTIONS_ALL
Definition: net.h:851
@ CONNECTIONS_OUT
Definition: net.h:850
std::string ToStringIPPort() const
std::unique_ptr< interfaces::Handler > m_handler_banned_list_changed
Definition: clientmodel.h:100
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut)
void showProgress(const QString &title, int nProgress)
QString blocksDir() const
QString getStatusBarWarnings() const
Return warnings to be displayed in status bar.
int getHeaderTipHeight() const
Definition: clientmodel.cpp:83
std::unique_ptr< interfaces::Handler > m_handler_show_progress
Definition: clientmodel.h:94
std::atomic< int64_t > cachedBestHeaderTime
Definition: clientmodel.h:86
std::unique_ptr< interfaces::Handler > m_handler_notify_alert_changed
Definition: clientmodel.h:99
interfaces::Node & m_node
Definition: clientmodel.h:93
Mutex m_cached_tip_mutex
Definition: clientmodel.h:89
PeerTableModel * getPeerTableModel()
std::atomic< int > cachedBestHeaderHeight
Definition: clientmodel.h:85
BlockHash getBestBlockHash() EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex)
int getNumConnections(NumConnections flags=CONNECTIONS_ALL) const
Return number of connections, default is in- and outbound (total)
Definition: clientmodel.cpp:69
void numConnectionsChanged(int count)
BlockSource getBlockSource() const
Returns the block source of the current importing/syncing state.
int getNumBlocks() const
int64_t getHeaderTipTime() const
Definition: clientmodel.cpp:97
std::unique_ptr< interfaces::Handler > m_handler_notify_block_tip
Definition: clientmodel.h:101
QString formatClientStartupTime() const
ClientModel(interfaces::Node &node, OptionsModel *optionsModel, QObject *parent=nullptr)
Definition: clientmodel.cpp:32
void TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, SyncType synctype)
std::unique_ptr< interfaces::Handler > m_handler_notify_num_connections_changed
Definition: clientmodel.h:96
std::unique_ptr< interfaces::Handler > m_handler_notify_network_active_changed
Definition: clientmodel.h:98
OptionsModel * optionsModel
Definition: clientmodel.h:103
BanTableModel * banTableModel
Definition: clientmodel.h:105
QThread *const m_thread
A thread to interact with m_node asynchronously.
Definition: clientmodel.h:108
std::unique_ptr< interfaces::Handler > m_handler_notify_header_tip
Definition: clientmodel.h:102
BanTableModel * getBanTableModel()
void unsubscribeFromCoreSignals()
void alertsChanged(const QString &warnings)
QString dataDir() const
std::atomic< int > m_cached_num_blocks
Definition: clientmodel.h:87
OptionsModel * getOptionsModel()
QString formatFullVersion() const
PeerTableModel * peerTableModel
Definition: clientmodel.h:104
bool getProxyInfo(std::string &ip_port) const
QString formatSubVersion() const
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes)
bool isReleaseVersion() const
void subscribeToCoreSignals()
void networkActiveChanged(bool networkActive)
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:48
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call.
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:58
virtual std::unique_ptr< Handler > handleNotifyBlockTip(NotifyBlockTipFn fn)=0
virtual std::unique_ptr< Handler > handleNotifyAlertChanged(NotifyAlertChangedFn fn)=0
virtual std::unique_ptr< Handler > handleNotifyHeaderTip(NotifyHeaderTipFn fn)=0
virtual std::unique_ptr< Handler > handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn)=0
virtual bilingual_str getWarnings()=0
Get warnings.
virtual std::unique_ptr< Handler > handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn)=0
virtual std::unique_ptr< Handler > handleShowProgress(ShowProgressFn fn)=0
virtual bool getProxy(Network net, proxyType &proxy_info)=0
Get proxy.
virtual BlockHash getBestBlockHash()=0
Get best block hash.
virtual size_t getMempoolSize()=0
Get mempool size.
virtual bool isLoadingBlocks()=0
Is loading blocks.
virtual size_t getNodeCount(CConnman::NumConnections flags)=0
Get number of connections.
virtual bool getHeaderTip(int &height, int64_t &block_time)=0
Get header tip height and time.
virtual int64_t getTotalBytesRecv()=0
Get total bytes recv.
virtual std::unique_ptr< Handler > handleBannedListChanged(BannedListChangedFn fn)=0
virtual int64_t getTotalBytesSent()=0
Get total bytes sent.
virtual size_t getMempoolDynamicUsage()=0
Get mempool dynamic usage.
virtual int getNumBlocks()=0
Get num blocks.
CService proxy
Definition: netbase.h:40
static int64_t nLastHeaderTipUpdateNotification
Definition: clientmodel.cpp:29
static int64_t nLastBlockTipUpdateNotification
Definition: clientmodel.cpp:30
SyncType
Definition: clientmodel.h:40
@ HEADER_PRESYNC
BlockSource
Definition: clientmodel.h:34
std::string FormatFullVersion()
const Config & GetConfig()
Definition: config.cpp:40
static const int MODEL_UPDATE_DELAY
Definition: guiconstants.h:11
QString boostPathToQString(const fs::path &path)
Convert OS specific boost path to QString through UTF-8.
Definition: guiutil.cpp:785
Definition: init.h:28
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
std::string userAgent(const Config &config)
Definition: net.cpp:3591
Network
A network type.
Definition: netaddress.h:44
NodeContext & m_node
Definition: interfaces.cpp:785
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
std::string translated
Definition: translation.h:19
Block tip (could be a header or not, depends on the subscribed signal).
Definition: node.h:269
#define LOCK(cs)
Definition: sync.h:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
int64_t GetStartupTime()
Definition: system.cpp:116
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: time.cpp:101
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:113