Browse Source

Peers tab

pull/7/head
Duke Leto 3 years ago
parent
commit
b055613e89
  1. 2
      silentdragon.pro
  2. 5
      src/mainwindow.cpp
  3. 5
      src/mainwindow.h
  4. 31
      src/mainwindow.ui
  5. 185
      src/peerstablemodel.cpp
  6. 46
      src/peerstablemodel.h
  7. 77
      src/rpc.cpp
  8. 32
      src/rpc.h

2
silentdragon.pro

@ -49,6 +49,7 @@ SOURCES += \
src/sendtab.cpp \
src/senttxstore.cpp \
src/txtablemodel.cpp \
src/peerstablemodel.cpp \
src/qrcodelabel.cpp \
src/connection.cpp \
src/fillediconlabel.cpp \
@ -73,6 +74,7 @@ HEADERS += \
src/3rdparty/qrcode/QrSegment.hpp \
src/settings.h \
src/txtablemodel.h \
src/peerstablemodel.h \
src/senttxstore.h \
src/qrcodelabel.h \
src/connection.h \

5
src/mainwindow.cpp

@ -120,6 +120,7 @@ MainWindow::MainWindow(QWidget *parent) :
setupMarketTab();
//setupChatTab();
setupHushTab();
setupPeersTab();
rpc = new RPC(this);
qDebug() << "Created RPC";
@ -1126,6 +1127,10 @@ void MainWindow::setupBalancesTab() {
});
}
void MainWindow::setupPeersTab() {
qDebug() << __FUNCTION__;
}
void MainWindow::setupHushTab() {
ui->hushlogo->setBasePixmap(QPixmap(":/img/res/zcashdlogo.gif"));
}

5
src/mainwindow.h

@ -68,7 +68,6 @@ public:
QLabel* statusLabel;
QLabel* statusIcon;
QLabel* loadingLabel;
QWidget* zcashdtab;
Logger* logger;
@ -78,6 +77,7 @@ private:
void closeEvent(QCloseEvent* event);
void setupSendTab();
void setupPeersTab();
void setupTransactionsTab();
void setupReceiveTab();
void setupBalancesTab();
@ -96,9 +96,6 @@ private:
Tx createTxFromSendPage();
bool confirmTx(Tx tx);
void turnstileDoMigration(QString fromAddr = "");
void turnstileProgress();
void cancelButton();
void sendButton();
void inputComboTextChanged(int index);

31
src/mainwindow.ui

@ -915,6 +915,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>Transactions</string>
@ -932,6 +933,28 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="peer_tab">
<attribute name="title">
<string>Peers</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTableView" name="peersTable">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_6">
<attribute name="title">
<string>Market</string>
@ -1612,14 +1635,6 @@
<string>Check git.hush.is for &amp;updates</string>
</property>
</action>
<action name="actionTurnstile_Migration">
<property name="text">
<string>Sapling &amp;turnstile</string>
</property>
<property name="shortcut">
<string>Ctrl+A, Ctrl+T</string>
</property>
</action>
<action name="actionImport_Private_Key">
<property name="text">
<string>&amp;Import private key</string>

185
src/peerstablemodel.cpp

