From 67330fbb519da936fef22446cc951e2ac23b7dbe Mon Sep 17 00:00:00 2001 From: Evan Duffield Date: Mon, 22 Dec 2014 19:28:52 -0700 Subject: [PATCH] Added Darksend to v11 --- src/qt/Makefile.am | 5 + src/qt/forms/darksendconfig.ui | 188 ++++++++++ src/qt/forms/overviewpage.ui | 615 +++++++++++++++++++++++++++++++++ src/qt/overviewpage.cpp | 219 +++++++++++- src/qt/overviewpage.h | 12 +- 5 files changed, 1034 insertions(+), 5 deletions(-) create mode 100644 src/qt/forms/darksendconfig.ui diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am index de9eea0eb..c171efac7 100644 --- a/src/qt/Makefile.am +++ b/src/qt/Makefile.am @@ -89,6 +89,7 @@ QT_FORMS_UI = \ forms/addressbookpage.ui \ forms/askpassphrasedialog.ui \ forms/coincontroldialog.ui \ + forms/darksendconfig.ui \ forms/editaddressdialog.ui \ forms/helpmessagedialog.ui \ forms/intro.ui \ @@ -115,6 +116,7 @@ QT_MOC_CPP = \ moc_coincontroldialog.cpp \ moc_coincontroltreewidget.cpp \ moc_csvmodelwriter.cpp \ + moc_darksendconfig.cpp \ moc_editaddressdialog.cpp \ moc_guiutil.cpp \ moc_intro.cpp \ @@ -177,6 +179,7 @@ BITCOIN_QT_H = \ coincontroldialog.h \ coincontroltreewidget.h \ csvmodelwriter.h \ + darksendconfig.h \ editaddressdialog.h \ guiconstants.h \ guiutil.h \ @@ -268,6 +271,7 @@ BITCOIN_QT_CPP = \ bitcoinunits.cpp \ clientmodel.cpp \ csvmodelwriter.cpp \ + darksendconfig.cpp \ guiutil.cpp \ intro.cpp \ monitoreddatamapper.cpp \ @@ -289,6 +293,7 @@ BITCOIN_QT_CPP += \ askpassphrasedialog.cpp \ coincontroldialog.cpp \ coincontroltreewidget.cpp \ + darksendconfig.cpp \ editaddressdialog.cpp \ openuridialog.cpp \ overviewpage.cpp \ diff --git a/src/qt/forms/darksendconfig.ui b/src/qt/forms/darksendconfig.ui new file mode 100644 index 000000000..02fb32e41 --- /dev/null +++ b/src/qt/forms/darksendconfig.ui @@ -0,0 +1,188 @@ + + + DarksendConfig + + + + 0 + 0 + 630 + 307 + + + + Configure Darksend+ + + + + + 20 + 70 + 151 + 27 + + + + Basic Privacy + + + + + + 20 + 140 + 151 + 27 + + + + High Privacy + + + + + + 20 + 210 + 151 + 27 + + + + Maximum Privacy + + + + + + 30 + 20 + 571 + 31 + + + + Please select an privacy level. + + + + + + 190 + 70 + 421 + 21 + + + + Use 2 separate masternodes to mix funds up to 1000DRK + + + + + + 190 + 140 + 411 + 21 + + + + Use 4 separate masternodes to mix funds up to 1000DRK + + + + + + 190 + 210 + 421 + 21 + + + + Use 8 separate masternodes + + + + + + 40 + 100 + 561 + 21 + + + + This option is the quickest and will cost about ~0.025DRK to anonymize 1000DRK + + + + + + 40 + 170 + 561 + 21 + + + + This option is moderately fast and will cost about 0.05DRK to anonymize 1000DRK + + + + + + 40 + 240 + 561 + 21 + + + + This is the slowest and most secure option. Using maximum anonymity will cost + + + + + + 40 + 260 + 561 + 21 + + + + 0.1DRK per 1000DRK you anonymize. + + + + + + 10 + 120 + 601 + 16 + + + + Qt::Horizontal + + + + + + 10 + 190 + 601 + 16 + + + + Qt::Horizontal + + + + + + diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index e66291278..f959aa632 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -254,6 +254,621 @@ + + + + + 0 + 275 + + + + Qt::LeftToRight + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 40 + 293 + 121 + + + + + QFormLayout::AllNonFixedFieldsGrow + + + 12 + + + 12 + + + + + Status: + + + + + + + Enabled/Disabled + + + + + + + Completion: + + + + + + + + 154 + 16777215 + + + + 24 + + + + + + + Darksend Balance: + + + + + + + + 75 + true + + + + 0 DRK + + + + + + + Amount and Rounds: + + + + + + + 1000 DRK / 8 Rounds + + + + + + + + + 10 + 10 + 66 + 20 + + + + + 75 + true + + + + Darksend + + + + + + 251 + 17 + 1 + 1 + + + + + + + + + 0 + 0 + 0 + + + + + + + 239 + 238 + 238 + + + + + + + 255 + 255 + 255 + + + + + + + 247 + 246 + 246 + + + + + + + 119 + 119 + 119 + + + + + + + 159 + 159 + 159 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 239 + 238 + 238 + + + + + + + 0 + 0 + 0 + + + + + + + 247 + 246 + 246 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 239 + 238 + 238 + + + + + + + 255 + 255 + 255 + + + + + + + 247 + 246 + 246 + + + + + + + 119 + 119 + 119 + + + + + + + 159 + 159 + 159 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 239 + 238 + 238 + + + + + + + 0 + 0 + 0 + + + + + + + 247 + 246 + 246 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 119 + 119 + 119 + + + + + + + 239 + 238 + 238 + + + + + + + 255 + 255 + 255 + + + + + + + 247 + 246 + 246 + + + + + + + 119 + 119 + 119 + + + + + + + 159 + 159 + 159 + + + + + + + 119 + 119 + 119 + + + + + + + 255 + 255 + 255 + + + + + + + 119 + 119 + 119 + + + + + + + 239 + 238 + 238 + + + + + + + 239 + 238 + 238 + + + + + + + 0 + 0 + 0 + + + + + + + 239 + 238 + 238 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + Qt::NoFocus + + + true + + + + + + true + + + + + + 10 + 220 + 291 + 51 + + + + Start/Stop Mixing + + + + + + 10 + 210 + 291 + 16 + + + + Qt::Horizontal + + + + + + 10 + 170 + 288 + 43 + + + + + 288 + 43 + + + + (Last Message) + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 8f93b7e44..86129fe7a 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -8,15 +8,19 @@ #include "bitcoinunits.h" #include "clientmodel.h" +#include "darksend.h" +#include "darksendconfig.h" #include "guiconstants.h" #include "guiutil.h" #include "optionsmodel.h" #include "transactionfilterproxy.h" #include "transactiontablemodel.h" #include "walletmodel.h" +#include "init.h" #include #include +#include #define DECORATION_SIZE 64 #define NUM_ITEMS 3 @@ -117,10 +121,26 @@ OverviewPage::OverviewPage(QWidget *parent) : connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex))); + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(darkSendStatus())); + timer->start(333); + // init "out of sync" warning labels ui->labelWalletStatus->setText("(" + tr("out of sync") + ")"); ui->labelTransactionsStatus->setText("(" + tr("out of sync") + ")"); + showingDarkSendMessage = 0; + darksendActionCheck = 0; + + if(fMasterNode){ + ui->toggleDarksend->setText("(Disabled)"); + ui->toggleDarksend->setEnabled(false); + }else if(!fEnableDarksend){ + ui->toggleDarksend->setText("Start Darksend Mixing"); + } else { + ui->toggleDarksend->setText("Stop Darksend Mixing"); + } + // start with displaying the "out of sync" warnings showOutOfSyncWarning(true); } @@ -136,15 +156,17 @@ OverviewPage::~OverviewPage() delete ui; } -void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance) +void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, qint64 anonymizedBalance) { int unit = walletModel->getOptionsModel()->getDisplayUnit(); currentBalance = balance; currentUnconfirmedBalance = unconfirmedBalance; currentImmatureBalance = immatureBalance; + currentAnonymizedBalance = anonymizedBalance; ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance)); ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance)); ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance)); + ui->labelAnonymized->setText(BitcoinUnits::formatWithUnit(unit, anonymizedBalance)); ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, balance + unconfirmedBalance + immatureBalance)); // only show immature (newly mined) balance if it's non-zero, so as not to complicate things @@ -183,10 +205,13 @@ void OverviewPage::setWalletModel(WalletModel *model) ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress); // Keep up to date with wallet - setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance()); - connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64))); + setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), model->getAnonymizedBalance()); + connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64))); connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + + connect(ui->runAutoDenom, SIGNAL(clicked()), this, SLOT(runDoAutomaticDenomination())); + connect(ui->toggleDarksend, SIGNAL(clicked()), this, SLOT(toggleDarksend())); } // update the display unit, to not use the default ("DRK") @@ -198,7 +223,7 @@ void OverviewPage::updateDisplayUnit() if(walletModel && walletModel->getOptionsModel()) { if(currentBalance != -1) - setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance); + setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance, currentAnonymizedBalance); // Update txdelegate->unit with the current unit txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit(); @@ -218,3 +243,189 @@ void OverviewPage::showOutOfSyncWarning(bool fShow) ui->labelWalletStatus->setVisible(fShow); ui->labelTransactionsStatus->setVisible(fShow); } + +void OverviewPage::updateDarksendProgress(){ + int64_t balance = pwalletMain->GetBalance(); + if(balance == 0){ + ui->darksendProgress->setValue(0); + QString s("No inputs detected"); + ui->darksendProgress->setToolTip(s); + return; + } + + std::ostringstream convert; + //Get average rounds of inputs + double a = ((double)pwalletMain->GetAverageAnonymizedRounds() / (double)nDarksendRounds)*100; + //Get the anon threshold + double max = nAnonymizeDarkcoinAmount; + //If it's more than the wallet amount, limit to that. + if(max > (double)(pwalletMain->GetBalance()/COIN)-1) max = (double)(pwalletMain->GetBalance()/COIN)-1; + //denominated balance / anon threshold -- the percentage that we've completed + double b = ((double)(pwalletMain->GetDenominatedBalance()/COIN) / max); + + double val = a*b; + if(val < 0) val = 0; + if(val > 100) val = 100; + + ui->darksendProgress->setValue(val);//rounds avg * denom progress + convert << "Inputs have an average of " << pwalletMain->GetAverageAnonymizedRounds() << " of " << nDarksendRounds << " rounds (" << a << "/" << b << ")"; + QString s(convert.str().c_str()); + ui->darksendProgress->setToolTip(s); +} + + +void OverviewPage::darkSendStatus() +{ + int nBestHeight = chainActive.Tip()->nHeight; + + if(nBestHeight != darkSendPool.cachedNumBlocks) + { + updateDarksendProgress(); + + std::ostringstream convert2; + convert2 << nAnonymizeDarkcoinAmount << " DRK / " << nDarksendRounds << " Rounds"; + QString s2(convert2.str().c_str()); + ui->labelAmountRounds->setText(s2); + } + + if(!fEnableDarksend) { + if(nBestHeight != darkSendPool.cachedNumBlocks) + { + darkSendPool.cachedNumBlocks = nBestHeight; + + ui->darksendEnabled->setText("Disabled"); + ui->darksendStatus->setText(""); + ui->toggleDarksend->setText("Start Darksend Mixing"); + } + + return; + } + + // check darksend status and unlock if needed + if(nBestHeight != darkSendPool.cachedNumBlocks) + { + // Balance and number of transactions might have changed + darkSendPool.cachedNumBlocks = nBestHeight; + + if (pwalletMain->GetBalance() - pwalletMain->GetAnonymizedBalance() > 2*COIN){ + if (walletModel->getEncryptionStatus() != WalletModel::Unencrypted){ + if((nAnonymizeDarkcoinAmount*COIN)-pwalletMain->GetAnonymizedBalance() > 1.1*COIN && + walletModel->getEncryptionStatus() == WalletModel::Locked){ + + WalletModel::UnlockContext ctx(walletModel->requestUnlock(false)); + if(!ctx.isValid()){ + //unlock was cancelled + fEnableDarksend = false; + darkSendPool.cachedNumBlocks = 0; + LogPrintf("Wallet is locked and user declined to unlock. Disabling Darksend.\n"); + } + } + if((nAnonymizeDarkcoinAmount*COIN)-pwalletMain->GetAnonymizedBalance() <= 1.1*COIN && + walletModel->getEncryptionStatus() == WalletModel::Unlocked && + darkSendPool.GetMyTransactionCount() == 0){ + + LogPrintf("Darksend is complete, locking wallet.\n"); + walletModel->setWalletLocked(true); + } + } + } + + /* *******************************************************/ + + ui->darksendEnabled->setText("Enabled"); + } + + int state = darkSendPool.GetState(); + int entries = darkSendPool.GetEntriesCount(); + int accepted = darkSendPool.GetLastEntryAccepted(); + + std::ostringstream convert; + + if(state == POOL_STATUS_ACCEPTING_ENTRIES) { + if(entries == 0) { + convert << "Darksend is idle"; + showingDarkSendMessage = 0; + } else if (accepted == 1) { + convert << "Darksend request complete: Your transaction was accepted into the pool!"; + if(showingDarkSendMessage % 10 > 8) { + darkSendPool.lastEntryAccepted = 0; + showingDarkSendMessage = 0; + } + } else { + if(showingDarkSendMessage % 70 <= 40) convert << "Submitted to masternode, entries " << entries << "/" << darkSendPool.GetMaxPoolTransactions(); + else if(showingDarkSendMessage % 70 <= 50) convert << "Submitted to masternode, Waiting for more entries (" << entries << "/" << darkSendPool.GetMaxPoolTransactions() << " ) ."; + else if(showingDarkSendMessage % 70 <= 60) convert << "Submitted to masternode, Waiting for more entries (" << entries << "/" << darkSendPool.GetMaxPoolTransactions() << " ) .."; + else if(showingDarkSendMessage % 70 <= 70) convert << "Submitted to masternode, Waiting for more entries (" << entries << "/" << darkSendPool.GetMaxPoolTransactions() << " ) ..."; + } + } else if(state == POOL_STATUS_SIGNING) { + if(showingDarkSendMessage % 70 <= 10) convert << "Found enough users, signing"; + else if(showingDarkSendMessage % 70 <= 20) convert << "Found enough users, signing ( waiting. )"; + else if(showingDarkSendMessage % 70 <= 30) convert << "Found enough users, signing ( waiting.. )"; + else if(showingDarkSendMessage % 70 <= 40) convert << "Found enough users, signing ( waiting... )"; + } else if(state == POOL_STATUS_TRANSMISSION) { + convert << "Transmitting final transaction"; + } else if (state == POOL_STATUS_IDLE) { + convert << "Darksend is idle"; + } else if (state == POOL_STATUS_FINALIZE_TRANSACTION) { + convert << "Finalizing transaction"; + } else if(state == POOL_STATUS_ERROR) { + convert << "Darksend request incomplete: " << darkSendPool.lastMessage << ". Will retry..."; + } else if(state == POOL_STATUS_SUCCESS) { + convert << "Darksend request complete: " << darkSendPool.lastMessage; + } else if(state == POOL_STATUS_QUEUE) { + if(showingDarkSendMessage % 70 <= 50) convert << "Submitted to masternode, waiting in queue ."; + else if(showingDarkSendMessage % 70 <= 60) convert << "Submitted to masternode, waiting in queue .."; + else if(showingDarkSendMessage % 70 <= 70) convert << "Submitted to masternode, waiting in queue ..."; + } else { + convert << "unknown state : id=" << state; + } + + if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) darkSendPool.Check(); + + QString s(convert.str().c_str()); + + if(s != ui->darksendStatus->text()) + LogPrintf("%s\n", convert.str().c_str()); + + ui->darksendStatus->setText(s); + + showingDarkSendMessage++; + darksendActionCheck++; + + // Get DarkSend Denomination Status +} + +void OverviewPage::runDoAutomaticDenomination(){ + darkSendPool.DoAutomaticDenominating(); +} + +void OverviewPage::toggleDarksend(){ + int64_t balance = pwalletMain->GetBalance(); + if(balance < 2.5*COIN){ + QMessageBox::warning(this, tr("Darksend"), + tr("Darksend requires at least 2.5 DRK to use."), + QMessageBox::Ok, QMessageBox::Ok); + return; + } + + + darkSendPool.cachedNumBlocks = 0; + + fEnableDarksend = !fEnableDarksend; + + if(!fEnableDarksend){ + ui->toggleDarksend->setText("Start Darksend Mixing"); + } else { + ui->toggleDarksend->setText("Stop Darksend Mixing"); + + /* show darksend configuration if client has defaults set */ + + if(nAnonymizeDarkcoinAmount == 0){ + DarksendConfig dlg(this); + dlg.setModel(walletModel); + dlg.exec(); + } + + darkSendPool.DoAutomaticDenominating(); + } +} diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 2507a3fb3..073790968 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -32,25 +32,35 @@ public: void setClientModel(ClientModel *clientModel); void setWalletModel(WalletModel *walletModel); void showOutOfSyncWarning(bool fShow); + void updateDarksendProgress(); public slots: - void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance); + void darkSendStatus(); + void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, qint64 anonymizedBalance); signals: void transactionClicked(const QModelIndex &index); private: + QTimer *timer; Ui::OverviewPage *ui; ClientModel *clientModel; WalletModel *walletModel; qint64 currentBalance; qint64 currentUnconfirmedBalance; qint64 currentImmatureBalance; + qint64 currentAnonymizedBalance; + int showingDarkSendMessage; + int darksendActionCheck; + int cachedNumBlocks; + TxViewDelegate *txdelegate; TransactionFilterProxy *filter; private slots: + void runDoAutomaticDenomination(); + void toggleDarksend(); void updateDisplayUnit(); void handleTransactionClicked(const QModelIndex &index); void updateAlerts(const QString &warnings);