Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

masternodelist.cpp
Go to the documentation of this file.
1 #include <qt/masternodelist.h>
2 #include <qt/forms/ui_masternodelist.h>
3 
5 #include <qt/clientmodel.h>
6 #include <clientversion.h>
7 #include <coins.h>
8 #include <qt/guiutil.h>
9 #include <init.h>
11 #include <netbase.h>
12 #include <sync.h>
13 #include <validation.h>
14 #include <wallet/wallet.h>
15 #include <qt/walletmodel.h>
16 
17 #include <univalue.h>
18 
19 #include <QMessageBox>
20 #include <QTimer>
21 #include <QtGui/QClipboard>
22 
24 {
25 #if QT_VERSION < 0x050200
26  const QDateTime dateTime1 = QDateTime::currentDateTime();
27  const QDateTime dateTime2 = QDateTime(dateTime1.date(), dateTime1.time(), Qt::UTC);
28  return dateTime1.secsTo(dateTime2);
29 #else
30  return QDateTime::currentDateTime().offsetFromUtc();
31 #endif
32 }
33 
35  QWidget(parent),
36  ui(new Ui::MasternodeList),
37  clientModel(0),
38  walletModel(0),
39  fFilterUpdatedDIP3(true),
40  nTimeFilterUpdatedDIP3(0),
41  nTimeUpdatedDIP3(0),
42  mnListChanged(true)
43 {
44  ui->setupUi(this);
45 
46  GUIUtil::setFont({ui->label_count_2,
47  ui->countLabelDIP3
49  GUIUtil::setFont({ui->label_filter_2}, GUIUtil::FontWeight::Normal, 15);
50 
51  int columnAddressWidth = 200;
52  int columnStatusWidth = 80;
53  int columnPoSeScoreWidth = 80;
54  int columnRegisteredWidth = 80;
55  int columnLastPaidWidth = 80;
56  int columnNextPaymentWidth = 100;
57  int columnPayeeWidth = 130;
58  int columnOperatorRewardWidth = 130;
59  int columnCollateralWidth = 130;
60  int columnOwnerWidth = 130;
61  int columnVotingWidth = 130;
62 
63  ui->tableWidgetMasternodesDIP3->setColumnWidth(0, columnAddressWidth);
64  ui->tableWidgetMasternodesDIP3->setColumnWidth(1, columnStatusWidth);
65  ui->tableWidgetMasternodesDIP3->setColumnWidth(2, columnPoSeScoreWidth);
66  ui->tableWidgetMasternodesDIP3->setColumnWidth(3, columnRegisteredWidth);
67  ui->tableWidgetMasternodesDIP3->setColumnWidth(4, columnLastPaidWidth);
68  ui->tableWidgetMasternodesDIP3->setColumnWidth(5, columnNextPaymentWidth);
69  ui->tableWidgetMasternodesDIP3->setColumnWidth(6, columnPayeeWidth);
70  ui->tableWidgetMasternodesDIP3->setColumnWidth(7, columnOperatorRewardWidth);
71  ui->tableWidgetMasternodesDIP3->setColumnWidth(8, columnCollateralWidth);
72  ui->tableWidgetMasternodesDIP3->setColumnWidth(9, columnOwnerWidth);
73  ui->tableWidgetMasternodesDIP3->setColumnWidth(10, columnVotingWidth);
74 
75  // dummy column for proTxHash
76  // TODO use a proper table model for the MN list
77  ui->tableWidgetMasternodesDIP3->insertColumn(11);
78  ui->tableWidgetMasternodesDIP3->setColumnHidden(11, true);
79 
80  ui->tableWidgetMasternodesDIP3->setContextMenuPolicy(Qt::CustomContextMenu);
81 
82 #if QT_VERSION >= 0x040700
83  ui->filterLineEditDIP3->setPlaceholderText(tr("Filter by any property (e.g. address or protx hash)"));
84 #endif
85 
86  QAction* copyProTxHashAction = new QAction(tr("Copy ProTx Hash"), this);
87  QAction* copyCollateralOutpointAction = new QAction(tr("Copy Collateral Outpoint"), this);
88  contextMenuDIP3 = new QMenu(this);
89  contextMenuDIP3->addAction(copyProTxHashAction);
90  contextMenuDIP3->addAction(copyCollateralOutpointAction);
91  connect(ui->tableWidgetMasternodesDIP3, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenuDIP3(const QPoint&)));
92  connect(ui->tableWidgetMasternodesDIP3, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(extraInfoDIP3_clicked()));
93  connect(copyProTxHashAction, SIGNAL(triggered()), this, SLOT(copyProTxHash_clicked()));
94  connect(copyCollateralOutpointAction, SIGNAL(triggered()), this, SLOT(copyCollateralOutpoint_clicked()));
95 
96  timer = new QTimer(this);
97  connect(timer, SIGNAL(timeout()), this, SLOT(updateDIP3ListScheduled()));
98  timer->start(1000);
99 
101 }
102 
104 {
105  delete ui;
106 }
107 
109 {
110  this->clientModel = model;
111  if (model) {
112  // try to update list when masternode count changes
113  connect(clientModel, SIGNAL(masternodeListChanged()), this, SLOT(handleMasternodeListChanged()));
114  }
115 }
116 
118 {
119  this->walletModel = model;
120 }
121 
122 void MasternodeList::showContextMenuDIP3(const QPoint& point)
123 {
124  QTableWidgetItem* item = ui->tableWidgetMasternodesDIP3->itemAt(point);
125  if (item) contextMenuDIP3->exec(QCursor::pos());
126 }
127 
129 {
130  LOCK(cs_dip3list);
131  mnListChanged = true;
132 }
133 
135 {
136  TRY_LOCK(cs_dip3list, fLockAcquired);
137  if (!fLockAcquired) return;
138 
139  if (!clientModel || ShutdownRequested()) {
140  return;
141  }
142 
143  // To prevent high cpu usage update only once in MASTERNODELIST_FILTER_COOLDOWN_SECONDS seconds
144  // after filter was last changed unless we want to force the update.
145  if (fFilterUpdatedDIP3) {
147  ui->countLabelDIP3->setText(tr("Please wait...") + " " + QString::number(nSecondsToWait));
148 
149  if (nSecondsToWait <= 0) {
150  updateDIP3List();
151  fFilterUpdatedDIP3 = false;
152  }
153  } else if (mnListChanged) {
155  int64_t nSecondsToWait = nTimeUpdatedDIP3 - GetTime() + nMnListUpdateSecods;
156 
157  if (nSecondsToWait <= 0) {
158  updateDIP3List();
159  mnListChanged = false;
160  }
161  }
162 }
163 
165 {
166  if (!clientModel || ShutdownRequested()) {
167  return;
168  }
169 
170  auto mnList = clientModel->getMasternodeList();
171  std::map<uint256, CTxDestination> mapCollateralDests;
172 
173  {
174  // Get all UTXOs for each MN collateral in one go so that we can reduce locking overhead for cs_main
175  // We also do this outside of the below Qt list update loop to reduce cs_main locking time to a minimum
176  LOCK(cs_main);
177  mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
178  CTxDestination collateralDest;
179  Coin coin;
180  if (GetUTXOCoin(dmn->collateralOutpoint, coin) && ExtractDestination(coin.out.scriptPubKey, collateralDest)) {
181  mapCollateralDests.emplace(dmn->proTxHash, collateralDest);
182  }
183  });
184  }
185 
186  LOCK(cs_dip3list);
187 
188  QString strToFilter;
189  ui->countLabelDIP3->setText(tr("Updating..."));
190  ui->tableWidgetMasternodesDIP3->setSortingEnabled(false);
191  ui->tableWidgetMasternodesDIP3->clearContents();
192  ui->tableWidgetMasternodesDIP3->setRowCount(0);
193 
195 
196  auto projectedPayees = mnList.GetProjectedMNPayees(mnList.GetValidMNsCount());
197  std::map<uint256, int> nextPayments;
198  for (size_t i = 0; i < projectedPayees.size(); i++) {
199  const auto& dmn = projectedPayees[i];
200  nextPayments.emplace(dmn->proTxHash, mnList.GetHeight() + (int)i + 1);
201  }
202 
203  std::set<COutPoint> setOutpts;
204  if (walletModel && ui->checkBoxMyMasternodesOnly->isChecked()) {
205  std::vector<COutPoint> vOutpts;
206  walletModel->listProTxCoins(vOutpts);
207  for (const auto& outpt : vOutpts) {
208  setOutpts.emplace(outpt);
209  }
210  }
211 
212  mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
213  if (walletModel && ui->checkBoxMyMasternodesOnly->isChecked()) {
214  bool fMyMasternode = setOutpts.count(dmn->collateralOutpoint) ||
215  walletModel->IsSpendable(dmn->pdmnState->keyIDOwner) ||
216  walletModel->IsSpendable(dmn->pdmnState->keyIDVoting) ||
217  walletModel->IsSpendable(dmn->pdmnState->scriptPayout) ||
218  walletModel->IsSpendable(dmn->pdmnState->scriptOperatorPayout);
219  if (!fMyMasternode) return;
220  }
221  // populate list
222  // Address, Protocol, Status, Active Seconds, Last Seen, Pub Key
223  QTableWidgetItem* addressItem = new QTableWidgetItem(QString::fromStdString(dmn->pdmnState->addr.ToString()));
224  QTableWidgetItem* statusItem = new QTableWidgetItem(mnList.IsMNValid(dmn) ? tr("ENABLED") : (mnList.IsMNPoSeBanned(dmn) ? tr("POSE_BANNED") : tr("UNKNOWN")));
225  QTableWidgetItem* PoSeScoreItem = new QTableWidgetItem(QString::number(dmn->pdmnState->nPoSePenalty));
226  QTableWidgetItem* registeredItem = new QTableWidgetItem(QString::number(dmn->pdmnState->nRegisteredHeight));
227  QTableWidgetItem* lastPaidItem = new QTableWidgetItem(QString::number(dmn->pdmnState->nLastPaidHeight));
228  QTableWidgetItem* nextPaymentItem = new QTableWidgetItem(nextPayments.count(dmn->proTxHash) ? QString::number(nextPayments[dmn->proTxHash]) : tr("UNKNOWN"));
229 
230  CTxDestination payeeDest;
231  QString payeeStr = tr("UNKNOWN");
232  if (ExtractDestination(dmn->pdmnState->scriptPayout, payeeDest)) {
233  payeeStr = QString::fromStdString(EncodeDestination(payeeDest));
234  }
235  QTableWidgetItem* payeeItem = new QTableWidgetItem(payeeStr);
236 
237  QString operatorRewardStr = tr("NONE");
238  if (dmn->nOperatorReward) {
239  operatorRewardStr = QString::number(dmn->nOperatorReward / 100.0, 'f', 2) + "% ";
240 
241  if (dmn->pdmnState->scriptOperatorPayout != CScript()) {
242  CTxDestination operatorDest;
243  if (ExtractDestination(dmn->pdmnState->scriptOperatorPayout, operatorDest)) {
244  operatorRewardStr += tr("to %1").arg(QString::fromStdString(EncodeDestination(operatorDest)));
245  } else {
246  operatorRewardStr += tr("to UNKNOWN");
247  }
248  } else {
249  operatorRewardStr += tr("but not claimed");
250  }
251  }
252  QTableWidgetItem* operatorRewardItem = new QTableWidgetItem(operatorRewardStr);
253 
254  QString collateralStr = tr("UNKNOWN");
255  auto collateralDestIt = mapCollateralDests.find(dmn->proTxHash);
256  if (collateralDestIt != mapCollateralDests.end()) {
257  collateralStr = QString::fromStdString(EncodeDestination(collateralDestIt->second));
258  }
259  QTableWidgetItem* collateralItem = new QTableWidgetItem(collateralStr);
260 
261  QString ownerStr = QString::fromStdString(EncodeDestination(dmn->pdmnState->keyIDOwner));
262  QTableWidgetItem* ownerItem = new QTableWidgetItem(ownerStr);
263 
264  QString votingStr = QString::fromStdString(EncodeDestination(dmn->pdmnState->keyIDVoting));
265  QTableWidgetItem* votingItem = new QTableWidgetItem(votingStr);
266 
267  QTableWidgetItem* proTxHashItem = new QTableWidgetItem(QString::fromStdString(dmn->proTxHash.ToString()));
268 
269  if (strCurrentFilterDIP3 != "") {
270  strToFilter = addressItem->text() + " " +
271  statusItem->text() + " " +
272  PoSeScoreItem->text() + " " +
273  registeredItem->text() + " " +
274  lastPaidItem->text() + " " +
275  nextPaymentItem->text() + " " +
276  payeeItem->text() + " " +
277  operatorRewardItem->text() + " " +
278  collateralItem->text() + " " +
279  ownerItem->text() + " " +
280  votingItem->text() + " " +
281  proTxHashItem->text();
282  if (!strToFilter.contains(strCurrentFilterDIP3)) return;
283  }
284 
285  ui->tableWidgetMasternodesDIP3->insertRow(0);
286  ui->tableWidgetMasternodesDIP3->setItem(0, 0, addressItem);
287  ui->tableWidgetMasternodesDIP3->setItem(0, 1, statusItem);
288  ui->tableWidgetMasternodesDIP3->setItem(0, 2, PoSeScoreItem);
289  ui->tableWidgetMasternodesDIP3->setItem(0, 3, registeredItem);
290  ui->tableWidgetMasternodesDIP3->setItem(0, 4, lastPaidItem);
291  ui->tableWidgetMasternodesDIP3->setItem(0, 5, nextPaymentItem);
292  ui->tableWidgetMasternodesDIP3->setItem(0, 6, payeeItem);
293  ui->tableWidgetMasternodesDIP3->setItem(0, 7, operatorRewardItem);
294  ui->tableWidgetMasternodesDIP3->setItem(0, 8, collateralItem);
295  ui->tableWidgetMasternodesDIP3->setItem(0, 9, ownerItem);
296  ui->tableWidgetMasternodesDIP3->setItem(0, 10, votingItem);
297  ui->tableWidgetMasternodesDIP3->setItem(0, 11, proTxHashItem);
298  });
299 
300  ui->countLabelDIP3->setText(QString::number(ui->tableWidgetMasternodesDIP3->rowCount()));
301  ui->tableWidgetMasternodesDIP3->setSortingEnabled(true);
302 }
303 
305 {
306  strCurrentFilterDIP3 = strFilterIn;
308  fFilterUpdatedDIP3 = true;
309  ui->countLabelDIP3->setText(tr("Please wait...") + " " + QString::number(MASTERNODELIST_FILTER_COOLDOWN_SECONDS));
310 }
311 
313 {
314  // no cooldown
316  fFilterUpdatedDIP3 = true;
317 }
318 
320 {
321  if (!clientModel) {
322  return nullptr;
323  }
324 
325  std::string strProTxHash;
326  {
327  LOCK(cs_dip3list);
328 
329  QItemSelectionModel* selectionModel = ui->tableWidgetMasternodesDIP3->selectionModel();
330  QModelIndexList selected = selectionModel->selectedRows();
331 
332  if (selected.count() == 0) return nullptr;
333 
334  QModelIndex index = selected.at(0);
335  int nSelectedRow = index.row();
336  strProTxHash = ui->tableWidgetMasternodesDIP3->item(nSelectedRow, 11)->text().toStdString();
337  }
338 
339  uint256 proTxHash;
340  proTxHash.SetHex(strProTxHash);
341 
342  auto mnList = clientModel->getMasternodeList();
343  return mnList.GetMN(proTxHash);
344 }
345 
347 {
348  auto dmn = GetSelectedDIP3MN();
349  if (!dmn) {
350  return;
351  }
352 
353  UniValue json(UniValue::VOBJ);
354  dmn->ToJson(json);
355 
356  // Title of popup window
357  QString strWindowtitle = tr("Additional information for DIP3 Masternode %1").arg(QString::fromStdString(dmn->proTxHash.ToString()));
358  QString strText = QString::fromStdString(json.write(2));
359 
360  QMessageBox::information(this, strWindowtitle, strText);
361 }
362 
364 {
365  auto dmn = GetSelectedDIP3MN();
366  if (!dmn) {
367  return;
368  }
369 
370  QApplication::clipboard()->setText(QString::fromStdString(dmn->proTxHash.ToString()));
371 }
372 
374 {
375  auto dmn = GetSelectedDIP3MN();
376  if (!dmn) {
377  return;
378  }
379 
380  QApplication::clipboard()->setText(QString::fromStdString(dmn->collateralOutpoint.ToStringShort()));
381 }
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:80
CMasternodeSync masternodeSync
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:158
CScript scriptPubKey
Definition: transaction.h:148
#define TRY_LOCK(cs, name)
Definition: sync.h:180
void setFont(const std::vector< QWidget *> &vecWidgets, FontWeight weight, int nPointSize, bool fItalic)
Workaround to set correct font styles in all themes since there is a bug in macOS which leads to issu...
Definition: guiutil.cpp:1552
A UTXO entry.
Definition: coins.h:29
CCriticalSection cs_dip3list
CDeterministicMNCPtr GetMN(const uint256 &proTxHash) const
CDeterministicMNCPtr GetSelectedDIP3MN()
bool ShutdownRequested()
Definition: init.cpp:179
void updateDIP3ListScheduled()
void setWalletModel(WalletModel *walletModel)
int64_t nTimeFilterUpdatedDIP3
CCriticalSection cs_main
Definition: validation.cpp:213
CTxOut out
unspent transaction output
Definition: coins.h:33
void extraInfoDIP3_clicked()
void handleMasternodeListChanged()
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
false true true true
Definition: bls_dkg.cpp:176
QString strCurrentFilterDIP3
std::shared_ptr< const CDeterministicMN > CDeterministicMNCPtr
bool IsBlockchainSynced()
ClientModel * clientModel
MasternodeList(QWidget *parent=0)
int64_t GetTime()
Return system time (or mocked time, if set)
Definition: utiltime.cpp:22
void updateFonts()
Update the font of all widgets where a custom font has been set with GUIUtil::setFont.
Definition: guiutil.cpp:1563
bool GetUTXOCoin(const COutPoint &outpoint, Coin &coin)
Definition: validation.cpp:439
void copyCollateralOutpoint_clicked()
QMenu * contextMenuDIP3
void showContextMenuDIP3(const QPoint &)
#define LOCK(cs)
Definition: sync.h:178
void listProTxCoins(std::vector< COutPoint > &vOutpts)
int64_t nTimeUpdatedDIP3
CDeterministicMNList getMasternodeList() const
Definition: clientmodel.cpp:88
Model for Dash network client.
Definition: clientmodel.h:42
#define MASTERNODELIST_FILTER_COOLDOWN_SECONDS
Masternode Manager page widget.
#define MASTERNODELIST_UPDATE_SECONDS
256-bit opaque blob.
Definition: uint256.h:123
void on_checkBoxMyMasternodesOnly_stateChanged(int state)
std::string EncodeDestination(const CTxDestination &dest)
Definition: base58.cpp:329
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:389
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:100
void doubleClicked(const QModelIndex &)
WalletModel * walletModel
Ui::MasternodeList * ui
void SetHex(const char *psz)
Definition: uint256.cpp:27
int GetOffsetFromUtc()
void setClientModel(ClientModel *clientModel)
void copyProTxHash_clicked()
void on_filterLineEditDIP3_textChanged(const QString &strFilterIn)
bool IsSpendable(const CTxDestination &dest) const
Released under the MIT license