diff --git a/src/interfaces/node.h b/src/interfaces/node.h --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -14,7 +14,11 @@ #include #include #include +#include +#include +struct CNodeStateStats; +struct CNodeStats; class Config; class HTTPRPCRequestProcessor; class proxyType; @@ -84,6 +88,11 @@ //! Get number of connections. virtual size_t getNodeCount(CConnman::NumConnections flags) = 0; + //! Get stats for connected nodes. + using NodesStats = + std::vector>; + virtual bool getNodesStats(NodesStats &stats) = 0; + //! Get total bytes recv. virtual int64_t getTotalBytesRecv() = 0; diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,32 @@ size_t getNodeCount(CConnman::NumConnections flags) override { return g_connman ? g_connman->GetNodeCount(flags) : 0; } + bool getNodesStats(NodesStats &stats) override { + stats.clear(); + + if (g_connman) { + std::vector stats_temp; + g_connman->GetNodeStats(stats_temp); + + stats.reserve(stats_temp.size()); + for (auto &node_stats_temp : stats_temp) { + stats.emplace_back(std::move(node_stats_temp), false, + CNodeStateStats()); + } + + // Try to retrieve the CNodeStateStats for each node. + TRY_LOCK(::cs_main, lockMain); + if (lockMain) { + for (auto &node_stats : stats) { + std::get<1>(node_stats) = + GetNodeStateStats(std::get<0>(node_stats).nodeid, + std::get<2>(node_stats)); + } + } + return true; + } + return false; + } int64_t getTotalBytesRecv() override { return g_connman ? g_connman->GetTotalBytesRecv() : 0; } diff --git a/src/net_processing.h b/src/net_processing.h --- a/src/net_processing.h +++ b/src/net_processing.h @@ -107,9 +107,9 @@ }; struct CNodeStateStats { - int nMisbehavior; - int nSyncHeight; - int nCommonHeight; + int nMisbehavior = 0; + int nSyncHeight = -1; + int nCommonHeight = -1; std::vector vHeightInFlight; }; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -39,7 +39,7 @@ peerTableModel(0), banTableModel(0), pollTimer(0) { cachedBestHeaderHeight = -1; cachedBestHeaderTime = -1; - peerTableModel = new PeerTableModel(this); + peerTableModel = new PeerTableModel(m_node, this); banTableModel = new BanTableModel(this); pollTimer = new QTimer(this); connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer())); diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -5,8 +5,8 @@ #ifndef BITCOIN_QT_PEERTABLEMODEL_H #define BITCOIN_QT_PEERTABLEMODEL_H -#include "net.h" -#include "net_processing.h" // For CNodeStateStats +#include +#include // For CNodeStateStats #include #include @@ -14,6 +14,10 @@ class ClientModel; class PeerTablePriv; +namespace interfaces { +class Node; +} + QT_BEGIN_NAMESPACE class QTimer; QT_END_NAMESPACE @@ -44,7 +48,7 @@ Q_OBJECT public: - explicit PeerTableModel(ClientModel *parent = 0); + explicit PeerTableModel(interfaces::Node &node, ClientModel *parent = 0); ~PeerTableModel(); const CNodeCombinedStats *getNodeStats(int idx); int getRowByNodeId(NodeId nodeid); @@ -77,6 +81,7 @@ void refresh(); private: + interfaces::Node &m_node; ClientModel *clientModel; QStringList columns; std::unique_ptr priv; diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -2,14 +2,15 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "peertablemodel.h" +#include -#include "clientmodel.h" -#include "guiconstants.h" -#include "guiutil.h" +#include +#include +#include -#include "sync.h" -#include "validation.h" // for cs_main +#include +#include +#include // for cs_main #include #include @@ -53,39 +54,28 @@ std::map mapNodeRows; /** Pull a full list of peers from vNodes into our cache */ - void refreshPeers() { + void refreshPeers(interfaces::Node &node) { { cachedNodeStats.clear(); - std::vector vstats; - if (g_connman) g_connman->GetNodeStats(vstats); - cachedNodeStats.reserve(vstats.size()); - for (const CNodeStats &nodestats : vstats) { + + interfaces::Node::NodesStats nodes_stats; + node.getNodesStats(nodes_stats); + cachedNodeStats.reserve(nodes_stats.size()); + for (auto &node_stats : nodes_stats) { CNodeCombinedStats stats; - stats.nodeStateStats.nMisbehavior = 0; - stats.nodeStateStats.nSyncHeight = -1; - stats.nodeStateStats.nCommonHeight = -1; - stats.fNodeStateStatsAvailable = false; - stats.nodeStats = nodestats; + stats.nodeStats = std::get<0>(node_stats); + stats.fNodeStateStatsAvailable = std::get<1>(node_stats); + stats.nodeStateStats = std::get<2>(node_stats); cachedNodeStats.append(stats); } } - // Try to retrieve the CNodeStateStats for each node. - { - TRY_LOCK(cs_main, lockMain); - if (lockMain) { - for (CNodeCombinedStats &stats : cachedNodeStats) { - stats.fNodeStateStatsAvailable = GetNodeStateStats( - stats.nodeStats.nodeid, stats.nodeStateStats); - } - } - } - - if (sortColumn >= 0) + if (sortColumn >= 0) { // sort cacheNodeStats (use stable sort to prevent rows jumping // around unnecessarily) qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder)); + } // build index map mapNodeRows.clear(); @@ -106,8 +96,8 @@ } }; -PeerTableModel::PeerTableModel(ClientModel *parent) - : QAbstractTableModel(parent), clientModel(parent), timer(0) { +PeerTableModel::PeerTableModel(interfaces::Node &node, ClientModel *parent) + : QAbstractTableModel(parent), m_node(node), clientModel(parent), timer(0) { columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent"); priv.reset(new PeerTablePriv()); @@ -212,7 +202,7 @@ void PeerTableModel::refresh() { Q_EMIT layoutAboutToBeChanged(); - priv->refreshPeers(); + priv->refreshPeers(m_node); Q_EMIT layoutChanged(); }