Skip to content

Commit

Permalink
Merge #1389: [GUI] MasternodeWidget-Wizard bugfixes
Browse files Browse the repository at this point in the history
2be6f7b [GUI] MasterNodeWizardDialog: fix RegTestNet default port 51476 (random-zebra)
68a92f9 [GUI] MasternodeWidget: unlock collateral output coin after MN deletion (random-zebra)
bdb13c8 [GUI][Model] Enforce required depth for mn collaterals (random-zebra)
1c197d2 [GUI] MasternodeWizard: lock collateral output coin after MN creation (random-zebra)
d56a8f8 [Trivial] Styling: spaces and brackets (random-zebra)

Pull request description:

  This PR fixes some issue with the masternode GUI interaction.

  **1)**  __MasternodeWizard: lock collateral output after MN creation.__
  The masternode configuration file is only read during init, and then the `COutPoint`s relative to the collateral of each entry is locked for spending. Thus, after creating a MN controller with the wizard, the collateral remains unlocked until the wallet is restarted, and therefore could be potentially spent or staked.

  **2)** __Enforce required depth for mn collaterals__
  The masternode collateral transaction requires at least 15 confirmations before the mn broadcast can be considered valid. Properly inform the user after creating a controller with the wizard, and when trying to start a masternode not yet confirmed.

  **3)** __MasternodeWidget: unlock collateral output coin after MN deletion__
  Mirrors (1). Unlock the collateral utxo when the masternode is deleted, otherwise it remains locked until wallet restart.

  **4)** __MasterNodeWizardDialog: fix RegTestNet default port__
  RegTest was using the fixed port value of TestNet instead of the default 51476.

ACKs for top commit:
  Fuzzbawls:
    utACK 2be6f7b
  furszy:
    code ACK 2be6f7b.

Tree-SHA512: a0d9a51b548dbf4d808ebdbd6ad696fc05f9d59c8768dafc7985e7753351ec1094c975c80c5b4cf7b788c45344432d5dfc241cca089236cdce904d1429db9608
  • Loading branch information
furszy committed Mar 10, 2020
2 parents df2db0d + 2be6f7b commit f80888b
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 84 deletions.
104 changes: 68 additions & 36 deletions src/qt/pivx/masternodeswidget.cpp
Expand Up @@ -37,14 +37,16 @@ class MNHolder : public FurListRow<QWidget*>
public:
MNHolder();

explicit MNHolder(bool _isLightTheme) : FurListRow(), isLightTheme(_isLightTheme){}
explicit MNHolder(bool _isLightTheme) : FurListRow(), isLightTheme(_isLightTheme) {}

