Line data Source code
1 : // Copyright (c) 2011-2013 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 "clientmodel.h"
6 :
7 : #include "bantablemodel.h"
8 : #include "guiconstants.h"
9 : #include "peertablemodel.h"
10 :
11 : #include "alert.h"
12 : #include "chainparams.h"
13 : #include "checkpoints.h"
14 : #include "clientversion.h"
15 : #include "net.h"
16 : #include "ui_interface.h"
17 : #include "util.h"
18 :
19 : #include <stdint.h>
20 :
21 : #include <QDebug>
22 : #include <QTimer>
23 :
24 0 : static const int64_t nClientStartupTime = GetTime();
25 :
26 0 : ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
27 : QObject(parent),
28 : optionsModel(optionsModel),
29 : peerTableModel(0),
30 : banTableModel(0),
31 : cachedNumBlocks(0),
32 : cachedBlockDate(QDateTime()),
33 : cachedReindexing(0),
34 : cachedImporting(0),
35 0 : pollTimer(0)
36 : {
37 0 : peerTableModel = new PeerTableModel(this);
38 0 : banTableModel = new BanTableModel(this);
39 0 : pollTimer = new QTimer(this);
40 0 : connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
41 0 : pollTimer->start(MODEL_UPDATE_DELAY);
42 :
43 0 : subscribeToCoreSignals();
44 0 : }
45 :
46 0 : ClientModel::~ClientModel()
47 : {
48 0 : unsubscribeFromCoreSignals();
49 0 : }
50 :
51 0 : int ClientModel::getNumConnections(unsigned int flags) const
52 : {
53 0 : LOCK(cs_vNodes);
54 0 : if (flags == CONNECTIONS_ALL) // Shortcut if we want total
55 0 : return vNodes.size();
56 :
57 0 : int nNum = 0;
58 0 : BOOST_FOREACH(const CNode* pnode, vNodes)
59 0 : if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
60 0 : nNum++;
61 :
62 0 : return nNum;
63 : }
64 :
65 0 : int ClientModel::getNumBlocks() const
66 : {
67 0 : LOCK(cs_main);
68 0 : return chainActive.Height();
69 : }
70 :
71 0 : quint64 ClientModel::getTotalBytesRecv() const
72 : {
73 0 : return CNode::GetTotalBytesRecv();
74 : }
75 :
76 0 : quint64 ClientModel::getTotalBytesSent() const
77 : {
78 0 : return CNode::GetTotalBytesSent();
79 : }
80 :
81 0 : QDateTime ClientModel::getLastBlockDate() const
82 : {
83 0 : LOCK(cs_main);
84 :
85 0 : if (chainActive.Tip())
86 0 : return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime());
87 :
88 0 : return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network
89 : }
90 :
91 0 : double ClientModel::getVerificationProgress() const
92 : {
93 0 : LOCK(cs_main);
94 0 : return Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip());
95 : }
96 :
97 0 : void ClientModel::updateTimer()
98 : {
99 : // Get required lock upfront. This avoids the GUI from getting stuck on
100 : // periodical polls if the core is holding the locks for a longer time -
101 : // for example, during a wallet rescan.
102 0 : TRY_LOCK(cs_main, lockMain);
103 0 : if (!lockMain)
104 0 : return;
105 :
106 : // Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
107 : // Periodically check and update with a timer.
108 0 : int newNumBlocks = getNumBlocks();
109 0 : QDateTime newBlockDate = getLastBlockDate();
110 :
111 : // check for changed number of blocks we have, number of blocks peers claim to have, reindexing state and importing state
112 0 : if (cachedNumBlocks != newNumBlocks ||
113 0 : cachedBlockDate != newBlockDate ||
114 0 : cachedReindexing != fReindex ||
115 0 : cachedImporting != fImporting)
116 : {
117 0 : cachedNumBlocks = newNumBlocks;
118 0 : cachedBlockDate = newBlockDate;
119 0 : cachedReindexing = fReindex;
120 0 : cachedImporting = fImporting;
121 :
122 0 : Q_EMIT numBlocksChanged(newNumBlocks, newBlockDate);
123 : }
124 :
125 0 : Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
126 : }
127 :
128 0 : void ClientModel::updateNumConnections(int numConnections)
129 : {
130 0 : Q_EMIT numConnectionsChanged(numConnections);
131 0 : }
132 :
133 0 : void ClientModel::updateAlert(const QString &hash, int status)
134 : {
135 : // Show error message notification for new alert
136 0 : if(status == CT_NEW)
137 : {
138 : uint256 hash_256;
139 0 : hash_256.SetHex(hash.toStdString());
140 0 : CAlert alert = CAlert::getAlertByHash(hash_256);
141 0 : if(!alert.IsNull())
142 : {
143 0 : Q_EMIT message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR);
144 0 : }
145 : }
146 :
147 0 : Q_EMIT alertsChanged(getStatusBarWarnings());
148 0 : }
149 :
150 0 : bool ClientModel::inInitialBlockDownload() const
151 : {
152 0 : return IsInitialBlockDownload();
153 : }
154 :
155 0 : enum BlockSource ClientModel::getBlockSource() const
156 : {
157 0 : if (fReindex)
158 : return BLOCK_SOURCE_REINDEX;
159 0 : else if (fImporting)
160 : return BLOCK_SOURCE_DISK;
161 0 : else if (getNumConnections() > 0)
162 : return BLOCK_SOURCE_NETWORK;
163 :
164 0 : return BLOCK_SOURCE_NONE;
165 : }
166 :
167 0 : QString ClientModel::getStatusBarWarnings() const
168 : {
169 0 : return QString::fromStdString(GetWarnings("statusbar"));
170 : }
171 :
172 0 : OptionsModel *ClientModel::getOptionsModel()
173 : {
174 0 : return optionsModel;
175 : }
176 :
177 0 : PeerTableModel *ClientModel::getPeerTableModel()
178 : {
179 0 : return peerTableModel;
180 : }
181 :
182 0 : BanTableModel *ClientModel::getBanTableModel()
183 : {
184 0 : return banTableModel;
185 : }
186 :
187 0 : QString ClientModel::formatFullVersion() const
188 : {
189 0 : return QString::fromStdString(FormatFullVersion());
190 : }
191 :
192 0 : QString ClientModel::formatSubVersion() const
193 : {
194 0 : return QString::fromStdString(strSubVersion);
195 : }
196 :
197 0 : QString ClientModel::formatBuildDate() const
198 : {
199 0 : return QString::fromStdString(CLIENT_DATE);
200 : }
201 :
202 0 : bool ClientModel::isReleaseVersion() const
203 : {
204 0 : return CLIENT_VERSION_IS_RELEASE;
205 : }
206 :
207 0 : QString ClientModel::clientName() const
208 : {
209 0 : return QString::fromStdString(CLIENT_NAME);
210 : }
211 :
212 0 : QString ClientModel::formatClientStartupTime() const
213 : {
214 0 : return QDateTime::fromTime_t(nClientStartupTime).toString();
215 : }
216 :
217 0 : void ClientModel::updateBanlist()
218 : {
219 0 : banTableModel->refresh();
220 0 : }
221 :
222 : // Handlers for core signals
223 0 : static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
224 : {
225 : // emits signal "showProgress"
226 : QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
227 : Q_ARG(QString, QString::fromStdString(title)),
228 0 : Q_ARG(int, nProgress));
229 0 : }
230 :
231 0 : static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
232 : {
233 : // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections);
234 : QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
235 : Q_ARG(int, newNumConnections));
236 0 : }
237 :
238 0 : static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status)
239 : {
240 0 : qDebug() << "NotifyAlertChanged: " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status);
241 : QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection,
242 : Q_ARG(QString, QString::fromStdString(hash.GetHex())),
243 0 : Q_ARG(int, status));
244 0 : }
245 :
246 0 : static void BannedListChanged(ClientModel *clientmodel)
247 : {
248 0 : qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__);
249 : QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
250 0 : }
251 :
252 0 : void ClientModel::subscribeToCoreSignals()
253 : {
254 : // Connect signals to client
255 0 : uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
256 0 : uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
257 0 : uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2));
258 0 : uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
259 0 : }
260 :
261 0 : void ClientModel::unsubscribeFromCoreSignals()
262 : {
263 : // Disconnect signals from client
264 0 : uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
265 0 : uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
266 0 : uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2));
267 0 : uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this));
268 0 : }
|