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.
5 #include "clientmodel.h"
7 #include "bantablemodel.h"
8 #include "guiconstants.h"
10 #include "peertablemodel.h"
13 #include "chainparams.h"
14 #include "checkpoints.h"
15 #include "clientversion.h"
16 #include "validation.h"
18 #include "txmempool.h"
19 #include "ui_interface.h"
30 static int64_t nLastHeaderTipUpdateNotification
= 0;
31 static int64_t nLastBlockTipUpdateNotification
= 0;
33 ClientModel::ClientModel(OptionsModel
*_optionsModel
, QObject
*parent
) :
35 optionsModel(_optionsModel
),
40 cachedBestHeaderHeight
= -1;
41 cachedBestHeaderTime
= -1;
42 peerTableModel
= new PeerTableModel(this);
43 banTableModel
= new BanTableModel(this);
44 pollTimer
= new QTimer(this);
45 connect(pollTimer
, SIGNAL(timeout()), this, SLOT(updateTimer()));
46 pollTimer
->start(MODEL_UPDATE_DELAY
);
48 subscribeToCoreSignals();
51 ClientModel::~ClientModel()
53 unsubscribeFromCoreSignals();
56 int ClientModel::getNumConnections(unsigned int flags
) const
58 CConnman::NumConnections connections
= CConnman::CONNECTIONS_NONE
;
60 if(flags
== CONNECTIONS_IN
)
61 connections
= CConnman::CONNECTIONS_IN
;
62 else if (flags
== CONNECTIONS_OUT
)
63 connections
= CConnman::CONNECTIONS_OUT
;
64 else if (flags
== CONNECTIONS_ALL
)
65 connections
= CConnman::CONNECTIONS_ALL
;
68 return g_connman
->GetNodeCount(connections
);
72 int ClientModel::getNumBlocks() const
75 return chainActive
.Height();
78 int ClientModel::getHeaderTipHeight() const
80 if (cachedBestHeaderHeight
== -1) {
81 // make sure we initially populate the cache via a cs_main lock
82 // otherwise we need to wait for a tip update
84 if (pindexBestHeader
) {
85 cachedBestHeaderHeight
= pindexBestHeader
->nHeight
;
86 cachedBestHeaderTime
= pindexBestHeader
->GetBlockTime();
89 return cachedBestHeaderHeight
;
92 int64_t ClientModel::getHeaderTipTime() const
94 if (cachedBestHeaderTime
== -1) {
96 if (pindexBestHeader
) {
97 cachedBestHeaderHeight
= pindexBestHeader
->nHeight
;
98 cachedBestHeaderTime
= pindexBestHeader
->GetBlockTime();
101 return cachedBestHeaderTime
;
104 quint64
ClientModel::getTotalBytesRecv() const
108 return g_connman
->GetTotalBytesRecv();
111 quint64
ClientModel::getTotalBytesSent() const
115 return g_connman
->GetTotalBytesSent();
118 QDateTime
ClientModel::getLastBlockDate() const
122 if (chainActive
.Tip())
123 return QDateTime::fromTime_t(chainActive
.Tip()->GetBlockTime());
125 return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network
128 long ClientModel::getMempoolSize() const
130 return mempool
.size();
133 size_t ClientModel::getMempoolDynamicUsage() const
135 return mempool
.DynamicMemoryUsage();
138 double ClientModel::getVerificationProgress(const CBlockIndex
*tipIn
) const
140 CBlockIndex
*tip
= const_cast<CBlockIndex
*>(tipIn
);
144 tip
= chainActive
.Tip();
146 return GuessVerificationProgress(Params().TxData(), tip
);
149 void ClientModel::updateTimer()
151 // no locking required at this point
152 // the following calls will acquire the required lock
153 Q_EMIT
mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage());
154 Q_EMIT
bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
157 void ClientModel::updateNumConnections(int numConnections
)
159 Q_EMIT
numConnectionsChanged(numConnections
);
162 void ClientModel::updateNetworkActive(bool networkActive
)
164 Q_EMIT
networkActiveChanged(networkActive
);
167 void ClientModel::updateAlert()
169 Q_EMIT
alertsChanged(getStatusBarWarnings());
172 bool ClientModel::inInitialBlockDownload() const
174 return IsInitialBlockDownload();
177 enum BlockSource
ClientModel::getBlockSource() const
180 return BLOCK_SOURCE_REINDEX
;
182 return BLOCK_SOURCE_DISK
;
183 else if (getNumConnections() > 0)
184 return BLOCK_SOURCE_NETWORK
;
186 return BLOCK_SOURCE_NONE
;
189 void ClientModel::setNetworkActive(bool active
)
192 g_connman
->SetNetworkActive(active
);
196 bool ClientModel::getNetworkActive() const
199 return g_connman
->GetNetworkActive();
204 QString
ClientModel::getStatusBarWarnings() const
206 return QString::fromStdString(GetWarnings("gui"));
209 OptionsModel
*ClientModel::getOptionsModel()
214 PeerTableModel
*ClientModel::getPeerTableModel()
216 return peerTableModel
;
219 BanTableModel
*ClientModel::getBanTableModel()
221 return banTableModel
;
224 QString
ClientModel::formatFullVersion() const
226 return QString::fromStdString(FormatFullVersion());
229 QString
ClientModel::formatSubVersion() const
231 return QString::fromStdString(strSubVersion
);
234 bool ClientModel::isReleaseVersion() const
236 return CLIENT_VERSION_IS_RELEASE
;
239 QString
ClientModel::formatClientStartupTime() const
241 return QDateTime::fromTime_t(GetStartupTime()).toString();
244 QString
ClientModel::dataDir() const
246 return GUIUtil::boostPathToQString(GetDataDir());
249 void ClientModel::updateBanlist()
251 banTableModel
->refresh();
254 // Handlers for core signals
255 static void ShowProgress(ClientModel
*clientmodel
, const std::string
&title
, int nProgress
)
257 // emits signal "showProgress"
258 QMetaObject::invokeMethod(clientmodel
, "showProgress", Qt::QueuedConnection
,
259 Q_ARG(QString
, QString::fromStdString(title
)),
260 Q_ARG(int, nProgress
));
263 static void NotifyNumConnectionsChanged(ClientModel
*clientmodel
, int newNumConnections
)
265 // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections);
266 QMetaObject::invokeMethod(clientmodel
, "updateNumConnections", Qt::QueuedConnection
,
267 Q_ARG(int, newNumConnections
));
270 static void NotifyNetworkActiveChanged(ClientModel
*clientmodel
, bool networkActive
)
272 QMetaObject::invokeMethod(clientmodel
, "updateNetworkActive", Qt::QueuedConnection
,
273 Q_ARG(bool, networkActive
));
276 static void NotifyAlertChanged(ClientModel
*clientmodel
)
278 qDebug() << "NotifyAlertChanged";
279 QMetaObject::invokeMethod(clientmodel
, "updateAlert", Qt::QueuedConnection
);
282 static void BannedListChanged(ClientModel
*clientmodel
)
284 qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__
);
285 QMetaObject::invokeMethod(clientmodel
, "updateBanlist", Qt::QueuedConnection
);
288 static void BlockTipChanged(ClientModel
*clientmodel
, bool initialSync
, const CBlockIndex
*pIndex
, bool fHeader
)
290 // lock free async UI updates in case we have a new block tip
291 // during initial sync, only update the UI if the last update
292 // was > 250ms (MODEL_UPDATE_DELAY) ago
295 now
= GetTimeMillis();
297 int64_t& nLastUpdateNotification
= fHeader
? nLastHeaderTipUpdateNotification
: nLastBlockTipUpdateNotification
;
300 // cache best headers time and height to reduce future cs_main locks
301 clientmodel
->cachedBestHeaderHeight
= pIndex
->nHeight
;
302 clientmodel
->cachedBestHeaderTime
= pIndex
->GetBlockTime();
304 // if we are in-sync, update the UI regardless of last update time
305 if (!initialSync
|| now
- nLastUpdateNotification
> MODEL_UPDATE_DELAY
) {
306 //pass an async signal to the UI thread
307 QMetaObject::invokeMethod(clientmodel
, "numBlocksChanged", Qt::QueuedConnection
,
308 Q_ARG(int, pIndex
->nHeight
),
309 Q_ARG(QDateTime
, QDateTime::fromTime_t(pIndex
->GetBlockTime())),
310 Q_ARG(double, clientmodel
->getVerificationProgress(pIndex
)),
311 Q_ARG(bool, fHeader
));
312 nLastUpdateNotification
= now
;
316 void ClientModel::subscribeToCoreSignals()
318 // Connect signals to client
319 uiInterface
.ShowProgress
.connect(boost::bind(ShowProgress
, this, _1
, _2
));
320 uiInterface
.NotifyNumConnectionsChanged
.connect(boost::bind(NotifyNumConnectionsChanged
, this, _1
));
321 uiInterface
.NotifyNetworkActiveChanged
.connect(boost::bind(NotifyNetworkActiveChanged
, this, _1
));
322 uiInterface
.NotifyAlertChanged
.connect(boost::bind(NotifyAlertChanged
, this));
323 uiInterface
.BannedListChanged
.connect(boost::bind(BannedListChanged
, this));
324 uiInterface
.NotifyBlockTip
.connect(boost::bind(BlockTipChanged
, this, _1
, _2
, false));
325 uiInterface
.NotifyHeaderTip
.connect(boost::bind(BlockTipChanged
, this, _1
, _2
, true));
328 void ClientModel::unsubscribeFromCoreSignals()
330 // Disconnect signals from client
331 uiInterface
.ShowProgress
.disconnect(boost::bind(ShowProgress
, this, _1
, _2
));
332 uiInterface
.NotifyNumConnectionsChanged
.disconnect(boost::bind(NotifyNumConnectionsChanged
, this, _1
));
333 uiInterface
.NotifyNetworkActiveChanged
.disconnect(boost::bind(NotifyNetworkActiveChanged
, this, _1
));
334 uiInterface
.NotifyAlertChanged
.disconnect(boost::bind(NotifyAlertChanged
, this));
335 uiInterface
.BannedListChanged
.disconnect(boost::bind(BannedListChanged
, this));
336 uiInterface
.NotifyBlockTip
.disconnect(boost::bind(BlockTipChanged
, this, _1
, _2
, false));
337 uiInterface
.NotifyHeaderTip
.disconnect(boost::bind(BlockTipChanged
, this, _1
, _2
, true));