Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ BITCOIN_QT_H = \
qt/macnotificationhandler.h \
qt/macos_appnap.h \
qt/masternodelist.h \
qt/masternodemodel.h \
qt/mnemonicverificationdialog.h \
qt/modaloverlay.h \
qt/networkstyle.h \
Expand Down Expand Up @@ -264,6 +265,7 @@ BITCOIN_QT_WALLET_CPP = \
qt/editaddressdialog.cpp \
qt/governancelist.cpp \
qt/masternodelist.cpp \
qt/masternodemodel.cpp \
qt/mnemonicverificationdialog.cpp \
qt/openuridialog.cpp \
qt/overviewpage.cpp \
Expand Down
268 changes: 116 additions & 152 deletions src/qt/masternodelist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
#include <qt/guiutil_font.h>
#include <qt/walletmodel.h>

#include <univalue.h>

#include <QApplication>
#include <QClipboard>
#include <QMessageBox>
#include <QTableWidgetItem>
Expand All @@ -34,6 +33,32 @@ class CMasternodeListWidgetItem : public QTableWidgetItem
}
};

int MasternodeList::columnWidth(int column)
{
switch (column) {
case Column::SERVICE:
return 200;
case Column::TYPE:
return 160;
case Column::STATUS:
case Column::POSE:
case Column::REGISTERED:
case Column::LAST_PAYMENT:
return 80;
case Column::NEXT_PAYMENT:
return 100;
case Column::PAYOUT_ADDRESS:
case Column::OPERATOR_REWARD:
case Column::COLLATERAL_ADDRESS:
case Column::OWNER_ADDRESS:
case Column::VOTING_ADDRESS:
return 130;
case Column::PROTX_HASH:
default:
return 80;
}
}

MasternodeList::MasternodeList(QWidget* parent) :
QWidget(parent),
ui(new Ui::MasternodeList)
Expand All @@ -43,35 +68,13 @@ MasternodeList::MasternodeList(QWidget* parent) :
GUIUtil::setFont({ui->label_count_2, ui->countLabelDIP3}, {GUIUtil::FontWeight::Bold, 14});
GUIUtil::setFont({ui->label_filter_2}, {GUIUtil::FontWeight::Normal, 15});

int columnAddressWidth = 200;
int columnTypeWidth = 160;
int columnStatusWidth = 80;
int columnPoSeScoreWidth = 80;
int columnRegisteredWidth = 80;
int columnLastPaidWidth = 80;
int columnNextPaymentWidth = 100;
int columnPayeeWidth = 130;
int columnOperatorRewardWidth = 130;
int columnCollateralWidth = 130;
int columnOwnerWidth = 130;
int columnVotingWidth = 130;

ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_SERVICE, columnAddressWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_TYPE, columnTypeWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_STATUS, columnStatusWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_POSE, columnPoSeScoreWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_REGISTERED, columnRegisteredWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_LAST_PAYMENT, columnLastPaidWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_NEXT_PAYMENT, columnNextPaymentWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_PAYOUT_ADDRESS, columnPayeeWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_OPERATOR_REWARD, columnOperatorRewardWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_COLLATERAL_ADDRESS, columnCollateralWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_OWNER_ADDRESS, columnOwnerWidth);
ui->tableWidgetMasternodesDIP3->setColumnWidth(COLUMN_VOTING_ADDRESS, columnVotingWidth);
for (int col = 0; col <= Column::COUNT; col++) {
ui->tableWidgetMasternodesDIP3->setColumnWidth(col, columnWidth(col));
}

// dummy column for proTxHash
ui->tableWidgetMasternodesDIP3->insertColumn(COLUMN_PROTX_HASH);
ui->tableWidgetMasternodesDIP3->setColumnHidden(COLUMN_PROTX_HASH, true);
ui->tableWidgetMasternodesDIP3->insertColumn(Column::PROTX_HASH);
ui->tableWidgetMasternodesDIP3->setColumnHidden(Column::PROTX_HASH, true);

ui->tableWidgetMasternodesDIP3->setContextMenuPolicy(Qt::CustomContextMenu);
ui->tableWidgetMasternodesDIP3->verticalHeader()->setVisible(false);
Expand Down Expand Up @@ -187,7 +190,6 @@ void MasternodeList::updateDIP3List()

LOCK(cs_dip3list);

