Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2011-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <qt/peertablemodel.h>7#include <qt/guiconstants.h>8#include <qt/guiutil.h>10#include <interfaces/node.h>12#include <utility>14#include <QList>15#include <QTimer>17PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent)18: QAbstractTableModel(parent),19m_node(node)20{21// set up timer for auto refresh22timer = new QTimer(this);23connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh);24timer->setInterval(MODEL_UPDATE_DELAY);26// load initial data27refresh();28}30PeerTableModel::~PeerTableModel() = default;32void PeerTableModel::startAutoRefresh()33{34timer->start();35}37void PeerTableModel::stopAutoRefresh()38{39timer->stop();40}42int PeerTableModel::rowCount(const QModelIndex& parent) const43{44if (parent.isValid()) {45return 0;46}47return m_peers_data.size();48}50int PeerTableModel::columnCount(const QModelIndex& parent) const51{52if (parent.isValid()) {53return 0;54}55return columns.length();56}58QVariant PeerTableModel::data(const QModelIndex& index, int role) const59{60if(!index.isValid())61return QVariant();63CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());65const auto column = static_cast<ColumnIndex>(index.column());66if (role == Qt::DisplayRole) {67switch (column) {68case NetNodeId:69return (qint64)rec->nodeStats.nodeid;70case Age:71return GUIUtil::FormatPeerAge(rec->nodeStats.m_connected);72case Address:73return QString::fromStdString(rec->nodeStats.m_addr_name);74case Direction:75return QString(rec->nodeStats.fInbound ?76//: An Inbound Connection from a Peer.77tr("Inbound") :78//: An Outbound Connection to a Peer.79tr("Outbound"));80case ConnectionType:81return GUIUtil::ConnectionTypeToQString(rec->nodeStats.m_conn_type, /*prepend_direction=*/false);82case Network:83return GUIUtil::NetworkToQString(rec->nodeStats.m_network);84case Ping:85return GUIUtil::formatPingTime(rec->nodeStats.m_min_ping_time);86case Sent:87return GUIUtil::formatBytes(rec->nodeStats.nSendBytes);88case Received:89return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes);90case Subversion:91return QString::fromStdString(rec->nodeStats.cleanSubVer);92} // no default case, so the compiler can warn about missing cases93assert(false);94} else if (role == Qt::TextAlignmentRole) {95switch (column) {96case NetNodeId:97case Age:98return QVariant(Qt::AlignRight | Qt::AlignVCenter);99case Address:100return {};101case Direction:102case ConnectionType:103case Network:104return QVariant(Qt::AlignCenter);105case Ping:106case Sent:107case Received:108return QVariant(Qt::AlignRight | Qt::AlignVCenter);109case Subversion:110return {};111} // no default case, so the compiler can warn about missing cases112assert(false);113} else if (role == StatsRole) {114return QVariant::fromValue(rec);115}117return QVariant();118}120QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const121{122if(orientation == Qt::Horizontal)123{124if(role == Qt::DisplayRole && section < columns.size())125{126return columns[section];127}128}129return QVariant();130}132Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const133{134if (!index.isValid()) return Qt::NoItemFlags;136Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;137return retval;138}140QModelIndex PeerTableModel::index(int row, int column, const QModelIndex& parent) const141{142Q_UNUSED(parent);144if (0 <= row && row < rowCount() && 0 <= column && column < columnCount()) {145return createIndex(row, column, const_cast<CNodeCombinedStats*>(&m_peers_data[row]));146}148return QModelIndex();149}151void PeerTableModel::refresh()152{153interfaces::Node::NodesStats nodes_stats;154m_node.getNodesStats(nodes_stats);155decltype(m_peers_data) new_peers_data;156new_peers_data.reserve(nodes_stats.size());157for (const auto& node_stats : nodes_stats) {158const CNodeCombinedStats stats{std::get<0>(node_stats), std::get<2>(node_stats), std::get<1>(node_stats)};159new_peers_data.append(stats);160}162// Handle peer addition or removal as suggested in Qt Docs. See:163// - https://doc.qt.io/qt-5/model-view-programming.html#inserting-and-removing-rows164// - https://doc.qt.io/qt-5/model-view-programming.html#resizable-models165// We take advantage of the fact that the std::vector returned166// by interfaces::Node::getNodesStats is sorted by nodeid.167for (int i = 0; i < m_peers_data.size();) {168if (i < new_peers_data.size() && m_peers_data.at(i).nodeStats.nodeid == new_peers_data.at(i).nodeStats.nodeid) {169++i;170continue;171}172// A peer has been removed from the table.173beginRemoveRows(QModelIndex(), i, i);174m_peers_data.erase(m_peers_data.begin() + i);175endRemoveRows();176}178if (m_peers_data.size() < new_peers_data.size()) {179// Some peers have been added to the end of the table.180beginInsertRows(QModelIndex(), m_peers_data.size(), new_peers_data.size() - 1);181m_peers_data.swap(new_peers_data);182endInsertRows();183} else {184m_peers_data.swap(new_peers_data);185}187const auto top_left = index(0, 0);188const auto bottom_right = index(rowCount() - 1, columnCount() - 1);189Q_EMIT dataChanged(top_left, bottom_right);190}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.