MNRow* createHolder(int pos) override{
if(!cachedRow) cachedRow = new MNRow();
MNRow* createHolder(int pos) override
{
if (!cachedRow) cachedRow = new MNRow();
return cachedRow;
}

void init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const override{
void init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const override
{
MNRow* row = static_cast<MNRow*>(holder);
QString label = index.data(Qt::DisplayRole).toString();
QString address = index.sibling(index.row(), MNModel::ADDRESS).data(Qt::DisplayRole).toString();
Expand All @@ -53,7 +55,8 @@ class MNHolder : public FurListRow<QWidget*>
row->updateView("Address: " + address, label, status, wasCollateralAccepted);
}

QColor rectColor(bool isHovered, bool isSelected) override{
QColor rectColor(bool isHovered, bool isSelected) override
{
return getRowColor(isLightTheme, isHovered, isSelected);
}

Expand Down Expand Up @@ -133,41 +136,46 @@ MasterNodesWidget::MasterNodesWidget(PIVXGUI *parent) :
connect(ui->btnAboutController, &OptionButton::clicked, [this](){window->openFAQ(10);});
}

void MasterNodesWidget::showEvent(QShowEvent *event){
void MasterNodesWidget::showEvent(QShowEvent *event)
{
if (mnModel) mnModel->updateMNList();
if(!timer) {
if (!timer) {
timer = new QTimer(this);
connect(timer, &QTimer::timeout, [this]() {mnModel->updateMNList();});
}
timer->start(30000);
}

void MasterNodesWidget::hideEvent(QHideEvent *event){
if(timer) timer->stop();
void MasterNodesWidget::hideEvent(QHideEvent *event)
{
if (timer) timer->stop();
}

void MasterNodesWidget::loadWalletModel(){
if(walletModel) {
void MasterNodesWidget::loadWalletModel()
{
if (walletModel) {
ui->listMn->setModel(mnModel);
ui->listMn->setModelColumn(AddressTableModel::Label);
updateListState();
}
}

void MasterNodesWidget::updateListState() {
void MasterNodesWidget::updateListState()
{
bool show = mnModel->rowCount() > 0;
ui->listMn->setVisible(show);
ui->emptyContainer->setVisible(!show);
ui->pushButtonStartAll->setVisible(show);
}

void MasterNodesWidget::onMNClicked(const QModelIndex &index){
void MasterNodesWidget::onMNClicked(const QModelIndex &index)
{
ui->listMn->setCurrentIndex(index);
QRect rect = ui->listMn->visualRect(index);
QPoint pos = rect.topRight();
pos.setX(pos.x() - (DECORATION_SIZE * 2));
pos.setY(pos.y() + (DECORATION_SIZE * 1.5));
if(!this->menu){
if (!this->menu) {
this->menu = new TooltipMenu(window, this);
this->menu->setEditBtnText(tr("Start"));
this->menu->setDeleteBtnText(tr("Delete"));
Expand All @@ -190,29 +198,33 @@ void MasterNodesWidget::onMNClicked(const QModelIndex &index){
ui->listMn->setFocus();
}

bool MasterNodesWidget::checkMNsNetwork() {
bool MasterNodesWidget::checkMNsNetwork()
{
bool isTierTwoSync = mnModel->isMNsNetworkSynced();
if (!isTierTwoSync) inform(tr("Please wait until the node is fully synced"));
return isTierTwoSync;
}

void MasterNodesWidget::onEditMNClicked(){
void MasterNodesWidget::onEditMNClicked()
{
if(walletModel) {
if (!checkMNsNetwork()) return;
if (!walletModel->isRegTestNetwork() && !checkMNsNetwork()) return;
if (index.sibling(index.row(), MNModel::WAS_COLLATERAL_ACCEPTED).data(Qt::DisplayRole).toBool()) {
// Start MN
QString strAlias = this->index.data(Qt::DisplayRole).toString();
if (ask(tr("Start Masternode"), tr("Are you sure you want to start masternode %1?\n").arg(strAlias))) {
if (!verifyWalletUnlocked()) return;
startAlias(strAlias);
}
}else {
inform(tr("Cannot start masternode, the collateral transaction has not been accepted by the network.\nPlease wait few more minutes."));
} else {
inform(tr("Cannot start masternode, the collateral transaction has not been confirmed by the network yet.\n"
"Please wait few more minutes (masternode collaterals require %1 confirmations).").arg(MASTERNODE_MIN_CONFIRMATIONS));
}
}
}

void MasterNodesWidget::startAlias(QString strAlias) {
void MasterNodesWidget::startAlias(QString strAlias)
{
QString strStatusHtml;
strStatusHtml += "Alias: " + strAlias + " ";

Expand All @@ -227,12 +239,14 @@ void MasterNodesWidget::startAlias(QString strAlias) {
updateModelAndInform(strStatusHtml);
}

void MasterNodesWidget::updateModelAndInform(QString informText) {
void MasterNodesWidget::updateModelAndInform(QString informText)
{
mnModel->updateMNList();
inform(informText);
}

bool MasterNodesWidget::startMN(CMasternodeConfig::CMasternodeEntry mne, std::string& strError) {
bool MasterNodesWidget::startMN(CMasternodeConfig::CMasternodeEntry mne, std::string& strError)
{
CMasternodeBroadcast mnb;
if (!CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb))
return false;
Expand All @@ -242,7 +256,8 @@ bool MasterNodesWidget::startMN(CMasternodeConfig::CMasternodeEntry mne, std::st
return true;
}

void MasterNodesWidget::onStartAllClicked(int type) {
void MasterNodesWidget::onStartAllClicked(int type)
{
if (!verifyWalletUnlocked()) return;
if (!checkMNsNetwork()) return;
if (isLoading) {
Expand All @@ -256,7 +271,8 @@ void MasterNodesWidget::onStartAllClicked(int type) {
}
}

bool MasterNodesWidget::startAll(QString& failText, bool onlyMissing) {
bool MasterNodesWidget::startAll(QString& failText, bool onlyMissing)
{
int amountOfMnFailed = 0;
int amountOfMnStarted = 0;
for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
Expand All @@ -282,7 +298,8 @@ bool MasterNodesWidget::startAll(QString& failText, bool onlyMissing) {
return true;
}

void MasterNodesWidget::run(int type) {
void MasterNodesWidget::run(int type)
{
bool isStartMissing = type == REQUEST_START_MISSING;
if (type == REQUEST_START_ALL || isStartMissing) {
QString failText;
Expand All @@ -294,15 +311,17 @@ void MasterNodesWidget::run(int type) {
isLoading = false;
}

void MasterNodesWidget::onError(QString error, int type) {
void MasterNodesWidget::onError(QString error, int type)
{
if (type == REQUEST_START_ALL) {
QMetaObject::invokeMethod(this, "inform", Qt::QueuedConnection,
Q_ARG(QString, "Error starting all Masternodes"));
}
}

void MasterNodesWidget::onInfoMNClicked() {
if(!verifyWalletUnlocked()) return;
void MasterNodesWidget::onInfoMNClicked()
{
if (!verifyWalletUnlocked()) return;
showHideOp(true);
MnInfoDialog* dialog = new MnInfoDialog(window);
QString label = index.data(Qt::DisplayRole).toString();
Expand All @@ -314,7 +333,7 @@ void MasterNodesWidget::onInfoMNClicked() {
dialog->setData(pubKey, label, address, txId, outIndex, status);
dialog->adjustSize();
showDialog(dialog, 3, 17);
if (dialog->exportMN){
if (dialog->exportMN) {
if (ask(tr("Remote Masternode Data"),
tr("You are just about to export the required data to run a Masternode\non a remote server to your clipboard.\n\n\n"
"You will only have to paste the data in the pivx.conf file\nof your remote server and start it, "
Expand All @@ -333,7 +352,10 @@ void MasterNodesWidget::onInfoMNClicked() {
dialog->deleteLater();
}

void MasterNodesWidget::onDeleteMNClicked(){
void MasterNodesWidget::onDeleteMNClicked()
{
QString txId = index.sibling(index.row(), MNModel::COLLATERAL_ID).data(Qt::DisplayRole).toString();
QString outIndex = index.sibling(index.row(), MNModel::COLLATERAL_OUT_INDEX).data(Qt::DisplayRole).toString();
QString qAliasString = index.data(Qt::DisplayRole).toString();
std::string aliasToRemove = qAliasString.toStdString();

Expand All @@ -342,7 +364,7 @@ void MasterNodesWidget::onDeleteMNClicked(){

std::string strConfFile = "masternode.conf";
std::string strDataDir = GetDataDir().string();
if (strConfFile != boost::filesystem::basename(strConfFile) + boost::filesystem::extension(strConfFile)){
if (strConfFile != boost::filesystem::basename(strConfFile) + boost::filesystem::extension(strConfFile)) {
throw std::runtime_error(strprintf(_("masternode.conf %s resides outside data directory %s"), strConfFile, strDataDir));
}

Expand Down Expand Up @@ -414,6 +436,14 @@ void MasterNodesWidget::onDeleteMNClicked(){
if (!pathNewConfFile.is_complete()) pathNewConfFile = GetDataDir() / pathNewConfFile;
rename(pathConfigFile, pathNewConfFile);

// Unlock collateral
bool convertOK = false;
unsigned int indexOut = outIndex.toUInt(&convertOK);
if(convertOK) {
COutPoint collateralOut(uint256(txId.toStdString()), indexOut);
walletModel->unlockCoin(collateralOut);
}

// Remove alias
masternodeConfig.remove(aliasToRemove);
// Update list
Expand All @@ -425,15 +455,16 @@ void MasterNodesWidget::onDeleteMNClicked(){
}
}

void MasterNodesWidget::onCreateMNClicked(){
if(verifyWalletUnlocked()) {
if(walletModel->getBalance() <= (COIN * 10000)){
void MasterNodesWidget::onCreateMNClicked()
{
if (verifyWalletUnlocked()) {
if (walletModel->getBalance() <= (COIN * 10000)) {
inform(tr("Not enough balance to create a masternode, 10,000 PIV required."));
return;
}
showHideOp(true);
MasterNodeWizardDialog *dialog = new MasterNodeWizardDialog(walletModel, window);
if(openDialogWithOpaqueBackgroundY(dialog, window, 5, 7)) {
if (openDialogWithOpaqueBackgroundY(dialog, window, 5, 7)) {
if (dialog->isOk) {
// Update list
mnModel->addMn(dialog->mnEntry);
Expand All @@ -448,7 +479,8 @@ void MasterNodesWidget::onCreateMNClicked(){
}
}

void MasterNodesWidget::changeTheme(bool isLightTheme, QString& theme){
void MasterNodesWidget::changeTheme(bool isLightTheme, QString& theme)
{
static_cast<MNHolder*>(this->delegate->getRowFactory())->isLightTheme = isLightTheme;
}

Expand Down

0 comments on commit f80888b

Please sign in to comment.