#include "masternodelist.h" #include "ui_masternodelist.h" #include "sync.h" #include "clientmodel.h" #include "walletmodel.h" #include "activemasternode.h" #include "masternode-sync.h" #include "masternodeconfig.h" #include "masternodeman.h" #include "wallet/wallet.h" #include "init.h" #include "guiutil.h" #include #include CCriticalSection cs_masternodes; MasternodeList::MasternodeList(const PlatformStyle *platformStyle, QWidget *parent) : QWidget(parent), ui(new Ui::MasternodeList), clientModel(0), walletModel(0) { ui->setupUi(this); ui->startButton->setEnabled(false); int columnAliasWidth = 100; int columnAddressWidth = 200; int columnProtocolWidth = 60; int columnStatusWidth = 80; int columnActiveWidth = 130; int columnLastSeenWidth = 130; ui->tableWidgetMyMasternodes->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); ui->tableWidgetMyMasternodes->setColumnWidth(0, columnAliasWidth); ui->tableWidgetMyMasternodes->setColumnWidth(1, columnAddressWidth); ui->tableWidgetMyMasternodes->setColumnWidth(2, columnProtocolWidth); ui->tableWidgetMyMasternodes->setColumnWidth(3, columnStatusWidth); ui->tableWidgetMyMasternodes->setColumnWidth(4, columnActiveWidth); ui->tableWidgetMyMasternodes->setColumnWidth(5, columnLastSeenWidth); ui->tableWidgetMasternodes->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); ui->tableWidgetMasternodes->setColumnWidth(0, columnAddressWidth); ui->tableWidgetMasternodes->setColumnWidth(1, columnProtocolWidth); ui->tableWidgetMasternodes->setColumnWidth(2, columnStatusWidth); ui->tableWidgetMasternodes->setColumnWidth(3, columnActiveWidth); ui->tableWidgetMasternodes->setColumnWidth(4, columnLastSeenWidth); ui->tableWidgetMyMasternodes->setContextMenuPolicy(Qt::CustomContextMenu); QAction *startAliasAction = new QAction(tr("Start alias"), this); contextMenu = new QMenu(); contextMenu->addAction(startAliasAction); connect(ui->tableWidgetMyMasternodes, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); connect(startAliasAction, SIGNAL(triggered()), this, SLOT(on_startButton_clicked())); timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(updateNodeList())); connect(timer, SIGNAL(timeout()), this, SLOT(updateMyNodeList())); timer->start(1000); updateNodeList(); } MasternodeList::~MasternodeList() { delete ui; } void MasternodeList::setClientModel(ClientModel *model) { this->clientModel = model; if(model) { // try to update list when masternode count changes connect(clientModel, SIGNAL(strMasternodesChanged(QString)), this, SLOT(updateNodeList())); } } void MasternodeList::setWalletModel(WalletModel *model) { this->walletModel = model; } void MasternodeList::showContextMenu(const QPoint &point) { QTableWidgetItem *item = ui->tableWidgetMyMasternodes->itemAt(point); if(item) contextMenu->exec(QCursor::pos()); } void MasternodeList::StartAlias(std::string strAlias) { std::string statusObj; statusObj += "
Alias: " + strAlias; BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { if(mne.getAlias() == strAlias) { std::string errorMessage; CMasternodeBroadcast mnb; bool result = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnb); if(result) { statusObj += "
Successfully started masternode." ; mnodeman.UpdateMasternodeList(mnb); mnb.Relay(); } else { statusObj += "
Failed to start masternode.
Error: " + errorMessage; } break; } } statusObj += "
"; QMessageBox msg; msg.setText(QString::fromStdString(statusObj)); msg.exec(); } void MasternodeList::StartAll(std::string strCommand) { int total = 0; int successful = 0; int fail = 0; std::string statusObj; BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { std::string errorMessage; CMasternodeBroadcast mnb; CTxIn vin = CTxIn(uint256S(mne.getTxHash()), uint32_t(atoi(mne.getOutputIndex().c_str()))); CMasternode *pmn = mnodeman.Find(vin); if(strCommand == "start-missing" && pmn) continue; bool result = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnb); if(result) { successful++; mnodeman.UpdateMasternodeList(mnb); mnb.Relay(); } else { fail++; statusObj += "\nFailed to start " + mne.getAlias() + ". Error: " + errorMessage; } total++; } pwalletMain->Lock(); std::string returnObj; returnObj = strprintf("Successfully started %d masternodes, failed to start %d, total %d", successful, fail, total); if (fail > 0) returnObj += statusObj; QMessageBox msg; msg.setText(QString::fromStdString(returnObj)); msg.exec(); } void MasternodeList::updateMyMasternodeInfo(QString alias, QString addr, QString privkey, QString txHash, QString txIndex, CMasternode *pmn) { LOCK(cs_mnlistupdate); bool bFound = false; int nodeRow = 0; for(int i=0; i < ui->tableWidgetMyMasternodes->rowCount(); i++) { if(ui->tableWidgetMyMasternodes->item(i, 0)->text() == alias) { bFound = true; nodeRow = i; break; } } if(nodeRow == 0 && !bFound) { nodeRow = ui->tableWidgetMyMasternodes->rowCount(); ui->tableWidgetMyMasternodes->insertRow(nodeRow); } QTableWidgetItem *aliasItem = new QTableWidgetItem(alias); QTableWidgetItem *addrItem = new QTableWidgetItem(addr); QTableWidgetItem *protocolItem = new QTableWidgetItem(QString::number(pmn ? pmn->protocolVersion : -1)); QTableWidgetItem *statusItem = new QTableWidgetItem(QString::fromStdString(pmn ? pmn->Status() : "MISSING")); QTableWidgetItem *activeSecondsItem = new QTableWidgetItem(QString::fromStdString(DurationToDHMS(pmn ? (pmn->lastPing.sigTime - pmn->sigTime) : 0))); QTableWidgetItem *lastSeenItem = new QTableWidgetItem(GUIUtil::dateTimeStr(pmn ? pmn->lastPing.sigTime : 0)); QTableWidgetItem *pubkeyItem = new QTableWidgetItem(QString::fromStdString(pmn ? CBitcoinAddress(pmn->pubkey.GetID()).ToString() : "")); ui->tableWidgetMyMasternodes->setItem(nodeRow, 0, aliasItem); ui->tableWidgetMyMasternodes->setItem(nodeRow, 1, addrItem); ui->tableWidgetMyMasternodes->setItem(nodeRow, 2, protocolItem); ui->tableWidgetMyMasternodes->setItem(nodeRow, 3, statusItem); ui->tableWidgetMyMasternodes->setItem(nodeRow, 4, activeSecondsItem); ui->tableWidgetMyMasternodes->setItem(nodeRow, 5, lastSeenItem); ui->tableWidgetMyMasternodes->setItem(nodeRow, 6, pubkeyItem); } void MasternodeList::updateMyNodeList(bool reset) { static int64_t lastMyListUpdate = 0; // automatically update my masternode list only once in MY_MASTERNODELIST_UPDATE_SECONDS seconds, // this update still can be triggered manually at any time via button click int64_t timeTillUpdate = lastMyListUpdate + MY_MASTERNODELIST_UPDATE_SECONDS - GetTime(); ui->secondsLabel->setText(QString::number(timeTillUpdate)); if(timeTillUpdate > 0 && !reset) return; lastMyListUpdate = GetTime(); ui->tableWidgetMasternodes->setSortingEnabled(false); BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { CTxIn vin = CTxIn(uint256S(mne.getTxHash()), uint32_t(atoi(mne.getOutputIndex().c_str()))); CMasternode *pmn = mnodeman.Find(vin); updateMyMasternodeInfo(QString::fromStdString(mne.getAlias()), QString::fromStdString(mne.getIp()), QString::fromStdString(mne.getPrivKey()), QString::fromStdString(mne.getTxHash()), QString::fromStdString(mne.getOutputIndex()), pmn); } ui->tableWidgetMasternodes->setSortingEnabled(true); // reset "timer" ui->secondsLabel->setText("0"); } void MasternodeList::updateNodeList() { static int64_t lastListUpdate = 0; // update only once in MASTERNODELIST_UPDATE_SECONDS seconds to prevent high cpu usage e.g. on filter change if(GetTime() - lastListUpdate < MASTERNODELIST_UPDATE_SECONDS) return; lastListUpdate = GetTime(); TRY_LOCK(cs_masternodes, lockMasternodes); if(!lockMasternodes) return; QString strToFilter; ui->countLabel->setText("Updating..."); ui->tableWidgetMasternodes->setSortingEnabled(false); ui->tableWidgetMasternodes->clearContents(); ui->tableWidgetMasternodes->setRowCount(0); std::vector vMasternodes = mnodeman.GetFullMasternodeVector(); BOOST_FOREACH(CMasternode& mn, vMasternodes) { // populate list // Address, Protocol, Status, Active Seconds, Last Seen, Pub Key QTableWidgetItem *addressItem = new QTableWidgetItem(QString::fromStdString(mn.addr.ToString())); QTableWidgetItem *protocolItem = new QTableWidgetItem(QString::number(mn.protocolVersion)); QTableWidgetItem *statusItem = new QTableWidgetItem(QString::fromStdString(mn.Status())); QTableWidgetItem *activeSecondsItem = new QTableWidgetItem(QString::fromStdString(DurationToDHMS(mn.lastPing.sigTime - mn.sigTime))); QTableWidgetItem *lastSeenItem = new QTableWidgetItem(GUIUtil::dateTimeStr(mn.lastPing.sigTime)); QTableWidgetItem *pubkeyItem = new QTableWidgetItem(QString::fromStdString(CBitcoinAddress(mn.pubkey.GetID()).ToString())); if (strCurrentFilter != "") { strToFilter = addressItem->text() + " " + protocolItem->text() + " " + statusItem->text() + " " + activeSecondsItem->text() + " " + lastSeenItem->text() + " " + pubkeyItem->text(); if (!strToFilter.contains(strCurrentFilter)) continue; } ui->tableWidgetMasternodes->insertRow(0); ui->tableWidgetMasternodes->setItem(0, 0, addressItem); ui->tableWidgetMasternodes->setItem(0, 1, protocolItem); ui->tableWidgetMasternodes->setItem(0, 2, statusItem); ui->tableWidgetMasternodes->setItem(0, 3, activeSecondsItem); ui->tableWidgetMasternodes->setItem(0, 4, lastSeenItem); ui->tableWidgetMasternodes->setItem(0, 5, pubkeyItem); } ui->countLabel->setText(QString::number(ui->tableWidgetMasternodes->rowCount())); ui->tableWidgetMasternodes->setSortingEnabled(true); } void MasternodeList::on_filterLineEdit_textChanged(const QString &filterString) { strCurrentFilter = filterString; ui->countLabel->setText("Please wait..."); } void MasternodeList::on_startButton_clicked() { // Find selected node alias QItemSelectionModel* selectionModel = ui->tableWidgetMyMasternodes->selectionModel(); QModelIndexList selected = selectionModel->selectedRows(); if(selected.count() == 0) return; QModelIndex index = selected.at(0); int r = index.row(); std::string strAlias = ui->tableWidgetMyMasternodes->item(r, 0)->text().toStdString(); // Display message box QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm masternode start"), tr("Are you sure you want to start masternode %1?").arg(QString::fromStdString(strAlias)), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); if(retval != QMessageBox::Yes) { return; } WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); if(encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) { WalletModel::UnlockContext ctx(walletModel->requestUnlock(true)); if(!ctx.isValid()) { // Unlock wallet was cancelled return; } StartAlias(strAlias); return; } StartAlias(strAlias); } void MasternodeList::on_startAllButton_clicked() { // Display message box QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm all masternodes start"), tr("Are you sure you want to start ALL masternodes?"), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); if(retval != QMessageBox::Yes) { return; } WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); if(encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) { WalletModel::UnlockContext ctx(walletModel->requestUnlock(true)); if(!ctx.isValid()) { // Unlock wallet was cancelled return; } StartAll(); return; } StartAll(); } void MasternodeList::on_startMissingButton_clicked() { if(masternodeSync.RequestedMasternodeAssets <= MASTERNODE_SYNC_LIST || masternodeSync.RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED) { QMessageBox::critical(this, tr("Command is not available right now"), tr("You can't use this command until masternode list is synced")); return; } // Display message box QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm missing masternodes start"), tr("Are you sure you want to start MISSING masternodes?"), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); if(retval != QMessageBox::Yes) { return; } WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); if(encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) { WalletModel::UnlockContext ctx(walletModel->requestUnlock(true)); if(!ctx.isValid()) { // Unlock wallet was cancelled return; } StartAll("start-missing"); return; } StartAll("start-missing"); } void MasternodeList::on_tableWidgetMyMasternodes_itemSelectionChanged() { if(ui->tableWidgetMyMasternodes->selectedItems().count() > 0) { ui->startButton->setEnabled(true); } } void MasternodeList::on_UpdateButton_clicked() { updateMyNodeList(true); }