Bitcoin ABC 0.34.3
P2P Digital Currency
Loading...
Searching...
No Matches
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 <util/time.h>
21#include <validation.h>
22
23#include <QDebug>
24#include <QMetaObject>
25#include <QThread>
26#include <QTimer>
27
28#include <cstdint>
29
30static SteadyClock::time_point g_last_header_tip_update_notification{};
31static SteadyClock::time_point g_last_block_tip_update_notification{};
32
34 QObject *parent)
35 : QObject(parent), m_node(node), optionsModel(_optionsModel),
36 peerTableModel(nullptr), banTableModel(nullptr),
37 m_thread(new QThread(this)) {
42
43 QTimer *timer = new QTimer;
44 timer->setInterval(MODEL_UPDATE_DELAY);
45 connect(timer, &QTimer::timeout, [this] {
46 // no locking required at this point
47 // the following calls will acquire the required lock
52 });
53 connect(m_thread, &QThread::finished, timer, &QObject::deleteLater);
54 connect(m_thread, &QThread::started, [timer] { timer->start(); });
55 // move timer to thread so that polling doesn't disturb main event loop
56 timer->moveToThread(m_thread);
57 m_thread->start();
58 QTimer::singleShot(0, timer, []() { util::ThreadRename("qt-clientmodl"); });
59
61}
62
65
66 m_thread->quit();
67 m_thread->wait();
68}
69
73
76
77 if (flags == CONNECTIONS_IN) {
78 connections = ConnectionDirection::In;
79 } else if (flags == CONNECTIONS_OUT) {
80 connections = ConnectionDirection::Out;
81 } else if (flags == CONNECTIONS_ALL) {
82 connections = ConnectionDirection::Both;
83 }
84
85 return m_node.getNodeCount(connections);
86}
87
89 if (cachedBestHeaderHeight == -1) {
90 // make sure we initially populate the cache via a cs_main lock
91 // otherwise we need to wait for a tip update
92 int height;
93 int64_t blockTime;
94 if (m_node.getHeaderTip(height, blockTime)) {
96 cachedBestHeaderTime = blockTime;
97 }
98 }
100}
101
103 if (cachedBestHeaderTime == -1) {
104 int height;
105 int64_t blockTime;
106 if (m_node.getHeaderTip(height, blockTime)) {
107 cachedBestHeaderHeight = height;
108 cachedBestHeaderTime = blockTime;
109 }
110 }
112}
113
120
122 BlockHash tip{WITH_LOCK(m_cached_tip_mutex, return m_cached_tip_blocks)};
123
124 if (!tip.IsNull()) {
125 return tip;
126 }
127
128 // Lock order must be: first `cs_main`, then `m_cached_tip_mutex`.
129 // The following will lock `cs_main` (and release it), so we must not
130 // own `m_cached_tip_mutex` here.
131 tip = m_node.getBestBlockHash();
132
134 // We checked that `m_cached_tip_blocks` is not null above, but then we
135 // released the mutex `m_cached_tip_mutex`, so it could have changed in the
136 // meantime. Thus, check again.
137 if (m_cached_tip_blocks.IsNull()) {
138 m_cached_tip_blocks = tip;
139 }
140 return m_cached_tip_blocks;
141}
142
144 if (m_node.isLoadingBlocks()) {
145 return BlockSource::DISK;
146 }
147 if (getNumConnections() > 0) {
149 }
150 return BlockSource::NONE;
151}
152
154 return QString::fromStdString(m_node.getWarnings().translated);
155}
156
160
164
168
170 return QString::fromStdString(FormatFullVersion());
171}
172
174 return QString::fromStdString(userAgent(GetConfig()));
175}
176
178 return CLIENT_VERSION_IS_RELEASE;
179}
180
182 return QDateTime::fromSecsSinceEpoch(GetStartupTime()).toString();
183}
184
188
192
195 double verification_progress, SyncType synctype)
196 EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex) {
197 if (synctype == SyncType::HEADER_SYNC) {
198 // cache best headers time and height to reduce future cs_main locks
199 cachedBestHeaderHeight = tip.block_height;
200 cachedBestHeaderTime = tip.block_time;
201 } else if (synctype == SyncType::BLOCK_SYNC) {
202 m_cached_num_blocks = tip.block_height;
203 WITH_LOCK(m_cached_tip_mutex, m_cached_tip_blocks = tip.block_hash;);
204 }
205
206 // Throttle GUI notifications about (a) blocks during initial sync, and (b)
207 // both blocks and headers during reindex.
208 const bool throttle = (sync_state != SynchronizationState::POST_INIT &&
209 synctype == SyncType::BLOCK_SYNC) ||
211 const auto now{throttle ? SteadyClock::now() : SteadyClock::time_point{}};
212 auto &nLastUpdateNotification = synctype != SyncType::BLOCK_SYNC
215 if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
216 return;
217 }
218
219 Q_EMIT numBlocksChanged(tip.block_height,
220 QDateTime::fromSecsSinceEpoch(tip.block_time),
221 verification_progress, synctype, sync_state);
222 nLastUpdateNotification = now;
223}
224
227 [this](const std::string &title, int progress,
228 [[maybe_unused]] bool resume_possible) {
229 Q_EMIT showProgress(QString::fromStdString(title), progress);
230 }));
232 [this](int new_num_connections) {
233 Q_EMIT numConnectionsChanged(new_num_connections);
234 }));
235 m_event_handlers.emplace_back(
236 m_node.handleNotifyNetworkActiveChanged([this](bool network_active) {
237 Q_EMIT networkActiveChanged(network_active);
238 }));
239 m_event_handlers.emplace_back(m_node.handleNotifyAlertChanged([this]() {
240 qDebug() << "ClientModel: NotifyAlertChanged";
241 Q_EMIT alertsChanged(getStatusBarWarnings());
242 }));
243 m_event_handlers.emplace_back(m_node.handleBannedListChanged([this]() {
244 qDebug() << "ClienModel: Requesting update for peer banlist";
245 QMetaObject::invokeMethod(banTableModel,
246 [this] { banTableModel->refresh(); });
247 }));
248 m_event_handlers.emplace_back(m_node.handleNotifyBlockTip(
249 [this](SynchronizationState sync_state, interfaces::BlockTip tip,
250 double verification_progress) {
251 TipChanged(sync_state, tip, verification_progress,
253 }));
254 m_event_handlers.emplace_back(m_node.handleNotifyHeaderTip(
255 [this](SynchronizationState sync_state, interfaces::BlockTip tip,
256 bool presync) {
257 TipChanged(sync_state, tip, /*verification_progress=*/0.0,
260 }));
261}
262
266
267bool ClientModel::getProxyInfo(std::string &ip_port) const {
268 Proxy ipv4, ipv6;
269 if (m_node.getProxy((Network)1, ipv4) &&
270 m_node.getProxy((Network)2, ipv6)) {
271 ip_port = ipv4.proxy.ToStringAddrPort();
272 return true;
273 }
274 return false;
275}
ArgsManager gArgs
Definition args.cpp:39
int flags
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition args.h:239
fs::path GetBlocksDirPath() const
Get blocks directory path.
Definition args.cpp:299
Qt model providing information about connected 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
Definition clientmodel.h:96
int getHeaderTipHeight() const
std::atomic< int64_t > cachedBestHeaderTime
Definition clientmodel.h:88
interfaces::Node & m_node
Definition clientmodel.h:95
Mutex m_cached_tip_mutex
Definition clientmodel.h:91
PeerTableModel * getPeerTableModel()
std::atomic< int > cachedBestHeaderHeight
Definition clientmodel.h:87
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)
BlockSource getBlockSource() const
Returns the block source of the current importing/syncing state.
int getNumBlocks() const
int64_t getHeaderTipTime() const
QString formatClientStartupTime() const
ClientModel(interfaces::Node &node, OptionsModel *optionsModel, QObject *parent=nullptr)
void TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, SyncType synctype)
OptionsModel * optionsModel
Definition clientmodel.h:97
BanTableModel * banTableModel
Definition clientmodel.h:99
QThread *const m_thread
A thread to interact with m_node asynchronously.
BanTableModel * getBanTableModel()
void unsubscribeFromCoreSignals()
QString dataDir() const
std::atomic< int > m_cached_num_blocks
Definition clientmodel.h:89
OptionsModel * getOptionsModel()
QString formatFullVersion() const
PeerTableModel * peerTableModel
Definition clientmodel.h:98
bool getProxyInfo(std::string &ip_port) const
QString formatSubVersion() const
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes)
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:77
Top-level interface for a bitcoin node (bitcoind process).
Definition node.h:59
virtual std::unique_ptr< Handler > handleShowProgress(ShowProgressFn fn)=0
virtual bilingual_str getWarnings()=0
Get warnings.
virtual std::unique_ptr< Handler > handleNotifyAlertChanged(NotifyAlertChangedFn fn)=0
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(ConnectionDirection 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 std::unique_ptr< Handler > handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn 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.
virtual std::unique_ptr< Handler > handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn)=0
static SteadyClock::time_point g_last_block_tip_update_notification
static SteadyClock::time_point g_last_header_tip_update_notification
SyncType
Definition clientmodel.h:40
@ HEADER_PRESYNC
BlockSource
Definition clientmodel.h:34
std::string FormatFullVersion()
const Config & GetConfig()
Definition config.cpp:40
static constexpr auto MODEL_UPDATE_DELAY
A delay between model updates.
QString boostPathToQString(const fs::path &path)
Convert OS specific boost path to QString through UTF-8.
Definition guiutil.cpp:796
void ThreadRename(std::string &&)
Rename a thread both in terms of an internal (in-memory) name as well as its system thread name.
std::string userAgent(const Config &config)
Definition net.cpp:3261
Network
A network type.
Definition netaddress.h:37
ConnectionDirection
Definition netbase.h:37
NodeContext & m_node
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:273
#define LOCK(cs)
Definition sync.h:295
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition sync.h:343
int64_t GetStartupTime()
Definition system.cpp:119
#define EXCLUSIVE_LOCKS_REQUIRED(...)
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition validation.h:112