QString strToFilter;
ui->countLabelDIP3->setText(tr("Updating…"));
ui->tableWidgetMasternodesDIP3->setSortingEnabled(false);
ui->tableWidgetMasternodesDIP3->clearContents();
Expand All @@ -208,6 +210,7 @@ void MasternodeList::updateDIP3List()
}
}

m_entries.clear();
mnList->forEachMN(/*only_valid=*/false, [&](const auto& dmn) {
if (walletModel && ui->checkBoxMyMasternodesOnly->isChecked()) {
bool fMyMasternode = setOutpts.count(dmn.getCollateralOutpoint()) ||
Expand All @@ -217,102 +220,72 @@ void MasternodeList::updateDIP3List()
walletModel->wallet().isSpendable(dmn.getScriptOperatorPayout());
if (!fMyMasternode) return;
}
// populate list
// Address, Protocol, Status, Active Seconds, Last Seen, Pub Key
auto addr_key = dmn.getNetInfoPrimary().GetKey();
QByteArray addr_ba(reinterpret_cast<const char*>(addr_key.data()), addr_key.size());
QTableWidgetItem* addressItem = new CMasternodeListWidgetItem<QByteArray>(
QString::fromStdString(dmn.getNetInfoPrimary().ToStringAddrPort()), addr_ba);
QTableWidgetItem* typeItem = new QTableWidgetItem(
QString::fromStdString(std::string(GetMnType(dmn.getType()).description)));
QTableWidgetItem* statusItem = new QTableWidgetItem(dmn.isBanned() ? tr("POSE_BANNED") : tr("ENABLED"));
QTableWidgetItem* PoSeScoreItem = new CMasternodeListWidgetItem<int>(QString::number(dmn.getPoSePenalty()),
dmn.getPoSePenalty());
QTableWidgetItem* registeredItem = new CMasternodeListWidgetItem<int>(QString::number(dmn.getRegisteredHeight()),
dmn.getRegisteredHeight());
QTableWidgetItem* lastPaidItem = new CMasternodeListWidgetItem<int>(QString::number(dmn.getLastPaidHeight()),
dmn.getLastPaidHeight());

QString strNextPayment = "UNKNOWN";
int nNextPayment = 0;
if (nextPayments.count(dmn.getProTxHash())) {
nNextPayment = nextPayments[dmn.getProTxHash()];
strNextPayment = QString::number(nNextPayment);
}
QTableWidgetItem* nextPaymentItem = new CMasternodeListWidgetItem<int>(strNextPayment, nNextPayment);

CTxDestination payeeDest;
QString payeeStr = tr("UNKNOWN");
if (ExtractDestination(dmn.getScriptPayout(), payeeDest)) {
payeeStr = QString::fromStdString(EncodeDestination(payeeDest));
}
QTableWidgetItem* payeeItem = new QTableWidgetItem(payeeStr);

QString operatorRewardStr = tr("NONE");
if (dmn.getOperatorReward()) {
operatorRewardStr = QString::number(dmn.getOperatorReward() / 100.0, 'f', 2) + "% ";

if (dmn.getScriptOperatorPayout() != CScript()) {
CTxDestination operatorDest;
if (ExtractDestination(dmn.getScriptOperatorPayout(), operatorDest)) {
operatorRewardStr += tr("to %1").arg(QString::fromStdString(EncodeDestination(operatorDest)));
} else {
operatorRewardStr += tr("to UNKNOWN");
}
} else {
operatorRewardStr += tr("but not claimed");
if (auto base_entry = mnList->getMN(dmn.getProTxHash())) {
int nNextPayment = 0;
if (auto it = nextPayments.find(dmn.getProTxHash()); it != nextPayments.end()) {
nNextPayment = it->second;
}

QString collateralStr = tr("UNKNOWN");
if (auto it = mapCollateralDests.find(dmn.getProTxHash()); it != mapCollateralDests.end()) {
collateralStr = QString::fromStdString(EncodeDestination(it->second));
}
}
QTableWidgetItem* operatorRewardItem = new CMasternodeListWidgetItem<uint16_t>(operatorRewardStr,
dmn.getOperatorReward());

QString collateralStr = tr("UNKNOWN");
auto collateralDestIt = mapCollateralDests.find(dmn.getProTxHash());
if (collateralDestIt != mapCollateralDests.end()) {
collateralStr = QString::fromStdString(EncodeDestination(collateralDestIt->second));
m_entries.push_back(std::make_unique<MasternodeEntry>(*base_entry, collateralStr, nNextPayment));
}
QTableWidgetItem* collateralItem = new QTableWidgetItem(collateralStr);

QString ownerStr = QString::fromStdString(EncodeDestination(PKHash(dmn.getKeyIdOwner())));
QTableWidgetItem* ownerItem = new QTableWidgetItem(ownerStr);

QString votingStr = QString::fromStdString(EncodeDestination(PKHash(dmn.getKeyIdVoting())));
QTableWidgetItem* votingItem = new QTableWidgetItem(votingStr);

QTableWidgetItem* proTxHashItem = new QTableWidgetItem(QString::fromStdString(dmn.getProTxHash().ToString()));

if (strCurrentFilterDIP3 != "") {
strToFilter = addressItem->text() + " " +
typeItem->text() + " " +
statusItem->text() + " " +
PoSeScoreItem->text() + " " +
registeredItem->text() + " " +
lastPaidItem->text() + " " +
nextPaymentItem->text() + " " +
payeeItem->text() + " " +
operatorRewardItem->text() + " " +
collateralItem->text() + " " +
ownerItem->text() + " " +
votingItem->text() + " " +
proTxHashItem->text();
if (!strToFilter.contains(strCurrentFilterDIP3)) return;
});

for (const auto& entry : m_entries) {
if (!strCurrentFilterDIP3.isEmpty()) {
QString strToFilter = entry->service() + " " +
entry->typeDescription() + " " +
(entry->isBanned() ? tr("POSE_BANNED") : tr("ENABLED")) + " " +
QString::number(entry->posePenalty()) + " " +
QString::number(entry->registeredHeight()) + " " +
QString::number(entry->lastPaidHeight()) + " " +
(entry->nextPaymentHeight() > 0 ? QString::number(entry->nextPaymentHeight()) : tr("UNKNOWN")) + " " +
entry->payoutAddress() + " " +
entry->operatorReward() + " " +
entry->collateralAddress() + " " +
entry->ownerAddress() + " " +
entry->votingAddress() + " " +
entry->proTxHash();
if (!strToFilter.contains(strCurrentFilterDIP3)) continue;
}

ui->tableWidgetMasternodesDIP3->insertRow(0);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_SERVICE, addressItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_TYPE, typeItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_STATUS, statusItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_POSE, PoSeScoreItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_REGISTERED, registeredItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_LAST_PAYMENT, lastPaidItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_NEXT_PAYMENT, nextPaymentItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_PAYOUT_ADDRESS, payeeItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_OPERATOR_REWARD, operatorRewardItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_COLLATERAL_ADDRESS, collateralItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_OWNER_ADDRESS, ownerItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_VOTING_ADDRESS, votingItem);
ui->tableWidgetMasternodesDIP3->setItem(0, COLUMN_PROTX_HASH, proTxHashItem);
});
int row = ui->tableWidgetMasternodesDIP3->rowCount();
ui->tableWidgetMasternodesDIP3->insertRow(row);

auto* addressItem = new CMasternodeListWidgetItem<QByteArray>(entry->service(), entry->serviceKey());
auto* typeItem = new QTableWidgetItem(entry->typeDescription());
auto* statusItem = new QTableWidgetItem(entry->isBanned() ? tr("POSE_BANNED") : tr("ENABLED"));
auto* PoSeScoreItem = new CMasternodeListWidgetItem<int>(QString::number(entry->posePenalty()), entry->posePenalty());
auto* registeredItem = new CMasternodeListWidgetItem<int>(QString::number(entry->registeredHeight()), entry->registeredHeight());
auto* lastPaidItem = new CMasternodeListWidgetItem<int>(QString::number(entry->lastPaidHeight()), entry->lastPaidHeight());
QString nextPaymentStr = entry->nextPaymentHeight() > 0 ? QString::number(entry->nextPaymentHeight()) : tr("UNKNOWN");
auto* nextPaymentItem = new CMasternodeListWidgetItem<int>(nextPaymentStr, entry->nextPaymentHeight());
auto* payeeItem = new QTableWidgetItem(entry->payoutAddress());
auto* operatorRewardItem = new CMasternodeListWidgetItem<uint16_t>(entry->operatorReward(), entry->operatorRewardPct());
auto* collateralItem = new QTableWidgetItem(entry->collateralAddress());
auto* ownerItem = new QTableWidgetItem(entry->ownerAddress());
auto* votingItem = new QTableWidgetItem(entry->votingAddress());
auto* proTxHashItem = new QTableWidgetItem(entry->proTxHash());

ui->tableWidgetMasternodesDIP3->setItem(row, Column::SERVICE, addressItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::TYPE, typeItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::STATUS, statusItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::POSE, PoSeScoreItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::REGISTERED, registeredItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::LAST_PAYMENT, lastPaidItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::NEXT_PAYMENT, nextPaymentItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::PAYOUT_ADDRESS, payeeItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::OPERATOR_REWARD, operatorRewardItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::COLLATERAL_ADDRESS, collateralItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::OWNER_ADDRESS, ownerItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::VOTING_ADDRESS, votingItem);
ui->tableWidgetMasternodesDIP3->setItem(row, Column::PROTX_HASH, proTxHashItem);
}

