Merge #162: Add network to peers window and peer details

e262a19b0b gui: display network in peer details (Jon Atack)
9136953073 gui: rename peer tab column headers, initialize in .h (Hennadii Stepanov)
05c08c696a gui: add network column in peers tab/window (Jon Atack)
e0e55060bf gui: fix broken doxygen formatting in src/qt/guiutil.h (Jon Atack)
0d5613f9de gui: create GUIUtil::NetworkToQString() utility function (Jon Atack)
af9103cc79 net, rpc: change CNodeStats::m_network from string to Network (Jon Atack)

Pull request description:

  and rename peers window column headers from NodeId and Node/Service to Peer Id and Address.

  ![Screenshot from 2020-12-27 14-45-31](https://user-images.githubusercontent.com/2415484/103172228-efec8600-4849-11eb-8cee-04a3d2ab1273.png)

ACKs for top commit:
  laanwj:
    ACK e262a19b0b

Tree-SHA512: 709c2a805c109c2dd033aca7b6b6dc94ebe2ce7a0168c71249e1e661c9c57d1f1c781a5b9ccf3b776bedeb83ae2fb5c505637337c45b1eb9a418cb1693a89761
This commit is contained in:
Wladimir J. van der Laan 2020-12-28 22:52:02 +01:00
commit d875bcc8f9
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
9 changed files with 127 additions and 75 deletions

View file

@ -566,7 +566,7 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
X(nServices); X(nServices);
X(addr); X(addr);
X(addrBind); X(addrBind);
stats.m_network = GetNetworkName(ConnectedThroughNetwork()); stats.m_network = ConnectedThroughNetwork();
stats.m_mapped_as = addr.GetMappedAS(m_asmap); stats.m_mapped_as = addr.GetMappedAS(m_asmap);
if (m_tx_relay != nullptr) { if (m_tx_relay != nullptr) {
LOCK(m_tx_relay->cs_filter); LOCK(m_tx_relay->cs_filter);

View file

@ -720,8 +720,8 @@ public:
CAddress addr; CAddress addr;
// Bind address of our side of the connection // Bind address of our side of the connection
CAddress addrBind; CAddress addrBind;
// Name of the network the peer connected through // Network the peer connected through
std::string m_network; Network m_network;
uint32_t m_mapped_as; uint32_t m_mapped_as;
std::string m_conn_type_string; std::string m_conn_type_string;
}; };

View file

@ -1100,14 +1100,17 @@
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QLabel" name="label_21"> <widget class="QLabel" name="peerNetworkLabel">
<property name="toolTip">
<string>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</string>
</property>
<property name="text"> <property name="text">
<string>Version</string> <string>Network</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLabel" name="peerVersion"> <widget class="QLabel" name="peerNetwork">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1123,14 +1126,14 @@
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label_28"> <widget class="QLabel" name="label_21">
<property name="text"> <property name="text">
<string>User Agent</string> <string>Version</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="3" column="1">
<widget class="QLabel" name="peerSubversion"> <widget class="QLabel" name="peerVersion">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1146,14 +1149,14 @@
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_28">
<property name="text"> <property name="text">
<string>Services</string> <string>User Agent</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="4" column="1">
<widget class="QLabel" name="peerServices"> <widget class="QLabel" name="peerSubversion">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1169,14 +1172,14 @@
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QLabel" name="label_29"> <widget class="QLabel" name="label_4">
<property name="text"> <property name="text">
<string>Starting Block</string> <string>Services</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="5" column="1">
<widget class="QLabel" name="peerHeight"> <widget class="QLabel" name="peerServices">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1192,14 +1195,14 @@
</widget> </widget>
</item> </item>
<item row="6" column="0"> <item row="6" column="0">
<widget class="QLabel" name="label_27"> <widget class="QLabel" name="label_29">
<property name="text"> <property name="text">
<string>Synced Headers</string> <string>Starting Block</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="6" column="1">
<widget class="QLabel" name="peerSyncHeight"> <widget class="QLabel" name="peerHeight">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1215,14 +1218,14 @@
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="7" column="0">
<widget class="QLabel" name="label_25"> <widget class="QLabel" name="label_27">
<property name="text"> <property name="text">
<string>Synced Blocks</string> <string>Synced Headers</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="7" column="1">
<widget class="QLabel" name="peerCommonHeight"> <widget class="QLabel" name="peerSyncHeight">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1238,14 +1241,14 @@
</widget> </widget>
</item> </item>
<item row="8" column="0"> <item row="8" column="0">
<widget class="QLabel" name="label_22"> <widget class="QLabel" name="label_25">
<property name="text"> <property name="text">
<string>Connection Time</string> <string>Synced Blocks</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="1"> <item row="8" column="1">
<widget class="QLabel" name="peerConnTime"> <widget class="QLabel" name="peerCommonHeight">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1261,14 +1264,14 @@
</widget> </widget>
</item> </item>
<item row="9" column="0"> <item row="9" column="0">
<widget class="QLabel" name="label_15"> <widget class="QLabel" name="label_22">
<property name="text"> <property name="text">
<string>Last Send</string> <string>Connection Time</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="1"> <item row="9" column="1">
<widget class="QLabel" name="peerLastSend"> <widget class="QLabel" name="peerConnTime">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1284,14 +1287,14 @@
</widget> </widget>
</item> </item>
<item row="10" column="0"> <item row="10" column="0">
<widget class="QLabel" name="label_19"> <widget class="QLabel" name="label_15">
<property name="text"> <property name="text">
<string>Last Receive</string> <string>Last Send</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="10" column="1"> <item row="10" column="1">
<widget class="QLabel" name="peerLastRecv"> <widget class="QLabel" name="peerLastSend">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1307,14 +1310,14 @@
</widget> </widget>
</item> </item>
<item row="11" column="0"> <item row="11" column="0">
<widget class="QLabel" name="label_18"> <widget class="QLabel" name="label_19">
<property name="text"> <property name="text">
<string>Sent</string> <string>Last Receive</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="11" column="1"> <item row="11" column="1">
<widget class="QLabel" name="peerBytesSent"> <widget class="QLabel" name="peerLastRecv">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1330,14 +1333,14 @@
</widget> </widget>
</item> </item>
<item row="12" column="0"> <item row="12" column="0">
<widget class="QLabel" name="label_20"> <widget class="QLabel" name="label_18">
<property name="text"> <property name="text">
<string>Received</string> <string>Sent</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="12" column="1"> <item row="12" column="1">
<widget class="QLabel" name="peerBytesRecv"> <widget class="QLabel" name="peerBytesSent">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1353,14 +1356,14 @@
</widget> </widget>
</item> </item>
<item row="13" column="0"> <item row="13" column="0">
<widget class="QLabel" name="label_26"> <widget class="QLabel" name="label_20">
<property name="text"> <property name="text">
<string>Ping Time</string> <string>Received</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="1"> <item row="13" column="1">
<widget class="QLabel" name="peerPingTime"> <widget class="QLabel" name="peerBytesRecv">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1376,17 +1379,14 @@
</widget> </widget>
</item> </item>
<item row="14" column="0"> <item row="14" column="0">
<widget class="QLabel" name="peerPingWaitLabel"> <widget class="QLabel" name="label_26">
<property name="toolTip">
<string>The duration of a currently outstanding ping.</string>
</property>
<property name="text"> <property name="text">
<string>Ping Wait</string> <string>Ping Time</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="14" column="1"> <item row="14" column="1">
<widget class="QLabel" name="peerPingWait"> <widget class="QLabel" name="peerPingTime">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1402,14 +1402,17 @@
</widget> </widget>
</item> </item>
<item row="15" column="0"> <item row="15" column="0">
<widget class="QLabel" name="peerMinPingLabel"> <widget class="QLabel" name="peerPingWaitLabel">
<property name="toolTip">
<string>The duration of a currently outstanding ping.</string>
</property>
<property name="text"> <property name="text">
<string>Min Ping</string> <string>Ping Wait</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="15" column="1"> <item row="15" column="1">
<widget class="QLabel" name="peerMinPing"> <widget class="QLabel" name="peerPingWait">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1425,14 +1428,14 @@
</widget> </widget>
</item> </item>
<item row="16" column="0"> <item row="16" column="0">
<widget class="QLabel" name="label_timeoffset"> <widget class="QLabel" name="peerMinPingLabel">
<property name="text"> <property name="text">
<string>Time Offset</string> <string>Min Ping</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="16" column="1"> <item row="16" column="1">
<widget class="QLabel" name="timeoffset"> <widget class="QLabel" name="peerMinPing">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1448,17 +1451,14 @@
</widget> </widget>
</item> </item>
<item row="17" column="0"> <item row="17" column="0">
<widget class="QLabel" name="peerMappedASLabel"> <widget class="QLabel" name="label_timeoffset">
<property name="toolTip">
<string>The mapped Autonomous System used for diversifying peer selection.</string>
</property>
<property name="text"> <property name="text">
<string>Mapped AS</string> <string>Time Offset</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="17" column="1"> <item row="17" column="1">
<widget class="QLabel" name="peerMappedAS"> <widget class="QLabel" name="timeoffset">
<property name="cursor"> <property name="cursor">
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
@ -1474,6 +1474,32 @@
</widget> </widget>
</item> </item>
<item row="18" column="0"> <item row="18" column="0">
<widget class="QLabel" name="peerMappedASLabel">
<property name="toolTip">
<string>The mapped Autonomous System used for diversifying peer selection.</string>
</property>
<property name="text">
<string>Mapped AS</string>
</property>
</widget>
</item>
<item row="18" column="1">
<widget class="QLabel" name="peerMappedAS">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="19" column="0">
<spacer name="verticalSpacer_3"> <spacer name="verticalSpacer_3">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>

View file

@ -749,6 +749,21 @@ QString boostPathToQString(const fs::path &path)
return QString::fromStdString(path.string()); return QString::fromStdString(path.string());
} }
QString NetworkToQString(Network net)
{
switch (net) {
case NET_UNROUTABLE: return QObject::tr("Unroutable");
case NET_IPV4: return "IPv4";
case NET_IPV6: return "IPv6";
case NET_ONION: return "Onion";
case NET_I2P: return "I2P";
case NET_CJDNS: return "CJDNS";
case NET_INTERNAL: return QObject::tr("Internal");
case NET_MAX: assert(false);
} // no default case, so the compiler can warn about missing cases
assert(false);
}
QString formatDurationStr(int secs) QString formatDurationStr(int secs)
{ {
QStringList strList; QStringList strList;

View file

@ -7,6 +7,7 @@
#include <amount.h> #include <amount.h>
#include <fs.h> #include <fs.h>
#include <netaddress.h>
#include <QEvent> #include <QEvent>
#include <QHeaderView> #include <QHeaderView>
@ -218,22 +219,25 @@ namespace GUIUtil
bool GetStartOnSystemStartup(); bool GetStartOnSystemStartup();
bool SetStartOnSystemStartup(bool fAutoStart); bool SetStartOnSystemStartup(bool fAutoStart);
/* Convert QString to OS specific boost path through UTF-8 */ /** Convert QString to OS specific boost path through UTF-8 */
fs::path qstringToBoostPath(const QString &path); fs::path qstringToBoostPath(const QString &path);
/* Convert OS specific boost path to QString through UTF-8 */ /** Convert OS specific boost path to QString through UTF-8 */
QString boostPathToQString(const fs::path &path); QString boostPathToQString(const fs::path &path);
/* Convert seconds into a QString with days, hours, mins, secs */ /** Convert enum Network to QString */
QString NetworkToQString(Network net);
/** Convert seconds into a QString with days, hours, mins, secs */
QString formatDurationStr(int secs); QString formatDurationStr(int secs);
/* Format CNodeStats.nServices bitmask into a user-readable string */ /** Format CNodeStats.nServices bitmask into a user-readable string */
QString formatServicesStr(quint64 mask); QString formatServicesStr(quint64 mask);
/* Format a CNodeStats.m_ping_usec into a user-readable string or display N/A, if 0*/ /** Format a CNodeStats.m_ping_usec into a user-readable string or display N/A, if 0 */
QString formatPingTime(int64_t ping_usec); QString formatPingTime(int64_t ping_usec);
/* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */ /** Format a CNodeCombinedStats.nTimeOffset into a user-readable string */
QString formatTimeOffset(int64_t nTimeOffset); QString formatTimeOffset(int64_t nTimeOffset);
QString formatNiceTimeOffset(qint64 secs); QString formatNiceTimeOffset(qint64 secs);

View file

@ -29,14 +29,16 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine
return pLeft->nodeid < pRight->nodeid; return pLeft->nodeid < pRight->nodeid;
case PeerTableModel::Address: case PeerTableModel::Address:
return pLeft->addrName.compare(pRight->addrName) < 0; return pLeft->addrName.compare(pRight->addrName) < 0;
case PeerTableModel::Subversion: case PeerTableModel::Network:
return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0; return pLeft->m_network < pRight->m_network;
case PeerTableModel::Ping: case PeerTableModel::Ping:
return pLeft->m_min_ping_usec < pRight->m_min_ping_usec; return pLeft->m_min_ping_usec < pRight->m_min_ping_usec;
case PeerTableModel::Sent: case PeerTableModel::Sent:
return pLeft->nSendBytes < pRight->nSendBytes; return pLeft->nSendBytes < pRight->nSendBytes;
case PeerTableModel::Received: case PeerTableModel::Received:
return pLeft->nRecvBytes < pRight->nRecvBytes; return pLeft->nRecvBytes < pRight->nRecvBytes;
case PeerTableModel::Subversion:
return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
} }
return false; return false;
@ -104,7 +106,6 @@ PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) :
m_node(node), m_node(node),
timer(nullptr) timer(nullptr)
{ {
columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent");
priv.reset(new PeerTablePriv()); priv.reset(new PeerTablePriv());
// set up timer for auto refresh // set up timer for auto refresh
@ -158,17 +159,21 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
case Address: case Address:
// prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection
return QString(rec->nodeStats.fInbound ? "" : "") + QString::fromStdString(rec->nodeStats.addrName); return QString(rec->nodeStats.fInbound ? "" : "") + QString::fromStdString(rec->nodeStats.addrName);
case Subversion: case Network:
return QString::fromStdString(rec->nodeStats.cleanSubVer); return GUIUtil::NetworkToQString(rec->nodeStats.m_network);
case Ping: case Ping:
return GUIUtil::formatPingTime(rec->nodeStats.m_min_ping_usec); return GUIUtil::formatPingTime(rec->nodeStats.m_min_ping_usec);
case Sent: case Sent:
return GUIUtil::formatBytes(rec->nodeStats.nSendBytes); return GUIUtil::formatBytes(rec->nodeStats.nSendBytes);
case Received: case Received:
return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes); return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes);
case Subversion:
return QString::fromStdString(rec->nodeStats.cleanSubVer);
} }
} else if (role == Qt::TextAlignmentRole) { } else if (role == Qt::TextAlignmentRole) {
switch (index.column()) { switch (index.column()) {
case Network:
return QVariant(Qt::AlignCenter);
case Ping: case Ping:
case Sent: case Sent:
case Received: case Received:

View file

@ -60,10 +60,11 @@ public:
enum ColumnIndex { enum ColumnIndex {
NetNodeId = 0, NetNodeId = 0,
Address = 1, Address = 1,
Ping = 2, Network = 2,
Sent = 3, Ping = 3,
Received = 4, Sent = 4,
Subversion = 5 Received = 5,
Subversion = 6
}; };
/** @name Methods overridden from QAbstractTableModel /** @name Methods overridden from QAbstractTableModel
@ -82,7 +83,7 @@ public Q_SLOTS:
private: private:
interfaces::Node& m_node; interfaces::Node& m_node;
QStringList columns; const QStringList columns{tr("Peer Id"), tr("Address"), tr("Network"), tr("Ping"), tr("Sent"), tr("Received"), tr("User Agent")};
std::unique_ptr<PeerTablePriv> priv; std::unique_ptr<PeerTablePriv> priv;
QTimer *timer; QTimer *timer;
}; };

View file

@ -1092,7 +1092,7 @@ void RPCConsole::updateDetailWidget()
const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected_rows.first().row()); const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected_rows.first().row());
// update the detail ui with latest node information // update the detail ui with latest node information
QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " "); QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " ");
peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid)); peerAddrDetails += tr("(peer id: %1)").arg(QString::number(stats->nodeStats.nodeid));
if (!stats->nodeStats.addrLocal.empty()) if (!stats->nodeStats.addrLocal.empty())
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal)); peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
ui->peerHeading->setText(peerAddrDetails); ui->peerHeading->setText(peerAddrDetails);
@ -1109,6 +1109,7 @@ void RPCConsole::updateDetailWidget()
ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion)); ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer)); ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound")); ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
ui->peerNetwork->setText(GUIUtil::NetworkToQString(stats->nodeStats.m_network));
if (stats->nodeStats.m_permissionFlags == PF_NONE) { if (stats->nodeStats.m_permissionFlags == PF_NONE) {
ui->peerPermissions->setText(tr("N/A")); ui->peerPermissions->setText(tr("N/A"));
} else { } else {

View file

@ -187,7 +187,7 @@ static RPCHelpMan getpeerinfo()
if (!(stats.addrLocal.empty())) { if (!(stats.addrLocal.empty())) {
obj.pushKV("addrlocal", stats.addrLocal); obj.pushKV("addrlocal", stats.addrLocal);
} }
obj.pushKV("network", stats.m_network); obj.pushKV("network", GetNetworkName(stats.m_network));
if (stats.m_mapped_as != 0) { if (stats.m_mapped_as != 0) {
obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as)); obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as));
} }