PIVX Core  5.6.99
P2P Digital Currency
masternodewizarddialog.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2022 The PIVX Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
6 #include "ui_masternodewizarddialog.h"
7 
8 #include "key_io.h"
9 #include "mnmodel.h"
10 #include "qt/walletmodel.h"
11 #include "qtutils.h"
12 
13 #include <QIntValidator>
14 #include <QRegularExpression>
15 
16 static inline QString formatParagraph(const QString& str) {
17  return "<p align=\"justify\" style=\"text-align:center;\">" + str + "</p>";
18 }
19 
20 static inline QString formatHtmlContent(const QString& str) {
21  return "<html><body>" + str + "</body></html>";
22 }
23 
24 static void initBtn(std::initializer_list<QPushButton*> args)
25 {
26  QSize BUTTON_SIZE = QSize(22, 22);
27  for (QPushButton* btn : args) {
28  btn->setMinimumSize(BUTTON_SIZE);
29  btn->setMaximumSize(BUTTON_SIZE);
30  btn->move(0, 0);
31  btn->show();
32  btn->raise();
33  btn->setVisible(false);
34  }
35 }
36 
38  FocusedDialog(parent),
39  ui(new Ui::MasterNodeWizardDialog),
40  icConfirm1(new QPushButton(this)),
41  icConfirm3(new QPushButton(this)),
42  icConfirm4(new QPushButton(this)),
43  walletModel(model),
44  mnModel(_mnModel)
45 {
46  ui->setupUi(this);
47 
48  this->setStyleSheet(parent->styleSheet());
49  setCssProperty(ui->frame, "container-dialog");
50  ui->frame->setContentsMargins(10,10,10,10);
51 
52  setCssProperty({ui->labelLine1, ui->labelLine3}, "line-purple");
53  setCssProperty({ui->groupBoxName, ui->groupContainer}, "container-border");
54  setCssProperty({ui->pushNumber1, ui->pushNumber3, ui->pushNumber4}, "btn-number-check");
55  setCssProperty({ui->pushName1, ui->pushName3, ui->pushName4}, "btn-name-check");
56 
57  ui->pushNumber1->setEnabled(false);
58  ui->pushNumber3->setEnabled(false);
59  ui->pushNumber4->setEnabled(false);
60  ui->pushName1->setEnabled(false);
61  ui->pushName3->setEnabled(false);
62  ui->pushName4->setEnabled(false);
63 
64  // Frame 1
65  setCssProperty(ui->labelTitle1, "text-title-dialog");
66  setCssProperty(ui->labelMessage1a, "text-main-grey");
67  setCssProperty(ui->labelMessage1b, "text-main-purple");
68 
69  QString collateralAmountStr = GUIUtil::formatBalance(mnModel->getMNCollateralRequiredAmount());
70  ui->labelMessage1a->setText(formatHtmlContent(
71  formatParagraph(tr("To create a PIVX Masternode you must dedicate %1 (the unit of PIVX) "
72  "to the network (however, these coins are still yours and will never leave your possession).").arg(collateralAmountStr)) +
73  formatParagraph(tr("You can deactivate the node and unlock the coins at any time."))));
74 
75  // Frame 3
76  setCssProperty(ui->labelTitle3, "text-title-dialog");
77  setCssProperty(ui->labelMessage3, "text-main-grey");
78 
79  ui->labelMessage3->setText(formatHtmlContent(
80  formatParagraph(tr("A transaction of %1 will be made").arg(collateralAmountStr)) +
81  formatParagraph(tr("to a new empty address in your wallet.")) +
82  formatParagraph(tr("The Address is labeled under the master node's name."))));
83 
84  initCssEditLine(ui->lineEditName);
85  // MN alias must not contain spaces or "#" character
86  QRegularExpression rx("^(?:(?![\\#\\s]).)*");
87  ui->lineEditName->setValidator(new QRegularExpressionValidator(rx, ui->lineEditName));
88 
89  // Frame 4
90  setCssProperty(ui->labelTitle4, "text-title-dialog");
91  setCssProperty({ui->labelSubtitleIp, ui->labelSubtitlePort}, "text-title");
92  setCssSubtitleScreen(ui->labelSubtitleAddressIp);
93 
94  initCssEditLine(ui->lineEditIpAddress);
95  initCssEditLine(ui->lineEditPort);
96  ui->stackedWidget->setCurrentIndex(pos);
97  ui->lineEditPort->setEnabled(false); // use default port number
99  ui->lineEditPort->setText("51476");
100  } else if (walletModel->isTestNetwork()) {
101  ui->lineEditPort->setText("51474");
102  } else {
103  ui->lineEditPort->setText("51472");
104  }
105 
106  // Confirm icons
107  ui->stackedIcon1->addWidget(icConfirm1);
108  ui->stackedIcon3->addWidget(icConfirm3);
109  ui->stackedIcon4->addWidget(icConfirm4);
110  initBtn({icConfirm1, icConfirm3, icConfirm4});
111  setCssProperty({icConfirm1, icConfirm3, icConfirm4}, "ic-step-confirm");
112 
113  // Connect btns
114  setCssBtnPrimary(ui->btnNext);
115  setCssProperty(ui->btnBack , "btn-dialog-cancel");
116  ui->btnBack->setVisible(false);
117  setCssProperty(ui->pushButtonSkip, "ic-close");
118 
119  connect(ui->pushButtonSkip, &QPushButton::clicked, this, &MasterNodeWizardDialog::close);
120  connect(ui->btnNext, &QPushButton::clicked, this, &MasterNodeWizardDialog::accept);
121  connect(ui->btnBack, &QPushButton::clicked, this, &MasterNodeWizardDialog::onBackClicked);
122 }
123 
124 void MasterNodeWizardDialog::showEvent(QShowEvent *event)
125 {
126  if (ui->btnNext) ui->btnNext->setFocus();
127 }
128 
130 {
131  switch(pos) {
132  case 0:{
133  ui->stackedWidget->setCurrentIndex(1);
134  ui->pushName4->setChecked(false);
135  ui->pushName3->setChecked(true);
136  ui->pushName1->setChecked(true);
137  icConfirm1->setVisible(true);
138  ui->pushNumber3->setChecked(true);
139  ui->btnBack->setVisible(true);
140  ui->lineEditName->setFocus();
141  break;
142  }
143  case 1: {
144  // No empty names accepted.
145  if (ui->lineEditName->text().isEmpty()) {
146  setCssEditLine(ui->lineEditName, false, true);
147  return;
148  }
149  setCssEditLine(ui->lineEditName, true, true);
150 
151  ui->stackedWidget->setCurrentIndex(2);
152  ui->pushName4->setChecked(false);
153  ui->pushName3->setChecked(true);
154  ui->pushName1->setChecked(true);
155  icConfirm3->setVisible(true);
156  ui->pushNumber4->setChecked(true);
157  ui->lineEditIpAddress->setFocus();
158  break;
159  }
160  case 2: {
161  // No empty address accepted
162  if (ui->lineEditIpAddress->text().isEmpty()) {
163  return;
164  }
165  icConfirm4->setVisible(true);
166  isOk = createMN();
167  QDialog::accept();
168  }
169  }
170  pos++;
171 }
172 
174 {
175  if (!walletModel) {
176  returnStr = tr("walletModel not set");
177  return false;
178  }
179 
180  // validate IP address
181  QString addressLabel = ui->lineEditName->text();
182  if (addressLabel.isEmpty()) {
183  returnStr = tr("address label cannot be empty");
184  return false;
185  }
186 
187  QString addressStr = ui->lineEditIpAddress->text();
188  QString portStr = ui->lineEditPort->text();
189  if (addressStr.isEmpty() || portStr.isEmpty()) {
190  returnStr = tr("IP or port cannot be empty");
191  return false;
192  }
193  if (!MNModel::validateMNIP(addressStr)) {
194  returnStr = tr("Invalid IP address");
195  return false;
196  }
197 
198  std::string alias = addressLabel.toStdString();
199  std::string ipAddress = addressStr.toStdString();
200  std::string port = portStr.toStdString();
201 
202  // create the mn key
203  CKey secret;
204  secret.MakeNewKey(false);
205  std::string mnKeyString = KeyIO::EncodeSecret(secret);
206 
207  // Look for a valid collateral utxo
208  COutPoint collateralOut;
209 
210  // If not found create a new collateral tx
211  if (!walletModel->getMNCollateralCandidate(collateralOut)) {
212  // New receive address
213  auto r = walletModel->getNewAddress(alias);
214  if (!r) {
215  // generate address fail
216  returnStr = tr(r.getError().c_str());
217  return false;
218  }
219 
220  if (!mnModel->createMNCollateral(addressLabel,
221  QString::fromStdString(r.getObjResult()->ToString()),
222  collateralOut,
223  returnStr)) {
224  // error str set internally
225  return false;
226  }
227  }
228 
229  mnEntry = mnModel->createLegacyMN(collateralOut, alias, ipAddress, port, mnKeyString, returnStr);
230  if (!mnEntry) {
231  // error str set inside createLegacyMN
232  return false;
233  }
234 
235  returnStr = tr("Masternode created! Wait %1 confirmations before starting it.").arg(mnModel->getMasternodeCollateralMinConf());
236  return true;
237 }
238 
240 {
241  if (pos == 0) return;
242  pos--;
243  switch(pos) {
244  case 0:{
245  ui->stackedWidget->setCurrentIndex(0);
246  ui->btnNext->setFocus();
247  ui->pushNumber1->setChecked(true);
248  ui->pushNumber4->setChecked(false);
249  ui->pushNumber3->setChecked(false);
250  ui->pushName4->setChecked(false);
251  ui->pushName3->setChecked(false);
252  ui->pushName1->setChecked(true);
253  icConfirm1->setVisible(false);
254  ui->btnBack->setVisible(false);
255  break;
256  }
257  case 1: {
258  ui->stackedWidget->setCurrentIndex(1);
259  ui->lineEditName->setFocus();
260  ui->pushNumber4->setChecked(false);
261  ui->pushNumber3->setChecked(true);
262  ui->pushName4->setChecked(false);
263  ui->pushName3->setChecked(true);
264  icConfirm3->setVisible(false);
265 
266  break;
267  }
268  }
269 }
270 
271 void MasterNodeWizardDialog::inform(const QString& text)
272 {
273  if (!snackBar)
274  snackBar = new SnackBar(nullptr, this);
275  snackBar->setText(text);
276  snackBar->resize(this->width(), snackBar->height());
277  openDialog(snackBar, this);
278 }
279 
281 {
282  delete snackBar;
283  delete ui;
284 }
An encapsulated private key.
Definition: key.h:30
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:158
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:72
bool createMNCollateral(const QString &alias, const QString &addr, COutPoint &ret_outpoint, QString &ret_error)
Definition: mnmodel.cpp:210
CAmount getMNCollateralRequiredAmount()
Definition: mnmodel.cpp:200
static bool validateMNIP(const QString &addrStr)
Definition: mnmodel.cpp:195
CMasternodeConfig::CMasternodeEntry * createLegacyMN(COutPoint &collateralOut, const std::string &alias, std::string &serviceAddr, const std::string &port, const std::string &mnKeyString, QString &ret_error)
Definition: mnmodel.cpp:318
int getMasternodeCollateralMinConf()
Definition: mnmodel.cpp:205
MasterNodeWizardDialog(WalletModel *walletMode, MNModel *mnModel, QWidget *parent=nullptr)
void inform(const QString &text)
Ui::MasterNodeWizardDialog * ui
void showEvent(QShowEvent *event) override
CMasternodeConfig::CMasternodeEntry * mnEntry
void setText(const QString &text)
Definition: snackbar.cpp:51
Interface to PIVX wallet from Qt view code.
Definition: walletmodel.h:109
CallResult< Destination > getNewAddress(const std::string &label="") const
bool isTestNetwork() const
Definition: walletmodel.cpp:76
bool getMNCollateralCandidate(COutPoint &outPoint)
bool isRegTestNetwork() const
Definition: walletmodel.cpp:81
QString formatBalance(CAmount amount, int nDisplayUnit, bool isZpiv)
Definition: guiutil.cpp:119
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:145
void initCssEditLine(QLineEdit *edit, bool isDialog)
Definition: qtutils.cpp:272
void setCssProperty(std::initializer_list< QWidget * > args, const QString &value)
Definition: qtutils.cpp:334
void setCssSubtitleScreen(QWidget *wid)
Definition: qtutils.cpp:329
void setCssBtnPrimary(QPushButton *btn, bool forceUpdate)
Definition: qtutils.cpp:302
bool openDialog(QDialog *widget, QWidget *gui)
Definition: qtutils.cpp:23
void setCssEditLine(QLineEdit *edit, bool isValid, bool forceUpdate)
Definition: qtutils.cpp:282