@ -0,0 +1,185 @@
// Copyright 2019-2021 The Hush developers
// Released under the GPLv3
#include "txtablemodel.h"
#include "settings.h"
#include "rpc.h"
PeersTableModel::PeersTableModel(QObject *parent)
: QAbstractTableModel(parent) {
headers << QObject::tr("PeerID") << QObject::tr("Address") << QObject::tr("ASN") << QObject::tr("TLS Cipher") << QObject::tr("TLS Verfied") << QObject::tr("Version") << QObject::tr("Protocol Version") << QObject::tr("Ping Time") << QObject::tr("Banscore") << QObject::tr("Bytes received") << QObject::tr("Bytes sent");
}
PeersTableModel::~PeersTableModel() {
delete modeldata;
}
void PeersTableModel::addData(const QList<PeerItem>& data) {
peers = new QList<PeerItem>();
std::copy(data.begin(), data.end(), std::back_inserter(*peers));
updateAllData();
}
bool PeersTableModel::exportToCsv(QString fileName) const {
if (!modeldata)
return false;
QFile file(fileName);
if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate))
return false;
QTextStream out(&file); // we will serialize the data into the file
// Write headers
for (int i = 0; i < headers.length(); i++) {
out << "\"" << headers[i] << "\",";
}
out << "\"Memo\"";
out << endl;
// Write out each row
for (int row = 0; row < modeldata->length(); row++) {
for (int col = 0; col < headers.length(); col++) {
out << "\"" << data(index(row, col), Qt::DisplayRole).toString() << "\",";
}
}
file.close();
return true;
}
void PeersTableModel::updateAllData() {
auto newmodeldata = new QList<PeerItem>();
// Copy peer data so GUI can use it
if (peers != nullptr) std::copy( peers->begin(), peers->end(), std::back_inserter(*newmodeldata));
// Sort by connection time
std::sort(newmodeldata->begin(), newmodeldata->end(), [=] (auto a, auto b) {
return a.conntime > b.conntime; // reverse sort
});
// And then swap out the modeldata with the new one.
delete modeldata;
modeldata = newmodeldata;
// do magic
dataChanged(index(0, 0), index(modeldata->size()-1, columnCount(index(0,0))-1));
layoutChanged();
}
int PeersTableModel::rowCount(const QModelIndex&) const
{
if (modeldata == nullptr) return 0;
return modeldata->size();
}
int PeersTableModel::columnCount(const QModelIndex&) const
{
return headers.size();
}
QVariant PeersTableModel::data(const QModelIndex &index, int role) const
{
// Align column 4 (amount) right
//if (role == Qt::TextAlignmentRole && index.column() == 3) return QVariant(Qt::AlignRight | Qt::AlignVCenter);
if (role == Qt::ForegroundRole) {
// peers with banscore >=50 will likely be banned soon, color them red
if (modeldata->at(index.row()).banscore >= 50) {
QBrush b;
b.setColor(Qt::red);
return b;
}
// Else, just return the default brush
QBrush b;
b.setColor(Qt::black);
return b;
}
auto dat = modeldata->at(index.row());
if (role == Qt::DisplayRole) {
switch (index.column()) {
case 0: return dat.peerid;
case 1: return dat.address;
case 2: return "AS" + QString::number(dat.asn);
case 3: return dat.tls_cipher;
case 4: return dat.tls_verified;
case 5: return dat.subver;
case 6: return dat.protocolversion;
case 7: return dat.pingtime;
case 8: return dat.banscore;
case 9: return dat.bytes_received;
case 10: return dat.bytes_sent;
}
}
if (role == Qt::ToolTipRole) {
switch (index.column()) {
case 0: return "";
}
}
/*
if (role == Qt::DecorationRole && index.column() == 0) {
if (!dat.memo.isEmpty()) {
// If the memo is a Payment URI, then show a payment request icon
if (dat.memo.startsWith("hush:")) {
QIcon icon(":/icons/res/paymentreq.gif");
return QVariant(icon.pixmap(16, 16));
} else {
// Return the info pixmap to indicate memo
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
return QVariant(icon.pixmap(16, 16));
}
} else {
// Empty pixmap to make it align
QPixmap p(16, 16);
p.fill(Qt::white);
return QVariant(p);
}
}
*/
return QVariant();
}
QVariant PeersTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::TextAlignmentRole && section == 3) return QVariant(Qt::AlignRight | Qt::AlignVCenter);
if (role == Qt::FontRole) {
QFont f;
f.setBold(true);
return f;
}
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
return headers.at(section);
}
return QVariant();
}
QString PeersTableModel::getPeerId(int row) const {
return QString::number(modeldata->at(row).peerid);
}
QString PeersTableModel::getAddress(int row) const {
return modeldata->at(row).address.trimmed();
}
qint64 PeersTableModel::getConntime(int row) const {
return modeldata->at(row).conntime;
}
QString PeersTableModel::getType(int row) const {
return modeldata->at(row).type;
}
QString PeersTableModel::getPingtime(int row) const {
return Settings::getDecimalString(modeldata->at(row).pingtime);
}

46
src/peerstablemodel.h

@ -0,0 +1,46 @@
// Copyright 2019-2021 The Hush developers
// Released under the GPLv3
#ifndef PEERSTABLEMODEL_H
#define PEERSTABLEMODEL_H
#include "precompiled.h"
struct PeerItem;
class PeersTableModel: public QAbstractTableModel
{
public:
PeersTableModel(QObject* parent);
~PeersTableModel();
QString getPeerId(int row) const;
QString getAddress(int row) const;
QString getType(int row) const;
qint64 getConntime(int row) const;
QString getASN(int row) const;
QString getSubver(int row) const;
QString getTLSCipher(int row) const;
bool getTLSVerified(int row) const;
QString getPingtime(int row) const;
unsigned int getBanscore(int row) const;
unsigned int getProtocolVersion(int row) const;
bool exportToCsv(QString fileName) const;
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
void addData (const QList<PeerItem>& data);
private:
void updateAllData();
QList<PeerItem>* peers = nullptr;
QList<PeerItem>* modeldata = nullptr;
QList<QString> headers;
};
#endif // PEERSTABLEMODEL_H

77
src/rpc.cpp

