Bitcoin ABC 0.32.4
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 <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
71 stop();
72}
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
115 if (m_cached_num_blocks == -1) {
117 }
118 return m_cached_num_blocks;
119}
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
158 return optionsModel;
159}
160
162 return peerTableModel;
163}
164
166 return banTableModel;
167}
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
185QString ClientModel::dataDir() const {
187}
188
189QString ClientModel::blocksDir() const {
191}
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,
252 SyncType::BLOCK_SYNC);
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,
258 presync ? SyncType::HEADER_PRESYNC
259 : SyncType::HEADER_SYNC);
260 }));
261}
262
264 m_event_handlers.clear();
265}
266
267bool ClientModel::getProxyInfo(std::string &ip_port) const {
268 proxyType ipv4, ipv6;
269 if (m_node.getProxy((Network)1, ipv4) &&
270 m_node.getProxy((Network)2, ipv6)) {
271 ip_port = ipv4.proxy.ToStringIPPort();
272 return true;
273 }
274 return false;
275}
ArgsManager gArgs
Definition: args.cpp:40
int flags
Definition: bitcoin-tx.cpp:542
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:300
Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call.
Definition: bantablemodel.h:42
std::string ToStringIPPort() 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
Definition: clientmodel.cpp:88
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)
Definition: clientmodel.cpp:74
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)
Definition: clientmodel.cpp:33
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.
Definition: clientmodel.h:102
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.
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: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 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(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 int getNumBlocks()=0
Get num blocks.
virtual std::unique_ptr< Handler > handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn)=0
CService proxy
Definition: netbase.h:60
static SteadyClock::time_point g_last_block_tip_update_notification
Definition: clientmodel.cpp:31
static SteadyClock::time_point g_last_header_tip_update_notification
Definition: clientmodel.cpp:30
SyncType
Definition: clientmodel.h:40
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.
Definition: guiconstants.h:14
QString boostPathToQString(const fs::path &path)
Convert OS specific boost path to QString through UTF-8.
Definition: guiutil.cpp:791
Definition: init.h:31
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:3137
Network
A network type.
Definition: netaddress.h:44
ConnectionDirection
Definition: netbase.h:32
NodeContext & m_node
Definition: interfaces.cpp:822
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:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
int64_t GetStartupTime()
Definition: system.cpp:117
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:119