ui->countLabelDIP3->setText(QString::number(ui->tableWidgetMasternodesDIP3->rowCount()));
ui->tableWidgetMasternodesDIP3->setSortingEnabled(true);
Expand All @@ -333,66 +306,57 @@ void MasternodeList::on_checkBoxMyMasternodesOnly_stateChanged(int state)
fFilterUpdatedDIP3 = true;
}

std::unique_ptr<const interfaces::MnEntry> MasternodeList::GetSelectedDIP3MN()
const MasternodeEntry* MasternodeList::GetSelectedEntry()
{
if (!clientModel) {
return nullptr;
}
LOCK(cs_dip3list);

std::string strProTxHash;
{
LOCK(cs_dip3list);
QItemSelectionModel* selectionModel = ui->tableWidgetMasternodesDIP3->selectionModel();
QModelIndexList selected = selectionModel->selectedRows();

QItemSelectionModel* selectionModel = ui->tableWidgetMasternodesDIP3->selectionModel();
QModelIndexList selected = selectionModel->selectedRows();
if (selected.count() == 0) return nullptr;

if (selected.count() == 0) return nullptr;
QModelIndex index = selected.at(0);
int nSelectedRow = index.row();
QString strProTxHash = ui->tableWidgetMasternodesDIP3->item(nSelectedRow, Column::PROTX_HASH)->text();

QModelIndex index = selected.at(0);
int nSelectedRow = index.row();
strProTxHash = ui->tableWidgetMasternodesDIP3->item(nSelectedRow, COLUMN_PROTX_HASH)->text().toStdString();
for (const auto& entry : m_entries) {
if (entry->proTxHash() == strProTxHash) {
return entry.get();
}
}

uint256 proTxHash;
proTxHash.SetHex(strProTxHash);

// Caller is responsible for nullptr checking return value
return clientModel->getMasternodeList().first->getMN(proTxHash);
return nullptr;
}

void MasternodeList::extraInfoDIP3_clicked()
{
auto dmn = GetSelectedDIP3MN();
if (!dmn) {
const auto* entry = GetSelectedEntry();
if (!entry) {
return;
}

UniValue json = dmn->toJson();

// Title of popup window
QString strWindowtitle =
tr("Additional information for DIP3 Masternode %1").arg(QString::fromStdString(dmn->getProTxHash().ToString()));
QString strText = QString::fromStdString(json.write(2));
QString strWindowtitle = tr("Additional information for DIP3 Masternode %1").arg(entry->proTxHash());
QString strText = entry->toJson();

QMessageBox::information(this, strWindowtitle, strText);
}

void MasternodeList::copyProTxHash_clicked()
{
auto dmn = GetSelectedDIP3MN();
if (!dmn) {
const auto* entry = GetSelectedEntry();
if (!entry) {
return;
}

QApplication::clipboard()->setText(QString::fromStdString(dmn->getProTxHash().ToString()));
QApplication::clipboard()->setText(entry->proTxHash());
}

void MasternodeList::copyCollateralOutpoint_clicked()
{
auto dmn = GetSelectedDIP3MN();
if (!dmn) {
const auto* entry = GetSelectedEntry();
if (!entry) {
return;
}

QApplication::clipboard()->setText(QString::fromStdString(dmn->getCollateralOutpoint().ToStringShort()));
QApplication::clipboard()->setText(entry->collateralOutpoint());
}
Loading