Dash Core  0.12.2.1
P2P Digital Currency
masternodelist.cpp
Go to the documentation of this file.
1 #include "masternodelist.h"
2 #include "ui_masternodelist.h"
3 
4 #include "activemasternode.h"
5 #include "clientmodel.h"
6 #include "init.h"
7 #include "guiutil.h"
8 #include "masternode-sync.h"
9 #include "masternodeconfig.h"
10 #include "masternodeman.h"
11 #include "sync.h"
12 #include "wallet/wallet.h"
13 #include "walletmodel.h"
14 
15 #include <QTimer>
16 #include <QMessageBox>
17 
19 {
20 #if QT_VERSION < 0x050200
21  const QDateTime dateTime1 = QDateTime::currentDateTime();
22  const QDateTime dateTime2 = QDateTime(dateTime1.date(), dateTime1.time(), Qt::UTC);
23  return dateTime1.secsTo(dateTime2);
24 #else
25  return QDateTime::currentDateTime().offsetFromUtc();
26 #endif
27 }
28 
29 MasternodeList::MasternodeList(const PlatformStyle *platformStyle, QWidget *parent) :
30  QWidget(parent),
31  ui(new Ui::MasternodeList),
32  clientModel(0),
33  walletModel(0)
34 {
35  ui->setupUi(this);
36 
37  ui->startButton->setEnabled(false);
38 
39  int columnAliasWidth = 100;
40  int columnAddressWidth = 200;
41  int columnProtocolWidth = 60;
42  int columnStatusWidth = 80;
43  int columnActiveWidth = 130;
44  int columnLastSeenWidth = 130;
45 
46  ui->tableWidgetMyMasternodes->setColumnWidth(0, columnAliasWidth);
47  ui->tableWidgetMyMasternodes->setColumnWidth(1, columnAddressWidth);
48  ui->tableWidgetMyMasternodes->setColumnWidth(2, columnProtocolWidth);
49  ui->tableWidgetMyMasternodes->setColumnWidth(3, columnStatusWidth);
50  ui->tableWidgetMyMasternodes->setColumnWidth(4, columnActiveWidth);
51  ui->tableWidgetMyMasternodes->setColumnWidth(5, columnLastSeenWidth);
52 
53  ui->tableWidgetMasternodes->setColumnWidth(0, columnAddressWidth);
54  ui->tableWidgetMasternodes->setColumnWidth(1, columnProtocolWidth);
55  ui->tableWidgetMasternodes->setColumnWidth(2, columnStatusWidth);
56  ui->tableWidgetMasternodes->setColumnWidth(3, columnActiveWidth);
57  ui->tableWidgetMasternodes->setColumnWidth(4, columnLastSeenWidth);
58 
59  ui->tableWidgetMyMasternodes->setContextMenuPolicy(Qt::CustomContextMenu);
60 
61  QAction *startAliasAction = new QAction(tr("Start alias"), this);
62  contextMenu = new QMenu();
63  contextMenu->addAction(startAliasAction);
64  connect(ui->tableWidgetMyMasternodes, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&)));
65  connect(startAliasAction, SIGNAL(triggered()), this, SLOT(on_startButton_clicked()));
66 
67  timer = new QTimer(this);
68  connect(timer, SIGNAL(timeout()), this, SLOT(updateNodeList()));
69  connect(timer, SIGNAL(timeout()), this, SLOT(updateMyNodeList()));
70  timer->start(1000);
71 
72  fFilterUpdated = false;
75 }
76 
78 {
79  delete ui;
80 }
81 
83 {
84  this->clientModel = model;
85  if(model) {
86  // try to update list when masternode count changes
87  connect(clientModel, SIGNAL(strMasternodesChanged(QString)), this, SLOT(updateNodeList()));
88  }
89 }
90 
92 {
93  this->walletModel = model;
94 }
95 
96 void MasternodeList::showContextMenu(const QPoint &point)
97 {
98  QTableWidgetItem *item = ui->tableWidgetMyMasternodes->itemAt(point);
99  if(item) contextMenu->exec(QCursor::pos());
100 }
101 
102 void MasternodeList::StartAlias(std::string strAlias)
103 {
104  std::string strStatusHtml;
105  strStatusHtml += "<center>Alias: " + strAlias;
106 
108  if(mne.getAlias() == strAlias) {
109  std::string strError;
111 
112  bool fSuccess = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb);
113 
114  if(fSuccess) {
115  strStatusHtml += "<br>Successfully started masternode.";
117  mnb.Relay(*g_connman);
119  } else {
120  strStatusHtml += "<br>Failed to start masternode.<br>Error: " + strError;
121  }
122  break;
123  }
124  }
125  strStatusHtml += "</center>";
126 
127  QMessageBox msg;
128  msg.setText(QString::fromStdString(strStatusHtml));
129  msg.exec();
130 
131  updateMyNodeList(true);
132 }
133 
134 void MasternodeList::StartAll(std::string strCommand)
135 {
136  int nCountSuccessful = 0;
137  int nCountFailed = 0;
138  std::string strFailedHtml;
139 
141  std::string strError;
143 
144  int32_t nOutputIndex = 0;
145  if(!ParseInt32(mne.getOutputIndex(), &nOutputIndex)) {
146  continue;
147  }
148 
149  COutPoint outpoint = COutPoint(uint256S(mne.getTxHash()), nOutputIndex);
150 
151  if(strCommand == "start-missing" && mnodeman.Has(outpoint)) continue;
152 
153  bool fSuccess = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb);
154 
155  if(fSuccess) {
156  nCountSuccessful++;
158  mnb.Relay(*g_connman);
160  } else {
161  nCountFailed++;
162  strFailedHtml += "\nFailed to start " + mne.getAlias() + ". Error: " + strError;
163  }
164  }
165  pwalletMain->Lock();
166 
167  std::string returnObj;
168  returnObj = strprintf("Successfully started %d masternodes, failed to start %d, total %d", nCountSuccessful, nCountFailed, nCountFailed + nCountSuccessful);
169  if (nCountFailed > 0) {
170  returnObj += strFailedHtml;
171  }
172 
173  QMessageBox msg;
174  msg.setText(QString::fromStdString(returnObj));
175  msg.exec();
176 
177  updateMyNodeList(true);
178 }
179 
180 void MasternodeList::updateMyMasternodeInfo(QString strAlias, QString strAddr, const COutPoint& outpoint)
181 {
182  bool fOldRowFound = false;
183  int nNewRow = 0;
184 
185  for(int i = 0; i < ui->tableWidgetMyMasternodes->rowCount(); i++) {
186  if(ui->tableWidgetMyMasternodes->item(i, 0)->text() == strAlias) {
187  fOldRowFound = true;
188  nNewRow = i;
189  break;
190  }
191  }
192 
193  if(nNewRow == 0 && !fOldRowFound) {
194  nNewRow = ui->tableWidgetMyMasternodes->rowCount();
195  ui->tableWidgetMyMasternodes->insertRow(nNewRow);
196  }
197 
198  masternode_info_t infoMn;
199  bool fFound = mnodeman.GetMasternodeInfo(outpoint, infoMn);
200 
201  QTableWidgetItem *aliasItem = new QTableWidgetItem(strAlias);
202  QTableWidgetItem *addrItem = new QTableWidgetItem(fFound ? QString::fromStdString(infoMn.addr.ToString()) : strAddr);
203  QTableWidgetItem *protocolItem = new QTableWidgetItem(QString::number(fFound ? infoMn.nProtocolVersion : -1));
204  QTableWidgetItem *statusItem = new QTableWidgetItem(QString::fromStdString(fFound ? CMasternode::StateToString(infoMn.nActiveState) : "MISSING"));
205  QTableWidgetItem *activeSecondsItem = new QTableWidgetItem(QString::fromStdString(DurationToDHMS(fFound ? (infoMn.nTimeLastPing - infoMn.sigTime) : 0)));
206  QTableWidgetItem *lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M",
207  fFound ? infoMn.nTimeLastPing + GetOffsetFromUtc() : 0)));
208  QTableWidgetItem *pubkeyItem = new QTableWidgetItem(QString::fromStdString(fFound ? CBitcoinAddress(infoMn.pubKeyCollateralAddress.GetID()).ToString() : ""));
209 
210  ui->tableWidgetMyMasternodes->setItem(nNewRow, 0, aliasItem);
211  ui->tableWidgetMyMasternodes->setItem(nNewRow, 1, addrItem);
212  ui->tableWidgetMyMasternodes->setItem(nNewRow, 2, protocolItem);
213  ui->tableWidgetMyMasternodes->setItem(nNewRow, 3, statusItem);
214  ui->tableWidgetMyMasternodes->setItem(nNewRow, 4, activeSecondsItem);
215  ui->tableWidgetMyMasternodes->setItem(nNewRow, 5, lastSeenItem);
216  ui->tableWidgetMyMasternodes->setItem(nNewRow, 6, pubkeyItem);
217 }
218 
220 {
221  TRY_LOCK(cs_mymnlist, fLockAcquired);
222  if(!fLockAcquired) {
223  return;
224  }
225  static int64_t nTimeMyListUpdated = 0;
226 
227  // automatically update my masternode list only once in MY_MASTERNODELIST_UPDATE_SECONDS seconds,
228  // this update still can be triggered manually at any time via button click
229  int64_t nSecondsTillUpdate = nTimeMyListUpdated + MY_MASTERNODELIST_UPDATE_SECONDS - GetTime();
230  ui->secondsLabel->setText(QString::number(nSecondsTillUpdate));
231 
232  if(nSecondsTillUpdate > 0 && !fForce) return;
233  nTimeMyListUpdated = GetTime();
234 
235  ui->tableWidgetMasternodes->setSortingEnabled(false);
237  int32_t nOutputIndex = 0;
238  if(!ParseInt32(mne.getOutputIndex(), &nOutputIndex)) {
239  continue;
240  }
241 
242  updateMyMasternodeInfo(QString::fromStdString(mne.getAlias()), QString::fromStdString(mne.getIp()), COutPoint(uint256S(mne.getTxHash()), nOutputIndex));
243  }
244  ui->tableWidgetMasternodes->setSortingEnabled(true);
245 
246  // reset "timer"
247  ui->secondsLabel->setText("0");
248 }
249 
251 {
252  TRY_LOCK(cs_mnlist, fLockAcquired);
253  if(!fLockAcquired) {
254  return;
255  }
256 
257  static int64_t nTimeListUpdated = GetTime();
258 
259  // to prevent high cpu usage update only once in MASTERNODELIST_UPDATE_SECONDS seconds
260  // or MASTERNODELIST_FILTER_COOLDOWN_SECONDS seconds after filter was last changed
261  int64_t nSecondsToWait = fFilterUpdated
263  : nTimeListUpdated - GetTime() + MASTERNODELIST_UPDATE_SECONDS;
264 
265  if(fFilterUpdated) ui->countLabel->setText(QString::fromStdString(strprintf("Please wait... %d", nSecondsToWait)));
266  if(nSecondsToWait > 0) return;
267 
268  nTimeListUpdated = GetTime();
269  fFilterUpdated = false;
270 
271  QString strToFilter;
272  ui->countLabel->setText("Updating...");
273  ui->tableWidgetMasternodes->setSortingEnabled(false);
274  ui->tableWidgetMasternodes->clearContents();
275  ui->tableWidgetMasternodes->setRowCount(0);
276  std::map<COutPoint, CMasternode> mapMasternodes = mnodeman.GetFullMasternodeMap();
277  int offsetFromUtc = GetOffsetFromUtc();
278 
279  for(auto& mnpair : mapMasternodes)
280  {
281  CMasternode mn = mnpair.second;
282  // populate list
283  // Address, Protocol, Status, Active Seconds, Last Seen, Pub Key
284  QTableWidgetItem *addressItem = new QTableWidgetItem(QString::fromStdString(mn.addr.ToString()));
285  QTableWidgetItem *protocolItem = new QTableWidgetItem(QString::number(mn.nProtocolVersion));
286  QTableWidgetItem *statusItem = new QTableWidgetItem(QString::fromStdString(mn.GetStatus()));
287  QTableWidgetItem *activeSecondsItem = new QTableWidgetItem(QString::fromStdString(DurationToDHMS(mn.lastPing.sigTime - mn.sigTime)));
288  QTableWidgetItem *lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M", mn.lastPing.sigTime + offsetFromUtc)));
289  QTableWidgetItem *pubkeyItem = new QTableWidgetItem(QString::fromStdString(CBitcoinAddress(mn.pubKeyCollateralAddress.GetID()).ToString()));
290 
291  if (strCurrentFilter != "")
292  {
293  strToFilter = addressItem->text() + " " +
294  protocolItem->text() + " " +
295  statusItem->text() + " " +
296  activeSecondsItem->text() + " " +
297  lastSeenItem->text() + " " +
298  pubkeyItem->text();
299  if (!strToFilter.contains(strCurrentFilter)) continue;
300  }
301 
302  ui->tableWidgetMasternodes->insertRow(0);
303  ui->tableWidgetMasternodes->setItem(0, 0, addressItem);
304  ui->tableWidgetMasternodes->setItem(0, 1, protocolItem);
305  ui->tableWidgetMasternodes->setItem(0, 2, statusItem);
306  ui->tableWidgetMasternodes->setItem(0, 3, activeSecondsItem);
307  ui->tableWidgetMasternodes->setItem(0, 4, lastSeenItem);
308  ui->tableWidgetMasternodes->setItem(0, 5, pubkeyItem);
309  }
310 
311  ui->countLabel->setText(QString::number(ui->tableWidgetMasternodes->rowCount()));
312  ui->tableWidgetMasternodes->setSortingEnabled(true);
313 }
314 
315 void MasternodeList::on_filterLineEdit_textChanged(const QString &strFilterIn)
316 {
317  strCurrentFilter = strFilterIn;
319  fFilterUpdated = true;
320  ui->countLabel->setText(QString::fromStdString(strprintf("Please wait... %d", MASTERNODELIST_FILTER_COOLDOWN_SECONDS)));
321 }
322 
324 {
325  std::string strAlias;
326  {
327  LOCK(cs_mymnlist);
328  // Find selected node alias
329  QItemSelectionModel* selectionModel = ui->tableWidgetMyMasternodes->selectionModel();
330  QModelIndexList selected = selectionModel->selectedRows();
331 
332  if(selected.count() == 0) return;
333 
334  QModelIndex index = selected.at(0);
335  int nSelectedRow = index.row();
336  strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString();
337  }
338 
339  // Display message box
340  QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm masternode start"),
341  tr("Are you sure you want to start masternode %1?").arg(QString::fromStdString(strAlias)),
342  QMessageBox::Yes | QMessageBox::Cancel,
343  QMessageBox::Cancel);
344 
345  if(retval != QMessageBox::Yes) return;
346 
348 
349  if(encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForMixingOnly) {
351 
352  if(!ctx.isValid()) return; // Unlock wallet was cancelled
353 
354  StartAlias(strAlias);
355  return;
356  }
357 
358  StartAlias(strAlias);
359 }
360 
362 {
363  // Display message box
364  QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm all masternodes start"),
365  tr("Are you sure you want to start ALL masternodes?"),
366  QMessageBox::Yes | QMessageBox::Cancel,
367  QMessageBox::Cancel);
368 
369  if(retval != QMessageBox::Yes) return;
370 
372 
373  if(encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForMixingOnly) {
375 
376  if(!ctx.isValid()) return; // Unlock wallet was cancelled
377 
378  StartAll();
379  return;
380  }
381 
382  StartAll();
383 }
384 
386 {
387 
389  QMessageBox::critical(this, tr("Command is not available right now"),
390  tr("You can't use this command until masternode list is synced"));
391  return;
392  }
393 
394  // Display message box
395  QMessageBox::StandardButton retval = QMessageBox::question(this,
396  tr("Confirm missing masternodes start"),
397  tr("Are you sure you want to start MISSING masternodes?"),
398  QMessageBox::Yes | QMessageBox::Cancel,
399  QMessageBox::Cancel);
400 
401  if(retval != QMessageBox::Yes) return;
402 
404 
405  if(encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForMixingOnly) {
407 
408  if(!ctx.isValid()) return; // Unlock wallet was cancelled
409 
410  StartAll("start-missing");
411  return;
412  }
413 
414  StartAll("start-missing");
415 }
416 
418 {
419  if(ui->tableWidgetMyMasternodes->selectedItems().count() > 0) {
420  ui->startButton->setEnabled(true);
421  }
422 }
423 
425 {
426  updateMyNodeList(true);
427 }
std::string DurationToDHMS(int64_t nDurationTime)
Definition: utiltime.cpp:91
CMasternodeMan mnodeman
MasternodeList(const PlatformStyle *platformStyle, QWidget *parent=0)
QTableWidget * tableWidgetMyMasternodes
CMasternodeSync masternodeSync
std::vector< CMasternodeEntry > & getEntries()
CMasternodeConfig masternodeConfig
#define TRY_LOCK(cs, name)
Definition: sync.h:170
void setWalletModel(WalletModel *walletModel)
void Relay(CConnman &connman)
Definition: masternode.cpp:665
#define strprintf
Definition: tinyformat.h:1011
#define MY_MASTERNODELIST_UPDATE_SECONDS
CMasternodePing lastPing
Definition: masternode.h:156
const std::string & getOutputIndex() const
std::string DateTimeStrFormat(const char *pszFormat, int64_t nTime)
Definition: utiltime.cpp:81
QString strCurrentFilter
ClientModel * clientModel
CCriticalSection cs_mymnlist
const std::string & getTxHash() const
EncryptionStatus getEncryptionStatus() const
CWallet * pwalletMain
std::string ToString(bool fUseGetnameinfo=true) const
Definition: netaddress.cpp:568
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:144
const std::string & getIp() const
Ui::MasternodeList * ui
int64_t nTimeLastPing
Definition: masternode.h:123
void on_tableWidgetMyMasternodes_itemSelectionChanged()
std::string GetStatus() const
Definition: masternode.cpp:314
void setClientModel(ClientModel *clientModel)
bool ParseInt32(const std::string &str, int32_t *out)
#define LOCK(cs)
Definition: sync.h:168
static secp256k1_context * ctx
Definition: tests.c:42
void showContextMenu(const QPoint &)
bool GetMasternodeInfo(const COutPoint &outpoint, masternode_info_t &mnInfoRet)
uint256 uint256S(const char *str)
Definition: uint256.h:140
static bool Create(const COutPoint &outpoint, const CService &service, const CKey &keyCollateralAddressNew, const CPubKey &pubKeyCollateralAddressNew, const CKey &keyMasternodeNew, const CPubKey &pubKeyMasternodeNew, std::string &strErrorRet, CMasternodeBroadcast &mnbRet)
Create Masternode broadcast, needs to be relayed manually after that.
Definition: masternode.cpp:397
QPushButton * startButton
#define MASTERNODELIST_FILTER_COOLDOWN_SECONDS
void setupUi(QWidget *MasternodeList)
void on_startButton_clicked()
#define MASTERNODELIST_UPDATE_SECONDS
CPubKey pubKeyCollateralAddress
Definition: masternode.h:116
int64_t sigTime
Definition: masternode.h:37
void on_filterLineEdit_textChanged(const QString &strFilterIn)
std::map< COutPoint, CMasternode > GetFullMasternodeMap()
void StartAll(std::string strCommand="start-all")
void on_startMissingButton_clicked()
CCriticalSection cs_mnlist
QMenu * contextMenu
bool Lock(bool fAllowMixing=false)
Definition: crypter.cpp:233
static std::string StateToString(int nStateIn)
Definition: masternode.cpp:294
void StartAlias(std::string strAlias)
WalletModel * walletModel
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:103
void NotifyMasternodeUpdates(CConnman &connman)
const std::string & getAlias() const
bool Has(const COutPoint &outpoint)
void on_startAllButton_clicked()
void updateMyMasternodeInfo(QString strAlias, QString strAddr, const COutPoint &outpoint)
int64_t GetTime()
For unit testing.
Definition: utiltime.cpp:20
void UpdateMasternodeList(CMasternodeBroadcast mnb, CConnman &connman)
Update masternode list and maps using provided CMasternodeBroadcast.
int GetOffsetFromUtc()
const std::string & getPrivKey() const
bool IsMasternodeListSynced()
QTableWidget * tableWidgetMasternodes
int64_t nTimeFilterUpdated
void on_UpdateButton_clicked()
void updateMyNodeList(bool fForce=false)
UnlockContext requestUnlock(bool fForMixingOnly=false)