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"
12 #include "chainparams.h"
13 #include "checkpoints.h"
14 #include "clientversion.h"
15 #include "validation.h"
17 #include "txmempool.h"
18 #include "ui_interface.h"
28 static const int64_t nClientStartupTime
= GetTime();
29 static int64_t nLastHeaderTipUpdateNotification
= 0;
30 static int64_t nLastBlockTipUpdateNotification
= 0;
32 ClientModel::ClientModel(OptionsModel
*_optionsModel
, QObject
*parent
) :
34 optionsModel(_optionsModel
),
39 peerTableModel
= new PeerTableModel(this);
40 banTableModel
= new BanTableModel(this);
41 pollTimer
= new QTimer(this);
42 connect(pollTimer
, SIGNAL(timeout()), this, SLOT(updateTimer()));
43 pollTimer
->start(MODEL_UPDATE_DELAY
);
45 subscribeToCoreSignals();
48 ClientModel::~ClientModel()
50 unsubscribeFromCoreSignals();
53 int ClientModel::getNumConnections(unsigned int flags
) const
55 CConnman::NumConnections connections
= CConnman::CONNECTIONS_NONE
;
57 if(flags
== CONNECTIONS_IN
)
58 connections
= CConnman::CONNECTIONS_IN
;
59 else if (flags
== CONNECTIONS_OUT
)
60 connections
= CConnman::CONNECTIONS_OUT
;
61 else if (flags
== CONNECTIONS_ALL
)
62 connections
= CConnman::CONNECTIONS_ALL
;
65 return g_connman
->GetNodeCount(connections
);
69 int ClientModel::getNumBlocks() const
72 return chainActive
.Height();
75 int ClientModel::getHeaderTipHeight() const
78 if (!pindexBestHeader
)
80 return pindexBestHeader
->nHeight
;
83 int64_t ClientModel::getHeaderTipTime() const
86 if (!pindexBestHeader
)
88 return pindexBestHeader
->GetBlockTime();
91 quint64
ClientModel::getTotalBytesRecv() const
95 return g_connman
->GetTotalBytesRecv();
98 quint64
ClientModel::getTotalBytesSent() const
102 return g_connman
->GetTotalBytesSent();
105 QDateTime
ClientModel::getLastBlockDate() const
109 if (chainActive
.Tip())
110 return QDateTime::fromTime_t(chainActive
.Tip()->GetBlockTime());
112 return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network
115 long ClientModel::getMempoolSize() const
117 return mempool
.size();
120 size_t ClientModel::getMempoolDynamicUsage() const
122 return mempool
.DynamicMemoryUsage();
125 double ClientModel::getVerificationProgress(const CBlockIndex
*tipIn
) const
127 CBlockIndex
*tip
= const_cast<CBlockIndex
*>(tipIn
);
131 tip
= chainActive
.Tip();
133 return GuessVerificationProgress(Params().TxData(), tip
);
136 void ClientModel::updateTimer()
138 // no locking required at this point
139 // the following calls will acquire the required lock
140 Q_EMIT
mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage());
141 Q_EMIT
bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
144 void ClientModel::updateNumConnections(int numConnections
)
146 Q_EMIT
numConnectionsChanged(numConnections
);
149 void ClientModel::updateNetworkActive(bool networkActive
)
151 Q_EMIT
networkActiveChanged(networkActive
);
154 void ClientModel::updateAlert()
156 Q_EMIT
alertsChanged(getStatusBarWarnings());
159 bool ClientModel::inInitialBlockDownload() const
161 return IsInitialBlockDownload();
164 enum BlockSource
ClientModel::getBlockSource() const
167 return BLOCK_SOURCE_REINDEX
;
169 return BLOCK_SOURCE_DISK
;
170 else if (getNumConnections() > 0)
171 return BLOCK_SOURCE_NETWORK
;
173 return BLOCK_SOURCE_NONE
;
176 void ClientModel::setNetworkActive(bool active
)
179 g_connman
->SetNetworkActive(active
);
183 bool ClientModel::getNetworkActive() const
186 return g_connman
->GetNetworkActive();
191 QString
ClientModel::getStatusBarWarnings() const
193 return QString::fromStdString(GetWarnings("gui"));
196 OptionsModel
*ClientModel::getOptionsModel()
201 PeerTableModel
*ClientModel::getPeerTableModel()
203 return peerTableModel
;
206 BanTableModel
*ClientModel::getBanTableModel()
208 return banTableModel
;
211 QString
ClientModel::formatFullVersion() const
213 return QString::fromStdString(FormatFullVersion());
216 QString
ClientModel::formatSubVersion() const
218 return QString::fromStdString(strSubVersion
);
221 bool ClientModel::isReleaseVersion() const
223 return CLIENT_VERSION_IS_RELEASE
;
226 QString
ClientModel::formatClientStartupTime() const
228 return QDateTime::fromTime_t(nClientStartupTime
).toString();
231 QString
ClientModel::dataDir() const
233 return GUIUtil::boostPathToQString(GetDataDir());
236 void ClientModel::updateBanlist()
238 banTableModel
->refresh();
241 // Handlers for core signals
242 static void ShowProgress(ClientModel
*clientmodel
, const std::string
&title
, int nProgress
)
244 // emits signal "showProgress"
245 QMetaObject::invokeMethod(clientmodel
, "showProgress", Qt::QueuedConnection
,
246 Q_ARG(QString
, QString::fromStdString(title
)),
247 Q_ARG(int, nProgress
));
250 static void NotifyNumConnectionsChanged(ClientModel
*clientmodel
, int newNumConnections
)
252 // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections);
253 QMetaObject::invokeMethod(clientmodel
, "updateNumConnections", Qt::QueuedConnection
,
254 Q_ARG(int, newNumConnections
));
257 static void NotifyNetworkActiveChanged(ClientModel
*clientmodel
, bool networkActive
)
259 QMetaObject::invokeMethod(clientmodel
, "updateNetworkActive", Qt::QueuedConnection
,
260 Q_ARG(bool, networkActive
));
263 static void NotifyAlertChanged(ClientModel
*clientmodel
)
265 qDebug() << "NotifyAlertChanged";
266 QMetaObject::invokeMethod(clientmodel
, "updateAlert", Qt::QueuedConnection
);
269 static void BannedListChanged(ClientModel
*clientmodel
)
271 qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__
);
272 QMetaObject::invokeMethod(clientmodel
, "updateBanlist", Qt::QueuedConnection
);
275 static void BlockTipChanged(ClientModel
*clientmodel
, bool initialSync
, const CBlockIndex
*pIndex
, bool fHeader
)
277 // lock free async UI updates in case we have a new block tip
278 // during initial sync, only update the UI if the last update
279 // was > 250ms (MODEL_UPDATE_DELAY) ago
282 now
= GetTimeMillis();
284 int64_t& nLastUpdateNotification
= fHeader
? nLastHeaderTipUpdateNotification
: nLastBlockTipUpdateNotification
;
286 // if we are in-sync, update the UI regardless of last update time
287 if (!initialSync
|| now
- nLastUpdateNotification
> MODEL_UPDATE_DELAY
) {
288 //pass a async signal to the UI thread
289 QMetaObject::invokeMethod(clientmodel
, "numBlocksChanged", Qt::QueuedConnection
,
290 Q_ARG(int, pIndex
->nHeight
),
291 Q_ARG(QDateTime
, QDateTime::fromTime_t(pIndex
->GetBlockTime())),
292 Q_ARG(double, clientmodel
->getVerificationProgress(pIndex
)),
293 Q_ARG(bool, fHeader
));
294 nLastUpdateNotification
= now
;
298 void ClientModel::subscribeToCoreSignals()
300 // Connect signals to client
301 uiInterface
.ShowProgress
.connect(boost::bind(ShowProgress
, this, _1
, _2
));
302 uiInterface
.NotifyNumConnectionsChanged
.connect(boost::bind(NotifyNumConnectionsChanged
, this, _1
));
303 uiInterface
.NotifyNetworkActiveChanged
.connect(boost::bind(NotifyNetworkActiveChanged
, this, _1
));
304 uiInterface
.NotifyAlertChanged
.connect(boost::bind(NotifyAlertChanged
, this));
305 uiInterface
.BannedListChanged
.connect(boost::bind(BannedListChanged
, this));
306 uiInterface
.NotifyBlockTip
.connect(boost::bind(BlockTipChanged
, this, _1
, _2
, false));
307 uiInterface
.NotifyHeaderTip
.connect(boost::bind(BlockTipChanged
, this, _1
, _2
, true));
310 void ClientModel::unsubscribeFromCoreSignals()
312 // Disconnect signals from client
313 uiInterface
.ShowProgress
.disconnect(boost::bind(ShowProgress
, this, _1
, _2
));
314 uiInterface
.NotifyNumConnectionsChanged
.disconnect(boost::bind(NotifyNumConnectionsChanged
, this, _1
));
315 uiInterface
.NotifyNetworkActiveChanged
.disconnect(boost::bind(NotifyNetworkActiveChanged
, this, _1
));
316 uiInterface
.NotifyAlertChanged
.disconnect(boost::bind(NotifyAlertChanged
, this));
317 uiInterface
.BannedListChanged
.disconnect(boost::bind(BannedListChanged
, this));
318 uiInterface
.NotifyBlockTip
.disconnect(boost::bind(BlockTipChanged
, this, _1
, _2
, false));
319 uiInterface
.NotifyHeaderTip
.disconnect(boost::bind(BlockTipChanged
, this, _1
, _2
, true));