@ -14,7 +14,7 @@ RPC::RPC(MainWindow* main) {
QTimer::singleShot(1, [=]() { cl->loadConnection(); });
this->main = main;
this->ui = main->ui;
this->ui = main->ui;
// Setup balances table model
balancesTableModel = new BalancesTableModel(main->ui->balancesTable);
@ -25,12 +25,17 @@ RPC::RPC(MainWindow* main) {
main->ui->transactionsTable->setModel(transactionsTableModel);
main->ui->transactionsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
peersTableModel = new PeersTableModel(ui->peersTable);
main->ui->peersTable->setModel(peersTableModel);
// tls cipher is wide
main->ui->peersTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
// Set up timer to refresh Price
priceTimer = new QTimer(main);
QObject::connect(priceTimer, &QTimer::timeout, [=]() {
refreshPrice();
});
priceTimer->start(Settings::priceRefreshSpeed); // Every hour
priceTimer->start(Settings::priceRefreshSpeed);
// Set up a timer to refresh the UI every few seconds
timer = new QTimer(main);
@ -46,7 +51,7 @@ RPC::RPC(MainWindow* main) {
//qDebug() << "Watching tx status";
watchTxStatus();
});
// Start at every 10s. When an operation is pending, this will change to every second
txTimer->start(Settings::updateSpeed);
usedAddresses = new QMap<QString, bool>();
@ -58,6 +63,7 @@ RPC::~RPC() {
delete transactionsTableModel;
delete balancesTableModel;
delete peersTableModel;
delete utxos;
delete allBalances;
@ -70,10 +76,6 @@ RPC::~RPC() {
void RPC::setEHushd(std::shared_ptr<QProcess> p) {
ehushd = p;
if (ehushd && ui->tabWidget->widget(4) == nullptr) {
ui->tabWidget->addTab(main->zcashdtab, "zcashd");
}
}
// Called when a connection to hushd is available.
@ -85,7 +87,7 @@ void RPC::setConnection(Connection* c) {
ui->statusBar->showMessage("Ready! Thank you for helping secure the Hush network by running a full node.");
// See if we need to remove the reindex/rescan flags from the zcash.conf file
// See if we need to remove the reindex/rescan flags from the conf file
auto hushConfLocation = Settings::getInstance()->getHushdConfLocation();
Settings::removeFromHushConf(hushConfLocation, "rescan");
Settings::removeFromHushConf(hushConfLocation, "reindex");
@ -239,6 +241,11 @@ void RPC::getBalance(const std::function<void(QJsonValue)>& cb) {
conn->doRPCWithDefaultErrorHandling(payload, cb);
}
void RPC::getPeerInfo(const std::function<void(QJsonValue)>& cb) {
QString method = "getpeerinfo";
conn->doRPCWithDefaultErrorHandling(makePayload(method), cb);
}
void RPC::getTransactions(const std::function<void(QJsonValue)>& cb) {
QString method = "listtransactions";
conn->doRPCWithDefaultErrorHandling(makePayload(method), cb);
@ -573,11 +580,10 @@ void RPC::getInfoThenRefresh(bool force) {
// TODO: store all future halvings
int blocks_until_halving= 2020000 - curBlock;
char halving_days[8];
sprintf(halving_days, "%.2f", (double) (blocks_until_halving * 150) / (60*60*24) );
int blocktime = 75; // seconds
sprintf(halving_days, "%.2f", (double) (blocks_until_halving * blocktime) / (60*60*24) );
QString ntzhash = reply["notarizedhash"].toString();
QString ntztxid = reply["notarizedtxid"].toString();
// Fuck The KYC Traitor named jl777
//QString kmdver = reply["KMDversion"].toString();
Settings::getInstance()->setHushdVersion(version);
@ -586,7 +592,6 @@ void RPC::getInfoThenRefresh(bool force) {
ui->notarizedtxidvalue->setText( ntztxid );
ui->lagvalue->setText( QString::number(lag) );
ui->version->setText( QString::number(version) );
//ui->kmdversion->setText( kmdver );
ui->protocolversion->setText( QString::number(protocolversion) );
ui->p2pport->setText( QString::number(p2pport) );
ui->rpcport->setText( QString::number(rpcport) );
@ -597,6 +602,7 @@ void RPC::getInfoThenRefresh(bool force) {
lastBlock = curBlock;
refreshBalances();
refreshPeers();
refreshAddresses(); // This calls refreshZSentTransactions() and refreshReceivedZTrans()
refreshTransactions();
}
@ -621,8 +627,8 @@ void RPC::getInfoThenRefresh(bool force) {
conn->doRPCIgnoreError(makePayload(method), [=](const QJsonValue& reply) {
qint64 solrate = reply.toInt();
// TODO: megasol
ui->solrate->setText(QString::number(solrate) % " Sol/s");
//TODO: format decimal
ui->solrate->setText(QString::number(solrate / 1000000) % " MegaSol/s");
});
// Get network info
@ -850,6 +856,49 @@ void RPC::refreshBalances() {
});
}
void RPC::refreshPeers() {
qDebug() << __func__;
if (conn == nullptr)
return noConnection();
getPeerInfo([=] (QJsonValue reply) {
QList<PeerItem> peerdata;
for (const auto& it : reply.toArray()) {
auto addr = it.toObject()["addr"].toString();
auto asn = (qint64)it.toObject()["mapped_as"].toInt();
auto recv = (qint64)it.toObject()["bytesrecv"].toInt();
auto sent = (qint64)it.toObject()["bytessent"].toInt();
PeerItem peer {
it.toObject()["id"].toInt(), // peerid
"", // type
(qint64)it.toObject()["conntime"].toInt(),
addr,
asn,
it.toObject()["tls_cipher"].toString(),
// don't convert the JS string "false" to a bool, which is true, lulz
it.toObject()["tls_verified"].toString() == 'true' ? true : false,
(qint64)(it.toObject()["banscore"].toInt()),
(qint64)(it.toObject()["version"].toInt()), // protocolversion
it.toObject()["subver"].toString(),
recv,
sent,
it.toObject()["pingtime"].toDouble(),
};
qDebug() << "Adding peer with address=" << addr << " and AS=" << asn
<< " bytesrecv=" << recv << " bytessent=" << sent;
peerdata.push_back(peer);
}
//qDebug() << peerdata;
// Update model data, which updates the table view
peersTableModel->addData(peerdata);
});
}
void RPC::refreshTransactions() {
if (conn == nullptr)
return noConnection();

32
src/rpc.h

@ -4,18 +4,16 @@
#define RPCCLIENT_H
#include "precompiled.h"
#include "balancestablemodel.h"
#include "txtablemodel.h"
#include "peerstablemodel.h"
#include "ui_mainwindow.h"
#include "mainwindow.h"
#include "connection.h"
class Turnstile;
struct TransactionItem {
QString type;
qint64 datetime;
qint64 datetime;
QString address;
QString txid;
double amount;
@ -24,6 +22,23 @@ struct TransactionItem {
QString memo;
};
struct PeerItem {
qint64 peerid;
QString type;
qint64 conntime;
QString address;
qint64 asn;
QString tls_cipher;
bool tls_verified;
qint64 banscore;
qint64 protocolversion;
QString subver;
qint64 bytes_received;
qint64 bytes_sent;
double pingtime;
};
struct WatchedTx {
QString opid;
Tx tx;
@ -44,6 +59,7 @@ public:
void refresh(bool force = false);
void refreshAddresses();
void refreshPeers();
void checkForUpdate(bool silent = true);
void refreshPrice();
@ -62,6 +78,7 @@ public:
void addNewTxToWatch(const QString& newOpid, WatchedTx wtx);
const TxTableModel* getTransactionsModel() { return transactionsTableModel; }
const PeersTableModel* getPeersModel() { return peersTableModel; }
const QList<QString>* getAllZAddresses() { return zaddresses; }
const QList<QString>* getAllTAddresses() { return taddresses; }
const QList<UnspentOutput>* getUTXOs() { return utxos; }
@ -87,7 +104,6 @@ public:
void getAllPrivKeys(const std::function<void(QList<QPair<QString, QString>>)>);
Turnstile* getTurnstile() { return turnstile; }
Connection* getConnection() { return conn; }
private:
@ -109,12 +125,12 @@ private:
void getTransparentUnspent (const std::function<void(QJsonValue)>& cb);
void getZUnspent (const std::function<void(QJsonValue)>& cb);
void getTransactions (const std::function<void(QJsonValue)>& cb);
void getPeerInfo (const std::function<void(QJsonValue)>& cb);
void getZAddresses (const std::function<void(QJsonValue)>& cb);
void getTAddresses (const std::function<void(QJsonValue)>& cb);
Connection* conn = nullptr;
std::shared_ptr<QProcess> ehushd = nullptr;
std::shared_ptr<QProcess> ehushd = nullptr;
QList<UnspentOutput>* utxos = nullptr;
QMap<QString, double>* allBalances = nullptr;
QMap<QString, bool>* usedAddresses = nullptr;
@ -124,6 +140,7 @@ private:
QMap<QString, WatchedTx> watchingOps;
TxTableModel* transactionsTableModel = nullptr;
PeersTableModel* peersTableModel = nullptr;
BalancesTableModel* balancesTableModel = nullptr;
QTimer* timer;
@ -132,7 +149,6 @@ private:
Ui::MainWindow* ui;
MainWindow* main;
Turnstile* turnstile;
// Current balance in the UI. If this number updates, then refresh the UI
QString currentBalance;

Loading…
Cancel
Save