Back to home page

Bitcoin sources

 
 

    


0001 // Copyright (c) 2011-2013 The Bitcoin developers
0002 // Distributed under the MIT/X11 software license, see the accompanying
0003 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
0004 
0005 #include "clientmodel.h"
0006 
0007 #include "guiconstants.h"
0008 #include "peertablemodel.h"
0009 
0010 #include "alert.h"
0011 #include "chainparams.h"
0012 #include "checkpoints.h"
0013 #include "clientversion.h"
0014 #include "main.h"
0015 #include "net.h"
0016 #include "ui_interface.h"
0017 #include "util.h"
0018 
0019 #include <stdint.h>
0020 
0021 #include <QDateTime>
0022 #include <QDebug>
0023 #include <QTimer>
0024 
0025 static const int64_t nClientStartupTime = GetTime();
0026 
0027 ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
0028     QObject(parent),
0029     optionsModel(optionsModel),
0030     peerTableModel(0),
0031     cachedNumBlocks(0),
0032     cachedReindexing(0), cachedImporting(0),
0033     numBlocksAtStartup(-1), pollTimer(0)
0034 {
0035     peerTableModel = new PeerTableModel(this);
0036     pollTimer = new QTimer(this);
0037     connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
0038     pollTimer->start(MODEL_UPDATE_DELAY);
0039 
0040     subscribeToCoreSignals();
0041 }
0042 
0043 ClientModel::~ClientModel()
0044 {
0045     unsubscribeFromCoreSignals();
0046 }
0047 
0048 int ClientModel::getNumConnections(unsigned int flags) const
0049 {
0050     LOCK(cs_vNodes);
0051     if (flags == CONNECTIONS_ALL) // Shortcut if we want total
0052         return vNodes.size();
0053 
0054     int nNum = 0;
0055     BOOST_FOREACH(CNode* pnode, vNodes)
0056     if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
0057         nNum++;
0058 
0059     return nNum;
0060 }
0061 
0062 int ClientModel::getNumBlocks() const
0063 {
0064     LOCK(cs_main);
0065     return chainActive.Height();
0066 }
0067 
0068 int ClientModel::getNumBlocksAtStartup()
0069 {
0070     if (numBlocksAtStartup == -1) numBlocksAtStartup = getNumBlocks();
0071     return numBlocksAtStartup;
0072 }
0073 
0074 quint64 ClientModel::getTotalBytesRecv() const
0075 {
0076     return CNode::GetTotalBytesRecv();
0077 }
0078 
0079 quint64 ClientModel::getTotalBytesSent() const
0080 {
0081     return CNode::GetTotalBytesSent();
0082 }
0083 
0084 QDateTime ClientModel::getLastBlockDate() const
0085 {
0086     LOCK(cs_main);
0087     if (chainActive.Tip())
0088         return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime());
0089     else
0090         return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network
0091 }
0092 
0093 double ClientModel::getVerificationProgress() const
0094 {
0095     LOCK(cs_main);
0096     return Checkpoints::GuessVerificationProgress(chainActive.Tip());
0097 }
0098 
0099 void ClientModel::updateTimer()
0100 {
0101     // Get required lock upfront. This avoids the GUI from getting stuck on
0102     // periodical polls if the core is holding the locks for a longer time -
0103     // for example, during a wallet rescan.
0104     TRY_LOCK(cs_main, lockMain);
0105     if(!lockMain)
0106         return;
0107     // Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
0108     // Periodically check and update with a timer.
0109     int newNumBlocks = getNumBlocks();
0110 
0111     // check for changed number of blocks we have, number of blocks peers claim to have, reindexing state and importing state
0112     if (cachedNumBlocks != newNumBlocks ||
0113         cachedReindexing != fReindex || cachedImporting != fImporting)
0114     {
0115         cachedNumBlocks = newNumBlocks;
0116         cachedReindexing = fReindex;
0117         cachedImporting = fImporting;
0118 
0119         emit numBlocksChanged(newNumBlocks);
0120     }
0121 
0122     emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
0123 }
0124 
0125 void ClientModel::updateNumConnections(int numConnections)
0126 {
0127     emit numConnectionsChanged(numConnections);
0128 }
0129 
0130 void ClientModel::updateAlert(const QString &hash, int status)
0131 {
0132     // Show error message notification for new alert
0133     if(status == CT_NEW)
0134     {
0135         uint256 hash_256;
0136         hash_256.SetHex(hash.toStdString());
0137         CAlert alert = CAlert::getAlertByHash(hash_256);
0138         if(!alert.IsNull())
0139         {
0140             emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR);
0141         }
0142     }
0143 
0144     emit alertsChanged(getStatusBarWarnings());
0145 }
0146 
0147 bool ClientModel::inInitialBlockDownload() const
0148 {
0149     return IsInitialBlockDownload();
0150 }
0151 
0152 enum BlockSource ClientModel::getBlockSource() const
0153 {
0154     if (fReindex)
0155         return BLOCK_SOURCE_REINDEX;
0156     else if (fImporting)
0157         return BLOCK_SOURCE_DISK;
0158     else if (getNumConnections() > 0)
0159         return BLOCK_SOURCE_NETWORK;
0160 
0161     return BLOCK_SOURCE_NONE;
0162 }
0163 
0164 QString ClientModel::getStatusBarWarnings() const
0165 {
0166     return QString::fromStdString(GetWarnings("statusbar"));
0167 }
0168 
0169 OptionsModel *ClientModel::getOptionsModel()
0170 {
0171     return optionsModel;
0172 }
0173 
0174 PeerTableModel *ClientModel::getPeerTableModel()
0175 {
0176     return peerTableModel;
0177 }
0178 
0179 QString ClientModel::formatFullVersion() const
0180 {
0181     return QString::fromStdString(FormatFullVersion());
0182 }
0183 
0184 QString ClientModel::formatBuildDate() const
0185 {
0186     return QString::fromStdString(CLIENT_DATE);
0187 }
0188 
0189 bool ClientModel::isReleaseVersion() const
0190 {
0191     return CLIENT_VERSION_IS_RELEASE;
0192 }
0193 
0194 QString ClientModel::clientName() const
0195 {
0196     return QString::fromStdString(CLIENT_NAME);
0197 }
0198 
0199 QString ClientModel::formatClientStartupTime() const
0200 {
0201     return QDateTime::fromTime_t(nClientStartupTime).toString();
0202 }
0203 
0204 // Handlers for core signals
0205 static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
0206 {
0207     // emits signal "showProgress"
0208     QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
0209                               Q_ARG(QString, QString::fromStdString(title)),
0210                               Q_ARG(int, nProgress));
0211 }
0212 
0213 static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
0214 {
0215     // Too noisy: qDebug() << "NotifyNumConnectionsChanged : " + QString::number(newNumConnections);
0216     QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
0217                               Q_ARG(int, newNumConnections));
0218 }
0219 
0220 static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status)
0221 {
0222     qDebug() << "NotifyAlertChanged : " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status);
0223     QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection,
0224                               Q_ARG(QString, QString::fromStdString(hash.GetHex())),
0225                               Q_ARG(int, status));
0226 }
0227 
0228 void ClientModel::subscribeToCoreSignals()
0229 {
0230     // Connect signals to client
0231     uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
0232     uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
0233     uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2));
0234 }
0235 
0236 void ClientModel::unsubscribeFromCoreSignals()
0237 {
0238     // Disconnect signals from client
0239     uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
0240     uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
0241     uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2));
0242 }