Bitcoin Core  24.99.0
P2P Digital Currency
clientmodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2021 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 #include <qt/peertablesortproxy.h>
12 
13 #include <clientversion.h>
14 #include <interfaces/handler.h>
15 #include <interfaces/node.h>
16 #include <net.h>
17 #include <netbase.h>
18 #include <util/system.h>
19 #include <util/threadnames.h>
20 #include <util/time.h>
21 #include <validation.h>
22 
23 #include <stdint.h>
24 
25 #include <QDebug>
26 #include <QMetaObject>
27 #include <QThread>
28 #include <QTimer>
29 
32 
33 ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QObject *parent) :
34  QObject(parent),
35  m_node(node),
36  optionsModel(_optionsModel),
37  peerTableModel(nullptr),
38  banTableModel(nullptr),
39  m_thread(new QThread(this))
40 {
43 
46  m_peer_table_sort_proxy->setSourceModel(peerTableModel);
47 
48  banTableModel = new BanTableModel(m_node, this);
49 
50  QTimer* timer = new QTimer;
51  timer->setInterval(MODEL_UPDATE_DELAY);
52  connect(timer, &QTimer::timeout, [this] {
53  // no locking required at this point
54  // the following calls will acquire the required lock
57  });
58  connect(m_thread, &QThread::finished, timer, &QObject::deleteLater);
59  connect(m_thread, &QThread::started, [timer] { timer->start(); });
60  // move timer to thread so that polling doesn't disturb main event loop
61  timer->moveToThread(m_thread);
62  m_thread->start();
63  QTimer::singleShot(0, timer, []() {
64  util::ThreadRename("qt-clientmodl");
65  });
66 
68 }
69 
71 {
73 
74  m_thread->quit();
75  m_thread->wait();
76 }
77 
78 int ClientModel::getNumConnections(unsigned int flags) const
79 {
81 
82  if(flags == CONNECTIONS_IN)
83  connections = ConnectionDirection::In;
84  else if (flags == CONNECTIONS_OUT)
85  connections = ConnectionDirection::Out;
86  else if (flags == CONNECTIONS_ALL)
87  connections = ConnectionDirection::Both;
88 
89  return m_node.getNodeCount(connections);
90 }
91 
93 {
94  if (cachedBestHeaderHeight == -1) {
95  // make sure we initially populate the cache via a cs_main lock
96  // otherwise we need to wait for a tip update
97  int height;
98  int64_t blockTime;
99  if (m_node.getHeaderTip(height, blockTime)) {
100  cachedBestHeaderHeight = height;
101  cachedBestHeaderTime = blockTime;
102  }
103  }
104  return cachedBestHeaderHeight;
105 }
106 
108 {
109  if (cachedBestHeaderTime == -1) {
110  int height;
111  int64_t blockTime;
112  if (m_node.getHeaderTip(height, blockTime)) {
113  cachedBestHeaderHeight = height;
114  cachedBestHeaderTime = blockTime;
115  }
116  }
117  return cachedBestHeaderTime;
118 }
119 
121 {
122  if (m_cached_num_blocks == -1) {
124  }
125  return m_cached_num_blocks;
126 }
127 
129 {
130  uint256 tip{WITH_LOCK(m_cached_tip_mutex, return m_cached_tip_blocks)};
131 
132  if (!tip.IsNull()) {
133  return tip;
134  }
135 
136  // Lock order must be: first `cs_main`, then `m_cached_tip_mutex`.
137  // The following will lock `cs_main` (and release it), so we must not
138  // own `m_cached_tip_mutex` here.
139  tip = m_node.getBestBlockHash();
140 
142  // We checked that `m_cached_tip_blocks` is not null above, but then we
143  // released the mutex `m_cached_tip_mutex`, so it could have changed in the
144  // meantime. Thus, check again.
145  if (m_cached_tip_blocks.IsNull()) {
146  m_cached_tip_blocks = tip;
147  }
148  return m_cached_tip_blocks;
149 }
150 
152 {
153  if (m_node.getReindex())
154  return BlockSource::REINDEX;
155  else if (m_node.getImporting())
156  return BlockSource::DISK;
157  else if (getNumConnections() > 0)
158  return BlockSource::NETWORK;
159 
160  return BlockSource::NONE;
161 }
162 
164 {
165  return QString::fromStdString(m_node.getWarnings().translated);
166 }
167 
169 {
170  return optionsModel;
171 }
172 
174 {
175  return peerTableModel;
176 }
177 
179 {
181 }
182 
184 {
185  return banTableModel;
186 }
187 
189 {
190  return QString::fromStdString(FormatFullVersion());
191 }
192 
194 {
195  return QString::fromStdString(strSubVersion);
196 }
197 
199 {
201 }
202 
204 {
205  return QDateTime::fromSecsSinceEpoch(GetStartupTime()).toString();
206 }
207 
208 QString ClientModel::dataDir() const
209 {
211 }
212 
213 QString ClientModel::blocksDir() const
214 {
216 }
217 
218 void ClientModel::TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, SyncType synctype)
219 {
220  if (synctype == SyncType::HEADER_SYNC) {
221  // cache best headers time and height to reduce future cs_main locks
224  } else if (synctype == SyncType::BLOCK_SYNC) {
226  WITH_LOCK(m_cached_tip_mutex, m_cached_tip_blocks = tip.block_hash;);
227  }
228 
229  // Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex.
230  const bool throttle = (sync_state != SynchronizationState::POST_INIT && synctype == SyncType::BLOCK_SYNC) || sync_state == SynchronizationState::INIT_REINDEX;
231  const int64_t now = throttle ? GetTimeMillis() : 0;
232  int64_t& nLastUpdateNotification = synctype != SyncType::BLOCK_SYNC ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
233  if (throttle && now < nLastUpdateNotification + count_milliseconds(MODEL_UPDATE_DELAY)) {
234  return;
235  }
236 
237  Q_EMIT numBlocksChanged(tip.block_height, QDateTime::fromSecsSinceEpoch(tip.block_time), verification_progress, synctype, sync_state);
238  nLastUpdateNotification = now;
239 }
240 
242 {
244  [this](const std::string& title, int progress, [[maybe_unused]] bool resume_possible) {
245  Q_EMIT showProgress(QString::fromStdString(title), progress);
246  });
248  [this](int new_num_connections) {
249  Q_EMIT numConnectionsChanged(new_num_connections);
250  });
252  [this](bool network_active) {
253  Q_EMIT networkActiveChanged(network_active);
254  });
256  [this]() {
257  qDebug() << "ClientModel: NotifyAlertChanged";
259  });
261  [this]() {
262  qDebug() << "ClienModel: Requesting update for peer banlist";
263  QMetaObject::invokeMethod(banTableModel, [this] { banTableModel->refresh(); });
264  });
266  [this](SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress) {
267  TipChanged(sync_state, tip, verification_progress, SyncType::BLOCK_SYNC);
268  });
270  [this](SynchronizationState sync_state, interfaces::BlockTip tip, bool presync) {
271  TipChanged(sync_state, tip, /*verification_progress=*/0.0, presync ? SyncType::HEADER_PRESYNC : SyncType::HEADER_SYNC);
272  });
273 }
274 
276 {
277  m_handler_show_progress->disconnect();
280  m_handler_notify_alert_changed->disconnect();
281  m_handler_banned_list_changed->disconnect();
282  m_handler_notify_block_tip->disconnect();
283  m_handler_notify_header_tip->disconnect();
284 }
285 
286 bool ClientModel::getProxyInfo(std::string& ip_port) const
287 {
288  Proxy ipv4, ipv6;
289  if (m_node.getProxy((Network) 1, ipv4) && m_node.getProxy((Network) 2, ipv6)) {
290  ip_port = ipv4.proxy.ToStringIPPort();
291  return true;
292  }
293  return false;
294 }
#define CLIENT_VERSION_IS_RELEASE
node::NodeContext m_node
Definition: bitcoin-gui.cpp:37
int flags
Definition: bitcoin-tx.cpp:525
const fs::path & GetBlocksDirPath() const
Get blocks directory path.
Definition: system.cpp:403
const fs::path & GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: system.h:303
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call.
Definition: bantablemodel.h:44
std::string ToStringIPPort() const
Definition: netaddress.cpp:924
std::unique_ptr< interfaces::Handler > m_handler_banned_list_changed
Definition: clientmodel.h:103
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:92
std::unique_ptr< interfaces::Handler > m_handler_show_progress
Definition: clientmodel.h:99
std::atomic< int64_t > cachedBestHeaderTime
Definition: clientmodel.h:91
std::unique_ptr< interfaces::Handler > m_handler_notify_alert_changed
Definition: clientmodel.h:102
interfaces::Node & m_node
Definition: clientmodel.h:95
Mutex m_cached_tip_mutex
Definition: clientmodel.h:94
PeerTableModel * getPeerTableModel()
PeerTableSortProxy * peerTableSortProxy()
std::atomic< int > cachedBestHeaderHeight
Definition: clientmodel.h:90
uint256 getBestBlockHash() EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex)
void numConnectionsChanged(int count)
int getNumBlocks() const
int64_t getHeaderTipTime() const
std::unique_ptr< interfaces::Handler > m_handler_notify_block_tip
Definition: clientmodel.h:104
QString formatClientStartupTime() const
int getNumConnections(unsigned int flags=CONNECTIONS_ALL) const
Return number of connections, default is in- and outbound (total)
Definition: clientmodel.cpp:78
enum BlockSource getBlockSource() const
Returns enum BlockSource of the current importing/syncing state.
ClientModel(interfaces::Node &node, OptionsModel *optionsModel, QObject *parent=nullptr)
Definition: clientmodel.cpp:33
std::unique_ptr< interfaces::Handler > m_handler_notify_num_connections_changed
Definition: clientmodel.h:100
std::unique_ptr< interfaces::Handler > m_handler_notify_network_active_changed
Definition: clientmodel.h:101
OptionsModel * optionsModel
Definition: clientmodel.h:106
BanTableModel * banTableModel
Definition: clientmodel.h:109
QThread *const m_thread
A thread to interact with m_node asynchronously.
Definition: clientmodel.h:112
std::unique_ptr< interfaces::Handler > m_handler_notify_header_tip
Definition: clientmodel.h:105
BanTableModel * getBanTableModel()
void unsubscribeFromCoreSignals()
void numBlocksChanged(int count, const QDateTime &blockDate, double nVerificationProgress, SyncType header, SynchronizationState sync_state)
void TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, SyncType synctype) EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex)
void alertsChanged(const QString &warnings)
QString dataDir() const
std::atomic< int > m_cached_num_blocks
Definition: clientmodel.h:92
OptionsModel * getOptionsModel()
QString formatFullVersion() const
PeerTableModel * peerTableModel
Definition: clientmodel.h:107
PeerTableSortProxy * m_peer_table_sort_proxy
Definition: clientmodel.h:108
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:41
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call.
Definition: netbase.h:49
CService proxy
Definition: netbase.h:56
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:70
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 bool getImporting()=0
Get importing.
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 getReindex()=0
Get reindex.
virtual size_t getMempoolSize()=0
Get mempool size.
virtual size_t getNodeCount(ConnectionDirection flags)=0
Get number of connections.
virtual bool getHeaderTip(int &height, int64_t &block_time)=0
Get header tip height and time.
virtual uint256 getBestBlockHash()=0
Get best block hash.
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 bool getProxy(Network net, Proxy &proxy_info)=0
Get proxy.
virtual int getNumBlocks()=0
Get num blocks.
256-bit opaque blob.
Definition: uint256.h:119
static int64_t nLastHeaderTipUpdateNotification
Definition: clientmodel.cpp:30
static int64_t nLastBlockTipUpdateNotification
Definition: clientmodel.cpp:31
SyncType
Definition: clientmodel.h:40
@ HEADER_PRESYNC
@ CONNECTIONS_IN
Definition: clientmodel.h:48
@ CONNECTIONS_OUT
Definition: clientmodel.h:49
@ CONNECTIONS_ALL
Definition: clientmodel.h:50
BlockSource
Definition: clientmodel.h:33
std::string FormatFullVersion()
static constexpr auto MODEL_UPDATE_DELAY
Definition: guiconstants.h:14
QString PathToQString(const fs::path &path)
Convert OS specific boost path to QString through UTF-8.
Definition: guiutil.cpp:665
Definition: init.h:25
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:59
std::string strSubVersion
Subversion as sent to the P2P network in version messages.
Definition: net.cpp:120
Network
A network type.
Definition: netaddress.h:44
ConnectionDirection
Definition: netbase.h:32
std::string translated
Definition: translation.h:20
Block tip (could be a header or not, depends on the subscribed signal).
Definition: node.h:276
uint256 block_hash
Definition: node.h:279
int64_t block_time
Definition: node.h:278
#define LOCK(cs)
Definition: sync.h:261
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:305
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: time.cpp:107
constexpr int64_t count_milliseconds(std::chrono::milliseconds t)
Definition: time.h:55
int64_t GetStartupTime()
Definition: system.cpp:1419
ArgsManager gArgs
Definition: system.cpp:86
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:88