LCOV - code coverage report
Current view: top level - src/qt - clientmodel.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 0 190 0.0 %
Date: 2020-09-26 01:30:44 Functions: 0 38 0.0 %

          Line data    Source code
       1             : // Copyright (c) 2011-2020 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 <qt/bantablemodel.h>
       8             : #include <qt/guiconstants.h>
       9             : #include <qt/guiutil.h>
      10             : #include <qt/peertablemodel.h>
      11             : 
      12             : #include <clientversion.h>
      13             : #include <interfaces/handler.h>
      14             : #include <interfaces/node.h>
      15             : #include <net.h>
      16             : #include <netbase.h>
      17             : #include <util/system.h>
      18             : #include <validation.h>
      19             : 
      20             : #include <stdint.h>
      21             : 
      22             : #include <QDebug>
      23             : #include <QThread>
      24             : #include <QTimer>
      25             : 
      26             : static int64_t nLastHeaderTipUpdateNotification = 0;
      27             : static int64_t nLastBlockTipUpdateNotification = 0;
      28             : 
      29           0 : ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QObject *parent) :
      30           0 :     QObject(parent),
      31           0 :     m_node(node),
      32           0 :     optionsModel(_optionsModel),
      33           0 :     peerTableModel(nullptr),
      34           0 :     banTableModel(nullptr),
      35           0 :     m_thread(new QThread(this))
      36           0 : {
      37           0 :     cachedBestHeaderHeight = -1;
      38           0 :     cachedBestHeaderTime = -1;
      39           0 :     peerTableModel = new PeerTableModel(m_node, this);
      40           0 :     banTableModel = new BanTableModel(m_node, this);
      41             : 
      42           0 :     QTimer* timer = new QTimer;
      43           0 :     timer->setInterval(MODEL_UPDATE_DELAY);
      44           0 :     connect(timer, &QTimer::timeout, [this] {
      45             :         // no locking required at this point
      46             :         // the following calls will acquire the required lock
      47           0 :         Q_EMIT mempoolSizeChanged(m_node.getMempoolSize(), m_node.getMempoolDynamicUsage());
      48           0 :         Q_EMIT bytesChanged(m_node.getTotalBytesRecv(), m_node.getTotalBytesSent());
      49           0 :     });
      50           0 :     connect(m_thread, &QThread::finished, timer, &QObject::deleteLater);
      51           0 :     connect(m_thread, &QThread::started, [timer] { timer->start(); });
      52             :     // move timer to thread so that polling doesn't disturb main event loop
      53           0 :     timer->moveToThread(m_thread);
      54           0 :     m_thread->start();
      55             : 
      56           0 :     subscribeToCoreSignals();
      57           0 : }
      58             : 
      59           0 : ClientModel::~ClientModel()
      60           0 : {
      61           0 :     unsubscribeFromCoreSignals();
      62             : 
      63           0 :     m_thread->quit();
      64           0 :     m_thread->wait();
      65           0 : }
      66             : 
      67           0 : int ClientModel::getNumConnections(unsigned int flags) const
      68             : {
      69             :     CConnman::NumConnections connections = CConnman::CONNECTIONS_NONE;
      70             : 
      71           0 :     if(flags == CONNECTIONS_IN)
      72           0 :         connections = CConnman::CONNECTIONS_IN;
      73           0 :     else if (flags == CONNECTIONS_OUT)
      74           0 :         connections = CConnman::CONNECTIONS_OUT;
      75           0 :     else if (flags == CONNECTIONS_ALL)
      76           0 :         connections = CConnman::CONNECTIONS_ALL;
      77             : 
      78           0 :     return m_node.getNodeCount(connections);
      79             : }
      80             : 
      81           0 : int ClientModel::getHeaderTipHeight() const
      82             : {
      83           0 :     if (cachedBestHeaderHeight == -1) {
      84             :         // make sure we initially populate the cache via a cs_main lock
      85             :         // otherwise we need to wait for a tip update
      86           0 :         int height;
      87           0 :         int64_t blockTime;
      88           0 :         if (m_node.getHeaderTip(height, blockTime)) {
      89           0 :             cachedBestHeaderHeight = height;
      90           0 :             cachedBestHeaderTime = blockTime;
      91           0 :         }
      92           0 :     }
      93           0 :     return cachedBestHeaderHeight;
      94             : }
      95             : 
      96           0 : int64_t ClientModel::getHeaderTipTime() const
      97             : {
      98           0 :     if (cachedBestHeaderTime == -1) {
      99           0 :         int height;
     100           0 :         int64_t blockTime;
     101           0 :         if (m_node.getHeaderTip(height, blockTime)) {
     102           0 :             cachedBestHeaderHeight = height;
     103           0 :             cachedBestHeaderTime = blockTime;
     104           0 :         }
     105           0 :     }
     106           0 :     return cachedBestHeaderTime;
     107             : }
     108             : 
     109           0 : int ClientModel::getNumBlocks() const
     110             : {
     111           0 :     if (m_cached_num_blocks == -1) {
     112           0 :         m_cached_num_blocks = m_node.getNumBlocks();
     113           0 :     }
     114           0 :     return m_cached_num_blocks;
     115             : }
     116             : 
     117           0 : uint256 ClientModel::getBestBlockHash()
     118             : {
     119           0 :     uint256 tip{WITH_LOCK(m_cached_tip_mutex, return m_cached_tip_blocks)};
     120             : 
     121           0 :     if (!tip.IsNull()) {
     122           0 :         return tip;
     123             :     }
     124             : 
     125             :     // Lock order must be: first `cs_main`, then `m_cached_tip_mutex`.
     126             :     // The following will lock `cs_main` (and release it), so we must not
     127             :     // own `m_cached_tip_mutex` here.
     128           0 :     tip = m_node.getBestBlockHash();
     129             : 
     130           0 :     LOCK(m_cached_tip_mutex);
     131             :     // We checked that `m_cached_tip_blocks` is not null above, but then we
     132             :     // released the mutex `m_cached_tip_mutex`, so it could have changed in the
     133             :     // meantime. Thus, check again.
     134           0 :     if (m_cached_tip_blocks.IsNull()) {
     135           0 :         m_cached_tip_blocks = tip;
     136           0 :     }
     137           0 :     return m_cached_tip_blocks;
     138           0 : }
     139             : 
     140           0 : void ClientModel::updateNumConnections(int numConnections)
     141             : {
     142           0 :     Q_EMIT numConnectionsChanged(numConnections);
     143           0 : }
     144             : 
     145           0 : void ClientModel::updateNetworkActive(bool networkActive)
     146             : {
     147           0 :     Q_EMIT networkActiveChanged(networkActive);
     148           0 : }
     149             : 
     150           0 : void ClientModel::updateAlert()
     151             : {
     152           0 :     Q_EMIT alertsChanged(getStatusBarWarnings());
     153           0 : }
     154             : 
     155           0 : enum BlockSource ClientModel::getBlockSource() const
     156             : {
     157           0 :     if (m_node.getReindex())
     158           0 :         return BlockSource::REINDEX;
     159           0 :     else if (m_node.getImporting())
     160           0 :         return BlockSource::DISK;
     161           0 :     else if (getNumConnections() > 0)
     162           0 :         return BlockSource::NETWORK;
     163             : 
     164           0 :     return BlockSource::NONE;
     165           0 : }
     166             : 
     167           0 : QString ClientModel::getStatusBarWarnings() const
     168             : {
     169           0 :     return QString::fromStdString(m_node.getWarnings().translated);
     170           0 : }
     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           0 : }
     191             : 
     192           0 : QString ClientModel::formatSubVersion() const
     193             : {
     194           0 :     return QString::fromStdString(strSubVersion);
     195             : }
     196             : 
     197           0 : bool ClientModel::isReleaseVersion() const
     198             : {
     199           0 :     return CLIENT_VERSION_IS_RELEASE;
     200             : }
     201             : 
     202           0 : QString ClientModel::formatClientStartupTime() const
     203             : {
     204           0 :     return QDateTime::fromTime_t(GetStartupTime()).toString();
     205           0 : }
     206             : 
     207           0 : QString ClientModel::dataDir() const
     208             : {
     209           0 :     return GUIUtil::boostPathToQString(GetDataDir());
     210             : }
     211             : 
     212           0 : QString ClientModel::blocksDir() const
     213             : {
     214           0 :     return GUIUtil::boostPathToQString(GetBlocksDir());
     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           0 :     bool invoked = QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
     227           0 :                               Q_ARG(QString, QString::fromStdString(title)),
     228           0 :                               Q_ARG(int, nProgress));
     229           0 :     assert(invoked);
     230           0 : }
     231             : 
     232           0 : static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
     233             : {
     234             :     // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections);
     235           0 :     bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
     236           0 :                               Q_ARG(int, newNumConnections));
     237           0 :     assert(invoked);
     238           0 : }
     239             : 
     240           0 : static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkActive)
     241             : {
     242           0 :     bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNetworkActive", Qt::QueuedConnection,
     243           0 :                               Q_ARG(bool, networkActive));
     244           0 :     assert(invoked);
     245           0 : }
     246             : 
     247           0 : static void NotifyAlertChanged(ClientModel *clientmodel)
     248             : {
     249           0 :     qDebug() << "NotifyAlertChanged";
     250           0 :     bool invoked = QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
     251           0 :     assert(invoked);
     252           0 : }
     253             : 
     254           0 : static void BannedListChanged(ClientModel *clientmodel)
     255             : {
     256           0 :     qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__);
     257           0 :     bool invoked = QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
     258           0 :     assert(invoked);
     259           0 : }
     260             : 
     261           0 : static void BlockTipChanged(ClientModel* clientmodel, SynchronizationState sync_state, interfaces::BlockTip tip, double verificationProgress, bool fHeader)
     262             : {
     263           0 :     if (fHeader) {
     264             :         // cache best headers time and height to reduce future cs_main locks
     265           0 :         clientmodel->cachedBestHeaderHeight = tip.block_height;
     266           0 :         clientmodel->cachedBestHeaderTime = tip.block_time;
     267           0 :     } else {
     268           0 :         clientmodel->m_cached_num_blocks = tip.block_height;
     269           0 :         WITH_LOCK(clientmodel->m_cached_tip_mutex, clientmodel->m_cached_tip_blocks = tip.block_hash;);
     270             :     }
     271             : 
     272             :     // Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex.
     273           0 :     const bool throttle = (sync_state != SynchronizationState::POST_INIT && !fHeader) || sync_state == SynchronizationState::INIT_REINDEX;
     274           0 :     const int64_t now = throttle ? GetTimeMillis() : 0;
     275           0 :     int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
     276           0 :     if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
     277           0 :         return;
     278             :     }
     279             : 
     280           0 :     bool invoked = QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
     281           0 :         Q_ARG(int, tip.block_height),
     282           0 :         Q_ARG(QDateTime, QDateTime::fromTime_t(tip.block_time)),
     283           0 :         Q_ARG(double, verificationProgress),
     284           0 :         Q_ARG(bool, fHeader),
     285           0 :         Q_ARG(SynchronizationState, sync_state));
     286           0 :     assert(invoked);
     287           0 :     nLastUpdateNotification = now;
     288           0 : }
     289             : 
     290           0 : void ClientModel::subscribeToCoreSignals()
     291             : {
     292             :     // Connect signals to client
     293           0 :     m_handler_show_progress = m_node.handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
     294           0 :     m_handler_notify_num_connections_changed = m_node.handleNotifyNumConnectionsChanged(std::bind(NotifyNumConnectionsChanged, this, std::placeholders::_1));
     295           0 :     m_handler_notify_network_active_changed = m_node.handleNotifyNetworkActiveChanged(std::bind(NotifyNetworkActiveChanged, this, std::placeholders::_1));
     296           0 :     m_handler_notify_alert_changed = m_node.handleNotifyAlertChanged(std::bind(NotifyAlertChanged, this));
     297           0 :     m_handler_banned_list_changed = m_node.handleBannedListChanged(std::bind(BannedListChanged, this));
     298           0 :     m_handler_notify_block_tip = m_node.handleNotifyBlockTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, false));
     299           0 :     m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, true));
     300           0 : }
     301             : 
     302           0 : void ClientModel::unsubscribeFromCoreSignals()
     303             : {
     304             :     // Disconnect signals from client
     305           0 :     m_handler_show_progress->disconnect();
     306           0 :     m_handler_notify_num_connections_changed->disconnect();
     307           0 :     m_handler_notify_network_active_changed->disconnect();
     308           0 :     m_handler_notify_alert_changed->disconnect();
     309           0 :     m_handler_banned_list_changed->disconnect();
     310           0 :     m_handler_notify_block_tip->disconnect();
     311           0 :     m_handler_notify_header_tip->disconnect();
     312           0 : }
     313             : 
     314           0 : bool ClientModel::getProxyInfo(std::string& ip_port) const
     315             : {
     316           0 :     proxyType ipv4, ipv6;
     317           0 :     if (m_node.getProxy((Network) 1, ipv4) && m_node.getProxy((Network) 2, ipv6)) {
     318           0 :       ip_port = ipv4.proxy.ToStringIPPort();
     319           0 :       return true;
     320             :     }
     321           0 :     return false;
     322           0 : }

Generated by: LCOV version 1.15