Fix locking issues in dash-qt masternodelist (#1328)

* Add last ping time to masternode_info_t

* Use thread safe functions to access mnodeman in masternodelist.cpp

* Fix masternodelist widget locking

* Protect access to widget data from StartAlias button
This commit is contained in:
Tim Flynn 2017-02-09 19:56:52 -05:00 committed by UdjinM6
parent 4fcc766a29
commit 0b54ab85c8
4 changed files with 55 additions and 28 deletions

View File

@ -323,6 +323,7 @@ masternode_info_t CMasternode::GetInfo()
info.nTimeLastChecked = nTimeLastChecked; info.nTimeLastChecked = nTimeLastChecked;
info.nTimeLastPaid = nTimeLastPaid; info.nTimeLastPaid = nTimeLastPaid;
info.nTimeLastWatchdogVote = nTimeLastWatchdogVote; info.nTimeLastWatchdogVote = nTimeLastWatchdogVote;
info.nTimeLastPing = lastPing.sigTime;
info.nActiveState = nActiveState; info.nActiveState = nActiveState;
info.nProtocolVersion = nProtocolVersion; info.nProtocolVersion = nProtocolVersion;
info.fInfoValid = true; info.fInfoValid = true;

View File

@ -112,6 +112,7 @@ struct masternode_info_t
nTimeLastChecked(0), nTimeLastChecked(0),
nTimeLastPaid(0), nTimeLastPaid(0),
nTimeLastWatchdogVote(0), nTimeLastWatchdogVote(0),
nTimeLastPing(0),
nActiveState(0), nActiveState(0),
nProtocolVersion(0), nProtocolVersion(0),
fInfoValid(false) fInfoValid(false)
@ -126,6 +127,7 @@ struct masternode_info_t
int64_t nTimeLastChecked; int64_t nTimeLastChecked;
int64_t nTimeLastPaid; int64_t nTimeLastPaid;
int64_t nTimeLastWatchdogVote; int64_t nTimeLastWatchdogVote;
int64_t nTimeLastPing;
int nActiveState; int nActiveState;
int nProtocolVersion; int nProtocolVersion;
bool fInfoValid; bool fInfoValid;

View File

@ -15,8 +15,6 @@
#include <QTimer> #include <QTimer>
#include <QMessageBox> #include <QMessageBox>
CCriticalSection cs_masternodes;
MasternodeList::MasternodeList(const PlatformStyle *platformStyle, QWidget *parent) : MasternodeList::MasternodeList(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent), QWidget(parent),
ui(new Ui::MasternodeList), ui(new Ui::MasternodeList),
@ -132,10 +130,14 @@ void MasternodeList::StartAll(std::string strCommand)
std::string strError; std::string strError;
CMasternodeBroadcast mnb; CMasternodeBroadcast mnb;
CTxIn txin = CTxIn(uint256S(mne.getTxHash()), uint32_t(atoi(mne.getOutputIndex().c_str()))); int32_t nOutputIndex = 0;
CMasternode *pmn = mnodeman.Find(txin); if(!ParseInt32(mne.getOutputIndex(), &nOutputIndex)) {
continue;
}
if(strCommand == "start-missing" && pmn) continue; CTxIn txin = CTxIn(uint256S(mne.getTxHash()), nOutputIndex);
if(strCommand == "start-missing" && mnodeman.Has(txin)) continue;
bool fSuccess = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb); bool fSuccess = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb);
@ -164,9 +166,8 @@ void MasternodeList::StartAll(std::string strCommand)
updateMyNodeList(true); updateMyNodeList(true);
} }
void MasternodeList::updateMyMasternodeInfo(QString strAlias, QString strAddr, CMasternode *pmn) void MasternodeList::updateMyMasternodeInfo(QString strAlias, QString strAddr, masternode_info_t& infoMn)
{ {
LOCK(cs_mnlistupdate);
bool fOldRowFound = false; bool fOldRowFound = false;
int nNewRow = 0; int nNewRow = 0;
@ -184,12 +185,13 @@ void MasternodeList::updateMyMasternodeInfo(QString strAlias, QString strAddr, C
} }
QTableWidgetItem *aliasItem = new QTableWidgetItem(strAlias); QTableWidgetItem *aliasItem = new QTableWidgetItem(strAlias);
QTableWidgetItem *addrItem = new QTableWidgetItem(pmn ? QString::fromStdString(pmn->addr.ToString()) : strAddr); QTableWidgetItem *addrItem = new QTableWidgetItem(infoMn.fInfoValid ? QString::fromStdString(infoMn.addr.ToString()) : strAddr);
QTableWidgetItem *protocolItem = new QTableWidgetItem(QString::number(pmn ? pmn->nProtocolVersion : -1)); QTableWidgetItem *protocolItem = new QTableWidgetItem(QString::number(infoMn.fInfoValid ? infoMn.nProtocolVersion : -1));
QTableWidgetItem *statusItem = new QTableWidgetItem(QString::fromStdString(pmn ? pmn->GetStatus() : "MISSING")); QTableWidgetItem *statusItem = new QTableWidgetItem(QString::fromStdString(infoMn.fInfoValid ? CMasternode::StateToString(infoMn.nActiveState) : "MISSING"));
QTableWidgetItem *activeSecondsItem = new QTableWidgetItem(QString::fromStdString(DurationToDHMS(pmn ? (pmn->lastPing.sigTime - pmn->sigTime) : 0))); QTableWidgetItem *activeSecondsItem = new QTableWidgetItem(QString::fromStdString(DurationToDHMS(infoMn.fInfoValid ? (infoMn.nTimeLastPing - infoMn.sigTime) : 0)));
QTableWidgetItem *lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M", pmn ? pmn->lastPing.sigTime + QDateTime::currentDateTime().offsetFromUtc() : 0))); QTableWidgetItem *lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M",
QTableWidgetItem *pubkeyItem = new QTableWidgetItem(QString::fromStdString(pmn ? CBitcoinAddress(pmn->pubKeyCollateralAddress.GetID()).ToString() : "")); infoMn.fInfoValid ? infoMn.nTimeLastPing + QDateTime::currentDateTime().offsetFromUtc() : 0)));
QTableWidgetItem *pubkeyItem = new QTableWidgetItem(QString::fromStdString(infoMn.fInfoValid ? CBitcoinAddress(infoMn.pubKeyCollateralAddress.GetID()).ToString() : ""));
ui->tableWidgetMyMasternodes->setItem(nNewRow, 0, aliasItem); ui->tableWidgetMyMasternodes->setItem(nNewRow, 0, aliasItem);
ui->tableWidgetMyMasternodes->setItem(nNewRow, 1, addrItem); ui->tableWidgetMyMasternodes->setItem(nNewRow, 1, addrItem);
@ -202,6 +204,10 @@ void MasternodeList::updateMyMasternodeInfo(QString strAlias, QString strAddr, C
void MasternodeList::updateMyNodeList(bool fForce) void MasternodeList::updateMyNodeList(bool fForce)
{ {
TRY_LOCK(cs_mymnlist, fLockAcquired);
if(!fLockAcquired) {
return;
}
static int64_t nTimeMyListUpdated = 0; static int64_t nTimeMyListUpdated = 0;
// automatically update my masternode list only once in MY_MASTERNODELIST_UPDATE_SECONDS seconds, // automatically update my masternode list only once in MY_MASTERNODELIST_UPDATE_SECONDS seconds,
@ -214,10 +220,16 @@ void MasternodeList::updateMyNodeList(bool fForce)
ui->tableWidgetMasternodes->setSortingEnabled(false); ui->tableWidgetMasternodes->setSortingEnabled(false);
BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
CTxIn txin = CTxIn(uint256S(mne.getTxHash()), uint32_t(atoi(mne.getOutputIndex().c_str()))); int32_t nOutputIndex = 0;
CMasternode *pmn = mnodeman.Find(txin); if(!ParseInt32(mne.getOutputIndex(), &nOutputIndex)) {
continue;
}
updateMyMasternodeInfo(QString::fromStdString(mne.getAlias()), QString::fromStdString(mne.getIp()), pmn); CTxIn txin = CTxIn(uint256S(mne.getTxHash()), nOutputIndex);
masternode_info_t infoMn = mnodeman.GetMasternodeInfo(txin);
updateMyMasternodeInfo(QString::fromStdString(mne.getAlias()), QString::fromStdString(mne.getIp()), infoMn);
} }
ui->tableWidgetMasternodes->setSortingEnabled(true); ui->tableWidgetMasternodes->setSortingEnabled(true);
@ -227,6 +239,11 @@ void MasternodeList::updateMyNodeList(bool fForce)
void MasternodeList::updateNodeList() void MasternodeList::updateNodeList()
{ {
TRY_LOCK(cs_mnlist, fLockAcquired);
if(!fLockAcquired) {
return;
}
static int64_t nTimeListUpdated = GetTime(); static int64_t nTimeListUpdated = GetTime();
// to prevent high cpu usage update only once in MASTERNODELIST_UPDATE_SECONDS seconds // to prevent high cpu usage update only once in MASTERNODELIST_UPDATE_SECONDS seconds
@ -241,9 +258,6 @@ void MasternodeList::updateNodeList()
nTimeListUpdated = GetTime(); nTimeListUpdated = GetTime();
fFilterUpdated = false; fFilterUpdated = false;
TRY_LOCK(cs_masternodes, lockMasternodes);
if(!lockMasternodes) return;
QString strToFilter; QString strToFilter;
ui->countLabel->setText("Updating..."); ui->countLabel->setText("Updating...");
ui->tableWidgetMasternodes->setSortingEnabled(false); ui->tableWidgetMasternodes->setSortingEnabled(false);
@ -296,15 +310,19 @@ void MasternodeList::on_filterLineEdit_textChanged(const QString &strFilterIn)
void MasternodeList::on_startButton_clicked() void MasternodeList::on_startButton_clicked()
{ {
// Find selected node alias std::string strAlias;
QItemSelectionModel* selectionModel = ui->tableWidgetMyMasternodes->selectionModel(); {
QModelIndexList selected = selectionModel->selectedRows(); LOCK(cs_mymnlist);
// Find selected node alias
QItemSelectionModel* selectionModel = ui->tableWidgetMyMasternodes->selectionModel();
QModelIndexList selected = selectionModel->selectedRows();
if(selected.count() == 0) return; if(selected.count() == 0) return;
QModelIndex index = selected.at(0); QModelIndex index = selected.at(0);
int nSelectedRow = index.row(); int nSelectedRow = index.row();
std::string strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString(); strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString();
}
// Display message box // Display message box
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm masternode start"), QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm masternode start"),

View File

@ -45,7 +45,7 @@ private:
bool fFilterUpdated; bool fFilterUpdated;
public Q_SLOTS: public Q_SLOTS:
void updateMyMasternodeInfo(QString strAlias, QString strAddr, CMasternode *pmn); void updateMyMasternodeInfo(QString strAlias, QString strAddr, masternode_info_t& infoMn);
void updateMyNodeList(bool fForce = false); void updateMyNodeList(bool fForce = false);
void updateNodeList(); void updateNodeList();
@ -56,7 +56,13 @@ private:
Ui::MasternodeList *ui; Ui::MasternodeList *ui;
ClientModel *clientModel; ClientModel *clientModel;
WalletModel *walletModel; WalletModel *walletModel;
CCriticalSection cs_mnlistupdate;
// Protects tableWidgetMasternodes
CCriticalSection cs_mnlist;
// Protects tableWidgetMyMasternodes
CCriticalSection cs_mymnlist;
QString strCurrentFilter; QString strCurrentFilter;
private Q_SLOTS: private Q_SLOTS: