Bitcoin Core 31.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
clientmodel.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-present 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 <bitcoin-build-config.h> // IWYU pragma: keep
6
7#include <qt/clientmodel.h>
8
9#include <qt/bantablemodel.h>
10#include <qt/guiconstants.h>
11#include <qt/guiutil.h>
12#include <qt/peertablemodel.h>
14
15#include <clientversion.h>
16#include <common/args.h>
17#include <common/system.h>
18#include <interfaces/handler.h>
19#include <interfaces/node.h>
20#include <net.h>
21#include <netbase.h>
22#include <util/threadnames.h>
23#include <util/time.h>
24#include <validation.h>
25
26#include <cstdint>
27
28#include <QDebug>
29#include <QMetaObject>
30#include <QThread>
31#include <QTimer>
32
33static SteadyClock::time_point g_last_header_tip_update_notification{};
34static SteadyClock::time_point g_last_block_tip_update_notification{};
35
36ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QObject *parent) :
37 QObject(parent),
38 m_node(node),
39 optionsModel(_optionsModel),
40 m_thread(new QThread(this))
41{
44
48
50
51 QTimer* timer = new QTimer;
52 timer->setInterval(MODEL_UPDATE_DELAY);
53 connect(timer, &QTimer::timeout, [this] {
54 // no locking required at this point
55 // the following calls will acquire the required lock
56 Q_EMIT mempoolSizeChanged(m_node.getMempoolSize(), m_node.getMempoolDynamicUsage(), m_node.getMempoolMaxUsage());
57 Q_EMIT bytesChanged(m_node.getTotalBytesRecv(), m_node.getTotalBytesSent());
58 });
59 connect(m_thread, &QThread::finished, timer, &QObject::deleteLater);
60 connect(m_thread, &QThread::started, [timer] { timer->start(); });
61 // move timer to thread so that polling doesn't disturb main event loop
62 timer->moveToThread(m_thread);
63 m_thread->start();
64 QTimer::singleShot(0, timer, []() {
65 util::ThreadRename("qt-clientmodl");
66 });
67
69}
70
72{
74
75 m_thread->quit();
76 m_thread->wait();
77}
78
83
85{
87
89 connections = ConnectionDirection::In;
90 else if (flags == CONNECTIONS_OUT)
91 connections = ConnectionDirection::Out;
92 else if (flags == CONNECTIONS_ALL)
93 connections = ConnectionDirection::Both;
94
95 return m_node.getNodeCount(connections);
96}
97
99{
100 if (cachedBestHeaderHeight == -1) {
101 // make sure we initially populate the cache via a cs_main lock
102 // otherwise we need to wait for a tip update
103 int height;
104 int64_t blockTime;
105 if (m_node.getHeaderTip(height, blockTime)) {
106 cachedBestHeaderHeight = height;
107 cachedBestHeaderTime = blockTime;
108 }
109 }
111}
112
114{
115 if (cachedBestHeaderTime == -1) {
116 int height;
117 int64_t blockTime;
118 if (m_node.getHeaderTip(height, blockTime)) {
119 cachedBestHeaderHeight = height;
120 cachedBestHeaderTime = blockTime;
121 }
122 }
124}
125
126
127std::map<CNetAddr, LocalServiceInfo> ClientModel::getNetLocalAddresses() const
128{
129 return m_node.getNetLocalAddresses();
130}
131
132
134{
135 if (m_cached_num_blocks == -1) {
136 m_cached_num_blocks = m_node.getNumBlocks();
137 }
138 return m_cached_num_blocks;
139}
140
142{
143 uint256 tip{WITH_LOCK(m_cached_tip_mutex, return m_cached_tip_blocks)};
144
145 if (!tip.IsNull()) {
146 return tip;
147 }
148
149 // Lock order must be: first `cs_main`, then `m_cached_tip_mutex`.
150 // The following will lock `cs_main` (and release it), so we must not
151 // own `m_cached_tip_mutex` here.
152 tip = m_node.getBestBlockHash();
153
155 // We checked that `m_cached_tip_blocks` is not null above, but then we
156 // released the mutex `m_cached_tip_mutex`, so it could have changed in the
157 // meantime. Thus, check again.
158 if (m_cached_tip_blocks.IsNull()) {
159 m_cached_tip_blocks = tip;
160 }
161 return m_cached_tip_blocks;
162}
163
165{
166 if (m_node.isLoadingBlocks()) return BlockSource::DISK;
167 if (getNumConnections() > 0) return BlockSource::NETWORK;
168 return BlockSource::NONE;
169}
170
172{
173 return QString::fromStdString(m_node.getWarnings().translated);
174}
175
180
185
190
195
197{
198 return QString::fromStdString(FormatFullVersion());
199}
200
202{
203 return QString::fromStdString(strSubVersion);
204}
205
207{
208 return CLIENT_VERSION_IS_RELEASE;
209}
210
212{
213 return QDateTime::currentDateTime().addSecs(-TicksSeconds(GetUptime())).toString();
214}
215
216QString ClientModel::dataDir() const
217{
218 return GUIUtil::PathToQString(gArgs.GetDataDirNet());
219}
220
222{
223 return GUIUtil::PathToQString(gArgs.GetBlocksDirPath());
224}
225
226void ClientModel::TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, SyncType synctype)
227{
228 if (synctype == SyncType::HEADER_SYNC) {
229 // cache best headers time and height to reduce future cs_main locks
232 } else if (synctype == SyncType::BLOCK_SYNC) {
234 WITH_LOCK(m_cached_tip_mutex, m_cached_tip_blocks = tip.block_hash;);
235 }
236
237 // Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex.
238 const bool throttle = (sync_state != SynchronizationState::POST_INIT && synctype == SyncType::BLOCK_SYNC) || sync_state == SynchronizationState::INIT_REINDEX;
239 const auto now{throttle ? SteadyClock::now() : SteadyClock::time_point{}};
241 if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
242 return;
243 }
244
245 Q_EMIT numBlocksChanged(tip.block_height, QDateTime::fromSecsSinceEpoch(tip.block_time), verification_progress, synctype, sync_state);
246 nLastUpdateNotification = now;
247}
248
250{
251 m_event_handlers.emplace_back(m_node.handleShowProgress(
252 [this](const std::string& title, int progress, [[maybe_unused]] bool resume_possible) {
253 Q_EMIT showProgress(QString::fromStdString(title), progress);
254 }));
255 m_event_handlers.emplace_back(m_node.handleNotifyNumConnectionsChanged(
256 [this](int new_num_connections) {
257 Q_EMIT numConnectionsChanged(new_num_connections);
258 }));
259 m_event_handlers.emplace_back(m_node.handleNotifyNetworkActiveChanged(
260 [this](bool network_active) {
261 Q_EMIT networkActiveChanged(network_active);
262 }));
263 m_event_handlers.emplace_back(m_node.handleNotifyAlertChanged(
264 [this]() {
265 qDebug() << "ClientModel: NotifyAlertChanged";
266 Q_EMIT alertsChanged(getStatusBarWarnings());
267 }));
268 m_event_handlers.emplace_back(m_node.handleBannedListChanged(
269 [this]() {
270 qDebug() << "ClienModel: Requesting update for peer banlist";
271 QMetaObject::invokeMethod(banTableModel, [this] { banTableModel->refresh(); });
272 }));
273 m_event_handlers.emplace_back(m_node.handleNotifyBlockTip(
274 [this](SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress) {
275 TipChanged(sync_state, tip, verification_progress, SyncType::BLOCK_SYNC);
276 }));
277 m_event_handlers.emplace_back(m_node.handleNotifyHeaderTip(
278 [this](SynchronizationState sync_state, interfaces::BlockTip tip, bool presync) {
279 TipChanged(sync_state, tip, /*verification_progress=*/0.0, presync ? SyncType::HEADER_PRESYNC : SyncType::HEADER_SYNC);
280 }));
281}
282
287
288bool ClientModel::getProxyInfo(std::string& ip_port) const
289{
290 Proxy ipv4, ipv6;
291 if (m_node.getProxy((Network) 1, ipv4) && m_node.getProxy((Network) 2, ipv6)) {
292 ip_port = ipv4.proxy.ToStringAddrPort();
293 return true;
294 }
295 return false;
296}
ArgsManager gArgs
Definition args.cpp:40
int flags
Qt model providing information about banned peers, similar to the "getpeerinfo" RPC call.
std::string ToStringAddrPort() const
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut)
QString blocksDir() const
QString getStatusBarWarnings() const
Return warnings to be displayed in status bar.
std::vector< std::unique_ptr< interfaces::Handler > > m_event_handlers
std::map< CNetAddr, LocalServiceInfo > getNetLocalAddresses() const
int getHeaderTipHeight() const
std::atomic< int64_t > cachedBestHeaderTime
Definition clientmodel.h:96
interfaces::Node & m_node
Mutex m_cached_tip_mutex
Definition clientmodel.h:99
PeerTableModel * getPeerTableModel()
PeerTableSortProxy * peerTableSortProxy()
std::atomic< int > cachedBestHeaderHeight
Definition clientmodel.h:95
uint256 getBestBlockHash() EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex)
BlockSource getBlockSource() const
Returns the block source of the current importing/syncing state.
int getNumBlocks() const
int64_t getHeaderTipTime() const
QString formatClientStartupTime() const
int getNumConnections(unsigned int flags=CONNECTIONS_ALL) const
Return number of connections, default is in- and outbound (total).
ClientModel(interfaces::Node &node, OptionsModel *optionsModel, QObject *parent=nullptr)
OptionsModel * optionsModel
BanTableModel * banTableModel
QThread *const m_thread
A thread to interact with m_node asynchronously.
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 mempoolSizeChanged(long count, size_t mempoolSizeInBytes, size_t mempoolMaxSizeInBytes)
QString dataDir() const
std::atomic< int > m_cached_num_blocks
Definition clientmodel.h:97
OptionsModel * getOptionsModel()
QString formatFullVersion() const
PeerTableModel * peerTableModel
PeerTableSortProxy * m_peer_table_sort_proxy
bool getProxyInfo(std::string &ip_port) const
QString formatSubVersion() const
bool isReleaseVersion() const
void subscribeToCoreSignals()
Interface from Qt to configuration data structure for Bitcoin client.
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call.
CService proxy
Definition netbase.h:66
constexpr bool IsNull() const
Definition uint256.h:48
Top-level interface for a bitcoin node (bitcoind process).
Definition node.h:70
256-bit opaque blob.
Definition uint256.h:195
static SteadyClock::time_point g_last_block_tip_update_notification
static SteadyClock::time_point g_last_header_tip_update_notification
SyncType
Definition clientmodel.h:42
@ CONNECTIONS_IN
Definition clientmodel.h:50
@ CONNECTIONS_OUT
Definition clientmodel.h:51
@ CONNECTIONS_ALL
Definition clientmodel.h:52
BlockSource
Definition clientmodel.h:36
std::string FormatFullVersion()
SteadyClock::duration GetUptime()
Monotonic uptime (not affected by system time changes).
Definition system.cpp:134
static constexpr auto MODEL_UPDATE_DELAY
QString PathToQString(const fs::path &path)
Convert OS specific boost path to QString through UTF-8.
Definition guiutil.cpp:675
void ThreadRename(const std::string &)
std::string strSubVersion
Subversion as sent to the P2P network in version messages.
Definition net.cpp:120
Network
A network type.
Definition netaddress.h:33
ConnectionDirection
Definition netbase.h:33
Block tip (could be a header or not, depends on the subscribed signal).
Definition node.h:275
uint256 block_hash
Definition node.h:278
int64_t block_time
Definition node.h:277
#define LOCK(cs)
Definition sync.h:258
#define WITH_LOCK(cs, code)
Definition sync.h:289
constexpr int64_t TicksSeconds(Duration d)
Definition time.h:79
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition validation.h:93