From 2af7ce84fb16033db1cf6a67e0d829eca1d60d72 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 26 Mar 2018 18:50:54 +0700 Subject: [PATCH 01/13] Merge #12610: Multiwallet for the GUI 779c5f984 Qt: hide RPCConsole wallet selector when no wallets are present (Jonas Schnelli) dc6f150f3 Qt: show wallet name in request dlg in case of multiwallet (Jonas Schnelli) 4826ca4b8 Qt: show wallet name in send confirmation dlg in case of multiwallet (Jonas Schnelli) cfa4133ce GUI: RPCConsole: Log wallet changes (Luke Dashjr) b6d04fc7c Qt: Get wallet name from WalletModel rather than passing it around (Luke Dashjr) 12d8d2681 Qt: When multiple wallets are used, include in notifications the name (Jonas Schnelli) d1ec34a76 Qt: QComboBox::setVisible doesn't work in toolbars, so defer adding it at all until needed (Luke Dashjr) d49cc70e6 Qt: Add wallet selector to debug console (Jonas Schnelli) d558f44c5 Bugfix: RPC: Add missing UnregisterHTTPHandler for /wallet/ (Luke Dashjr) 85d531971 Qt: Ensure UI updates only come from the currently selected walletView (Luke Dashjr) e449f9a9e Qt: Add a combobox to toolbar to select from multiple wallets (Luke Dashjr) 3dba3c3ac Qt: Load all wallets into WalletModels (Luke Dashjr) Pull request description: This is an overhaul of #11383 (plus some additions). It avoids unnecessary coupling of httpserver/jsonrpc and the wallet as well as it avoids pointer pure passing (and pointer deletion) of `CWallet` (plus other minor design changes). Additionally it adds the wallet name to the sendconfirmation and request dialog (in case multiwallet is active) Tree-SHA512: 3d06e18badbc5d1821e488bf1dae463bb0be544cf11b2b618e025812bfdd13c5f39604bb93b4c705313930e7dc4e66f4848b9469ba14871bade58e7a027246a1 --- src/httprpc.cpp | 3 ++ src/qt/bitcoingui.cpp | 54 +++++++++++++++++++++++++----- src/qt/bitcoingui.h | 28 +++++++++++----- src/qt/dash.cpp | 28 +++++++++------- src/qt/forms/debugwindow.ui | 16 +++++++++ src/qt/receivecoinsdialog.cpp | 4 +-- src/qt/receiverequestdialog.cpp | 9 +++-- src/qt/receiverequestdialog.h | 6 ++-- src/qt/rpcconsole.cpp | 58 +++++++++++++++++++++++++++------ src/qt/rpcconsole.h | 15 +++++---- src/qt/sendcoinsdialog.cpp | 6 ++-- src/qt/walletframe.cpp | 11 +++++-- src/qt/walletframe.h | 3 +- src/qt/walletmodel.cpp | 20 ++++++++++-- src/qt/walletmodel.h | 7 +++- src/qt/walletview.cpp | 14 ++++---- src/qt/walletview.h | 7 ++-- 17 files changed, 217 insertions(+), 72 deletions(-) diff --git a/src/httprpc.cpp b/src/httprpc.cpp index c2b01b3c820f..7fc6fc0dc63a 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -258,6 +258,9 @@ void StopHTTPRPC() { LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n"); UnregisterHTTPHandler("/", true); +#ifdef ENABLE_WALLET + UnregisterHTTPHandler("/wallet/", false); +#endif if (httpRPCTimerInterface) { RPCUnsetTimerInterface(httpRPCTimerInterface.get()); httpRPCTimerInterface.reset(); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index ef71c6fc2e0a..963ce24f27da 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #endif // ENABLE_WALLET #ifdef Q_OS_MAC @@ -41,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -70,10 +72,6 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM = #endif ; -/** Display name for default wallet name. Uses tilde to avoid name - * collisions in the future with additional wallets */ -const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; - BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : QMainWindow(parent), enableWallet(false), @@ -88,6 +86,7 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle * progressBar(0), progressDialog(0), appMenuBar(0), + appToolBar(0), overviewAction(0), historyAction(0), masternodeAction(0), @@ -588,6 +587,7 @@ void BitcoinGUI::createToolBars() if(walletFrame) { QToolBar *toolbar = new QToolBar(tr("Tabs toolbar")); + appToolBar = toolbar; toolbar->setContextMenuPolicy(Qt::PreventContextMenu); toolbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); toolbar->setToolButtonStyle(Qt::ToolButtonTextOnly); @@ -612,6 +612,15 @@ void BitcoinGUI::createToolBars() toolbar->setMovable(false); // remove unused icon in upper left corner overviewAction->setChecked(true); +#ifdef ENABLE_WALLET + QWidget *spacer = new QWidget(); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + toolbar->addWidget(spacer); + + m_wallet_selector = new QComboBox(); + connect(m_wallet_selector, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(setCurrentWallet(const QString&))); +#endif + QLabel *logoLabel = new QLabel(); logoLabel->setObjectName("lblToolbarLogo"); logoLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); @@ -729,12 +738,22 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) } #ifdef ENABLE_WALLET -bool BitcoinGUI::addWallet(const QString& name, WalletModel *walletModel) +bool BitcoinGUI::addWallet(WalletModel *walletModel) { if(!walletFrame) return false; + const QString name = walletModel->getWalletName(); setWalletActionsEnabled(true); - return walletFrame->addWallet(name, walletModel); + m_wallet_selector->addItem(name); + if (m_wallet_selector->count() == 2) { + m_wallet_selector_label = new QLabel(); + m_wallet_selector_label->setText(tr("Wallet:") + " "); + m_wallet_selector_label->setBuddy(m_wallet_selector); + appToolBar->addWidget(m_wallet_selector_label); + appToolBar->addWidget(m_wallet_selector); + } + rpcConsole->addWallet(walletModel); + return walletFrame->addWallet(walletModel); } bool BitcoinGUI::setCurrentWallet(const QString& name) @@ -1317,7 +1336,7 @@ void BitcoinGUI::showEvent(QShowEvent *event) } #ifdef ENABLE_WALLET -void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label) +void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName) { IncomingTransactionMessage itx = { date, unit, amount, type, address, label @@ -1386,8 +1405,11 @@ void BitcoinGUI::showIncomingTransactions() for (auto& itx : txs) { // On new transaction, make an info balloon QString msg = tr("Date: %1\n").arg(itx.date) + - tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(itx.unit, itx.amount, true)) + - tr("Type: %1\n").arg(itx.type); + tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(itx.unit, itx.amount, true)); + if (WalletModel::isMultiwallet() && !walletName.isEmpty()) { + msg += tr("Wallet: %1\n").arg(walletName); + } + msg += tr("Type: %1\n").arg(itx.type); if (!itx.label.isEmpty()) msg += tr("Label: %1\n").arg(itx.label); else if (!itx.address.isEmpty()) @@ -1496,6 +1518,20 @@ void BitcoinGUI::setEncryptionStatus(int status) break; } } + +void BitcoinGUI::updateWalletStatus() +{ + if (!walletFrame) { + return; + } + WalletView * const walletView = walletFrame->currentWalletView(); + if (!walletView) { + return; + } + WalletModel * const walletModel = walletView->getWalletModel(); + setEncryptionStatus(walletModel->getEncryptionStatus()); + setHDStatus(walletModel->hdEnabled()); +} #endif // ENABLE_WALLET void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 4083cf6a654d..503e42c3a781 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -38,6 +38,7 @@ class ModalOverlay; QT_BEGIN_NAMESPACE class QAction; +class QComboBox; class QProgressBar; class QProgressDialog; class QToolButton; @@ -52,7 +53,6 @@ class BitcoinGUI : public QMainWindow Q_OBJECT public: - static const QString DEFAULT_WALLET; static const std::string DEFAULT_UIPLATFORM; explicit BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0); @@ -68,8 +68,7 @@ class BitcoinGUI : public QMainWindow The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending functionality. */ - bool addWallet(const QString& name, WalletModel *walletModel); - bool setCurrentWallet(const QString& name); + bool addWallet(WalletModel *walletModel); void removeAllWallets(); #endif // ENABLE_WALLET bool enableWallet; @@ -96,6 +95,7 @@ class BitcoinGUI : public QMainWindow QProgressDialog *progressDialog; QMenuBar *appMenuBar; + QToolBar *appToolBar; QToolButton *overviewAction; QToolButton *historyAction; QToolButton *masternodeAction; @@ -130,6 +130,9 @@ class BitcoinGUI : public QMainWindow QAction *showHelpMessageAction; QAction *showPrivateSendHelpAction; + QLabel *m_wallet_selector_label; + QComboBox *m_wallet_selector; + QSystemTrayIcon *trayIcon; QMenu *trayIconMenu; QMenu *dockIconMenu; @@ -212,22 +215,29 @@ public Q_SLOTS: void message(const QString &title, const QString &message, unsigned int style, bool *ret = nullptr); #ifdef ENABLE_WALLET - /** Set the hd-enabled status as shown in the UI. - @param[in] status current hd enabled status - @see WalletModel::EncryptionStatus - */ - void setHDStatus(int hdEnabled); + bool setCurrentWallet(const QString& name); + /** Set the UI status indicators based on the currently selected wallet. + */ + void updateWalletStatus(); +private: /** Set the encryption status as shown in the UI. @param[in] status current encryption status @see WalletModel::EncryptionStatus */ void setEncryptionStatus(int status); + /** Set the hd-enabled status as shown in the UI. + @param[in] status current hd enabled status + @see WalletModel::EncryptionStatus + */ + void setHDStatus(int hdEnabled); + +public Q_SLOTS: bool handlePaymentRequest(const SendCoinsRecipient& recipient); /** Show incoming transaction notification for new transactions. */ - void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label); + void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName); void showIncomingTransactions(); #endif // ENABLE_WALLET diff --git a/src/qt/dash.cpp b/src/qt/dash.cpp index 29d90bb47434..597483d8fb2e 100644 --- a/src/qt/dash.cpp +++ b/src/qt/dash.cpp @@ -232,7 +232,7 @@ public Q_SLOTS: QTimer *pollShutdownTimer; #ifdef ENABLE_WALLET PaymentServer* paymentServer; - WalletModel *walletModel; + std::vector m_wallet_models; #endif int returnValue; const PlatformStyle *platformStyle; @@ -334,7 +334,7 @@ BitcoinApplication::BitcoinApplication(int &argc, char **argv): pollShutdownTimer(0), #ifdef ENABLE_WALLET paymentServer(0), - walletModel(0), + m_wallet_models(), #endif returnValue(0) { @@ -461,8 +461,10 @@ void BitcoinApplication::requestShutdown() #ifdef ENABLE_WALLET window->removeAllWallets(); - delete walletModel; - walletModel = 0; + for (WalletModel *walletModel : m_wallet_models) { + delete walletModel; + } + m_wallet_models.clear(); #endif delete clientModel; clientModel = 0; @@ -491,16 +493,20 @@ void BitcoinApplication::initializeResult(bool success) window->setClientModel(clientModel); #ifdef ENABLE_WALLET - // TODO: Expose secondary wallets - if (HasWallets()) - { - walletModel = new WalletModel(platformStyle, GetWallets()[0], optionsModel); - - window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel); - window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET); + bool fFirstWallet = true; + for (CWallet* pwallet : GetWallets()) { + WalletModel * const walletModel = new WalletModel(platformStyle, pwallet, optionsModel); + + window->addWallet(walletModel); + if (fFirstWallet) { + window->setCurrentWallet(walletModel->getWalletName()); + fFirstWallet = false; + } connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)), paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray))); + + m_wallet_models.push_back(walletModel); } #endif diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 9df65c113916..e7992fdd3f3a 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -494,6 +494,22 @@ 4 + + + + Wallet: + + + + + + + + (none) + + + + diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 155abc915b35..a393e7e19765 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -143,7 +143,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked() ui->reqAmount->value(), ui->reqMessage->text()); ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this); dialog->setAttribute(Qt::WA_DeleteOnClose); - dialog->setModel(model->getOptionsModel()); + dialog->setModel(model); dialog->setInfo(info); dialog->show(); clear(); @@ -156,7 +156,7 @@ void ReceiveCoinsDialog::on_recentRequestsView_doubleClicked(const QModelIndex & { const RecentRequestsTableModel *submodel = model->getRecentRequestsTableModel(); ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this); - dialog->setModel(model->getOptionsModel()); + dialog->setModel(model); dialog->setInfo(submodel->entry(index.row()).recipient); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 441d3662da9a..6bb9c1238f1c 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -107,12 +107,12 @@ ReceiveRequestDialog::~ReceiveRequestDialog() delete ui; } -void ReceiveRequestDialog::setModel(OptionsModel *_model) +void ReceiveRequestDialog::setModel(WalletModel *_model) { this->model = _model; if (_model) - connect(_model, SIGNAL(displayUnitChanged(int)), this, SLOT(update())); + connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(update())); // update the display unit if necessary update(); @@ -143,11 +143,14 @@ void ReceiveRequestDialog::update() uri + "\">" + GUIUtil::HtmlEscape(uri) + "
"; html += ""+tr("Address")+": " + GUIUtil::HtmlEscape(info.address) + "
"; if(info.amount) - html += ""+tr("Amount")+": " + BitcoinUnits::formatHtmlWithUnit(model->getDisplayUnit(), info.amount) + "
"; + html += ""+tr("Amount")+": " + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), info.amount) + "
"; if(!info.label.isEmpty()) html += ""+tr("Label")+": " + GUIUtil::HtmlEscape(info.label) + "
"; if(!info.message.isEmpty()) html += ""+tr("Message")+": " + GUIUtil::HtmlEscape(info.message) + "
"; + if(model->isMultiwallet()) { + html += ""+tr("Wallet")+": " + GUIUtil::HtmlEscape(model->getWalletName()) + "
"; + } ui->outUri->setText(html); #ifdef USE_QRCODE diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index 303db5bac698..71feb54f42f8 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -12,8 +12,6 @@ #include #include -class OptionsModel; - namespace Ui { class ReceiveRequestDialog; } @@ -53,7 +51,7 @@ class ReceiveRequestDialog : public QDialog explicit ReceiveRequestDialog(QWidget *parent = 0); ~ReceiveRequestDialog(); - void setModel(OptionsModel *model); + void setModel(WalletModel *model); void setInfo(const SendCoinsRecipient &info); private Q_SLOTS: @@ -64,7 +62,7 @@ private Q_SLOTS: private: Ui::ReceiveRequestDialog *ui; - OptionsModel *model; + WalletModel *model; SendCoinsRecipient info; }; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 35889bc9cb61..37402e3aa873 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -91,7 +92,7 @@ class RPCExecutor : public QObject Q_OBJECT public Q_SLOTS: - void request(const QString &command); + void request(const QString &command, const QString &walletID); Q_SIGNALS: void reply(int category, const QString &command); @@ -152,7 +153,7 @@ class QtRPCTimerInterface: public RPCTimerInterface * @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data */ -bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut) +bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const std::string *walletID) { std::vector< std::vector > stack; stack.push_back(std::vector()); @@ -310,10 +311,8 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string & req.params = RPCConvertValues(stack.back()[0], std::vector(stack.back().begin() + 1, stack.back().end())); req.strMethod = stack.back()[0]; #ifdef ENABLE_WALLET - // TODO: Move this logic to WalletModel - if (HasWallets()) { - // in Qt, use always the wallet with index 0 when running with multiple wallets - QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(GetWallets()[0]->GetName())); + if (walletID && !walletID->empty()) { + QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(*walletID)); req.URI = "/wallet/"+std::string(encodedName.constData(), encodedName.length()); } #endif @@ -392,7 +391,7 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string & } } -void RPCExecutor::request(const QString &command) +void RPCExecutor::request(const QString &command, const QString &walletID) { try { @@ -423,7 +422,8 @@ void RPCExecutor::request(const QString &command) " example: getblock(getblockhash(0),true)[tx][0]\n\n"))); return; } - if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand)) + std::string wallet_id = walletID.toStdString(); + if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand, nullptr, &wallet_id)) { Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); return; @@ -498,6 +498,10 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) : connect(ui->fontSmallerButton, SIGNAL(clicked()), this, SLOT(fontSmaller())); connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear())); + // disable the wallet selector by default + ui->WalletSelector->setVisible(false); + ui->WalletSelectorLabel->setVisible(false); + // Wallet Repair Buttons // connect(ui->btn_salvagewallet, SIGNAL(clicked()), this, SLOT(walletSalvage())); // Disable salvage option in GUI, it's way too powerful and can lead to funds loss @@ -735,6 +739,23 @@ void RPCConsole::setClientModel(ClientModel *model) } } +#ifdef ENABLE_WALLET +void RPCConsole::addWallet(WalletModel * const walletModel) +{ + const QString name = walletModel->getWalletName(); + // use name for text and internal data object (to allow to move to a wallet id later) + ui->WalletSelector->addItem(name, name); + if (ui->WalletSelector->count() == 2 && !isVisible()) { + // First wallet added, set to default so long as the window isn't presently visible (and potentially in use) + ui->WalletSelector->setCurrentIndex(1); + } + if (ui->WalletSelector->count() > 2) { + ui->WalletSelector->setVisible(true); + ui->WalletSelectorLabel->setVisible(true); + } +} +#endif + static QString categoryClass(int category) { switch(category) @@ -1016,8 +1037,25 @@ void RPCConsole::on_lineEdit_returnPressed() cmdBeforeBrowsing = QString(); + QString walletID; +#ifdef ENABLE_WALLET + const int wallet_index = ui->WalletSelector->currentIndex(); + if (wallet_index > 0) { + walletID = (QString)ui->WalletSelector->itemData(wallet_index).value(); + } + + if (m_last_wallet_id != walletID) { + if (walletID.isEmpty()) { + message(CMD_REQUEST, tr("Executing command without any wallet")); + } else { + message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(walletID)); + } + m_last_wallet_id = walletID; + } +#endif + message(CMD_REQUEST, QString::fromStdString(strFilteredCmd)); - Q_EMIT cmdRequest(cmd); + Q_EMIT cmdRequest(cmd, walletID); cmd = QString::fromStdString(strFilteredCmd); @@ -1065,7 +1103,7 @@ void RPCConsole::startExecutor() // Replies from executor object must go to this object connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString))); // Requests from this object must go to executor - connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString))); + connect(this, SIGNAL(cmdRequest(QString, QString)), executor, SLOT(request(QString, QString))); // On stopExecutor signal // - quit the Qt event loop in the execution thread diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 1ade453af74f..11a99f86befd 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -19,6 +19,7 @@ class ClientModel; class PlatformStyle; class RPCTimerInterface; +class WalletModel; namespace Ui { class RPCConsole; @@ -38,12 +39,13 @@ class RPCConsole: public QWidget explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent); ~RPCConsole(); - static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr); - static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr) { - return RPCParseCommandLine(strResult, strCommand, true, pstrFilteredOut); + static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr); + static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr) { + return RPCParseCommandLine(strResult, strCommand, true, pstrFilteredOut, walletID); } void setClientModel(ClientModel *model); + void addWallet(WalletModel * const walletModel); enum MessageClass { MC_ERROR, @@ -94,7 +96,7 @@ public Q_SLOTS: void fontBigger(); void fontSmaller(); void setFontSize(int newSize); - + /** Wallet repair options */ void walletSalvage(); void walletRescan(); @@ -102,7 +104,7 @@ public Q_SLOTS: void walletZaptxes2(); void walletUpgrade(); void walletReindex(); - + /** Append the message to the message widget */ void message(int category, const QString &message, bool html = false); /** Set number of connections shown in the UI */ @@ -139,7 +141,7 @@ public Q_SLOTS: Q_SIGNALS: // For RPC command executor void stopExecutor(); - void cmdRequest(const QString &command); + void cmdRequest(const QString &command, const QString &walletID); /** Get restart command-line parameters and handle restart */ void handleRestart(QStringList args); @@ -175,6 +177,7 @@ public Q_SLOTS: int consoleFontSize; QCompleter *autoCompleter; QThread thread; + QString m_last_wallet_id; /** Update UI with latest network info from model. */ void updateNetworkState(); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index fd699c97f9ca..36316e6abf75 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -331,10 +331,12 @@ void SendCoinsDialog::send(QList recipients) QStringList formatted; for (const SendCoinsRecipient &rcp : currentTransaction.getRecipients()) { - // generate bold amount string + // generate bold amount string with wallet name in case of multiwallet QString amount = "" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); + if (model->isMultiwallet()) { + amount.append(" "+tr("from wallet %1").arg(GUIUtil::HtmlEscape(model->getWalletName()))+" "); + } amount.append(" "); - // generate monospace address string QString address = "" + rcp.address; address.append(""); diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 6f08ac82ea70..0b3806608014 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include @@ -39,10 +40,16 @@ void WalletFrame::setClientModel(ClientModel *_clientModel) this->clientModel = _clientModel; } -bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel) +bool WalletFrame::addWallet(WalletModel *walletModel) { - if (!gui || !clientModel || !walletModel || mapWalletViews.count(name) > 0) + if (!gui || !clientModel || !walletModel) { return false; + } + + const QString name = walletModel->getWalletName(); + if (mapWalletViews.count(name) > 0) { + return false; + } WalletView *walletView = new WalletView(platformStyle, this); walletView->setBitcoinGUI(gui); diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 55210b080a65..78aff0f166c5 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -36,7 +36,7 @@ class WalletFrame : public QFrame void setClientModel(ClientModel *clientModel); - bool addWallet(const QString& name, WalletModel *walletModel); + bool addWallet(WalletModel *walletModel); bool setCurrentWallet(const QString& name); bool removeWallet(const QString &name); void removeAllWallets(); @@ -59,6 +59,7 @@ class WalletFrame : public QFrame const PlatformStyle *platformStyle; +public: WalletView *currentWalletView(); public Q_SLOTS: diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 221218680929..4c69ec9019b3 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -138,8 +138,9 @@ void WalletModel::updateStatus() { EncryptionStatus newEncryptionStatus = getEncryptionStatus(); - if(cachedEncryptionStatus != newEncryptionStatus) - Q_EMIT encryptionStatusChanged(newEncryptionStatus); + if(cachedEncryptionStatus != newEncryptionStatus) { + Q_EMIT encryptionStatusChanged(); + } } void WalletModel::pollBalanceChanged() @@ -808,3 +809,18 @@ int WalletModel::getDefaultConfirmTarget() const { return nTxConfirmTarget; } + +QString WalletModel::getWalletName() const +{ + LOCK(wallet->cs_wallet); + QString walletName = QString::fromStdString(wallet->GetName()); + if (walletName.endsWith(".dat")) { + walletName.truncate(walletName.size() - 4); + } + return walletName; +} + +bool WalletModel::isMultiwallet() +{ + return gArgs.GetArgs("-wallet").size() > 1; +} diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 27a64a4d9e8c..518f0a4cf75b 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -133,6 +133,8 @@ class WalletModel : public QObject TransactionTableModel *getTransactionTableModel(); RecentRequestsTableModel *getRecentRequestsTableModel(); + CWallet *getWallet() const { return wallet; }; + CAmount getBalance(const CCoinControl *coinControl = nullptr) const; CAmount getUnconfirmedBalance() const; CAmount getImmatureBalance() const; @@ -232,6 +234,9 @@ class WalletModel : public QObject int getRealOutpointPrivateSendRounds(const COutPoint& outpoint) const; + QString getWalletName() const; + + static bool isMultiwallet(); private: CWallet *wallet; bool fHaveWatchOnly; @@ -270,7 +275,7 @@ class WalletModel : public QObject const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); // Encryption status of wallet changed - void encryptionStatusChanged(int status); + void encryptionStatusChanged(); // Signal emitted when wallet needs to be unlocked // It is valid behaviour for listeners to keep the wallet locked after this signal; diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 7383f31a47cf..6415198db6df 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -134,13 +134,13 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui) connect(this, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int))); // Pass through encryption status changed signals - connect(this, SIGNAL(encryptionStatusChanged(int)), gui, SLOT(setEncryptionStatus(int))); + connect(this, SIGNAL(encryptionStatusChanged()), gui, SLOT(updateWalletStatus())); // Pass through transaction notifications - connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString,QString))); + connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString,QString,QString))); // Connect HD enabled state signal - connect(this, SIGNAL(hdEnabledStatusChanged(int)), gui, SLOT(setHDStatus(int))); + connect(this, SIGNAL(hdEnabledStatusChanged()), gui, SLOT(updateWalletStatus())); } } @@ -178,11 +178,11 @@ void WalletView::setWalletModel(WalletModel *_walletModel) connect(_walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); // Handle changes in encryption status - connect(_walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int))); + connect(_walletModel, SIGNAL(encryptionStatusChanged()), this, SIGNAL(encryptionStatusChanged())); updateEncryptionStatus(); // update HD status - Q_EMIT hdEnabledStatusChanged(_walletModel->hdEnabled()); + Q_EMIT hdEnabledStatusChanged(); // Balloon pop-up for new transaction connect(_walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), @@ -222,7 +222,7 @@ void WalletView::processNewTransaction(const QModelIndex& parent, int start, int QString address = ttm->data(index, TransactionTableModel::AddressRole).toString(); QString label = ttm->data(index, TransactionTableModel::LabelRole).toString(); - Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label); + Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label, walletModel->getWalletName()); } void WalletView::gotoOverviewPage() @@ -303,7 +303,7 @@ void WalletView::showOutOfSyncWarning(bool fShow) void WalletView::updateEncryptionStatus() { - Q_EMIT encryptionStatusChanged(walletModel->getEncryptionStatus()); + Q_EMIT encryptionStatusChanged(); } void WalletView::encryptWallet(bool status) diff --git a/src/qt/walletview.h b/src/qt/walletview.h index ba92577bdfea..b40a186d9dfb 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -46,6 +46,7 @@ class WalletView : public QStackedWidget The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic. */ void setClientModel(ClientModel *clientModel); + WalletModel *getWalletModel() { return walletModel; } /** Set the wallet model. The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending functionality. @@ -132,11 +133,11 @@ public Q_SLOTS: /** Fired when a message should be reported to the user */ void message(const QString &title, const QString &message, unsigned int style); /** Encryption status of wallet changed */ - void encryptionStatusChanged(int status); + void encryptionStatusChanged(); /** HD-Enabled status of wallet changed (only possible during startup) */ - void hdEnabledStatusChanged(int hdEnabled); + void hdEnabledStatusChanged(); /** Notify that a new transaction appeared */ - void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label); + void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName); /** Notify that the out of sync warning icon has been pressed */ void outOfSyncWarningClicked(); }; From a6703749379e2a2c4d31a125d89c24f4a9822c8d Mon Sep 17 00:00:00 2001 From: pasta Date: Sun, 12 Jul 2020 00:45:00 -0500 Subject: [PATCH 02/13] fix incomingTransaction notifications Signed-off-by: pasta --- src/qt/bitcoingui.cpp | 6 +++--- src/qt/bitcoingui.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 963ce24f27da..cc216640216c 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1339,7 +1339,7 @@ void BitcoinGUI::showEvent(QShowEvent *event) void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName) { IncomingTransactionMessage itx = { - date, unit, amount, type, address, label + date, unit, amount, type, address, label, walletName }; incomingTransactions.emplace_back(itx); @@ -1406,8 +1406,8 @@ void BitcoinGUI::showIncomingTransactions() // On new transaction, make an info balloon QString msg = tr("Date: %1\n").arg(itx.date) + tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(itx.unit, itx.amount, true)); - if (WalletModel::isMultiwallet() && !walletName.isEmpty()) { - msg += tr("Wallet: %1\n").arg(walletName); + if (WalletModel::isMultiwallet() && !itx.walletName.isEmpty()) { + msg += tr("Wallet: %1\n").arg(itx.walletName); } msg += tr("Type: %1\n").arg(itx.type); if (!itx.label.isEmpty()) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 503e42c3a781..954e8ebdbafe 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -159,6 +159,7 @@ class BitcoinGUI : public QMainWindow QString type; QString address; QString label; + QString walletName; }; std::list incomingTransactions; QTimer* incomingTransactionsTimer; From c240e70e38b3445f9dcf2233799f4a778304f388 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Tue, 14 Jul 2020 01:21:48 +0200 Subject: [PATCH 03/13] qt: Add the wallet selector widget before the dash logo in the toolbar --- src/qt/bitcoingui.cpp | 24 +++++++++++++----------- src/qt/bitcoingui.h | 1 + 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index cc216640216c..f2d79e0a1850 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -87,6 +87,7 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle * progressDialog(0), appMenuBar(0), appToolBar(0), + appToolBarLogoAction(0), overviewAction(0), historyAction(0), masternodeAction(0), @@ -613,11 +614,7 @@ void BitcoinGUI::createToolBars() overviewAction->setChecked(true); #ifdef ENABLE_WALLET - QWidget *spacer = new QWidget(); - spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - toolbar->addWidget(spacer); - - m_wallet_selector = new QComboBox(); + m_wallet_selector = new QComboBox(this); connect(m_wallet_selector, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(setCurrentWallet(const QString&))); #endif @@ -625,7 +622,7 @@ void BitcoinGUI::createToolBars() logoLabel->setObjectName("lblToolbarLogo"); logoLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - toolbar->addWidget(logoLabel); + appToolBarLogoAction = toolbar->addWidget(logoLabel); /** Create additional container for toolbar and walletFrame and make it the central widget. This is a workaround mostly for toolbar styling on Mac OS but should work fine for every other OSes too. @@ -746,11 +743,16 @@ bool BitcoinGUI::addWallet(WalletModel *walletModel) setWalletActionsEnabled(true); m_wallet_selector->addItem(name); if (m_wallet_selector->count() == 2) { - m_wallet_selector_label = new QLabel(); - m_wallet_selector_label->setText(tr("Wallet:") + " "); - m_wallet_selector_label->setBuddy(m_wallet_selector); - appToolBar->addWidget(m_wallet_selector_label); - appToolBar->addWidget(m_wallet_selector); + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(m_wallet_selector); + layout->setSpacing(0); + layout->setMargin(0); + layout->setContentsMargins(5, 0, 5, 0); + QWidget* walletSelector = new QWidget(this); + walletSelector->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + walletSelector->setObjectName("walletSelector"); + walletSelector->setLayout(layout); + appToolBar->insertWidget(appToolBarLogoAction, walletSelector); } rpcConsole->addWallet(walletModel); return walletFrame->addWallet(walletModel); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 954e8ebdbafe..f86f1230546f 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -96,6 +96,7 @@ class BitcoinGUI : public QMainWindow QMenuBar *appMenuBar; QToolBar *appToolBar; + QAction* appToolBarLogoAction; QToolButton *overviewAction; QToolButton *historyAction; QToolButton *masternodeAction; From 8acba4620574ae298b39164d9a32b57c2715ad77 Mon Sep 17 00:00:00 2001 From: pasta Date: Sun, 12 Jul 2020 00:52:25 -0500 Subject: [PATCH 04/13] privatesend: Implement multiwallet support With the introduction of better mutliwallet support, privatesend only worked for your first wallet. This commit implements multiwallet for privatesend such that the wallet you start the mixing from is the wallet mixing will occur in. Signed-off-by: pasta --- src/privatesend/privatesend-client.cpp | 169 +++++++++++++++---------- src/privatesend/privatesend-client.h | 15 ++- src/qt/bitcoingui.cpp | 2 +- src/qt/overviewpage.cpp | 15 ++- src/rpc/privatesend.cpp | 7 +- src/wallet/init.cpp | 13 +- src/wallet/wallet.cpp | 2 +- 7 files changed, 135 insertions(+), 88 deletions(-) diff --git a/src/privatesend/privatesend-client.cpp b/src/privatesend/privatesend-client.cpp index 0ff222af023e..b931d9165c16 100644 --- a/src/privatesend/privatesend-client.cpp +++ b/src/privatesend/privatesend-client.cpp @@ -32,7 +32,7 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& if (!CheckDiskSpace()) { ResetPool(); - fPrivateSendRunning = false; + StopMixing(); LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::ProcessMessage -- Not enough disk space, disabling PrivateSend.\n"); return; } @@ -225,6 +225,24 @@ void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string& } } +bool CPrivateSendClientManager::StartMixing(CWallet* pwallet) { + if (IsMixing()) { + return false; + } + assert(pwallet != nullptr); + mixingWallet = pwallet; + return true; +} + +void CPrivateSendClientManager::StopMixing() { + mixingWallet = nullptr; +} + +bool CPrivateSendClientManager::IsMixing() const +{ + return mixingWallet != nullptr; +} + void CPrivateSendClientSession::ResetPool() { txMyCollateral = CMutableTransaction(); @@ -261,13 +279,13 @@ void CPrivateSendClientSession::UnlockCoins() if (!privateSendClient.fEnablePrivateSend) return; while (true) { - TRY_LOCK(GetWallets()[0]->cs_wallet, lockWallet); + TRY_LOCK(GetMixingWallet()->cs_wallet, lockWallet); if (!lockWallet) { MilliSleep(50); continue; } for (const auto& outpoint : vecOutPointLocked) - GetWallets()[0]->UnlockCoin(outpoint); + GetMixingWallet()->UnlockCoin(outpoint); break; } @@ -355,6 +373,17 @@ bool CPrivateSendClientManager::GetMixingMasternodesInfo(std::vectornKeysLeftSinceAutoBackup = 0; // no backup, no "keys since last backup" + StopMixing(); + GetMixingWallet()->nKeysLeftSinceAutoBackup = 0; // no backup, no "keys since last backup" return false; case -1: // Automatic backup failed, nothing else we can do until user fixes the issue manually. @@ -698,24 +727,24 @@ bool CPrivateSendClientManager::CheckAutomaticBackup() return false; } - if (GetWallets()[0]->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_STOP) { + if (GetMixingWallet()->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_STOP) { // We should never get here via mixing itself but probably something else is still actively using keypool - LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d, no mixing available.\n", GetWallets()[0]->nKeysLeftSinceAutoBackup); - strAutoDenomResult = strprintf(_("Very low number of keys left: %d") + ", " + _("no mixing available."), GetWallets()[0]->nKeysLeftSinceAutoBackup); + LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d, no mixing available.\n", GetMixingWallet()->nKeysLeftSinceAutoBackup); + strAutoDenomResult = strprintf(_("Very low number of keys left: %d") + ", " + _("no mixing available."), GetMixingWallet()->nKeysLeftSinceAutoBackup); // It's getting really dangerous, stop mixing - fPrivateSendRunning = false; + StopMixing(); return false; - } else if (GetWallets()[0]->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) { + } else if (GetMixingWallet()->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) { // Low number of keys left but it's still more or less safe to continue - LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d\n", GetWallets()[0]->nKeysLeftSinceAutoBackup); - strAutoDenomResult = strprintf(_("Very low number of keys left: %d"), GetWallets()[0]->nKeysLeftSinceAutoBackup); + LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d\n", GetMixingWallet()->nKeysLeftSinceAutoBackup); + strAutoDenomResult = strprintf(_("Very low number of keys left: %d"), GetMixingWallet()->nKeysLeftSinceAutoBackup); if (fCreateAutoBackups) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Trying to create new backup.\n"); std::string warningString; std::string errorString; - if (!GetWallets()[0]->AutoBackupWallet("", warningString, errorString)) { + if (!GetMixingWallet()->AutoBackupWallet("", warningString, errorString)) { if (!warningString.empty()) { // There were some issues saving backup but yet more or less safe to continue LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- WARNING! Something went wrong on automatic backup: %s\n", warningString); @@ -733,7 +762,7 @@ bool CPrivateSendClientManager::CheckAutomaticBackup() } } - LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Keys left since latest backup: %d\n", GetWallets()[0]->nKeysLeftSinceAutoBackup); + LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Keys left since latest backup: %d\n", GetMixingWallet()->nKeysLeftSinceAutoBackup); return true; } @@ -751,15 +780,15 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool return false; } - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false; + if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; CAmount nBalanceNeedsAnonymized; { LOCK2(cs_main, mempool.cs); - LOCK(GetWallets()[0]->cs_wallet); + LOCK(GetMixingWallet()->cs_wallet); - if (!fDryRun && GetWallets()[0]->IsLocked(true)) { + if (!fDryRun && GetMixingWallet()->IsLocked(true)) { strAutoDenomResult = _("Wallet is locked."); return false; } @@ -783,7 +812,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool } // check if there is anything left to do - CAmount nBalanceAnonymized = GetWallets()[0]->GetAnonymizedBalance(); + CAmount nBalanceAnonymized = GetMixingWallet()->GetAnonymizedBalance(); nBalanceNeedsAnonymized = privateSendClient.nPrivateSendAmount*COIN - nBalanceAnonymized; if (nBalanceNeedsAnonymized < 0) { @@ -795,13 +824,13 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool CAmount nValueMin = CPrivateSend::GetSmallestDenomination(); // if there are no confirmed DS collateral inputs yet - if (!GetWallets()[0]->HasCollateralInputs()) { + if (!GetMixingWallet()->HasCollateralInputs()) { // should have some additional amount for them nValueMin += CPrivateSend::GetMaxCollateralAmount(); } // including denoms but applying some restrictions - CAmount nBalanceAnonymizable = GetWallets()[0]->GetAnonymizableBalance(); + CAmount nBalanceAnonymizable = GetMixingWallet()->GetAnonymizableBalance(); // mixable balance is way too small if (nBalanceAnonymizable < nValueMin) { @@ -811,10 +840,10 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool } // excluding denoms - CAmount nBalanceAnonimizableNonDenom = GetWallets()[0]->GetAnonymizableBalance(true); + CAmount nBalanceAnonimizableNonDenom = GetMixingWallet()->GetAnonymizableBalance(true); // denoms - CAmount nBalanceDenominatedConf = GetWallets()[0]->GetDenominatedBalance(); - CAmount nBalanceDenominatedUnconf = GetWallets()[0]->GetDenominatedBalance(true); + CAmount nBalanceDenominatedConf = GetMixingWallet()->GetDenominatedBalance(); + CAmount nBalanceDenominatedUnconf = GetMixingWallet()->GetDenominatedBalance(true); CAmount nBalanceDenominated = nBalanceDenominatedConf + nBalanceDenominatedUnconf; CAmount nBalanceToDenominate = privateSendClient.nPrivateSendAmount * COIN - nBalanceDenominated; @@ -863,8 +892,8 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool } //check if we have the collateral sized inputs - if (!GetWallets()[0]->HasCollateralInputs()) { - return !GetWallets()[0]->HasCollateralInputs(false) && MakeCollateralAmounts(connman); + if (!GetMixingWallet()->HasCollateralInputs()) { + return !GetMixingWallet()->HasCollateralInputs(false) && MakeCollateralAmounts(connman); } if (nSessionID) { @@ -888,14 +917,14 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool //check our collateral and create new if needed std::string strReason; if (txMyCollateral == CMutableTransaction()) { - if (!GetWallets()[0]->CreateCollateralTransaction(txMyCollateral, strReason)) { + if (!GetMixingWallet()->CreateCollateralTransaction(txMyCollateral, strReason)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- create collateral error:%s\n", strReason); return false; } } else { if (!CPrivateSend::IsCollateralValid(txMyCollateral)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- invalid collateral, recreating...\n"); - if (!GetWallets()[0]->CreateCollateralTransaction(txMyCollateral, strReason)) { + if (!GetMixingWallet()->CreateCollateralTransaction(txMyCollateral, strReason)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- create collateral error: %s\n", strReason); return false; } @@ -903,10 +932,10 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool } // lock the funds we're going to use for our collateral for (const auto& txin : txMyCollateral.vin) { - GetWallets()[0]->LockCoin(txin.prevout); + GetMixingWallet()->LockCoin(txin.prevout); vecOutPointLocked.push_back(txin.prevout); } - } // LOCK2(cs_main, GetWallets()[0]->cs_wallet); + } // LOCK2(cs_main, GetMixingWallet()->cs_wallet); // Always attempt to join an existing queue if (JoinExistingQueue(nBalanceNeedsAnonymized, connman)) { @@ -923,14 +952,14 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool fDryRun) { if (fMasternodeMode) return false; // no client-side mixing on masternodes - if (!fEnablePrivateSend || !fPrivateSendRunning) return false; + if (!fEnablePrivateSend || !IsMixing()) return false; if (!masternodeSync.IsBlockchainSynced()) { strAutoDenomResult = _("Can't mix while sync in progress."); return false; } - if (!fDryRun && GetWallets()[0]->IsLocked(true)) { + if (!fDryRun && GetMixingWallet()->IsLocked(true)) { strAutoDenomResult = _("Wallet is locked."); return false; } @@ -1013,7 +1042,7 @@ CDeterministicMNCPtr CPrivateSendClientManager::GetRandomNotUsedMasternode() bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman) { - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false; + if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; auto mnList = deterministicMNManager->GetListAtChainTip(); @@ -1042,7 +1071,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize std::vector > vecPSInOutPairsTmp; // Try to match their denominations if possible, select exact number of denominations - if (!GetWallets()[0]->SelectPSInOutPairsByDenominations(dsq.nDenom, nBalanceNeedsAnonymized, vecPSInOutPairsTmp)) { + if (!GetMixingWallet()->SelectPSInOutPairsByDenominations(dsq.nDenom, nBalanceNeedsAnonymized, vecPSInOutPairsTmp)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- Couldn't match denomination %d (%s)\n", dsq.nDenom, CPrivateSend::DenominationToString(dsq.nDenom)); continue; } @@ -1072,7 +1101,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman) { - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false; + if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; if (nBalanceNeedsAnonymized <= 0) return false; int nTries = 0; @@ -1081,7 +1110,7 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, C // find available denominated amounts std::set setAmounts; - if (!GetWallets()[0]->SelectDenominatedAmounts(nBalanceNeedsAnonymized, setAmounts)) { + if (!GetMixingWallet()->SelectDenominatedAmounts(nBalanceNeedsAnonymized, setAmounts)) { // this should never happen LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- Can't mix: no compatible inputs found!\n"); strAutoDenomResult = _("Can't mix: no compatible inputs found!"); @@ -1187,7 +1216,7 @@ void CPrivateSendClientManager::ProcessPendingDsaRequest(CConnman& connman) bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) { LOCK2(cs_main, mempool.cs); - LOCK(GetWallets()[0]->cs_wallet); + LOCK(GetMixingWallet()->cs_wallet); std::string strError; std::vector > vecPSInOutPairs, vecPSInOutPairsTmp; @@ -1238,9 +1267,9 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std::vector >& vecPSInOutPairsRet) { - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false; + if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; - if (GetWallets()[0]->IsLocked(true)) { + if (GetMixingWallet()->IsLocked(true)) { strErrorRet = "Wallet locked, unable to create transaction!"; return false; } @@ -1252,7 +1281,7 @@ bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std:: vecPSInOutPairsRet.clear(); - bool fSelected = GetWallets()[0]->SelectPSInOutPairsByDenominations(nSessionDenom, CPrivateSend::GetMaxPoolAmount(), vecPSInOutPairsRet); + bool fSelected = GetMixingWallet()->SelectPSInOutPairsByDenominations(nSessionDenom, CPrivateSend::GetMaxPoolAmount(), vecPSInOutPairsRet); if (!fSelected) { strErrorRet = "Can't select current denominated inputs"; return false; @@ -1264,7 +1293,7 @@ bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std:: bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, const std::vector >& vecPSInOutPairsIn, std::vector >& vecPSInOutPairsRet, bool fDryRun) { AssertLockHeld(cs_main); - AssertLockHeld(GetWallets()[0]->cs_wallet); + AssertLockHeld(GetMixingWallet()->cs_wallet); if (!CPrivateSend::IsValidDenomination(nSessionDenom)) { strErrorRet = "Incorrect session denom"; @@ -1295,7 +1324,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds ++nSteps; continue; } - scriptDenom = keyHolderStorage.AddKey(GetWallets()[0]); + scriptDenom = keyHolderStorage.AddKey(GetMixingWallet()); } vecPSInOutPairsRet.emplace_back(pair.first, CTxOut(nDenomAmount, scriptDenom)); // step is complete @@ -1313,7 +1342,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds } for (const auto& pair : vecPSInOutPairsRet) { - GetWallets()[0]->LockCoin(pair.first.prevout); + GetMixingWallet()->LockCoin(pair.first.prevout); vecOutPointLocked.push_back(pair.first.prevout); } @@ -1323,17 +1352,17 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds // Create collaterals by looping through inputs grouped by addresses bool CPrivateSendClientSession::MakeCollateralAmounts(CConnman& connman) { - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false; + if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; LOCK2(cs_main, mempool.cs); - LOCK(GetWallets()[0]->cs_wallet); + LOCK(GetMixingWallet()->cs_wallet); // NOTE: We do not allow txes larger than 100kB, so we have to limit number of inputs here. // We still want to consume a lot of inputs to avoid creating only smaller denoms though. // Knowing that each CTxIn is at least 148b big, 400 inputs should take 400 x ~148b = ~60kB. // This still leaves more than enough room for another data of typical MakeCollateralAmounts tx. std::vector vecTally; - if (!GetWallets()[0]->SelectCoinsGroupedByAddresses(vecTally, false, false, true, 400)) { + if (!GetMixingWallet()->SelectCoinsGroupedByAddresses(vecTally, false, false, true, 400)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- SelectCoinsGroupedByAddresses can't find any inputs!\n"); return false; } @@ -1365,9 +1394,9 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta { AssertLockHeld(cs_main); AssertLockHeld(mempool.cs); - AssertLockHeld(GetWallets()[0]->cs_wallet); + AssertLockHeld(GetMixingWallet()->cs_wallet); - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false; + if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; // Skip way too tiny amounts if (tallyItem.nAmount < CPrivateSend::GetCollateralAmount()) { @@ -1391,9 +1420,9 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta std::vector vecSend; // make our collateral address - CReserveKey reservekeyCollateral(GetWallets()[0]); + CReserveKey reservekeyCollateral(GetMixingWallet()); // make our change address - CReserveKey reservekeyChange(GetWallets()[0]); + CReserveKey reservekeyChange(GetMixingWallet()); CScript scriptCollateral; CPubKey vchPubKey; @@ -1422,7 +1451,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta coinControl.Select(outpoint); } - bool fSuccess = GetWallets()[0]->CreateTransaction(vecSend, wtx, reservekeyChange, + bool fSuccess = GetMixingWallet()->CreateTransaction(vecSend, wtx, reservekeyChange, nFeeRet, nChangePosRet, strFail, coinControl); if (!fSuccess) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- ONLY_NONDENOMINATED: %s\n", strFail); @@ -1430,7 +1459,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta if (fTryDenominated) { // Try to also use denominated coins (we can't mix denominated without collaterals anyway). coinControl.nCoinType = CoinType::ALL_COINS; - if (!GetWallets()[0]->CreateTransaction(vecSend, wtx, reservekeyChange, + if (!GetMixingWallet()->CreateTransaction(vecSend, wtx, reservekeyChange, nFeeRet, nChangePosRet, strFail, coinControl)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- ALL_COINS Error: %s\n", strFail); reservekeyCollateral.ReturnKey(); @@ -1449,7 +1478,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta // use the same nCachedLastSuccessBlock as for DS mixing to prevent race CValidationState state; - if (!GetWallets()[0]->CommitTransaction(wtx, reservekeyChange, &connman, state)) { + if (!GetMixingWallet()->CommitTransaction(wtx, reservekeyChange, &connman, state)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- CommitTransaction failed! Reason given: %s\n", state.GetRejectReason()); return false; } @@ -1462,17 +1491,17 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta // Create denominations by looping through inputs grouped by addresses bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, CConnman& connman) { - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false; + if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; LOCK2(cs_main, mempool.cs); - LOCK(GetWallets()[0]->cs_wallet); + LOCK(GetMixingWallet()->cs_wallet); // NOTE: We do not allow txes larger than 100kB, so we have to limit number of inputs here. // We still want to consume a lot of inputs to avoid creating only smaller denoms though. // Knowing that each CTxIn is at least 148b big, 400 inputs should take 400 x ~148b = ~60kB. // This still leaves more than enough room for another data of typical CreateDenominated tx. std::vector vecTally; - if (!GetWallets()[0]->SelectCoinsGroupedByAddresses(vecTally, true, true, true, 400)) { + if (!GetMixingWallet()->SelectCoinsGroupedByAddresses(vecTally, true, true, true, 400)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- SelectCoinsGroupedByAddresses can't find any inputs!\n"); return false; } @@ -1482,7 +1511,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, return a.nAmount > b.nAmount; }); - bool fCreateMixingCollaterals = !GetWallets()[0]->HasCollateralInputs(); + bool fCreateMixingCollaterals = !GetMixingWallet()->HasCollateralInputs(); for (const auto& item : vecTally) { if (!CreateDenominated(nBalanceToDenominate, item, fCreateMixingCollaterals, connman)) continue; @@ -1498,9 +1527,9 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, { AssertLockHeld(cs_main); AssertLockHeld(mempool.cs); - AssertLockHeld(GetWallets()[0]->cs_wallet); + AssertLockHeld(GetMixingWallet()->cs_wallet); - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false; + if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; std::vector vecSend; CKeyHolderStorage keyHolderStorageDenom; @@ -1520,7 +1549,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, // ****** Add an output for mixing collaterals ************ / if (fCreateMixingCollaterals) { - CScript scriptCollateral = keyHolderStorageDenom.AddKey(GetWallets()[0]); + CScript scriptCollateral = keyHolderStorageDenom.AddKey(GetMixingWallet()); vecSend.push_back((CRecipient){scriptCollateral, CPrivateSend::GetMaxCollateralAmount(), false}); nValueLeft -= CPrivateSend::GetMaxCollateralAmount() + nOutputFee; } @@ -1533,7 +1562,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, std::map mapDenomCount; for (auto nDenomValue : vecStandardDenoms) { - mapDenomCount.insert(std::pair(nDenomValue, GetWallets()[0]->CountInputsWithAmount(nDenomValue))); + mapDenomCount.insert(std::pair(nDenomValue, GetMixingWallet()->CountInputsWithAmount(nDenomValue))); } // Will generate outputs for the createdenoms up to privatesendmaxdenoms per denom @@ -1571,7 +1600,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, // add each output up to 11 times or until it can't be added again or until we reach nPrivateSendDenomsGoal while (needMoreOutputs() && nOutputs <= 10 && currentDenomIt->second < privateSendClient.nPrivateSendDenomsGoal) { - CScript scriptDenom = keyHolderStorageDenom.AddKey(GetWallets()[0]); + CScript scriptDenom = keyHolderStorageDenom.AddKey(GetMixingWallet()); vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false}); @@ -1635,7 +1664,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, // Never go above the cap unless it's the largest denom if (nDenomValue != nLargestDenomValue && it->second >= privateSendClient.nPrivateSendDenomsHardCap) break; - CScript scriptDenom = keyHolderStorageDenom.AddKey(GetWallets()[0]); + CScript scriptDenom = keyHolderStorageDenom.AddKey(GetMixingWallet()); vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false}); // increment outputs and subtract denomination amount @@ -1681,9 +1710,9 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, int nChangePosRet = -1; std::string strFail = ""; // make our change address - CReserveKey reservekeyChange(GetWallets()[0]); + CReserveKey reservekeyChange(GetMixingWallet()); - bool fSuccess = GetWallets()[0]->CreateTransaction(vecSend, wtx, reservekeyChange, + bool fSuccess = GetMixingWallet()->CreateTransaction(vecSend, wtx, reservekeyChange, nFeeRet, nChangePosRet, strFail, coinControl); if (!fSuccess) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- Error: %s\n", strFail); @@ -1694,7 +1723,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, keyHolderStorageDenom.KeepAll(); CValidationState state; - if (!GetWallets()[0]->CommitTransaction(wtx, reservekeyChange, &connman, state)) { + if (!GetMixingWallet()->CommitTransaction(wtx, reservekeyChange, &connman, state)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- CommitTransaction failed! Reason given: %s\n", state.GetRejectReason()); return false; } @@ -1770,7 +1799,7 @@ void CPrivateSendClientManager::GetJsonInfo(UniValue& obj) const obj.clear(); obj.setObject(); obj.pushKV("enabled", fEnablePrivateSend); - obj.pushKV("running", fPrivateSendRunning); + obj.pushKV("running", IsMixing()); obj.pushKV("multisession", fPrivateSendMultiSession); obj.pushKV("max_sessions", nPrivateSendSessions); obj.pushKV("max_rounds", nPrivateSendRounds); diff --git a/src/privatesend/privatesend-client.h b/src/privatesend/privatesend-client.h index 52115d619cc4..dbd30855f0da 100644 --- a/src/privatesend/privatesend-client.h +++ b/src/privatesend/privatesend-client.h @@ -163,6 +163,7 @@ class CPrivateSendClientSession : public CPrivateSendBaseSession std::string GetStatus(bool fWaitForBlock); bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const; + CWallet* GetMixingWallet() const; /// Passively run mixing in the background according to the configuration in settings bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false); @@ -193,6 +194,8 @@ class CPrivateSendClientManager : public CPrivateSendBaseManager int nMinBlocksToWait; // how many blocks to wait after one successful mixing tx in non-multisession mode std::string strAutoDenomResult; + CWallet* mixingWallet; + // Keep track of current block height int nCachedBlockHeight; @@ -208,7 +211,6 @@ class CPrivateSendClientManager : public CPrivateSendBaseManager int nPrivateSendDenomsGoal; int nPrivateSendDenomsHardCap; bool fEnablePrivateSend; - bool fPrivateSendRunning; bool fPrivateSendMultiSession; int nCachedNumBlocks; //used for the overview screen @@ -226,15 +228,20 @@ class CPrivateSendClientManager : public CPrivateSendBaseManager nPrivateSendDenomsGoal(DEFAULT_PRIVATESEND_DENOMS_GOAL), nPrivateSendDenomsHardCap(DEFAULT_PRIVATESEND_DENOMS_HARDCAP), fEnablePrivateSend(false), - fPrivateSendRunning(false), fPrivateSendMultiSession(DEFAULT_PRIVATESEND_MULTISESSION), nCachedNumBlocks(std::numeric_limits::max()), - fCreateAutoBackups(true) + fCreateAutoBackups(true), + mixingWallet(nullptr) { } void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61); + + + bool StartMixing(CWallet* pwallet); + void StopMixing(); + bool IsMixing() const; void ResetPool(); std::string GetStatuses(); @@ -242,6 +249,8 @@ class CPrivateSendClientManager : public CPrivateSendBaseManager bool GetMixingMasternodesInfo(std::vector& vecDmnsRet) const; + CWallet* GetMixingWallet() const; + /// Passively run mixing in the background according to the configuration in settings bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index f2d79e0a1850..70a3b9b73429 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1049,7 +1049,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer // Disabling macOS App Nap on initial sync, disk, reindex operations and mixing. bool disableAppNap = !masternodeSync.IsSynced(); #ifdef ENABLE_WALLET - disableAppNap |= privateSendClient.fPrivateSendRunning; + disableAppNap |= privateSendClient.IsMixing(); #endif // ENABLE_WALLET if (disableAppNap) { m_app_nap_inhibitor->disableAppNap(); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 46e2fc69f619..e93d894f2971 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -181,7 +181,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) ui->labelPrivateSendEnabled->setToolTip(tr("Automatic backups are disabled, no mixing available!")); } } else { - if(!privateSendClient.fPrivateSendRunning){ + if(!privateSendClient.IsMixing()){ ui->togglePrivateSend->setText(tr("Start Mixing")); } else { ui->togglePrivateSend->setText(tr("Stop Mixing")); @@ -500,7 +500,7 @@ void OverviewPage::privateSendStatus(bool fForce) } ui->labelPrivateSendEnabled->setToolTip(strKeysLeftText); - if (!privateSendClient.fPrivateSendRunning) { + if (!privateSendClient.IsMixing()) { if (nBestHeight != privateSendClient.nCachedNumBlocks) { privateSendClient.nCachedNumBlocks = nBestHeight; updatePrivateSendProgress(); @@ -557,7 +557,7 @@ void OverviewPage::privateSendStatus(bool fForce) } } - QString strEnabled = privateSendClient.fPrivateSendRunning ? tr("Enabled") : tr("Disabled"); + QString strEnabled = privateSendClient.IsMixing() ? tr("Enabled") : tr("Disabled"); // Show how many keys left in advanced PS UI mode only if(fShowAdvancedPSUI) strEnabled += ", " + strKeysLeftText; ui->labelPrivateSendEnabled->setText(strEnabled); @@ -600,7 +600,7 @@ void OverviewPage::togglePrivateSend(){ QMessageBox::Ok, QMessageBox::Ok); settings.setValue("hasMixed", "hasMixed"); } - if(!privateSendClient.fPrivateSendRunning){ + if(!privateSendClient.IsMixing()){ const CAmount nMinAmount = CPrivateSend::GetSmallestDenomination() + CPrivateSend::GetMaxCollateralAmount(); if(currentBalance < nMinAmount){ QString strMinAmount(BitcoinUnits::formatWithUnit(nDisplayUnit, nMinAmount)); @@ -628,14 +628,15 @@ void OverviewPage::togglePrivateSend(){ } - privateSendClient.fPrivateSendRunning = !privateSendClient.fPrivateSendRunning; privateSendClient.nCachedNumBlocks = std::numeric_limits::max(); - if(!privateSendClient.fPrivateSendRunning){ + if (privateSendClient.IsMixing()) { ui->togglePrivateSend->setText(tr("Start Mixing")); privateSendClient.ResetPool(); + privateSendClient.StopMixing(); } else { ui->togglePrivateSend->setText(tr("Stop Mixing")); + privateSendClient.StartMixing(walletModel->getWallet()); } } @@ -663,5 +664,5 @@ void OverviewPage::DisablePrivateSendCompletely() { if (nWalletBackups <= 0) { ui->labelPrivateSendEnabled->setText("(" + tr("Disabled") + ")"); } - privateSendClient.fPrivateSendRunning = false; + privateSendClient.StopMixing(); } diff --git a/src/rpc/privatesend.cpp b/src/rpc/privatesend.cpp index 6447a8f7ca7d..8ff307a06d9c 100644 --- a/src/rpc/privatesend.cpp +++ b/src/rpc/privatesend.cpp @@ -50,13 +50,16 @@ UniValue privatesend(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please unlock wallet for mixing with walletpassphrase first."); } - privateSendClient.fPrivateSendRunning = true; + if (!privateSendClient.StartMixing(pwallet)) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing has been started already."); + } + bool result = privateSendClient.DoAutomaticDenominating(*g_connman); return "Mixing " + (result ? "started successfully" : ("start failed: " + privateSendClient.GetStatuses() + ", will retry")); } if (request.params[0].get_str() == "stop") { - privateSendClient.fPrivateSendRunning = false; + privateSendClient.StopMixing(); return "Mixing was stopped"; } diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 8d96744ba641..397b62fef2f3 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -374,8 +374,8 @@ void WalletInit::Flush() { if (privateSendClient.fEnablePrivateSend) { // Stop PrivateSend, release keys - privateSendClient.fPrivateSendRunning = false; privateSendClient.ResetPool(); + privateSendClient.StopMixing(); } for (CWallet* pwallet : GetWallets()) { pwallet->Flush(false); @@ -408,10 +408,15 @@ void WalletInit::AutoLockMasternodeCollaterals() void WalletInit::InitPrivateSendSettings() { if (!HasWallets()) { - privateSendClient.fEnablePrivateSend = privateSendClient.fPrivateSendRunning = false; + privateSendClient.fEnablePrivateSend = false; + privateSendClient.StopMixing(); } else { privateSendClient.fEnablePrivateSend = gArgs.GetBoolArg("-enableprivatesend", true); - privateSendClient.fPrivateSendRunning = GetWallets()[0]->IsLocked() ? false : gArgs.GetBoolArg("-privatesendautostart", DEFAULT_PRIVATESEND_AUTOSTART); + if (GetWallets()[0]->IsLocked()) { + privateSendClient.StopMixing(); + } else if (gArgs.GetBoolArg("-privatesendautostart", DEFAULT_PRIVATESEND_AUTOSTART)) { + privateSendClient.StartMixing(GetWallets()[0]); + } } privateSendClient.fPrivateSendMultiSession = gArgs.GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION); privateSendClient.nPrivateSendSessions = std::min(std::max((int)gArgs.GetArg("-privatesendsessions", DEFAULT_PRIVATESEND_SESSIONS), MIN_PRIVATESEND_SESSIONS), MAX_PRIVATESEND_SESSIONS); @@ -423,7 +428,7 @@ void WalletInit::InitPrivateSendSettings() if (privateSendClient.fEnablePrivateSend) { LogPrintf("PrivateSend: autostart=%d, multisession=%d," /* Continued */ "sessions=%d, rounds=%d, amount=%d, denoms_goal=%d, denoms_hardcap=%d\n", - privateSendClient.fPrivateSendRunning, privateSendClient.fPrivateSendMultiSession, + privateSendClient.IsMixing(), privateSendClient.fPrivateSendMultiSession, privateSendClient.nPrivateSendSessions, privateSendClient.nPrivateSendRounds, privateSendClient.nPrivateSendAmount, privateSendClient.nPrivateSendDenomsGoal, privateSendClient.nPrivateSendDenomsHardCap); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 833965e8c2d8..ebb51e4a0bbc 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4342,7 +4342,7 @@ bool CWallet::NewKeyPool() batch.ErasePool(nIndex); } setExternalKeyPool.clear(); - privateSendClient.fPrivateSendRunning = false; + privateSendClient.StopMixing(); nKeysLeftSinceAutoBackup = 0; m_pool_key_to_index.clear(); From 167e0f402c1ba06289a90e9d0791344e59a8c354 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 16 Jul 2020 15:23:29 +0300 Subject: [PATCH 05/13] Split mixing options out of mixing manager --- src/dsnotificationinterface.cpp | 2 +- src/masternode/masternode-utils.cpp | 2 +- src/net_processing.cpp | 2 +- src/privatesend/privatesend-client.cpp | 78 ++++++++++++-------------- src/privatesend/privatesend-client.h | 45 +++++++++------ src/qt/bitcoingui.cpp | 6 +- src/qt/coincontroldialog.cpp | 4 +- src/qt/optionsdialog.cpp | 2 +- src/qt/optionsmodel.cpp | 18 +++--- src/qt/overviewpage.cpp | 60 ++++++++++---------- src/qt/walletmodel.cpp | 4 +- src/rpc/privatesend.cpp | 25 ++++++--- src/wallet/init.cpp | 42 +++++++------- src/wallet/rpcwallet.cpp | 4 +- src/wallet/wallet.cpp | 26 ++++----- 15 files changed, 167 insertions(+), 153 deletions(-) diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp index a6d8cbd7a6b0..42c6e87093ec 100644 --- a/src/dsnotificationinterface.cpp +++ b/src/dsnotificationinterface.cpp @@ -62,7 +62,7 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con CPrivateSend::UpdatedBlockTip(pindexNew); #ifdef ENABLE_WALLET - privateSendClient.UpdatedBlockTip(pindexNew); + privateSendClientManager.UpdatedBlockTip(pindexNew); #endif // ENABLE_WALLET llmq::quorumInstantSendManager->UpdatedBlockTip(pindexNew); diff --git a/src/masternode/masternode-utils.cpp b/src/masternode/masternode-utils.cpp index ae3ae41c9df5..e032ca54f52d 100644 --- a/src/masternode/masternode-utils.cpp +++ b/src/masternode/masternode-utils.cpp @@ -24,7 +24,7 @@ void CMasternodeUtils::ProcessMasternodeConnections(CConnman& connman) { std::vector vecDmns; // will be empty when no wallet #ifdef ENABLE_WALLET - privateSendClient.GetMixingMasternodesInfo(vecDmns); + privateSendClientManager.GetMixingMasternodesInfo(vecDmns); #endif // ENABLE_WALLET // Don't disconnect masternode connections when we have less then the desired amount of outbound nodes diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 5b0ff964e759..f17a2a13552d 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3542,7 +3542,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr { //probably one the extensions #ifdef ENABLE_WALLET - privateSendClient.ProcessMessage(pfrom, strCommand, vRecv, *connman, enable_bip61); + privateSendClientManager.ProcessMessage(pfrom, strCommand, vRecv, *connman, enable_bip61); #endif // ENABLE_WALLET privateSendServer.ProcessMessage(pfrom, strCommand, vRecv, *connman, enable_bip61); sporkManager.ProcessSpork(pfrom, strCommand, vRecv, *connman); diff --git a/src/privatesend/privatesend-client.cpp b/src/privatesend/privatesend-client.cpp index b931d9165c16..0a90ca5d6868 100644 --- a/src/privatesend/privatesend-client.cpp +++ b/src/privatesend/privatesend-client.cpp @@ -22,12 +22,13 @@ #include #include -CPrivateSendClientManager privateSendClient; +CPrivateSendClientManager privateSendClientManager; +CPrivateSendClientOptions privateSendClientOptions; void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61) { if (fMasternodeMode) return; - if (!fEnablePrivateSend) return; + if (!privateSendClientOptions.fEnablePrivateSend) return; if (!masternodeSync.IsBlockchainSynced()) return; if (!CheckDiskSpace()) { @@ -134,7 +135,7 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61) { if (fMasternodeMode) return; - if (!privateSendClient.fEnablePrivateSend) return; + if (!privateSendClientOptions.fEnablePrivateSend) return; if (!masternodeSync.IsBlockchainSynced()) return; if (strCommand == NetMsgType::DSSTATUSUPDATE) { @@ -276,7 +277,7 @@ void CPrivateSendClientSession::SetNull() // void CPrivateSendClientSession::UnlockCoins() { - if (!privateSendClient.fEnablePrivateSend) return; + if (!privateSendClientOptions.fEnablePrivateSend) return; while (true) { TRY_LOCK(GetMixingWallet()->cs_wallet, lockWallet); @@ -375,7 +376,7 @@ bool CPrivateSendClientManager::GetMixingMasternodesInfo(std::vectorGetAnonymizedBalance(); - nBalanceNeedsAnonymized = privateSendClient.nPrivateSendAmount*COIN - nBalanceAnonymized; + nBalanceNeedsAnonymized = privateSendClientOptions.nPrivateSendAmount*COIN - nBalanceAnonymized; if (nBalanceNeedsAnonymized < 0) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- Nothing to do\n"); @@ -845,7 +846,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool CAmount nBalanceDenominatedConf = GetMixingWallet()->GetDenominatedBalance(); CAmount nBalanceDenominatedUnconf = GetMixingWallet()->GetDenominatedBalance(true); CAmount nBalanceDenominated = nBalanceDenominatedConf + nBalanceDenominatedUnconf; - CAmount nBalanceToDenominate = privateSendClient.nPrivateSendAmount * COIN - nBalanceDenominated; + CAmount nBalanceToDenominate = privateSendClientOptions.nPrivateSendAmount * COIN - nBalanceDenominated; // adjust nBalanceNeedsAnonymized to consume final denom if (nBalanceDenominated - nBalanceAnonymized > nBalanceNeedsAnonymized) { @@ -908,7 +909,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool SetNull(); // should be no unconfirmed denoms in non-multi-session mode - if (!privateSendClient.fPrivateSendMultiSession && nBalanceDenominatedUnconf > 0) { + if (!privateSendClientOptions.fPrivateSendMultiSession && nBalanceDenominatedUnconf > 0) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- Found unconfirmed denominated outputs, will wait till they confirm to continue.\n"); strAutoDenomResult = _("Found unconfirmed denominated outputs, will wait till they confirm to continue."); return false; @@ -952,7 +953,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool fDryRun) { if (fMasternodeMode) return false; // no client-side mixing on masternodes - if (!fEnablePrivateSend || !IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !IsMixing()) return false; if (!masternodeSync.IsBlockchainSynced()) { strAutoDenomResult = _("Can't mix while sync in progress."); @@ -978,7 +979,7 @@ bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool LOCK(cs_deqsessions); bool fResult = true; - if ((int)deqSessions.size() < nPrivateSendSessions) { + if ((int)deqSessions.size() < privateSendClientOptions.nPrivateSendSessions) { deqSessions.emplace_back(); } for (auto& session : deqSessions) { @@ -1042,13 +1043,13 @@ CDeterministicMNCPtr CPrivateSendClientManager::GetRandomNotUsedMasternode() bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman) { - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; auto mnList = deterministicMNManager->GetListAtChainTip(); // Look through the queues and see if anything matches CPrivateSendQueue dsq; - while (privateSendClient.GetQueueItemAndTry(dsq)) { + while (privateSendClientManager.GetQueueItemAndTry(dsq)) { auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint); if (!dmn) { @@ -1076,7 +1077,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize continue; } - privateSendClient.AddUsedMasternode(dsq.masternodeOutpoint); + privateSendClientManager.AddUsedMasternode(dsq.masternodeOutpoint); if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- skipping masternode connection, addr=%s\n", dmn->pdmnState->addr.ToString()); @@ -1101,7 +1102,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman) { - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; if (nBalanceNeedsAnonymized <= 0) return false; int nTries = 0; @@ -1119,7 +1120,7 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, C // otherwise, try one randomly while (nTries < 10) { - auto dmn = privateSendClient.GetRandomNotUsedMasternode(); + auto dmn = privateSendClientManager.GetRandomNotUsedMasternode(); if (!dmn) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- Can't find random masternode!\n"); @@ -1127,7 +1128,7 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, C return false; } - privateSendClient.AddUsedMasternode(dmn->collateralOutpoint); + privateSendClientManager.AddUsedMasternode(dmn->collateralOutpoint); // skip next mn payments winners if (dmn->pdmnState->nLastPaidHeight + nMnCount < mnList.GetHeight() + 8) { @@ -1228,7 +1229,7 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) std::vector > vecInputsByRounds; - for (int i = 0; i < privateSendClient.nPrivateSendRounds; i++) { + for (int i = 0; i < privateSendClientOptions.nPrivateSendRounds; i++) { if (PrepareDenominate(i, i, strError, vecPSInOutPairs, vecPSInOutPairsTmp, true)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i); vecInputsByRounds.emplace_back(i, vecPSInOutPairsTmp.size()); @@ -1254,7 +1255,7 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) } // We failed? That's strange but let's just make final attempt and try to mix everything - if (PrepareDenominate(0, privateSendClient.nPrivateSendRounds - 1, strError, vecPSInOutPairs, vecPSInOutPairsTmp)) { + if (PrepareDenominate(0, privateSendClientOptions.nPrivateSendRounds - 1, strError, vecPSInOutPairs, vecPSInOutPairsTmp)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for all rounds, success\n"); return SendDenominate(vecPSInOutPairsTmp, connman); } @@ -1267,7 +1268,7 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std::vector >& vecPSInOutPairsRet) { - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; if (GetMixingWallet()->IsLocked(true)) { strErrorRet = "Wallet locked, unable to create transaction!"; @@ -1352,7 +1353,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds // Create collaterals by looping through inputs grouped by addresses bool CPrivateSendClientSession::MakeCollateralAmounts(CConnman& connman) { - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; LOCK2(cs_main, mempool.cs); LOCK(GetMixingWallet()->cs_wallet); @@ -1396,7 +1397,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta AssertLockHeld(mempool.cs); AssertLockHeld(GetMixingWallet()->cs_wallet); - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; // Skip way too tiny amounts if (tallyItem.nAmount < CPrivateSend::GetCollateralAmount()) { @@ -1483,7 +1484,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta return false; } - privateSendClient.UpdatedSuccessBlock(); + privateSendClientManager.UpdatedSuccessBlock(); return true; } @@ -1491,7 +1492,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta // Create denominations by looping through inputs grouped by addresses bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, CConnman& connman) { - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; LOCK2(cs_main, mempool.cs); LOCK(GetMixingWallet()->cs_wallet); @@ -1529,7 +1530,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, AssertLockHeld(mempool.cs); AssertLockHeld(GetMixingWallet()->cs_wallet); - if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; std::vector vecSend; CKeyHolderStorage keyHolderStorageDenom; @@ -1599,7 +1600,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, }; // add each output up to 11 times or until it can't be added again or until we reach nPrivateSendDenomsGoal - while (needMoreOutputs() && nOutputs <= 10 && currentDenomIt->second < privateSendClient.nPrivateSendDenomsGoal) { + while (needMoreOutputs() && nOutputs <= 10 && currentDenomIt->second < privateSendClientOptions.nPrivateSendDenomsGoal) { CScript scriptDenom = keyHolderStorageDenom.AddKey(GetMixingWallet()); vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false}); @@ -1622,7 +1623,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, for (const auto it : mapDenomCount) { // Check if this specific denom could use another loop, check that there aren't nPrivateSendDenomsGoal of this // denom and that our nValueLeft/nBalanceToDenominate is enough to create one of these denoms, if so, loop again. - if (it.second < privateSendClient.nPrivateSendDenomsGoal && (nValueLeft >= it.first + nOutputFee) && nBalanceToDenominate > 0) { + if (it.second < privateSendClientOptions.nPrivateSendDenomsGoal && (nValueLeft >= it.first + nOutputFee) && nBalanceToDenominate > 0) { finished = false; LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- 1 - NOT finished - nDenomValue: %f, count: %d, nValueLeft: %f, nBalanceToDenominate: %f\n", @@ -1662,7 +1663,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, auto it = mapDenomCount.find(nDenomValue); for (int i = 0; i < denomsToCreate; i++) { // Never go above the cap unless it's the largest denom - if (nDenomValue != nLargestDenomValue && it->second >= privateSendClient.nPrivateSendDenomsHardCap) break; + if (nDenomValue != nLargestDenomValue && it->second >= privateSendClientOptions.nPrivateSendDenomsHardCap) break; CScript scriptDenom = keyHolderStorageDenom.AddKey(GetMixingWallet()); vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false}); @@ -1729,7 +1730,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, } // use the same nCachedLastSuccessBlock as for DS mixing to prevent race - privateSendClient.UpdatedSuccessBlock(); + privateSendClientManager.UpdatedSuccessBlock(); LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- txid=%s\n", wtx.GetHash().GetHex()); return true; @@ -1761,7 +1762,7 @@ void CPrivateSendClientManager::UpdatedBlockTip(const CBlockIndex* pindex) void CPrivateSendClientManager::DoMaintenance(CConnman& connman) { - if (!fEnablePrivateSend) return; + if (!privateSendClientOptions.fEnablePrivateSend) return; if (fMasternodeMode) return; // no client-side mixing on masternodes if (!masternodeSync.IsBlockchainSynced() || ShutdownRequested()) return; @@ -1798,14 +1799,7 @@ void CPrivateSendClientManager::GetJsonInfo(UniValue& obj) const LOCK(cs_deqsessions); obj.clear(); obj.setObject(); - obj.pushKV("enabled", fEnablePrivateSend); obj.pushKV("running", IsMixing()); - obj.pushKV("multisession", fPrivateSendMultiSession); - obj.pushKV("max_sessions", nPrivateSendSessions); - obj.pushKV("max_rounds", nPrivateSendRounds); - obj.pushKV("max_amount", nPrivateSendAmount); - obj.pushKV("denoms_goal", nPrivateSendDenomsGoal); - obj.pushKV("denoms_hardcap", nPrivateSendDenomsHardCap); obj.pushKV("queue_size", GetQueueSize()); UniValue arrSessions(UniValue::VARR); diff --git a/src/privatesend/privatesend-client.h b/src/privatesend/privatesend-client.h index dbd30855f0da..b217bda44f65 100644 --- a/src/privatesend/privatesend-client.h +++ b/src/privatesend/privatesend-client.h @@ -12,6 +12,7 @@ #include class CPrivateSendClientManager; +class CPrivateSendClientOptions; class CConnman; class CNode; class UniValue; @@ -52,7 +53,10 @@ static const int PRIVATESEND_KEYS_THRESHOLD_WARNING = 100; static const int PRIVATESEND_KEYS_THRESHOLD_STOP = 50; // The main object for accessing mixing -extern CPrivateSendClientManager privateSendClient; +extern CPrivateSendClientManager privateSendClientManager; + +// The object to store application wide mixing options +extern CPrivateSendClientOptions privateSendClientOptions; class CPendingDsaRequest { @@ -205,14 +209,6 @@ class CPrivateSendClientManager : public CPrivateSendBaseManager bool CheckAutomaticBackup(); public: - int nPrivateSendSessions; - int nPrivateSendRounds; - int nPrivateSendAmount; - int nPrivateSendDenomsGoal; - int nPrivateSendDenomsHardCap; - bool fEnablePrivateSend; - bool fPrivateSendMultiSession; - int nCachedNumBlocks; //used for the overview screen bool fCreateAutoBackups; //builtin support for automatic backups @@ -223,12 +219,6 @@ class CPrivateSendClientManager : public CPrivateSendBaseManager nMinBlocksToWait(1), strAutoDenomResult(), nCachedBlockHeight(0), - nPrivateSendRounds(DEFAULT_PRIVATESEND_ROUNDS), - nPrivateSendAmount(DEFAULT_PRIVATESEND_AMOUNT), - nPrivateSendDenomsGoal(DEFAULT_PRIVATESEND_DENOMS_GOAL), - nPrivateSendDenomsHardCap(DEFAULT_PRIVATESEND_DENOMS_HARDCAP), - fEnablePrivateSend(false), - fPrivateSendMultiSession(DEFAULT_PRIVATESEND_MULTISESSION), nCachedNumBlocks(std::numeric_limits::max()), fCreateAutoBackups(true), mixingWallet(nullptr) @@ -237,8 +227,6 @@ class CPrivateSendClientManager : public CPrivateSendBaseManager void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61); - - bool StartMixing(CWallet* pwallet); void StopMixing(); bool IsMixing() const; @@ -270,4 +258,27 @@ class CPrivateSendClientManager : public CPrivateSendBaseManager void GetJsonInfo(UniValue& obj) const; }; +/* Application wide mixing options */ +class CPrivateSendClientOptions +{ +public: + int nPrivateSendSessions; + int nPrivateSendRounds; + int nPrivateSendAmount; + int nPrivateSendDenomsGoal; + int nPrivateSendDenomsHardCap; + bool fEnablePrivateSend; + bool fPrivateSendMultiSession; + + CPrivateSendClientOptions() : + nPrivateSendRounds(DEFAULT_PRIVATESEND_ROUNDS), + nPrivateSendAmount(DEFAULT_PRIVATESEND_AMOUNT), + nPrivateSendDenomsGoal(DEFAULT_PRIVATESEND_DENOMS_GOAL), + nPrivateSendDenomsHardCap(DEFAULT_PRIVATESEND_DENOMS_HARDCAP), + fEnablePrivateSend(false), + fPrivateSendMultiSession(DEFAULT_PRIVATESEND_MULTISESSION) + { + } +}; + #endif // BITCOIN_PRIVATESEND_PRIVATESEND_CLIENT_H diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 70a3b9b73429..333069876d57 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -780,8 +780,8 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) sendCoinsAction->setEnabled(enabled); sendCoinsMenuAction->setEnabled(enabled); #ifdef ENABLE_WALLET - privateSendCoinsAction->setEnabled(enabled && privateSendClient.fEnablePrivateSend); - privateSendCoinsMenuAction->setEnabled(enabled && privateSendClient.fEnablePrivateSend); + privateSendCoinsAction->setEnabled(enabled && privateSendClientOptions.fEnablePrivateSend); + privateSendCoinsMenuAction->setEnabled(enabled && privateSendClientOptions.fEnablePrivateSend); #else privateSendCoinsAction->setEnabled(enabled); privateSendCoinsMenuAction->setEnabled(enabled); @@ -1049,7 +1049,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer // Disabling macOS App Nap on initial sync, disk, reindex operations and mixing. bool disableAppNap = !masternodeSync.IsSynced(); #ifdef ENABLE_WALLET - disableAppNap |= privateSendClient.IsMixing(); + disableAppNap |= privateSendClientManager.IsMixing(); #endif // ENABLE_WALLET if (disableAppNap) { m_app_nap_inhibitor->disableAppNap(); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 0829ce7efb05..28f8f3169a3f 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -501,7 +501,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // unselect non-fully-mixed, this can happen when users switch from Send to PrivateSend if (coinControl()->IsUsingPrivateSend()) { int nRounds = model->getRealOutpointPrivateSendRounds(outpt); - if (nRounds < privateSendClient.nPrivateSendRounds) { + if (nRounds < privateSendClientOptions.nPrivateSendRounds) { coinControl()->UnSelect(outpt); fUnselectedNonMixed = true; continue; @@ -707,7 +707,7 @@ void CoinControlDialog::updateView() COutPoint outpoint = COutPoint(out.tx->tx->GetHash(), out.i); int nRounds = model->getRealOutpointPrivateSendRounds(outpoint); - if ((coinControl()->IsUsingPrivateSend() && nRounds >= privateSendClient.nPrivateSendRounds) || !(coinControl()->IsUsingPrivateSend())) { + if ((coinControl()->IsUsingPrivateSend() && nRounds >= privateSendClientOptions.nPrivateSendRounds) || !(coinControl()->IsUsingPrivateSend())) { nSum += out.tx->tx->vout[out.i].nValue; nChildren++; diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index d77498cfbbe5..495287cef0d5 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -288,7 +288,7 @@ void OptionsDialog::on_okButton_clicked() { mapper->submit(); #ifdef ENABLE_WALLET - privateSendClient.nCachedNumBlocks = std::numeric_limits::max(); + privateSendClientManager.nCachedNumBlocks = std::numeric_limits::max(); if(HasWallets()) GetWallets()[0]->MarkDirty(); #endif // ENABLE_WALLET diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index efb95f56e80c..83465d330c82 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -138,7 +138,7 @@ void OptionsModel::Init(bool resetSettings) settings.setValue("nPrivateSendRounds", DEFAULT_PRIVATESEND_ROUNDS); if (!gArgs.SoftSetArg("-privatesendrounds", settings.value("nPrivateSendRounds").toString().toStdString())) addOverriddenOption("-privatesendrounds"); - privateSendClient.nPrivateSendRounds = settings.value("nPrivateSendRounds").toInt(); + privateSendClientOptions.nPrivateSendRounds = settings.value("nPrivateSendRounds").toInt(); if (!settings.contains("nPrivateSendAmount")) { // for migration from old settings @@ -149,13 +149,13 @@ void OptionsModel::Init(bool resetSettings) } if (!gArgs.SoftSetArg("-privatesendamount", settings.value("nPrivateSendAmount").toString().toStdString())) addOverriddenOption("-privatesendamount"); - privateSendClient.nPrivateSendAmount = settings.value("nPrivateSendAmount").toInt(); + privateSendClientOptions.nPrivateSendAmount = settings.value("nPrivateSendAmount").toInt(); if (!settings.contains("fPrivateSendMultiSession")) settings.setValue("fPrivateSendMultiSession", DEFAULT_PRIVATESEND_MULTISESSION); if (!gArgs.SoftSetBoolArg("-privatesendmultisession", settings.value("fPrivateSendMultiSession").toBool())) addOverriddenOption("-privatesendmultisession"); - privateSendClient.fPrivateSendMultiSession = settings.value("fPrivateSendMultiSession").toBool(); + privateSendClientOptions.fPrivateSendMultiSession = settings.value("fPrivateSendMultiSession").toBool(); #endif // Network @@ -470,24 +470,24 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in case PrivateSendRounds: if (settings.value("nPrivateSendRounds") != value) { - privateSendClient.nPrivateSendRounds = value.toInt(); - settings.setValue("nPrivateSendRounds", privateSendClient.nPrivateSendRounds); + privateSendClientOptions.nPrivateSendRounds = value.toInt(); + settings.setValue("nPrivateSendRounds", privateSendClientOptions.nPrivateSendRounds); Q_EMIT privateSendRoundsChanged(); } break; case PrivateSendAmount: if (settings.value("nPrivateSendAmount") != value) { - privateSendClient.nPrivateSendAmount = value.toInt(); - settings.setValue("nPrivateSendAmount", privateSendClient.nPrivateSendAmount); + privateSendClientOptions.nPrivateSendAmount = value.toInt(); + settings.setValue("nPrivateSendAmount", privateSendClientOptions.nPrivateSendAmount); Q_EMIT privateSentAmountChanged(); } break; case PrivateSendMultiSession: if (settings.value("fPrivateSendMultiSession") != value) { - privateSendClient.fPrivateSendMultiSession = value.toBool(); - settings.setValue("fPrivateSendMultiSession", privateSendClient.fPrivateSendMultiSession); + privateSendClientOptions.fPrivateSendMultiSession = value.toBool(); + settings.setValue("fPrivateSendMultiSession", privateSendClientOptions.fPrivateSendMultiSession); } break; #endif diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index e93d894f2971..deb08989259a 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -172,7 +172,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) // start with displaying the "out of sync" warnings showOutOfSyncWarning(true); - if(!privateSendClient.fEnablePrivateSend) return; + if(!privateSendClientOptions.fEnablePrivateSend) return; // Disable any PS UI for masternode or when autobackup is disabled or failed for whatever reason if(fMasternodeMode || nWalletBackups <= 0){ @@ -181,14 +181,14 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) ui->labelPrivateSendEnabled->setToolTip(tr("Automatic backups are disabled, no mixing available!")); } } else { - if(!privateSendClient.IsMixing()){ + if(!privateSendClientManager.IsMixing()){ ui->togglePrivateSend->setText(tr("Start Mixing")); } else { ui->togglePrivateSend->setText(tr("Stop Mixing")); } // Disable privateSendClient builtin support for automatic backups while we are in GUI, // we'll handle automatic backups and user warnings in privateSendStatus() - privateSendClient.fCreateAutoBackups = false; + privateSendClientManager.fCreateAutoBackups = false; timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(privateSendStatus())); @@ -308,7 +308,7 @@ void OverviewPage::setWalletModel(WalletModel *model) // Initialize PS UI privateSendStatus(true); - if(!privateSendClient.fEnablePrivateSend) return; + if(!privateSendClientOptions.fEnablePrivateSend) return; connect(model->getOptionsModel(), SIGNAL(privateSendRoundsChanged()), this, SLOT(updatePrivateSendProgress())); connect(model->getOptionsModel(), SIGNAL(privateSentAmountChanged()), this, SLOT(updatePrivateSendProgress())); @@ -357,7 +357,7 @@ void OverviewPage::updatePrivateSendProgress() if(!walletModel) return; QString strAmountAndRounds; - QString strPrivateSendAmount = BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, privateSendClient.nPrivateSendAmount * COIN, false, BitcoinUnits::separatorAlways); + QString strPrivateSendAmount = BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, privateSendClientOptions.nPrivateSendAmount * COIN, false, BitcoinUnits::separatorAlways); if(currentBalance == 0) { @@ -366,7 +366,7 @@ void OverviewPage::updatePrivateSendProgress() // when balance is zero just show info from settings strPrivateSendAmount = strPrivateSendAmount.remove(strPrivateSendAmount.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1); - strAmountAndRounds = strPrivateSendAmount + " / " + tr("%n Rounds", "", privateSendClient.nPrivateSendRounds); + strAmountAndRounds = strPrivateSendAmount + " / " + tr("%n Rounds", "", privateSendClientOptions.nPrivateSendRounds); ui->labelAmountRounds->setToolTip(tr("No inputs detected")); ui->labelAmountRounds->setText(strAmountAndRounds); @@ -378,15 +378,15 @@ void OverviewPage::updatePrivateSendProgress() CAmount nMaxToAnonymize = nAnonymizableBalance + currentAnonymizedBalance; // If it's more than the anon threshold, limit to that. - if(nMaxToAnonymize > privateSendClient.nPrivateSendAmount*COIN) nMaxToAnonymize = privateSendClient.nPrivateSendAmount*COIN; + if(nMaxToAnonymize > privateSendClientOptions.nPrivateSendAmount*COIN) nMaxToAnonymize = privateSendClientOptions.nPrivateSendAmount*COIN; if(nMaxToAnonymize == 0) return; - if(nMaxToAnonymize >= privateSendClient.nPrivateSendAmount * COIN) { + if(nMaxToAnonymize >= privateSendClientOptions.nPrivateSendAmount * COIN) { ui->labelAmountRounds->setToolTip(tr("Found enough compatible inputs to mix %1") .arg(strPrivateSendAmount)); strPrivateSendAmount = strPrivateSendAmount.remove(strPrivateSendAmount.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1); - strAmountAndRounds = strPrivateSendAmount + " / " + tr("%n Rounds", "", privateSendClient.nPrivateSendRounds); + strAmountAndRounds = strPrivateSendAmount + " / " + tr("%n Rounds", "", privateSendClientOptions.nPrivateSendRounds); } else { QString strMaxToAnonymize = BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, nMaxToAnonymize, false, BitcoinUnits::separatorAlways); ui->labelAmountRounds->setToolTip(tr("Not enough compatible inputs to mix %2,
" @@ -397,7 +397,7 @@ void OverviewPage::updatePrivateSendProgress() strMaxToAnonymize = strMaxToAnonymize.remove(strMaxToAnonymize.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1); strAmountAndRounds = "" + QString(BitcoinUnits::factor(nDisplayUnit) == 1 ? "" : "~") + strMaxToAnonymize + - " / " + tr("%n Rounds", "", privateSendClient.nPrivateSendRounds) + ""; + " / " + tr("%n Rounds", "", privateSendClientOptions.nPrivateSendRounds) + ""; } ui->labelAmountRounds->setText(strAmountAndRounds); @@ -436,7 +436,7 @@ void OverviewPage::updatePrivateSendProgress() // apply some weights to them ... float denomWeight = 1; - float anonNormWeight = privateSendClient.nPrivateSendRounds; + float anonNormWeight = privateSendClientOptions.nPrivateSendRounds; float anonFullWeight = 2; float fullWeight = denomWeight + anonNormWeight + anonFullWeight; // ... and calculate the whole progress @@ -452,7 +452,7 @@ void OverviewPage::updatePrivateSendProgress() tr("Denominated") + ": %2%
" + tr("Partially mixed") + ": %3%
" + tr("Mixed") + ": %4%
" + - tr("Denominated inputs have %5 of %n rounds on average", "", privateSendClient.nPrivateSendRounds)) + tr("Denominated inputs have %5 of %n rounds on average", "", privateSendClientOptions.nPrivateSendRounds)) .arg(progress).arg(denomPart).arg(anonNormPart).arg(anonFullPart) .arg(nAverageAnonymizedRounds); ui->privateSendProgress->setToolTip(strToolPip); @@ -460,10 +460,10 @@ void OverviewPage::updatePrivateSendProgress() void OverviewPage::updateAdvancedPSUI(bool fShowAdvancedPSUI) { this->fShowAdvancedPSUI = fShowAdvancedPSUI; - int nNumItems = (!privateSendClient.fEnablePrivateSend || !fShowAdvancedPSUI) ? NUM_ITEMS : NUM_ITEMS_ADV; + int nNumItems = (!privateSendClientOptions.fEnablePrivateSend || !fShowAdvancedPSUI) ? NUM_ITEMS : NUM_ITEMS_ADV; SetupTransactionList(nNumItems); - if (!privateSendClient.fEnablePrivateSend) return; + if (!privateSendClientOptions.fEnablePrivateSend) return; ui->framePrivateSend->setVisible(true); ui->labelCompletitionText->setVisible(fShowAdvancedPSUI); @@ -491,7 +491,7 @@ void OverviewPage::privateSendStatus(bool fForce) int nBestHeight = clientModel->getNumBlocks(); // We are processing more than 1 block per second, we'll just leave - if(nBestHeight > privateSendClient.nCachedNumBlocks && GetTime() - nLastDSProgressBlockTime <= 1) return; + if(nBestHeight > privateSendClientManager.nCachedNumBlocks && GetTime() - nLastDSProgressBlockTime <= 1) return; nLastDSProgressBlockTime = GetTime(); QString strKeysLeftText(tr("keys left: %1").arg(walletModel->getKeysLeftSinceAutoBackup())); @@ -500,9 +500,9 @@ void OverviewPage::privateSendStatus(bool fForce) } ui->labelPrivateSendEnabled->setToolTip(strKeysLeftText); - if (!privateSendClient.IsMixing()) { - if (nBestHeight != privateSendClient.nCachedNumBlocks) { - privateSendClient.nCachedNumBlocks = nBestHeight; + if (!privateSendClientManager.IsMixing()) { + if (nBestHeight != privateSendClientManager.nCachedNumBlocks) { + privateSendClientManager.nCachedNumBlocks = nBestHeight; updatePrivateSendProgress(); } @@ -557,7 +557,7 @@ void OverviewPage::privateSendStatus(bool fForce) } } - QString strEnabled = privateSendClient.IsMixing() ? tr("Enabled") : tr("Disabled"); + QString strEnabled = privateSendClientManager.IsMixing() ? tr("Enabled") : tr("Disabled"); // Show how many keys left in advanced PS UI mode only if(fShowAdvancedPSUI) strEnabled += ", " + strKeysLeftText; ui->labelPrivateSendEnabled->setText(strEnabled); @@ -579,15 +579,15 @@ void OverviewPage::privateSendStatus(bool fForce) } // check privatesend status and unlock if needed - if(nBestHeight != privateSendClient.nCachedNumBlocks) { + if(nBestHeight != privateSendClientManager.nCachedNumBlocks) { // Balance and number of transactions might have changed - privateSendClient.nCachedNumBlocks = nBestHeight; + privateSendClientManager.nCachedNumBlocks = nBestHeight; updatePrivateSendProgress(); } setWidgetsVisible(true); - ui->labelSubmittedDenom->setText(QString(privateSendClient.GetSessionDenoms().c_str())); + ui->labelSubmittedDenom->setText(QString(privateSendClientManager.GetSessionDenoms().c_str())); } void OverviewPage::togglePrivateSend(){ @@ -600,7 +600,7 @@ void OverviewPage::togglePrivateSend(){ QMessageBox::Ok, QMessageBox::Ok); settings.setValue("hasMixed", "hasMixed"); } - if(!privateSendClient.IsMixing()){ + if(!privateSendClientManager.IsMixing()){ const CAmount nMinAmount = CPrivateSend::GetSmallestDenomination() + CPrivateSend::GetMaxCollateralAmount(); if(currentBalance < nMinAmount){ QString strMinAmount(BitcoinUnits::formatWithUnit(nDisplayUnit, nMinAmount)); @@ -617,7 +617,7 @@ void OverviewPage::togglePrivateSend(){ if(!ctx.isValid()) { //unlock was cancelled - privateSendClient.nCachedNumBlocks = std::numeric_limits::max(); + privateSendClientManager.nCachedNumBlocks = std::numeric_limits::max(); QMessageBox::warning(this, tr("PrivateSend"), tr("Wallet is locked and user declined to unlock. Disabling PrivateSend."), QMessageBox::Ok, QMessageBox::Ok); @@ -628,15 +628,15 @@ void OverviewPage::togglePrivateSend(){ } - privateSendClient.nCachedNumBlocks = std::numeric_limits::max(); + privateSendClientManager.nCachedNumBlocks = std::numeric_limits::max(); - if (privateSendClient.IsMixing()) { + if (privateSendClientManager.IsMixing()) { ui->togglePrivateSend->setText(tr("Start Mixing")); - privateSendClient.ResetPool(); - privateSendClient.StopMixing(); + privateSendClientManager.ResetPool(); + privateSendClientManager.StopMixing(); } else { ui->togglePrivateSend->setText(tr("Stop Mixing")); - privateSendClient.StartMixing(walletModel->getWallet()); + privateSendClientManager.StartMixing(walletModel->getWallet()); } } @@ -664,5 +664,5 @@ void OverviewPage::DisablePrivateSendCompletely() { if (nWalletBackups <= 0) { ui->labelPrivateSendEnabled->setText("(" + tr("Disabled") + ")"); } - privateSendClient.StopMixing(); + privateSendClientManager.StopMixing(); } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 4c69ec9019b3..6f1e9566b9e9 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -155,13 +155,13 @@ void WalletModel::pollBalanceChanged() if(!lockWallet) return; - if(fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks || privateSendClient.nPrivateSendRounds != cachedPrivateSendRounds) + if(fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks || privateSendClientOptions.nPrivateSendRounds != cachedPrivateSendRounds) { fForceCheckBalanceChanged = false; // Balance and number of transactions might have changed cachedNumBlocks = chainActive.Height(); - cachedPrivateSendRounds = privateSendClient.nPrivateSendRounds; + cachedPrivateSendRounds = privateSendClientOptions.nPrivateSendRounds; checkBalanceChanged(); if(transactionTableModel) diff --git a/src/rpc/privatesend.cpp b/src/rpc/privatesend.cpp index 8ff307a06d9c..21a12a4eea46 100644 --- a/src/rpc/privatesend.cpp +++ b/src/rpc/privatesend.cpp @@ -32,7 +32,7 @@ UniValue privatesend(const JSONRPCRequest& request) if (fMasternodeMode) throw JSONRPCError(RPC_INTERNAL_ERROR, "Client-side mixing is not supported on masternodes"); - if (!privateSendClient.fEnablePrivateSend) { + if (!privateSendClientOptions.fEnablePrivateSend) { if (!gArgs.GetBoolArg("-enableprivatesend", true)) { // otherwise it's on by default, unless cmd line option says otherwise throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing is disabled via -enableprivatesend=0 command line option, remove it to enable mixing again"); @@ -50,21 +50,21 @@ UniValue privatesend(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please unlock wallet for mixing with walletpassphrase first."); } - if (!privateSendClient.StartMixing(pwallet)) { + if (!privateSendClientManager.StartMixing(pwallet)) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing has been started already."); } - bool result = privateSendClient.DoAutomaticDenominating(*g_connman); - return "Mixing " + (result ? "started successfully" : ("start failed: " + privateSendClient.GetStatuses() + ", will retry")); + bool result = privateSendClientManager.DoAutomaticDenominating(*g_connman); + return "Mixing " + (result ? "started successfully" : ("start failed: " + privateSendClientManager.GetStatuses() + ", will retry")); } if (request.params[0].get_str() == "stop") { - privateSendClient.StopMixing(); + privateSendClientManager.StopMixing(); return "Mixing was stopped"; } if (request.params[0].get_str() == "reset") { - privateSendClient.ResetPool(); + privateSendClientManager.ResetPool(); return "Mixing was reset"; } @@ -89,13 +89,13 @@ UniValue getprivatesendinfo(const JSONRPCRequest& request) "\nResult (for regular nodes):\n" "{\n" " \"enabled\": true|false, (bool) Whether mixing functionality is enabled\n" - " \"running\": true|false, (bool) Whether mixing is currently running\n" " \"multisession\": true|false, (bool) Whether PrivateSend Multisession option is enabled\n" " \"max_sessions\": xxx, (numeric) How many parallel mixing sessions can there be at once\n" " \"max_rounds\": xxx, (numeric) How many rounds to mix\n" " \"max_amount\": xxx, (numeric) Target PrivateSend balance in " + CURRENCY_UNIT + "\n" " \"max_denoms\": xxx, (numeric) How many inputs of each denominated amount to create\n" " \"queue_size\": xxx, (numeric) How many queues there are currently on the network\n" + " \"running\": true|false, (bool) Whether mixing is currently running\n" " \"sessions\": (array of json objects)\n" " [\n" " {\n" @@ -133,13 +133,22 @@ UniValue getprivatesendinfo(const JSONRPCRequest& request) #ifdef ENABLE_WALLET - privateSendClient.GetJsonInfo(obj); + + obj.pushKV("enabled", privateSendClientOptions.fEnablePrivateSend); + obj.pushKV("multisession", privateSendClientOptions.fPrivateSendMultiSession); + obj.pushKV("max_sessions", privateSendClientOptions.nPrivateSendSessions); + obj.pushKV("max_rounds", privateSendClientOptions.nPrivateSendRounds); + obj.pushKV("max_amount", privateSendClientOptions.nPrivateSendAmount); + obj.pushKV("denoms_goal", privateSendClientOptions.nPrivateSendDenomsGoal); + obj.pushKV("denoms_hardcap", privateSendClientOptions.nPrivateSendDenomsHardCap); CWallet* const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) { return obj; } + privateSendClientManager.GetJsonInfo(obj); + obj.pushKV("keys_left", pwallet->nKeysLeftSinceAutoBackup); obj.push_back(Pair("warnings", pwallet->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING ? "WARNING: keypool is almost depleted!" : "")); diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 397b62fef2f3..cf2756cbebd5 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -364,18 +364,18 @@ void WalletInit::Start(CScheduler& scheduler) // Run a thread to flush wallet periodically scheduler.scheduleEvery(MaybeCompactWalletDB, 500); - if (!fMasternodeMode && privateSendClient.fEnablePrivateSend) { - scheduler.scheduleEvery(std::bind(&CPrivateSendClientManager::DoMaintenance, std::ref(privateSendClient), + if (!fMasternodeMode && privateSendClientOptions.fEnablePrivateSend) { + scheduler.scheduleEvery(std::bind(&CPrivateSendClientManager::DoMaintenance, std::ref(privateSendClientManager), std::ref(*g_connman)), 1 * 1000); } } void WalletInit::Flush() { - if (privateSendClient.fEnablePrivateSend) { + if (privateSendClientOptions.fEnablePrivateSend) { // Stop PrivateSend, release keys - privateSendClient.ResetPool(); - privateSendClient.StopMixing(); + privateSendClientManager.ResetPool(); + privateSendClientManager.StopMixing(); } for (CWallet* pwallet : GetWallets()) { pwallet->Flush(false); @@ -408,30 +408,30 @@ void WalletInit::AutoLockMasternodeCollaterals() void WalletInit::InitPrivateSendSettings() { if (!HasWallets()) { - privateSendClient.fEnablePrivateSend = false; - privateSendClient.StopMixing(); + privateSendClientOptions.fEnablePrivateSend = false; + privateSendClientManager.StopMixing(); } else { - privateSendClient.fEnablePrivateSend = gArgs.GetBoolArg("-enableprivatesend", true); + privateSendClientOptions.fEnablePrivateSend = gArgs.GetBoolArg("-enableprivatesend", true); if (GetWallets()[0]->IsLocked()) { - privateSendClient.StopMixing(); + privateSendClientManager.StopMixing(); } else if (gArgs.GetBoolArg("-privatesendautostart", DEFAULT_PRIVATESEND_AUTOSTART)) { - privateSendClient.StartMixing(GetWallets()[0]); + privateSendClientManager.StartMixing(GetWallets()[0]); } } - privateSendClient.fPrivateSendMultiSession = gArgs.GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION); - privateSendClient.nPrivateSendSessions = std::min(std::max((int)gArgs.GetArg("-privatesendsessions", DEFAULT_PRIVATESEND_SESSIONS), MIN_PRIVATESEND_SESSIONS), MAX_PRIVATESEND_SESSIONS); - privateSendClient.nPrivateSendRounds = std::min(std::max((int)gArgs.GetArg("-privatesendrounds", DEFAULT_PRIVATESEND_ROUNDS), MIN_PRIVATESEND_ROUNDS), MAX_PRIVATESEND_ROUNDS); - privateSendClient.nPrivateSendAmount = std::min(std::max((int)gArgs.GetArg("-privatesendamount", DEFAULT_PRIVATESEND_AMOUNT), MIN_PRIVATESEND_AMOUNT), MAX_PRIVATESEND_AMOUNT); - privateSendClient.nPrivateSendDenomsGoal = std::min(std::max((int)gArgs.GetArg("-privatesenddenomsgoal", DEFAULT_PRIVATESEND_DENOMS_GOAL), MIN_PRIVATESEND_DENOMS_GOAL), MAX_PRIVATESEND_DENOMS_GOAL); - privateSendClient.nPrivateSendDenomsHardCap = std::min(std::max((int)gArgs.GetArg("-privatesenddenomshardcap", DEFAULT_PRIVATESEND_DENOMS_HARDCAP), MIN_PRIVATESEND_DENOMS_HARDCAP), MAX_PRIVATESEND_DENOMS_HARDCAP); + privateSendClientOptions.fPrivateSendMultiSession = gArgs.GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION); + privateSendClientOptions.nPrivateSendSessions = std::min(std::max((int)gArgs.GetArg("-privatesendsessions", DEFAULT_PRIVATESEND_SESSIONS), MIN_PRIVATESEND_SESSIONS), MAX_PRIVATESEND_SESSIONS); + privateSendClientOptions.nPrivateSendRounds = std::min(std::max((int)gArgs.GetArg("-privatesendrounds", DEFAULT_PRIVATESEND_ROUNDS), MIN_PRIVATESEND_ROUNDS), MAX_PRIVATESEND_ROUNDS); + privateSendClientOptions.nPrivateSendAmount = std::min(std::max((int)gArgs.GetArg("-privatesendamount", DEFAULT_PRIVATESEND_AMOUNT), MIN_PRIVATESEND_AMOUNT), MAX_PRIVATESEND_AMOUNT); + privateSendClientOptions.nPrivateSendDenomsGoal = std::min(std::max((int)gArgs.GetArg("-privatesenddenomsgoal", DEFAULT_PRIVATESEND_DENOMS_GOAL), MIN_PRIVATESEND_DENOMS_GOAL), MAX_PRIVATESEND_DENOMS_GOAL); + privateSendClientOptions.nPrivateSendDenomsHardCap = std::min(std::max((int)gArgs.GetArg("-privatesenddenomshardcap", DEFAULT_PRIVATESEND_DENOMS_HARDCAP), MIN_PRIVATESEND_DENOMS_HARDCAP), MAX_PRIVATESEND_DENOMS_HARDCAP); - if (privateSendClient.fEnablePrivateSend) { + if (privateSendClientOptions.fEnablePrivateSend) { LogPrintf("PrivateSend: autostart=%d, multisession=%d," /* Continued */ "sessions=%d, rounds=%d, amount=%d, denoms_goal=%d, denoms_hardcap=%d\n", - privateSendClient.IsMixing(), privateSendClient.fPrivateSendMultiSession, - privateSendClient.nPrivateSendSessions, privateSendClient.nPrivateSendRounds, - privateSendClient.nPrivateSendAmount, - privateSendClient.nPrivateSendDenomsGoal, privateSendClient.nPrivateSendDenomsHardCap); + privateSendClientManager.IsMixing(), privateSendClientOptions.fPrivateSendMultiSession, + privateSendClientOptions.nPrivateSendSessions, privateSendClientOptions.nPrivateSendRounds, + privateSendClientOptions.nPrivateSendAmount, + privateSendClientOptions.nPrivateSendDenomsGoal, privateSendClientOptions.nPrivateSendDenomsHardCap); } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e85f68360224..5cb1340441a9 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2682,7 +2682,7 @@ UniValue setprivatesendrounds(const JSONRPCRequest& request) if (nRounds > MAX_PRIVATESEND_ROUNDS || nRounds < MIN_PRIVATESEND_ROUNDS) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid number of rounds"); - privateSendClient.nPrivateSendRounds = nRounds; + privateSendClientOptions.nPrivateSendRounds = nRounds; return NullUniValue; } @@ -2710,7 +2710,7 @@ UniValue setprivatesendamount(const JSONRPCRequest& request) if (nAmount > MAX_PRIVATESEND_AMOUNT || nAmount < MIN_PRIVATESEND_AMOUNT) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount of " + CURRENCY_UNIT + " as mixing goal amount"); - privateSendClient.nPrivateSendAmount = nAmount; + privateSendClientOptions.nPrivateSendAmount = nAmount; return NullUniValue; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index ebb51e4a0bbc..698c2e5dd528 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1657,7 +1657,7 @@ int CWallet::GetCappedOutpointPrivateSendRounds(const COutPoint& outpoint) const { LOCK(cs_wallet); int realPrivateSendRounds = GetRealOutpointPrivateSendRounds(outpoint); - return realPrivateSendRounds > privateSendClient.nPrivateSendRounds ? privateSendClient.nPrivateSendRounds : realPrivateSendRounds; + return realPrivateSendRounds > privateSendClientOptions.nPrivateSendRounds ? privateSendClientOptions.nPrivateSendRounds : realPrivateSendRounds; } bool CWallet::IsDenominated(const COutPoint& outpoint) const @@ -2359,7 +2359,7 @@ CAmount CWalletTx::GetAnonymizedCredit(bool fUseCache) const if (pwallet->IsSpent(hashTx, i) || !CPrivateSend::IsDenominatedAmount(txout.nValue)) continue; const int nRounds = pwallet->GetCappedOutpointPrivateSendRounds(outpoint); - if (nRounds >= privateSendClient.nPrivateSendRounds){ + if (nRounds >= privateSendClientOptions.nPrivateSendRounds){ nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); if (!MoneyRange(nCredit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); @@ -2568,7 +2568,7 @@ CAmount CWallet::GetBalance() const CAmount CWallet::GetAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfirmed) const { - if(!privateSendClient.fEnablePrivateSend) return 0; + if(!privateSendClientOptions.fEnablePrivateSend) return 0; std::vector vecTally; if(!SelectCoinsGroupedByAddresses(vecTally, fSkipDenominated, true, fSkipUnconfirmed)) return 0; @@ -2590,7 +2590,7 @@ CAmount CWallet::GetAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfi CAmount CWallet::GetAnonymizedBalance() const { - if(!privateSendClient.fEnablePrivateSend) return 0; + if(!privateSendClientOptions.fEnablePrivateSend) return 0; CAmount nTotal = 0; @@ -2607,7 +2607,7 @@ CAmount CWallet::GetAnonymizedBalance() const // that's ok as long as we use it for informational purposes only float CWallet::GetAverageAnonymizedRounds() const { - if(!privateSendClient.fEnablePrivateSend) return 0; + if(!privateSendClientOptions.fEnablePrivateSend) return 0; int nTotal = 0; int nCount = 0; @@ -2629,7 +2629,7 @@ float CWallet::GetAverageAnonymizedRounds() const // that's ok as long as we use it for informational purposes only CAmount CWallet::GetNormalizedAnonymizedBalance() const { - if(!privateSendClient.fEnablePrivateSend) return 0; + if(!privateSendClientOptions.fEnablePrivateSend) return 0; CAmount nTotal = 0; @@ -2643,7 +2643,7 @@ CAmount CWallet::GetNormalizedAnonymizedBalance() const if (it->second.GetDepthInMainChain() < 0) continue; int nRounds = GetCappedOutpointPrivateSendRounds(outpoint); - nTotal += nValue * nRounds / privateSendClient.nPrivateSendRounds; + nTotal += nValue * nRounds / privateSendClientOptions.nPrivateSendRounds; } return nTotal; @@ -2651,7 +2651,7 @@ CAmount CWallet::GetNormalizedAnonymizedBalance() const CAmount CWallet::GetDenominatedBalance(bool unconfirmed) const { - if(!privateSendClient.fEnablePrivateSend) return 0; + if(!privateSendClientOptions.fEnablePrivateSend) return 0; CAmount nTotal = 0; @@ -2826,11 +2826,11 @@ void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const if (nCoinType == CoinType::ONLY_FULLY_MIXED) { if (!CPrivateSend::IsDenominatedAmount(pcoin->tx->vout[i].nValue)) continue; int nRounds = GetCappedOutpointPrivateSendRounds(COutPoint(wtxid, i)); - found = nRounds >= privateSendClient.nPrivateSendRounds; + found = nRounds >= privateSendClientOptions.nPrivateSendRounds; } else if(nCoinType == CoinType::ONLY_READY_TO_MIX) { if (!CPrivateSend::IsDenominatedAmount(pcoin->tx->vout[i].nValue)) continue; int nRounds = GetCappedOutpointPrivateSendRounds(COutPoint(wtxid, i)); - found = nRounds < privateSendClient.nPrivateSendRounds; + found = nRounds < privateSendClientOptions.nPrivateSendRounds; } else if(nCoinType == CoinType::ONLY_NONDENOMINATED) { if (CPrivateSend::IsCollateralAmount(pcoin->tx->vout[i].nValue)) continue; // do not use collateral amounts found = !CPrivateSend::IsDenominatedAmount(pcoin->tx->vout[i].nValue); @@ -3212,7 +3212,7 @@ bool CWallet::SelectCoins(const std::vector& vAvailableCoins, const CAm // Make sure to include mixed preset inputs only, // even if some non-mixed inputs were manually selected via CoinControl int nRounds = GetRealOutpointPrivateSendRounds(outpoint); - if (nRounds < privateSendClient.nPrivateSendRounds) continue; + if (nRounds < privateSendClientOptions.nPrivateSendRounds) continue; } nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue; setPresetCoins.insert(CInputCoin(pcoin, outpoint.n)); @@ -3415,7 +3415,7 @@ bool CWallet::SelectCoinsGroupedByAddresses(std::vector& vecTa // otherwise they will just lead to higher fee / lower priority if(wtx.tx->vout[i].nValue <= nSmallestDenom/10) continue; // ignore mixed - if(GetCappedOutpointPrivateSendRounds(COutPoint(outpoint.hash, i)) >= privateSendClient.nPrivateSendRounds) continue; + if(GetCappedOutpointPrivateSendRounds(COutPoint(outpoint.hash, i)) >= privateSendClientOptions.nPrivateSendRounds) continue; } if (itTallyItem == mapTally.end()) { @@ -4342,7 +4342,7 @@ bool CWallet::NewKeyPool() batch.ErasePool(nIndex); } setExternalKeyPool.clear(); - privateSendClient.StopMixing(); + privateSendClientManager.StopMixing(); nKeysLeftSinceAutoBackup = 0; m_pool_key_to_index.clear(); From 59bc2ca2b7ec15a5818bc436c8c2a93bdd8e7667 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 16 Jul 2020 15:23:37 +0300 Subject: [PATCH 06/13] Split dsq processing out of mixing manager Signed-off-by: pasta --- src/net_processing.cpp | 1 + src/privatesend/privatesend-client.cpp | 91 +++++++++++++++++++------- src/privatesend/privatesend-client.h | 25 ++++++- src/rpc/privatesend.cpp | 1 + src/wallet/init.cpp | 3 +- 5 files changed, 93 insertions(+), 28 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index f17a2a13552d..f2c110126301 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3542,6 +3542,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr { //probably one the extensions #ifdef ENABLE_WALLET + privateSendClientQueueManager.ProcessMessage(pfrom, strCommand, vRecv, *connman, enable_bip61); privateSendClientManager.ProcessMessage(pfrom, strCommand, vRecv, *connman, enable_bip61); #endif // ENABLE_WALLET privateSendServer.ProcessMessage(pfrom, strCommand, vRecv, *connman, enable_bip61); diff --git a/src/privatesend/privatesend-client.cpp b/src/privatesend/privatesend-client.cpp index 0a90ca5d6868..e1fac1bdabed 100644 --- a/src/privatesend/privatesend-client.cpp +++ b/src/privatesend/privatesend-client.cpp @@ -23,18 +23,17 @@ #include CPrivateSendClientManager privateSendClientManager; +CPrivateSendClientQueueManager privateSendClientQueueManager; CPrivateSendClientOptions privateSendClientOptions; -void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61) +void CPrivateSendClientQueueManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61) { if (fMasternodeMode) return; if (!privateSendClientOptions.fEnablePrivateSend) return; if (!masternodeSync.IsBlockchainSynced()) return; if (!CheckDiskSpace()) { - ResetPool(); - StopMixing(); - LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::ProcessMessage -- Not enough disk space, disabling PrivateSend.\n"); + LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientQueueManager::ProcessMessage -- Not enough disk space, disabling PrivateSend.\n"); return; } @@ -85,14 +84,9 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& // if the queue is ready, submit if we can if (dsq.fReady) { - LOCK(cs_deqsessions); - for (auto& session : deqSessions) { - CDeterministicMNCPtr mnMixing; - if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->pdmnState->addr == dmn->pdmnState->addr && session.GetState() == POOL_STATE_QUEUE) { - LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- PrivateSend queue (%s) is ready on masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); - session.SubmitDenominate(connman); - return; - } + if (privateSendClientManager.TrySubmitDenominate(dmn->pdmnState->addr, connman)) { + LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- PrivateSend queue (%s) is ready on masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); + return; } } else { int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq(); @@ -108,13 +102,7 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); - LOCK(cs_deqsessions); - for (auto& session : deqSessions) { - CDeterministicMNCPtr mnMixing; - if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->collateralOutpoint == dsq.masternodeOutpoint) { - dsq.fTried = true; - } - } + privateSendClientManager.MarkAlreadyJoinedQueueAsTried(dsq); TRY_LOCK(cs_vecqueue, lockRecv); if (!lockRecv) return; @@ -122,7 +110,23 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& dsq.Relay(connman); } - } else if (strCommand == NetMsgType::DSSTATUSUPDATE || + } +} + +void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61) +{ + if (fMasternodeMode) return; + if (!privateSendClientOptions.fEnablePrivateSend) return; + if (!masternodeSync.IsBlockchainSynced()) return; + + if (!CheckDiskSpace()) { + ResetPool(); + StopMixing(); + LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::ProcessMessage -- Not enough disk space, disabling PrivateSend.\n"); + return; + } + + if (strCommand == NetMsgType::DSSTATUSUPDATE || strCommand == NetMsgType::DSFINALTX || strCommand == NetMsgType::DSCOMPLETE) { LOCK(cs_deqsessions); @@ -428,8 +432,6 @@ void CPrivateSendClientManager::CheckTimeout() { if (fMasternodeMode) return; - CheckQueue(); - if (!privateSendClientOptions.fEnablePrivateSend || !IsMixing()) return; LOCK(cs_deqsessions); @@ -1049,7 +1051,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize // Look through the queues and see if anything matches CPrivateSendQueue dsq; - while (privateSendClientManager.GetQueueItemAndTry(dsq)) { + while (privateSendClientQueueManager.GetQueueItemAndTry(dsq)) { auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint); if (!dmn) { @@ -1214,6 +1216,32 @@ void CPrivateSendClientManager::ProcessPendingDsaRequest(CConnman& connman) } } +bool CPrivateSendClientManager::TrySubmitDenominate(const CService& mnAddr, CConnman& connman) +{ + LOCK(cs_deqsessions); + for (auto& session : deqSessions) { + CDeterministicMNCPtr mnMixing; + if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->pdmnState->addr == mnAddr && session.GetState() == POOL_STATE_QUEUE) { + session.SubmitDenominate(connman); + return true; + } + } + return false; +} + +bool CPrivateSendClientManager::MarkAlreadyJoinedQueueAsTried(CPrivateSendQueue& dsq) const +{ + LOCK(cs_deqsessions); + for (const auto& session : deqSessions) { + CDeterministicMNCPtr mnMixing; + if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->collateralOutpoint == dsq.masternodeOutpoint) { + dsq.fTried = true; + return true; + } + } + return false; +} + bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) { LOCK2(cs_main, mempool.cs); @@ -1760,6 +1788,16 @@ void CPrivateSendClientManager::UpdatedBlockTip(const CBlockIndex* pindex) LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight); } +void CPrivateSendClientQueueManager::DoMaintenance() +{ + if (!privateSendClientOptions.fEnablePrivateSend) return; + if (fMasternodeMode) return; // no client-side mixing on masternodes + + if (!masternodeSync.IsBlockchainSynced() || ShutdownRequested()) return; + + CheckQueue(); +} + void CPrivateSendClientManager::DoMaintenance(CConnman& connman) { if (!privateSendClientOptions.fEnablePrivateSend) return; @@ -1800,7 +1838,6 @@ void CPrivateSendClientManager::GetJsonInfo(UniValue& obj) const obj.clear(); obj.setObject(); obj.pushKV("running", IsMixing()); - obj.pushKV("queue_size", GetQueueSize()); UniValue arrSessions(UniValue::VARR); for (const auto& session : deqSessions) { @@ -1812,3 +1849,9 @@ void CPrivateSendClientManager::GetJsonInfo(UniValue& obj) const } obj.pushKV("sessions", arrSessions); } + +void DoPrivateSendMaintenance(CConnman& connman) +{ + privateSendClientQueueManager.DoMaintenance(); + privateSendClientManager.DoMaintenance(connman); +} diff --git a/src/privatesend/privatesend-client.h b/src/privatesend/privatesend-client.h index b217bda44f65..f0f7bd2e2d39 100644 --- a/src/privatesend/privatesend-client.h +++ b/src/privatesend/privatesend-client.h @@ -11,10 +11,13 @@ #include -class CPrivateSendClientManager; class CPrivateSendClientOptions; +class CPrivateSendClientManager; +class CPrivateSendClientQueueManager; + class CConnman; class CNode; + class UniValue; static const int MIN_PRIVATESEND_SESSIONS = 1; @@ -55,6 +58,9 @@ static const int PRIVATESEND_KEYS_THRESHOLD_STOP = 50; // The main object for accessing mixing extern CPrivateSendClientManager privateSendClientManager; +// The object to track mixing queues +extern CPrivateSendClientQueueManager privateSendClientQueueManager; + // The object to store application wide mixing options extern CPrivateSendClientOptions privateSendClientOptions; @@ -182,9 +188,19 @@ class CPrivateSendClientSession : public CPrivateSendBaseSession void GetJsonInfo(UniValue& obj) const; }; +/** Used to keep track of mixing queues + */ +class CPrivateSendClientQueueManager : public CPrivateSendBaseManager +{ +public: + void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61); + + void DoMaintenance(); +}; + /** Used to keep track of current status of mixing pool */ -class CPrivateSendClientManager : public CPrivateSendBaseManager +class CPrivateSendClientManager { private: // Keep track of the used Masternodes @@ -242,6 +258,9 @@ class CPrivateSendClientManager : public CPrivateSendBaseManager /// Passively run mixing in the background according to the configuration in settings bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false); + bool TrySubmitDenominate(const CService& mnAddr, CConnman& connman); + bool MarkAlreadyJoinedQueueAsTried(CPrivateSendQueue& dsq) const; + void CheckTimeout(); void ProcessPendingDsaRequest(CConnman& connman); @@ -281,4 +300,6 @@ class CPrivateSendClientOptions } }; +void DoPrivateSendMaintenance(CConnman& connman); + #endif // BITCOIN_PRIVATESEND_PRIVATESEND_CLIENT_H diff --git a/src/rpc/privatesend.cpp b/src/rpc/privatesend.cpp index 21a12a4eea46..28bfeb6b6097 100644 --- a/src/rpc/privatesend.cpp +++ b/src/rpc/privatesend.cpp @@ -141,6 +141,7 @@ UniValue getprivatesendinfo(const JSONRPCRequest& request) obj.pushKV("max_amount", privateSendClientOptions.nPrivateSendAmount); obj.pushKV("denoms_goal", privateSendClientOptions.nPrivateSendDenomsGoal); obj.pushKV("denoms_hardcap", privateSendClientOptions.nPrivateSendDenomsHardCap); + obj.pushKV("queue_size", privateSendClientQueueManager.GetQueueSize()); CWallet* const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) { diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index cf2756cbebd5..b261fa5d68ef 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -365,8 +365,7 @@ void WalletInit::Start(CScheduler& scheduler) scheduler.scheduleEvery(MaybeCompactWalletDB, 500); if (!fMasternodeMode && privateSendClientOptions.fEnablePrivateSend) { - scheduler.scheduleEvery(std::bind(&CPrivateSendClientManager::DoMaintenance, std::ref(privateSendClientManager), - std::ref(*g_connman)), 1 * 1000); + scheduler.scheduleEvery(std::bind(&DoPrivateSendMaintenance, std::ref(*g_connman)), 1 * 1000); } } From 11255fd86e994b31411c418cc98ef7059a9b44eb Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 16 Jul 2020 15:23:47 +0300 Subject: [PATCH 07/13] Drop `GetMixingWallet()`s, pass `CWallet*` into `CPrivateSendClientSession` via ctor --- src/privatesend/privatesend-client.cpp | 135 ++++++++++++------------- src/privatesend/privatesend-client.h | 10 +- 2 files changed, 67 insertions(+), 78 deletions(-) diff --git a/src/privatesend/privatesend-client.cpp b/src/privatesend/privatesend-client.cpp index e1fac1bdabed..5c040d8b3ebd 100644 --- a/src/privatesend/privatesend-client.cpp +++ b/src/privatesend/privatesend-client.cpp @@ -284,13 +284,13 @@ void CPrivateSendClientSession::UnlockCoins() if (!privateSendClientOptions.fEnablePrivateSend) return; while (true) { - TRY_LOCK(GetMixingWallet()->cs_wallet, lockWallet); + TRY_LOCK(mixingWallet->cs_wallet, lockWallet); if (!lockWallet) { MilliSleep(50); continue; } for (const auto& outpoint : vecOutPointLocked) - GetMixingWallet()->UnlockCoin(outpoint); + mixingWallet->UnlockCoin(outpoint); break; } @@ -378,17 +378,6 @@ bool CPrivateSendClientManager::GetMixingMasternodesInfo(std::vectornKeysLeftSinceAutoBackup = 0; // no backup, no "keys since last backup" + mixingWallet->nKeysLeftSinceAutoBackup = 0; // no backup, no "keys since last backup" return false; case -1: // Automatic backup failed, nothing else we can do until user fixes the issue manually. @@ -730,24 +719,24 @@ bool CPrivateSendClientManager::CheckAutomaticBackup() return false; } - if (GetMixingWallet()->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_STOP) { + if (mixingWallet->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_STOP) { // We should never get here via mixing itself but probably something else is still actively using keypool - LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d, no mixing available.\n", GetMixingWallet()->nKeysLeftSinceAutoBackup); - strAutoDenomResult = strprintf(_("Very low number of keys left: %d") + ", " + _("no mixing available."), GetMixingWallet()->nKeysLeftSinceAutoBackup); + LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d, no mixing available.\n", mixingWallet->nKeysLeftSinceAutoBackup); + strAutoDenomResult = strprintf(_("Very low number of keys left: %d") + ", " + _("no mixing available."), mixingWallet->nKeysLeftSinceAutoBackup); // It's getting really dangerous, stop mixing StopMixing(); return false; - } else if (GetMixingWallet()->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) { + } else if (mixingWallet->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) { // Low number of keys left but it's still more or less safe to continue - LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d\n", GetMixingWallet()->nKeysLeftSinceAutoBackup); - strAutoDenomResult = strprintf(_("Very low number of keys left: %d"), GetMixingWallet()->nKeysLeftSinceAutoBackup); + LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d\n", mixingWallet->nKeysLeftSinceAutoBackup); + strAutoDenomResult = strprintf(_("Very low number of keys left: %d"), mixingWallet->nKeysLeftSinceAutoBackup); if (fCreateAutoBackups) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Trying to create new backup.\n"); std::string warningString; std::string errorString; - if (!GetMixingWallet()->AutoBackupWallet("", warningString, errorString)) { + if (!mixingWallet->AutoBackupWallet("", warningString, errorString)) { if (!warningString.empty()) { // There were some issues saving backup but yet more or less safe to continue LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- WARNING! Something went wrong on automatic backup: %s\n", warningString); @@ -765,7 +754,7 @@ bool CPrivateSendClientManager::CheckAutomaticBackup() } } - LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Keys left since latest backup: %d\n", GetMixingWallet()->nKeysLeftSinceAutoBackup); + LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Keys left since latest backup: %d\n", mixingWallet->nKeysLeftSinceAutoBackup); return true; } @@ -783,15 +772,15 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool return false; } - if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; CAmount nBalanceNeedsAnonymized; { LOCK2(cs_main, mempool.cs); - LOCK(GetMixingWallet()->cs_wallet); + LOCK(mixingWallet->cs_wallet); - if (!fDryRun && GetMixingWallet()->IsLocked(true)) { + if (!fDryRun && mixingWallet->IsLocked(true)) { strAutoDenomResult = _("Wallet is locked."); return false; } @@ -815,7 +804,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool } // check if there is anything left to do - CAmount nBalanceAnonymized = GetMixingWallet()->GetAnonymizedBalance(); + CAmount nBalanceAnonymized = mixingWallet->GetAnonymizedBalance(); nBalanceNeedsAnonymized = privateSendClientOptions.nPrivateSendAmount*COIN - nBalanceAnonymized; if (nBalanceNeedsAnonymized < 0) { @@ -827,13 +816,13 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool CAmount nValueMin = CPrivateSend::GetSmallestDenomination(); // if there are no confirmed DS collateral inputs yet - if (!GetMixingWallet()->HasCollateralInputs()) { + if (!mixingWallet->HasCollateralInputs()) { // should have some additional amount for them nValueMin += CPrivateSend::GetMaxCollateralAmount(); } // including denoms but applying some restrictions - CAmount nBalanceAnonymizable = GetMixingWallet()->GetAnonymizableBalance(); + CAmount nBalanceAnonymizable = mixingWallet->GetAnonymizableBalance(); // mixable balance is way too small if (nBalanceAnonymizable < nValueMin) { @@ -843,10 +832,10 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool } // excluding denoms - CAmount nBalanceAnonimizableNonDenom = GetMixingWallet()->GetAnonymizableBalance(true); + CAmount nBalanceAnonimizableNonDenom = mixingWallet->GetAnonymizableBalance(true); // denoms - CAmount nBalanceDenominatedConf = GetMixingWallet()->GetDenominatedBalance(); - CAmount nBalanceDenominatedUnconf = GetMixingWallet()->GetDenominatedBalance(true); + CAmount nBalanceDenominatedConf = mixingWallet->GetDenominatedBalance(); + CAmount nBalanceDenominatedUnconf = mixingWallet->GetDenominatedBalance(true); CAmount nBalanceDenominated = nBalanceDenominatedConf + nBalanceDenominatedUnconf; CAmount nBalanceToDenominate = privateSendClientOptions.nPrivateSendAmount * COIN - nBalanceDenominated; @@ -895,8 +884,8 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool } //check if we have the collateral sized inputs - if (!GetMixingWallet()->HasCollateralInputs()) { - return !GetMixingWallet()->HasCollateralInputs(false) && MakeCollateralAmounts(connman); + if (!mixingWallet->HasCollateralInputs()) { + return !mixingWallet->HasCollateralInputs(false) && MakeCollateralAmounts(connman); } if (nSessionID) { @@ -920,14 +909,14 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool //check our collateral and create new if needed std::string strReason; if (txMyCollateral == CMutableTransaction()) { - if (!GetMixingWallet()->CreateCollateralTransaction(txMyCollateral, strReason)) { + if (!mixingWallet->CreateCollateralTransaction(txMyCollateral, strReason)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- create collateral error:%s\n", strReason); return false; } } else { if (!CPrivateSend::IsCollateralValid(txMyCollateral)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- invalid collateral, recreating...\n"); - if (!GetMixingWallet()->CreateCollateralTransaction(txMyCollateral, strReason)) { + if (!mixingWallet->CreateCollateralTransaction(txMyCollateral, strReason)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- create collateral error: %s\n", strReason); return false; } @@ -935,10 +924,10 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool } // lock the funds we're going to use for our collateral for (const auto& txin : txMyCollateral.vin) { - GetMixingWallet()->LockCoin(txin.prevout); + mixingWallet->LockCoin(txin.prevout); vecOutPointLocked.push_back(txin.prevout); } - } // LOCK2(cs_main, GetMixingWallet()->cs_wallet); + } // LOCK2(cs_main, mixingWallet->cs_wallet); // Always attempt to join an existing queue if (JoinExistingQueue(nBalanceNeedsAnonymized, connman)) { @@ -962,7 +951,7 @@ bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool return false; } - if (!fDryRun && GetMixingWallet()->IsLocked(true)) { + if (!fDryRun && mixingWallet->IsLocked(true)) { strAutoDenomResult = _("Wallet is locked."); return false; } @@ -982,7 +971,7 @@ bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool LOCK(cs_deqsessions); bool fResult = true; if ((int)deqSessions.size() < privateSendClientOptions.nPrivateSendSessions) { - deqSessions.emplace_back(); + deqSessions.emplace_back(mixingWallet); } for (auto& session : deqSessions) { if (!CheckAutomaticBackup()) return false; @@ -1045,7 +1034,7 @@ CDeterministicMNCPtr CPrivateSendClientManager::GetRandomNotUsedMasternode() bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman) { - if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; auto mnList = deterministicMNManager->GetListAtChainTip(); @@ -1074,7 +1063,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize std::vector > vecPSInOutPairsTmp; // Try to match their denominations if possible, select exact number of denominations - if (!GetMixingWallet()->SelectPSInOutPairsByDenominations(dsq.nDenom, nBalanceNeedsAnonymized, vecPSInOutPairsTmp)) { + if (!mixingWallet->SelectPSInOutPairsByDenominations(dsq.nDenom, nBalanceNeedsAnonymized, vecPSInOutPairsTmp)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- Couldn't match denomination %d (%s)\n", dsq.nDenom, CPrivateSend::DenominationToString(dsq.nDenom)); continue; } @@ -1104,7 +1093,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman) { - if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; if (nBalanceNeedsAnonymized <= 0) return false; int nTries = 0; @@ -1113,7 +1102,7 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, C // find available denominated amounts std::set setAmounts; - if (!GetMixingWallet()->SelectDenominatedAmounts(nBalanceNeedsAnonymized, setAmounts)) { + if (!mixingWallet->SelectDenominatedAmounts(nBalanceNeedsAnonymized, setAmounts)) { // this should never happen LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- Can't mix: no compatible inputs found!\n"); strAutoDenomResult = _("Can't mix: no compatible inputs found!"); @@ -1245,7 +1234,7 @@ bool CPrivateSendClientManager::MarkAlreadyJoinedQueueAsTried(CPrivateSendQueue& bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) { LOCK2(cs_main, mempool.cs); - LOCK(GetMixingWallet()->cs_wallet); + LOCK(mixingWallet->cs_wallet); std::string strError; std::vector > vecPSInOutPairs, vecPSInOutPairsTmp; @@ -1296,9 +1285,9 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std::vector >& vecPSInOutPairsRet) { - if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; - if (GetMixingWallet()->IsLocked(true)) { + if (mixingWallet->IsLocked(true)) { strErrorRet = "Wallet locked, unable to create transaction!"; return false; } @@ -1310,7 +1299,7 @@ bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std:: vecPSInOutPairsRet.clear(); - bool fSelected = GetMixingWallet()->SelectPSInOutPairsByDenominations(nSessionDenom, CPrivateSend::GetMaxPoolAmount(), vecPSInOutPairsRet); + bool fSelected = mixingWallet->SelectPSInOutPairsByDenominations(nSessionDenom, CPrivateSend::GetMaxPoolAmount(), vecPSInOutPairsRet); if (!fSelected) { strErrorRet = "Can't select current denominated inputs"; return false; @@ -1322,7 +1311,7 @@ bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std:: bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, const std::vector >& vecPSInOutPairsIn, std::vector >& vecPSInOutPairsRet, bool fDryRun) { AssertLockHeld(cs_main); - AssertLockHeld(GetMixingWallet()->cs_wallet); + AssertLockHeld(mixingWallet->cs_wallet); if (!CPrivateSend::IsValidDenomination(nSessionDenom)) { strErrorRet = "Incorrect session denom"; @@ -1353,7 +1342,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds ++nSteps; continue; } - scriptDenom = keyHolderStorage.AddKey(GetMixingWallet()); + scriptDenom = keyHolderStorage.AddKey(mixingWallet); } vecPSInOutPairsRet.emplace_back(pair.first, CTxOut(nDenomAmount, scriptDenom)); // step is complete @@ -1371,7 +1360,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds } for (const auto& pair : vecPSInOutPairsRet) { - GetMixingWallet()->LockCoin(pair.first.prevout); + mixingWallet->LockCoin(pair.first.prevout); vecOutPointLocked.push_back(pair.first.prevout); } @@ -1381,17 +1370,17 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds // Create collaterals by looping through inputs grouped by addresses bool CPrivateSendClientSession::MakeCollateralAmounts(CConnman& connman) { - if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; LOCK2(cs_main, mempool.cs); - LOCK(GetMixingWallet()->cs_wallet); + LOCK(mixingWallet->cs_wallet); // NOTE: We do not allow txes larger than 100kB, so we have to limit number of inputs here. // We still want to consume a lot of inputs to avoid creating only smaller denoms though. // Knowing that each CTxIn is at least 148b big, 400 inputs should take 400 x ~148b = ~60kB. // This still leaves more than enough room for another data of typical MakeCollateralAmounts tx. std::vector vecTally; - if (!GetMixingWallet()->SelectCoinsGroupedByAddresses(vecTally, false, false, true, 400)) { + if (!mixingWallet->SelectCoinsGroupedByAddresses(vecTally, false, false, true, 400)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- SelectCoinsGroupedByAddresses can't find any inputs!\n"); return false; } @@ -1423,9 +1412,9 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta { AssertLockHeld(cs_main); AssertLockHeld(mempool.cs); - AssertLockHeld(GetMixingWallet()->cs_wallet); + AssertLockHeld(mixingWallet->cs_wallet); - if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; // Skip way too tiny amounts if (tallyItem.nAmount < CPrivateSend::GetCollateralAmount()) { @@ -1449,9 +1438,9 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta std::vector vecSend; // make our collateral address - CReserveKey reservekeyCollateral(GetMixingWallet()); + CReserveKey reservekeyCollateral(mixingWallet); // make our change address - CReserveKey reservekeyChange(GetMixingWallet()); + CReserveKey reservekeyChange(mixingWallet); CScript scriptCollateral; CPubKey vchPubKey; @@ -1480,7 +1469,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta coinControl.Select(outpoint); } - bool fSuccess = GetMixingWallet()->CreateTransaction(vecSend, wtx, reservekeyChange, + bool fSuccess = mixingWallet->CreateTransaction(vecSend, wtx, reservekeyChange, nFeeRet, nChangePosRet, strFail, coinControl); if (!fSuccess) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- ONLY_NONDENOMINATED: %s\n", strFail); @@ -1488,7 +1477,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta if (fTryDenominated) { // Try to also use denominated coins (we can't mix denominated without collaterals anyway). coinControl.nCoinType = CoinType::ALL_COINS; - if (!GetMixingWallet()->CreateTransaction(vecSend, wtx, reservekeyChange, + if (!mixingWallet->CreateTransaction(vecSend, wtx, reservekeyChange, nFeeRet, nChangePosRet, strFail, coinControl)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- ALL_COINS Error: %s\n", strFail); reservekeyCollateral.ReturnKey(); @@ -1520,17 +1509,17 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta // Create denominations by looping through inputs grouped by addresses bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, CConnman& connman) { - if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; LOCK2(cs_main, mempool.cs); - LOCK(GetMixingWallet()->cs_wallet); + LOCK(mixingWallet->cs_wallet); // NOTE: We do not allow txes larger than 100kB, so we have to limit number of inputs here. // We still want to consume a lot of inputs to avoid creating only smaller denoms though. // Knowing that each CTxIn is at least 148b big, 400 inputs should take 400 x ~148b = ~60kB. // This still leaves more than enough room for another data of typical CreateDenominated tx. std::vector vecTally; - if (!GetMixingWallet()->SelectCoinsGroupedByAddresses(vecTally, true, true, true, 400)) { + if (!mixingWallet->SelectCoinsGroupedByAddresses(vecTally, true, true, true, 400)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- SelectCoinsGroupedByAddresses can't find any inputs!\n"); return false; } @@ -1540,7 +1529,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, return a.nAmount > b.nAmount; }); - bool fCreateMixingCollaterals = !GetMixingWallet()->HasCollateralInputs(); + bool fCreateMixingCollaterals = !mixingWallet->HasCollateralInputs(); for (const auto& item : vecTally) { if (!CreateDenominated(nBalanceToDenominate, item, fCreateMixingCollaterals, connman)) continue; @@ -1556,9 +1545,9 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, { AssertLockHeld(cs_main); AssertLockHeld(mempool.cs); - AssertLockHeld(GetMixingWallet()->cs_wallet); + AssertLockHeld(mixingWallet->cs_wallet); - if (!privateSendClientOptions.fEnablePrivateSend || !privateSendClientManager.IsMixing()) return false; + if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; std::vector vecSend; CKeyHolderStorage keyHolderStorageDenom; @@ -1578,7 +1567,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, // ****** Add an output for mixing collaterals ************ / if (fCreateMixingCollaterals) { - CScript scriptCollateral = keyHolderStorageDenom.AddKey(GetMixingWallet()); + CScript scriptCollateral = keyHolderStorageDenom.AddKey(mixingWallet); vecSend.push_back((CRecipient){scriptCollateral, CPrivateSend::GetMaxCollateralAmount(), false}); nValueLeft -= CPrivateSend::GetMaxCollateralAmount() + nOutputFee; } @@ -1591,7 +1580,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, std::map mapDenomCount; for (auto nDenomValue : vecStandardDenoms) { - mapDenomCount.insert(std::pair(nDenomValue, GetMixingWallet()->CountInputsWithAmount(nDenomValue))); + mapDenomCount.insert(std::pair(nDenomValue, mixingWallet->CountInputsWithAmount(nDenomValue))); } // Will generate outputs for the createdenoms up to privatesendmaxdenoms per denom @@ -1629,7 +1618,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, // add each output up to 11 times or until it can't be added again or until we reach nPrivateSendDenomsGoal while (needMoreOutputs() && nOutputs <= 10 && currentDenomIt->second < privateSendClientOptions.nPrivateSendDenomsGoal) { - CScript scriptDenom = keyHolderStorageDenom.AddKey(GetMixingWallet()); + CScript scriptDenom = keyHolderStorageDenom.AddKey(mixingWallet); vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false}); @@ -1693,7 +1682,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, // Never go above the cap unless it's the largest denom if (nDenomValue != nLargestDenomValue && it->second >= privateSendClientOptions.nPrivateSendDenomsHardCap) break; - CScript scriptDenom = keyHolderStorageDenom.AddKey(GetMixingWallet()); + CScript scriptDenom = keyHolderStorageDenom.AddKey(mixingWallet); vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false}); // increment outputs and subtract denomination amount @@ -1739,9 +1728,9 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, int nChangePosRet = -1; std::string strFail = ""; // make our change address - CReserveKey reservekeyChange(GetMixingWallet()); + CReserveKey reservekeyChange(mixingWallet); - bool fSuccess = GetMixingWallet()->CreateTransaction(vecSend, wtx, reservekeyChange, + bool fSuccess = mixingWallet->CreateTransaction(vecSend, wtx, reservekeyChange, nFeeRet, nChangePosRet, strFail, coinControl); if (!fSuccess) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- Error: %s\n", strFail); diff --git a/src/privatesend/privatesend-client.h b/src/privatesend/privatesend-client.h index f0f7bd2e2d39..2b44182f493c 100644 --- a/src/privatesend/privatesend-client.h +++ b/src/privatesend/privatesend-client.h @@ -120,6 +120,8 @@ class CPrivateSendClientSession : public CPrivateSendBaseSession CKeyHolderStorage keyHolderStorage; // storage for keys used in PrepareDenominate + CWallet* mixingWallet; + /// Create denominations bool CreateDenominated(CAmount nBalanceToDenominate, CConnman& connman); bool CreateDenominated(CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals, CConnman& connman); @@ -153,14 +155,15 @@ class CPrivateSendClientSession : public CPrivateSendBaseSession void SetNull(); public: - CPrivateSendClientSession() : + CPrivateSendClientSession(CWallet* pwallet) : vecOutPointLocked(), strLastMessage(), strAutoDenomResult(), mixingMasternode(), txMyCollateral(), pendingDsaRequest(), - keyHolderStorage() + keyHolderStorage(), + mixingWallet(pwallet) { } @@ -173,7 +176,6 @@ class CPrivateSendClientSession : public CPrivateSendBaseSession std::string GetStatus(bool fWaitForBlock); bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const; - CWallet* GetMixingWallet() const; /// Passively run mixing in the background according to the configuration in settings bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false); @@ -253,8 +255,6 @@ class CPrivateSendClientManager bool GetMixingMasternodesInfo(std::vector& vecDmnsRet) const; - CWallet* GetMixingWallet() const; - /// Passively run mixing in the background according to the configuration in settings bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false); From a7e0957c82781805ec67f8c6696278d964637828 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 16 Jul 2020 15:23:58 +0300 Subject: [PATCH 08/13] Create one PS manager per wallet --- src/dsnotificationinterface.cpp | 4 +- src/masternode/masternode-utils.cpp | 4 +- src/net_processing.cpp | 4 +- src/privatesend/privatesend-client.cpp | 36 +++++++++++------- src/privatesend/privatesend-client.h | 2 +- src/qt/bitcoingui.cpp | 4 +- src/qt/optionsdialog.cpp | 7 ++-- src/qt/overviewpage.cpp | 51 +++++++++++++++----------- src/rpc/privatesend.cpp | 14 ++++--- src/wallet/init.cpp | 27 ++++++++------ src/wallet/wallet.cpp | 7 +++- 11 files changed, 98 insertions(+), 62 deletions(-) diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp index 42c6e87093ec..16e4eed4062a 100644 --- a/src/dsnotificationinterface.cpp +++ b/src/dsnotificationinterface.cpp @@ -62,7 +62,9 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con CPrivateSend::UpdatedBlockTip(pindexNew); #ifdef ENABLE_WALLET - privateSendClientManager.UpdatedBlockTip(pindexNew); + for (auto& pair : privateSendClientManagers) { + pair.second->UpdatedBlockTip(pindexNew); + } #endif // ENABLE_WALLET llmq::quorumInstantSendManager->UpdatedBlockTip(pindexNew); diff --git a/src/masternode/masternode-utils.cpp b/src/masternode/masternode-utils.cpp index e032ca54f52d..ec7bc0f3ff3e 100644 --- a/src/masternode/masternode-utils.cpp +++ b/src/masternode/masternode-utils.cpp @@ -24,7 +24,9 @@ void CMasternodeUtils::ProcessMasternodeConnections(CConnman& connman) { std::vector vecDmns; // will be empty when no wallet #ifdef ENABLE_WALLET - privateSendClientManager.GetMixingMasternodesInfo(vecDmns); + for (const auto& pair : privateSendClientManagers) { + pair.second->GetMixingMasternodesInfo(vecDmns); + } #endif // ENABLE_WALLET // Don't disconnect masternode connections when we have less then the desired amount of outbound nodes diff --git a/src/net_processing.cpp b/src/net_processing.cpp index f2c110126301..5a9756863c15 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3543,7 +3543,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr //probably one the extensions #ifdef ENABLE_WALLET privateSendClientQueueManager.ProcessMessage(pfrom, strCommand, vRecv, *connman, enable_bip61); - privateSendClientManager.ProcessMessage(pfrom, strCommand, vRecv, *connman, enable_bip61); + for (auto& pair : privateSendClientManagers) { + pair.second->ProcessMessage(pfrom, strCommand, vRecv, *connman, enable_bip61); + } #endif // ENABLE_WALLET privateSendServer.ProcessMessage(pfrom, strCommand, vRecv, *connman, enable_bip61); sporkManager.ProcessSpork(pfrom, strCommand, vRecv, *connman); diff --git a/src/privatesend/privatesend-client.cpp b/src/privatesend/privatesend-client.cpp index 5c040d8b3ebd..e5824a5d5342 100644 --- a/src/privatesend/privatesend-client.cpp +++ b/src/privatesend/privatesend-client.cpp @@ -22,7 +22,7 @@ #include #include -CPrivateSendClientManager privateSendClientManager; +std::map privateSendClientManagers; CPrivateSendClientQueueManager privateSendClientQueueManager; CPrivateSendClientOptions privateSendClientOptions; @@ -84,9 +84,11 @@ void CPrivateSendClientQueueManager::ProcessMessage(CNode* pfrom, const std::str // if the queue is ready, submit if we can if (dsq.fReady) { - if (privateSendClientManager.TrySubmitDenominate(dmn->pdmnState->addr, connman)) { - LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- PrivateSend queue (%s) is ready on masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); - return; + for (auto& pair : privateSendClientManagers) { + if (pair.second->TrySubmitDenominate(dmn->pdmnState->addr, connman)) { + LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- PrivateSend queue (%s) is ready on masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); + return; + } } } else { int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq(); @@ -102,7 +104,11 @@ void CPrivateSendClientQueueManager::ProcessMessage(CNode* pfrom, const std::str LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); - privateSendClientManager.MarkAlreadyJoinedQueueAsTried(dsq); + for (const auto& pair : privateSendClientManagers) { + if (pair.second->MarkAlreadyJoinedQueueAsTried(dsq)) { + break; + } + } TRY_LOCK(cs_vecqueue, lockRecv); if (!lockRecv) return; @@ -666,7 +672,7 @@ void CPrivateSendClientSession::CompletedTransaction(PoolMessage nMessageID) if (nMessageID == MSG_SUCCESS) { LogPrint(BCLog::PRIVATESEND, "CompletedTransaction -- success\n"); - privateSendClientManager.UpdatedSuccessBlock(); + privateSendClientManagers.at(mixingWallet->GetName())->UpdatedSuccessBlock(); keyHolderStorage.KeepAll(); } else { LogPrint(BCLog::PRIVATESEND, "CompletedTransaction -- error\n"); @@ -1068,7 +1074,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize continue; } - privateSendClientManager.AddUsedMasternode(dsq.masternodeOutpoint); + privateSendClientManagers.at(mixingWallet->GetName())->AddUsedMasternode(dsq.masternodeOutpoint); if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- skipping masternode connection, addr=%s\n", dmn->pdmnState->addr.ToString()); @@ -1111,7 +1117,7 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, C // otherwise, try one randomly while (nTries < 10) { - auto dmn = privateSendClientManager.GetRandomNotUsedMasternode(); + auto dmn = privateSendClientManagers.at(mixingWallet->GetName())->GetRandomNotUsedMasternode(); if (!dmn) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- Can't find random masternode!\n"); @@ -1119,7 +1125,7 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, C return false; } - privateSendClientManager.AddUsedMasternode(dmn->collateralOutpoint); + privateSendClientManagers.at(mixingWallet->GetName())->AddUsedMasternode(dmn->collateralOutpoint); // skip next mn payments winners if (dmn->pdmnState->nLastPaidHeight + nMnCount < mnList.GetHeight() + 8) { @@ -1496,12 +1502,12 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta // use the same nCachedLastSuccessBlock as for DS mixing to prevent race CValidationState state; - if (!GetMixingWallet()->CommitTransaction(wtx, reservekeyChange, &connman, state)) { + if (!mixingWallet->CommitTransaction(wtx, reservekeyChange, &connman, state)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- CommitTransaction failed! Reason given: %s\n", state.GetRejectReason()); return false; } - privateSendClientManager.UpdatedSuccessBlock(); + privateSendClientManagers.at(mixingWallet->GetName())->UpdatedSuccessBlock(); return true; } @@ -1741,13 +1747,13 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, keyHolderStorageDenom.KeepAll(); CValidationState state; - if (!GetMixingWallet()->CommitTransaction(wtx, reservekeyChange, &connman, state)) { + if (!mixingWallet->CommitTransaction(wtx, reservekeyChange, &connman, state)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- CommitTransaction failed! Reason given: %s\n", state.GetRejectReason()); return false; } // use the same nCachedLastSuccessBlock as for DS mixing to prevent race - privateSendClientManager.UpdatedSuccessBlock(); + privateSendClientManagers.at(mixingWallet->GetName())->UpdatedSuccessBlock(); LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- txid=%s\n", wtx.GetHash().GetHex()); return true; @@ -1842,5 +1848,7 @@ void CPrivateSendClientManager::GetJsonInfo(UniValue& obj) const void DoPrivateSendMaintenance(CConnman& connman) { privateSendClientQueueManager.DoMaintenance(); - privateSendClientManager.DoMaintenance(connman); + for (auto& pair : privateSendClientManagers) { + pair.second->DoMaintenance(connman); + } } diff --git a/src/privatesend/privatesend-client.h b/src/privatesend/privatesend-client.h index 2b44182f493c..0db1527e8f1b 100644 --- a/src/privatesend/privatesend-client.h +++ b/src/privatesend/privatesend-client.h @@ -56,7 +56,7 @@ static const int PRIVATESEND_KEYS_THRESHOLD_WARNING = 100; static const int PRIVATESEND_KEYS_THRESHOLD_STOP = 50; // The main object for accessing mixing -extern CPrivateSendClientManager privateSendClientManager; +extern std::map privateSendClientManagers; // The object to track mixing queues extern CPrivateSendClientQueueManager privateSendClientQueueManager; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 333069876d57..7ec28b45fcc7 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1049,7 +1049,9 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer // Disabling macOS App Nap on initial sync, disk, reindex operations and mixing. bool disableAppNap = !masternodeSync.IsSynced(); #ifdef ENABLE_WALLET - disableAppNap |= privateSendClientManager.IsMixing(); + for (const auto& pair : privateSendClientManagers) { + disableAppNap |= pair.second->IsMixing(); + } #endif // ENABLE_WALLET if (disableAppNap) { m_app_nap_inhibitor->disableAppNap(); diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 495287cef0d5..ea246e9eafff 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -288,9 +288,10 @@ void OptionsDialog::on_okButton_clicked() { mapper->submit(); #ifdef ENABLE_WALLET - privateSendClientManager.nCachedNumBlocks = std::numeric_limits::max(); - if(HasWallets()) - GetWallets()[0]->MarkDirty(); + for (auto& pwallet : GetWallets()) { + privateSendClientManagers.at(pwallet->GetName())->nCachedNumBlocks = std::numeric_limits::max(); + pwallet->MarkDirty(); + } #endif // ENABLE_WALLET accept(); updateDefaultProxyNets(); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index deb08989259a..9b5df879df80 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -181,14 +181,16 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) ui->labelPrivateSendEnabled->setToolTip(tr("Automatic backups are disabled, no mixing available!")); } } else { - if(!privateSendClientManager.IsMixing()){ - ui->togglePrivateSend->setText(tr("Start Mixing")); - } else { - ui->togglePrivateSend->setText(tr("Stop Mixing")); - } // Disable privateSendClient builtin support for automatic backups while we are in GUI, // we'll handle automatic backups and user warnings in privateSendStatus() - privateSendClientManager.fCreateAutoBackups = false; + for (auto& pair : privateSendClientManagers) { + if (!pair.second->IsMixing()) { + ui->togglePrivateSend->setText(tr("Start Mixing")); + } else { + ui->togglePrivateSend->setText(tr("Stop Mixing")); + } + pair.second->fCreateAutoBackups = false; + } timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(privateSendStatus())); @@ -490,8 +492,10 @@ void OverviewPage::privateSendStatus(bool fForce) static int64_t nLastDSProgressBlockTime = 0; int nBestHeight = clientModel->getNumBlocks(); + CPrivateSendClientManager* privateSendClientManager = privateSendClientManagers.find(walletModel->getWallet()->GetName())->second; + // We are processing more than 1 block per second, we'll just leave - if(nBestHeight > privateSendClientManager.nCachedNumBlocks && GetTime() - nLastDSProgressBlockTime <= 1) return; + if(nBestHeight > privateSendClientManager->nCachedNumBlocks && GetTime() - nLastDSProgressBlockTime <= 1) return; nLastDSProgressBlockTime = GetTime(); QString strKeysLeftText(tr("keys left: %1").arg(walletModel->getKeysLeftSinceAutoBackup())); @@ -500,9 +504,9 @@ void OverviewPage::privateSendStatus(bool fForce) } ui->labelPrivateSendEnabled->setToolTip(strKeysLeftText); - if (!privateSendClientManager.IsMixing()) { - if (nBestHeight != privateSendClientManager.nCachedNumBlocks) { - privateSendClientManager.nCachedNumBlocks = nBestHeight; + if (!privateSendClientManager->IsMixing()) { + if (nBestHeight != privateSendClientManager->nCachedNumBlocks) { + privateSendClientManager->nCachedNumBlocks = nBestHeight; updatePrivateSendProgress(); } @@ -557,7 +561,7 @@ void OverviewPage::privateSendStatus(bool fForce) } } - QString strEnabled = privateSendClientManager.IsMixing() ? tr("Enabled") : tr("Disabled"); + QString strEnabled = privateSendClientManager->IsMixing() ? tr("Enabled") : tr("Disabled"); // Show how many keys left in advanced PS UI mode only if(fShowAdvancedPSUI) strEnabled += ", " + strKeysLeftText; ui->labelPrivateSendEnabled->setText(strEnabled); @@ -579,15 +583,15 @@ void OverviewPage::privateSendStatus(bool fForce) } // check privatesend status and unlock if needed - if(nBestHeight != privateSendClientManager.nCachedNumBlocks) { + if(nBestHeight != privateSendClientManager->nCachedNumBlocks) { // Balance and number of transactions might have changed - privateSendClientManager.nCachedNumBlocks = nBestHeight; + privateSendClientManager->nCachedNumBlocks = nBestHeight; updatePrivateSendProgress(); } setWidgetsVisible(true); - ui->labelSubmittedDenom->setText(QString(privateSendClientManager.GetSessionDenoms().c_str())); + ui->labelSubmittedDenom->setText(QString(privateSendClientManager->GetSessionDenoms().c_str())); } void OverviewPage::togglePrivateSend(){ @@ -600,7 +604,10 @@ void OverviewPage::togglePrivateSend(){ QMessageBox::Ok, QMessageBox::Ok); settings.setValue("hasMixed", "hasMixed"); } - if(!privateSendClientManager.IsMixing()){ + + CPrivateSendClientManager* privateSendClientManager = privateSendClientManagers.find(walletModel->getWallet()->GetName())->second; + + if (!privateSendClientManager->IsMixing()) { const CAmount nMinAmount = CPrivateSend::GetSmallestDenomination() + CPrivateSend::GetMaxCollateralAmount(); if(currentBalance < nMinAmount){ QString strMinAmount(BitcoinUnits::formatWithUnit(nDisplayUnit, nMinAmount)); @@ -617,7 +624,7 @@ void OverviewPage::togglePrivateSend(){ if(!ctx.isValid()) { //unlock was cancelled - privateSendClientManager.nCachedNumBlocks = std::numeric_limits::max(); + privateSendClientManager->nCachedNumBlocks = std::numeric_limits::max(); QMessageBox::warning(this, tr("PrivateSend"), tr("Wallet is locked and user declined to unlock. Disabling PrivateSend."), QMessageBox::Ok, QMessageBox::Ok); @@ -628,15 +635,15 @@ void OverviewPage::togglePrivateSend(){ } - privateSendClientManager.nCachedNumBlocks = std::numeric_limits::max(); + privateSendClientManager->nCachedNumBlocks = std::numeric_limits::max(); - if (privateSendClientManager.IsMixing()) { + if (privateSendClientManager->IsMixing()) { ui->togglePrivateSend->setText(tr("Start Mixing")); - privateSendClientManager.ResetPool(); - privateSendClientManager.StopMixing(); + privateSendClientManager->ResetPool(); + privateSendClientManager->StopMixing(); } else { ui->togglePrivateSend->setText(tr("Stop Mixing")); - privateSendClientManager.StartMixing(walletModel->getWallet()); + privateSendClientManager->StartMixing(walletModel->getWallet()); } } @@ -664,5 +671,5 @@ void OverviewPage::DisablePrivateSendCompletely() { if (nWalletBackups <= 0) { ui->labelPrivateSendEnabled->setText("(" + tr("Disabled") + ")"); } - privateSendClientManager.StopMixing(); + privateSendClientManagers.at(walletModel->getWallet()->GetName())->StopMixing(); } diff --git a/src/rpc/privatesend.cpp b/src/rpc/privatesend.cpp index 28bfeb6b6097..78777c90d9dd 100644 --- a/src/rpc/privatesend.cpp +++ b/src/rpc/privatesend.cpp @@ -43,6 +43,8 @@ UniValue privatesend(const JSONRPCRequest& request) } } + auto it = privateSendClientManagers.find(pwallet->GetName()); + if (request.params[0].get_str() == "start") { { LOCK(pwallet->cs_wallet); @@ -50,21 +52,21 @@ UniValue privatesend(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please unlock wallet for mixing with walletpassphrase first."); } - if (!privateSendClientManager.StartMixing(pwallet)) { + if (!it->second->StartMixing(pwallet)) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing has been started already."); } - bool result = privateSendClientManager.DoAutomaticDenominating(*g_connman); - return "Mixing " + (result ? "started successfully" : ("start failed: " + privateSendClientManager.GetStatuses() + ", will retry")); + bool result = it->second->DoAutomaticDenominating(*g_connman); + return "Mixing " + (result ? "started successfully" : ("start failed: " + it->second->GetStatuses() + ", will retry")); } if (request.params[0].get_str() == "stop") { - privateSendClientManager.StopMixing(); + it->second->StopMixing(); return "Mixing was stopped"; } if (request.params[0].get_str() == "reset") { - privateSendClientManager.ResetPool(); + it->second->ResetPool(); return "Mixing was reset"; } @@ -148,7 +150,7 @@ UniValue getprivatesendinfo(const JSONRPCRequest& request) return obj; } - privateSendClientManager.GetJsonInfo(obj); + privateSendClientManagers.at(pwallet->GetName())->GetJsonInfo(obj); obj.pushKV("keys_left", pwallet->nKeysLeftSinceAutoBackup); obj.push_back(Pair("warnings", pwallet->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index b261fa5d68ef..1cc4e10d9a6a 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -371,12 +371,13 @@ void WalletInit::Start(CScheduler& scheduler) void WalletInit::Flush() { - if (privateSendClientOptions.fEnablePrivateSend) { - // Stop PrivateSend, release keys - privateSendClientManager.ResetPool(); - privateSendClientManager.StopMixing(); - } for (CWallet* pwallet : GetWallets()) { + if (privateSendClientOptions.fEnablePrivateSend) { + // Stop PrivateSend, release keys + auto it = privateSendClientManagers.find(pwallet->GetName()); + it->second->ResetPool(); + it->second->StopMixing(); + } pwallet->Flush(false); } } @@ -408,13 +409,17 @@ void WalletInit::InitPrivateSendSettings() { if (!HasWallets()) { privateSendClientOptions.fEnablePrivateSend = false; - privateSendClientManager.StopMixing(); } else { privateSendClientOptions.fEnablePrivateSend = gArgs.GetBoolArg("-enableprivatesend", true); - if (GetWallets()[0]->IsLocked()) { - privateSendClientManager.StopMixing(); - } else if (gArgs.GetBoolArg("-privatesendautostart", DEFAULT_PRIVATESEND_AUTOSTART)) { - privateSendClientManager.StartMixing(GetWallets()[0]); + } + bool fAutoStart = gArgs.GetBoolArg("-privatesendautostart", DEFAULT_PRIVATESEND_AUTOSTART); + if (privateSendClientOptions.fEnablePrivateSend) { + for (auto& pwallet : GetWallets()) { + if (pwallet->IsLocked()) { + privateSendClientManagers.at(pwallet->GetName())->StopMixing(); + } else if (fAutoStart) { + privateSendClientManagers.at(pwallet->GetName())->StartMixing(pwallet); + } } } privateSendClientOptions.fPrivateSendMultiSession = gArgs.GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION); @@ -427,7 +432,7 @@ void WalletInit::InitPrivateSendSettings() if (privateSendClientOptions.fEnablePrivateSend) { LogPrintf("PrivateSend: autostart=%d, multisession=%d," /* Continued */ "sessions=%d, rounds=%d, amount=%d, denoms_goal=%d, denoms_hardcap=%d\n", - privateSendClientManager.IsMixing(), privateSendClientOptions.fPrivateSendMultiSession, + fAutoStart, privateSendClientOptions.fPrivateSendMultiSession, privateSendClientOptions.nPrivateSendSessions, privateSendClientOptions.nPrivateSendRounds, privateSendClientOptions.nPrivateSendAmount, privateSendClientOptions.nPrivateSendDenomsGoal, privateSendClientOptions.nPrivateSendDenomsHardCap); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 698c2e5dd528..cf8663a09a92 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -53,6 +53,7 @@ bool AddWallet(CWallet* wallet) std::vector::const_iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet); if (i != vpwallets.end()) return false; vpwallets.push_back(wallet); + privateSendClientManagers.emplace(std::make_pair(wallet->GetName(), new CPrivateSendClientManager())); return true; } @@ -63,6 +64,10 @@ bool RemoveWallet(CWallet* wallet) std::vector::iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet); if (i == vpwallets.end()) return false; vpwallets.erase(i); + auto it = privateSendClientManagers.find(wallet->GetName()); + delete it->second; + it->second = nullptr; + privateSendClientManagers.erase(it); return true; } @@ -4342,7 +4347,7 @@ bool CWallet::NewKeyPool() batch.ErasePool(nIndex); } setExternalKeyPool.clear(); - privateSendClientManager.StopMixing(); + privateSendClientManagers.at(GetName())->StopMixing(); nKeysLeftSinceAutoBackup = 0; m_pool_key_to_index.clear(); From 4ac00e558926817aa0417b0df23fb5f5c795642f Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Fri, 17 Jul 2020 02:27:35 +0300 Subject: [PATCH 09/13] Do not clear the object pased into `CPrivateSendClient*::GetJsonInfo()` Just verify that it's of a proper type instead --- src/privatesend/privatesend-client.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/privatesend/privatesend-client.cpp b/src/privatesend/privatesend-client.cpp index e5824a5d5342..9ff9ce9c7d4a 100644 --- a/src/privatesend/privatesend-client.cpp +++ b/src/privatesend/privatesend-client.cpp @@ -1814,8 +1814,7 @@ void CPrivateSendClientManager::DoMaintenance(CConnman& connman) void CPrivateSendClientSession::GetJsonInfo(UniValue& obj) const { - obj.clear(); - obj.setObject(); + assert(obj.isObject()); if (mixingMasternode != nullptr) { assert(mixingMasternode->pdmnState); obj.pushKV("protxhash", mixingMasternode->proTxHash.ToString()); @@ -1830,8 +1829,7 @@ void CPrivateSendClientSession::GetJsonInfo(UniValue& obj) const void CPrivateSendClientManager::GetJsonInfo(UniValue& obj) const { LOCK(cs_deqsessions); - obj.clear(); - obj.setObject(); + assert(obj.isObject()); obj.pushKV("running", IsMixing()); UniValue arrSessions(UniValue::VARR); From 50b09b88e40299f81e25aaa5a1614ad4f7140426 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Fri, 17 Jul 2020 02:30:00 +0300 Subject: [PATCH 10/13] Add `CPrivateSendClientOptions::GetJsonInfo()` --- src/privatesend/privatesend-client.cpp | 12 ++++++++++++ src/privatesend/privatesend-client.h | 2 ++ src/rpc/privatesend.cpp | 11 +++-------- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/privatesend/privatesend-client.cpp b/src/privatesend/privatesend-client.cpp index 9ff9ce9c7d4a..1cb8020f701a 100644 --- a/src/privatesend/privatesend-client.cpp +++ b/src/privatesend/privatesend-client.cpp @@ -1843,6 +1843,18 @@ void CPrivateSendClientManager::GetJsonInfo(UniValue& obj) const obj.pushKV("sessions", arrSessions); } +void CPrivateSendClientOptions::GetJsonInfo(UniValue& obj) const +{ + assert(obj.isObject()); + obj.pushKV("enabled", privateSendClientOptions.fEnablePrivateSend); + obj.pushKV("multisession", privateSendClientOptions.fPrivateSendMultiSession); + obj.pushKV("max_sessions", privateSendClientOptions.nPrivateSendSessions); + obj.pushKV("max_rounds", privateSendClientOptions.nPrivateSendRounds); + obj.pushKV("max_amount", privateSendClientOptions.nPrivateSendAmount); + obj.pushKV("denoms_goal", privateSendClientOptions.nPrivateSendDenomsGoal); + obj.pushKV("denoms_hardcap", privateSendClientOptions.nPrivateSendDenomsHardCap); +} + void DoPrivateSendMaintenance(CConnman& connman) { privateSendClientQueueManager.DoMaintenance(); diff --git a/src/privatesend/privatesend-client.h b/src/privatesend/privatesend-client.h index 0db1527e8f1b..e716c9df5808 100644 --- a/src/privatesend/privatesend-client.h +++ b/src/privatesend/privatesend-client.h @@ -298,6 +298,8 @@ class CPrivateSendClientOptions fPrivateSendMultiSession(DEFAULT_PRIVATESEND_MULTISESSION) { } + + void GetJsonInfo(UniValue& obj) const; }; void DoPrivateSendMaintenance(CConnman& connman); diff --git a/src/rpc/privatesend.cpp b/src/rpc/privatesend.cpp index 78777c90d9dd..085cced8227a 100644 --- a/src/rpc/privatesend.cpp +++ b/src/rpc/privatesend.cpp @@ -136,14 +136,9 @@ UniValue getprivatesendinfo(const JSONRPCRequest& request) #ifdef ENABLE_WALLET - obj.pushKV("enabled", privateSendClientOptions.fEnablePrivateSend); - obj.pushKV("multisession", privateSendClientOptions.fPrivateSendMultiSession); - obj.pushKV("max_sessions", privateSendClientOptions.nPrivateSendSessions); - obj.pushKV("max_rounds", privateSendClientOptions.nPrivateSendRounds); - obj.pushKV("max_amount", privateSendClientOptions.nPrivateSendAmount); - obj.pushKV("denoms_goal", privateSendClientOptions.nPrivateSendDenomsGoal); - obj.pushKV("denoms_hardcap", privateSendClientOptions.nPrivateSendDenomsHardCap); - obj.pushKV("queue_size", privateSendClientQueueManager.GetQueueSize()); + privateSendClientOptions.GetJsonInfo(obj); + + obj.pushKV("queue_size", privateSendClientQueueManager.GetQueueSize()); CWallet* const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) { From 8fedc083fc8cf4bb0b2c0ab36515b44989306383 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Fri, 17 Jul 2020 02:25:11 +0200 Subject: [PATCH 11/13] privatesend|qt|rpc|wallet: Improve CPrivateSendClientOptions - Makes it singleton to make sure we always only have one instance of it - Protects its members by making them private and adding set/getters - Makes it thread safe --- src/privatesend/privatesend-client.cpp | 134 +++++++++++++++++-------- src/privatesend/privatesend-client.h | 30 +++++- src/qt/bitcoingui.cpp | 4 +- src/qt/coincontroldialog.cpp | 4 +- src/qt/optionsmodel.cpp | 18 ++-- src/qt/overviewpage.cpp | 24 ++--- src/qt/walletmodel.cpp | 5 +- src/rpc/privatesend.cpp | 4 +- src/wallet/init.cpp | 45 +++------ src/wallet/rpcwallet.cpp | 4 +- src/wallet/wallet.cpp | 24 ++--- 11 files changed, 178 insertions(+), 118 deletions(-) diff --git a/src/privatesend/privatesend-client.cpp b/src/privatesend/privatesend-client.cpp index 1cb8020f701a..fe4cc044eac7 100644 --- a/src/privatesend/privatesend-client.cpp +++ b/src/privatesend/privatesend-client.cpp @@ -24,12 +24,14 @@ std::map privateSendClientManagers; CPrivateSendClientQueueManager privateSendClientQueueManager; -CPrivateSendClientOptions privateSendClientOptions; + +CPrivateSendClientOptions* CPrivateSendClientOptions::_instance{nullptr}; +std::once_flag CPrivateSendClientOptions::onceFlag; void CPrivateSendClientQueueManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61) { if (fMasternodeMode) return; - if (!privateSendClientOptions.fEnablePrivateSend) return; + if (!CPrivateSendClientOptions::IsEnabled()) return; if (!masternodeSync.IsBlockchainSynced()) return; if (!CheckDiskSpace()) { @@ -122,7 +124,7 @@ void CPrivateSendClientQueueManager::ProcessMessage(CNode* pfrom, const std::str void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61) { if (fMasternodeMode) return; - if (!privateSendClientOptions.fEnablePrivateSend) return; + if (!CPrivateSendClientOptions::IsEnabled()) return; if (!masternodeSync.IsBlockchainSynced()) return; if (!CheckDiskSpace()) { @@ -145,7 +147,7 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61) { if (fMasternodeMode) return; - if (!privateSendClientOptions.fEnablePrivateSend) return; + if (!CPrivateSendClientOptions::IsEnabled()) return; if (!masternodeSync.IsBlockchainSynced()) return; if (strCommand == NetMsgType::DSSTATUSUPDATE) { @@ -287,7 +289,7 @@ void CPrivateSendClientSession::SetNull() // void CPrivateSendClientSession::UnlockCoins() { - if (!privateSendClientOptions.fEnablePrivateSend) return; + if (!CPrivateSendClientOptions::IsEnabled()) return; while (true) { TRY_LOCK(mixingWallet->cs_wallet, lockWallet); @@ -427,7 +429,7 @@ void CPrivateSendClientManager::CheckTimeout() { if (fMasternodeMode) return; - if (!privateSendClientOptions.fEnablePrivateSend || !IsMixing()) return; + if (!CPrivateSendClientOptions::IsEnabled() || !IsMixing()) return; LOCK(cs_deqsessions); for (auto& session : deqSessions) { @@ -551,7 +553,7 @@ void CPrivateSendClientSession::ProcessPoolStateUpdate(CPrivateSendStatusUpdate // bool CPrivateSendClientSession::SignFinalTransaction(const CTransaction& finalTransactionNew, CNode* pnode, CConnman& connman) { - if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !mixingWallet) return false; if (fMasternodeMode || pnode == nullptr) return false; if (!mixingMasternode) return false; @@ -693,14 +695,14 @@ bool CPrivateSendClientManager::WaitForAnotherBlock() { if (!masternodeSync.IsBlockchainSynced()) return true; - if (privateSendClientOptions.fPrivateSendMultiSession) return false; + if (CPrivateSendClientOptions::IsMultiSessionEnabled()) return false; return nCachedBlockHeight - nCachedLastSuccessBlock < nMinBlocksToWait; } bool CPrivateSendClientManager::CheckAutomaticBackup() { - if (!privateSendClientOptions.fEnablePrivateSend || !IsMixing()) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !IsMixing()) return false; switch (nWalletBackups) { case 0: @@ -778,7 +780,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool return false; } - if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !mixingWallet) return false; CAmount nBalanceNeedsAnonymized; @@ -811,7 +813,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool // check if there is anything left to do CAmount nBalanceAnonymized = mixingWallet->GetAnonymizedBalance(); - nBalanceNeedsAnonymized = privateSendClientOptions.nPrivateSendAmount*COIN - nBalanceAnonymized; + nBalanceNeedsAnonymized = CPrivateSendClientOptions::GetAmount() * COIN - nBalanceAnonymized; if (nBalanceNeedsAnonymized < 0) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- Nothing to do\n"); @@ -843,7 +845,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool CAmount nBalanceDenominatedConf = mixingWallet->GetDenominatedBalance(); CAmount nBalanceDenominatedUnconf = mixingWallet->GetDenominatedBalance(true); CAmount nBalanceDenominated = nBalanceDenominatedConf + nBalanceDenominatedUnconf; - CAmount nBalanceToDenominate = privateSendClientOptions.nPrivateSendAmount * COIN - nBalanceDenominated; + CAmount nBalanceToDenominate = CPrivateSendClientOptions::GetAmount() * COIN - nBalanceDenominated; // adjust nBalanceNeedsAnonymized to consume final denom if (nBalanceDenominated - nBalanceAnonymized > nBalanceNeedsAnonymized) { @@ -906,7 +908,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool SetNull(); // should be no unconfirmed denoms in non-multi-session mode - if (!privateSendClientOptions.fPrivateSendMultiSession && nBalanceDenominatedUnconf > 0) { + if (!CPrivateSendClientOptions::IsMultiSessionEnabled() && nBalanceDenominatedUnconf > 0) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- Found unconfirmed denominated outputs, will wait till they confirm to continue.\n"); strAutoDenomResult = _("Found unconfirmed denominated outputs, will wait till they confirm to continue."); return false; @@ -950,7 +952,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool fDryRun) { if (fMasternodeMode) return false; // no client-side mixing on masternodes - if (!privateSendClientOptions.fEnablePrivateSend || !IsMixing()) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !IsMixing()) return false; if (!masternodeSync.IsBlockchainSynced()) { strAutoDenomResult = _("Can't mix while sync in progress."); @@ -976,7 +978,7 @@ bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool LOCK(cs_deqsessions); bool fResult = true; - if ((int)deqSessions.size() < privateSendClientOptions.nPrivateSendSessions) { + if ((int)deqSessions.size() < CPrivateSendClientOptions::GetSessions()) { deqSessions.emplace_back(mixingWallet); } for (auto& session : deqSessions) { @@ -1040,7 +1042,7 @@ CDeterministicMNCPtr CPrivateSendClientManager::GetRandomNotUsedMasternode() bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman) { - if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !mixingWallet) return false; auto mnList = deterministicMNManager->GetListAtChainTip(); @@ -1099,7 +1101,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman) { - if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !mixingWallet) return false; if (nBalanceNeedsAnonymized <= 0) return false; int nTries = 0; @@ -1252,7 +1254,7 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) std::vector > vecInputsByRounds; - for (int i = 0; i < privateSendClientOptions.nPrivateSendRounds; i++) { + for (int i = 0; i < CPrivateSendClientOptions::GetRounds(); i++) { if (PrepareDenominate(i, i, strError, vecPSInOutPairs, vecPSInOutPairsTmp, true)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i); vecInputsByRounds.emplace_back(i, vecPSInOutPairsTmp.size()); @@ -1278,7 +1280,7 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) } // We failed? That's strange but let's just make final attempt and try to mix everything - if (PrepareDenominate(0, privateSendClientOptions.nPrivateSendRounds - 1, strError, vecPSInOutPairs, vecPSInOutPairsTmp)) { + if (PrepareDenominate(0, CPrivateSendClientOptions::GetRounds() - 1, strError, vecPSInOutPairs, vecPSInOutPairsTmp)) { LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for all rounds, success\n"); return SendDenominate(vecPSInOutPairsTmp, connman); } @@ -1291,7 +1293,7 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std::vector >& vecPSInOutPairsRet) { - if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !mixingWallet) return false; if (mixingWallet->IsLocked(true)) { strErrorRet = "Wallet locked, unable to create transaction!"; @@ -1376,7 +1378,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds // Create collaterals by looping through inputs grouped by addresses bool CPrivateSendClientSession::MakeCollateralAmounts(CConnman& connman) { - if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !mixingWallet) return false; LOCK2(cs_main, mempool.cs); LOCK(mixingWallet->cs_wallet); @@ -1420,7 +1422,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta AssertLockHeld(mempool.cs); AssertLockHeld(mixingWallet->cs_wallet); - if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !mixingWallet) return false; // Skip way too tiny amounts if (tallyItem.nAmount < CPrivateSend::GetCollateralAmount()) { @@ -1515,7 +1517,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta // Create denominations by looping through inputs grouped by addresses bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, CConnman& connman) { - if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !mixingWallet) return false; LOCK2(cs_main, mempool.cs); LOCK(mixingWallet->cs_wallet); @@ -1553,7 +1555,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, AssertLockHeld(mempool.cs); AssertLockHeld(mixingWallet->cs_wallet); - if (!privateSendClientOptions.fEnablePrivateSend || !mixingWallet) return false; + if (!CPrivateSendClientOptions::IsEnabled() || !mixingWallet) return false; std::vector vecSend; CKeyHolderStorage keyHolderStorageDenom; @@ -1623,7 +1625,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, }; // add each output up to 11 times or until it can't be added again or until we reach nPrivateSendDenomsGoal - while (needMoreOutputs() && nOutputs <= 10 && currentDenomIt->second < privateSendClientOptions.nPrivateSendDenomsGoal) { + while (needMoreOutputs() && nOutputs <= 10 && currentDenomIt->second < CPrivateSendClientOptions::GetDenomsGoal()) { CScript scriptDenom = keyHolderStorageDenom.AddKey(mixingWallet); vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false}); @@ -1646,7 +1648,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, for (const auto it : mapDenomCount) { // Check if this specific denom could use another loop, check that there aren't nPrivateSendDenomsGoal of this // denom and that our nValueLeft/nBalanceToDenominate is enough to create one of these denoms, if so, loop again. - if (it.second < privateSendClientOptions.nPrivateSendDenomsGoal && (nValueLeft >= it.first + nOutputFee) && nBalanceToDenominate > 0) { + if (it.second < CPrivateSendClientOptions::GetDenomsGoal() && (nValueLeft >= it.first + nOutputFee) && nBalanceToDenominate > 0) { finished = false; LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- 1 - NOT finished - nDenomValue: %f, count: %d, nValueLeft: %f, nBalanceToDenominate: %f\n", @@ -1686,7 +1688,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, auto it = mapDenomCount.find(nDenomValue); for (int i = 0; i < denomsToCreate; i++) { // Never go above the cap unless it's the largest denom - if (nDenomValue != nLargestDenomValue && it->second >= privateSendClientOptions.nPrivateSendDenomsHardCap) break; + if (nDenomValue != nLargestDenomValue && it->second >= CPrivateSendClientOptions::GetDenomsHardCap()) break; CScript scriptDenom = keyHolderStorageDenom.AddKey(mixingWallet); vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false}); @@ -1785,7 +1787,7 @@ void CPrivateSendClientManager::UpdatedBlockTip(const CBlockIndex* pindex) void CPrivateSendClientQueueManager::DoMaintenance() { - if (!privateSendClientOptions.fEnablePrivateSend) return; + if (!CPrivateSendClientOptions::IsEnabled()) return; if (fMasternodeMode) return; // no client-side mixing on masternodes if (!masternodeSync.IsBlockchainSynced() || ShutdownRequested()) return; @@ -1795,7 +1797,7 @@ void CPrivateSendClientQueueManager::DoMaintenance() void CPrivateSendClientManager::DoMaintenance(CConnman& connman) { - if (!privateSendClientOptions.fEnablePrivateSend) return; + if (!CPrivateSendClientOptions::IsEnabled()) return; if (fMasternodeMode) return; // no client-side mixing on masternodes if (!masternodeSync.IsBlockchainSynced() || ShutdownRequested()) return; @@ -1843,18 +1845,6 @@ void CPrivateSendClientManager::GetJsonInfo(UniValue& obj) const obj.pushKV("sessions", arrSessions); } -void CPrivateSendClientOptions::GetJsonInfo(UniValue& obj) const -{ - assert(obj.isObject()); - obj.pushKV("enabled", privateSendClientOptions.fEnablePrivateSend); - obj.pushKV("multisession", privateSendClientOptions.fPrivateSendMultiSession); - obj.pushKV("max_sessions", privateSendClientOptions.nPrivateSendSessions); - obj.pushKV("max_rounds", privateSendClientOptions.nPrivateSendRounds); - obj.pushKV("max_amount", privateSendClientOptions.nPrivateSendAmount); - obj.pushKV("denoms_goal", privateSendClientOptions.nPrivateSendDenomsGoal); - obj.pushKV("denoms_hardcap", privateSendClientOptions.nPrivateSendDenomsHardCap); -} - void DoPrivateSendMaintenance(CConnman& connman) { privateSendClientQueueManager.DoMaintenance(); @@ -1862,3 +1852,65 @@ void DoPrivateSendMaintenance(CConnman& connman) pair.second->DoMaintenance(connman); } } + +CPrivateSendClientOptions& CPrivateSendClientOptions::Get() +{ + std::call_once(onceFlag, CPrivateSendClientOptions::Init); + assert(CPrivateSendClientOptions::_instance); + return *CPrivateSendClientOptions::_instance; +} + +void CPrivateSendClientOptions::SetEnabled(bool fEnabled) +{ + CPrivateSendClientOptions& options = CPrivateSendClientOptions::Get(); + LOCK(options.cs_ps_options); + options.fEnablePrivateSend = fEnabled; +} + +void CPrivateSendClientOptions::SetMultiSessionEnabled(bool fEnabled) +{ + CPrivateSendClientOptions& options = CPrivateSendClientOptions::Get(); + LOCK(options.cs_ps_options); + options.fPrivateSendMultiSession = fEnabled; +} + +void CPrivateSendClientOptions::SetRounds(int nRounds) +{ + CPrivateSendClientOptions& options = CPrivateSendClientOptions::Get(); + LOCK(options.cs_ps_options); + options.nPrivateSendRounds = nRounds; +} + +void CPrivateSendClientOptions::SetAmount(CAmount amount) +{ + CPrivateSendClientOptions& options = CPrivateSendClientOptions::Get(); + LOCK(options.cs_ps_options); + options.nPrivateSendAmount = amount; +} + +void CPrivateSendClientOptions::Init() +{ + assert(!CPrivateSendClientOptions::_instance); + static CPrivateSendClientOptions instance; + LOCK(instance.cs_ps_options); + instance.fPrivateSendMultiSession = gArgs.GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION); + instance.nPrivateSendSessions = std::min(std::max((int)gArgs.GetArg("-privatesendsessions", DEFAULT_PRIVATESEND_SESSIONS), MIN_PRIVATESEND_SESSIONS), MAX_PRIVATESEND_SESSIONS); + instance.nPrivateSendRounds = std::min(std::max((int)gArgs.GetArg("-privatesendrounds", DEFAULT_PRIVATESEND_ROUNDS), MIN_PRIVATESEND_ROUNDS), MAX_PRIVATESEND_ROUNDS); + instance.nPrivateSendAmount = std::min(std::max((int)gArgs.GetArg("-privatesendamount", DEFAULT_PRIVATESEND_AMOUNT), MIN_PRIVATESEND_AMOUNT), MAX_PRIVATESEND_AMOUNT); + instance.nPrivateSendDenomsGoal = std::min(std::max((int)gArgs.GetArg("-privatesenddenomsgoal", DEFAULT_PRIVATESEND_DENOMS_GOAL), MIN_PRIVATESEND_DENOMS_GOAL), MAX_PRIVATESEND_DENOMS_GOAL); + instance.nPrivateSendDenomsHardCap = std::min(std::max((int)gArgs.GetArg("-privatesenddenomshardcap", DEFAULT_PRIVATESEND_DENOMS_HARDCAP), MIN_PRIVATESEND_DENOMS_HARDCAP), MAX_PRIVATESEND_DENOMS_HARDCAP); + CPrivateSendClientOptions::_instance = &instance; +} + +void CPrivateSendClientOptions::GetJsonInfo(UniValue& obj) +{ + assert(obj.isObject()); + CPrivateSendClientOptions& options = CPrivateSendClientOptions::Get(); + obj.pushKV("enabled", options.fEnablePrivateSend); + obj.pushKV("multisession", options.fPrivateSendMultiSession); + obj.pushKV("max_sessions", options.nPrivateSendSessions); + obj.pushKV("max_rounds", options.nPrivateSendRounds); + obj.pushKV("max_amount", options.nPrivateSendAmount); + obj.pushKV("denoms_goal", options.nPrivateSendDenomsGoal); + obj.pushKV("denoms_hardcap", options.nPrivateSendDenomsHardCap); +} diff --git a/src/privatesend/privatesend-client.h b/src/privatesend/privatesend-client.h index e716c9df5808..6b979f94a745 100644 --- a/src/privatesend/privatesend-client.h +++ b/src/privatesend/privatesend-client.h @@ -61,9 +61,6 @@ extern std::map privateSendClient // The object to track mixing queues extern CPrivateSendClientQueueManager privateSendClientQueueManager; -// The object to store application wide mixing options -extern CPrivateSendClientOptions privateSendClientOptions; - class CPendingDsaRequest { private: @@ -281,6 +278,27 @@ class CPrivateSendClientManager class CPrivateSendClientOptions { public: + static int GetSessions() { return CPrivateSendClientOptions::Get().nPrivateSendSessions; } + static int GetRounds() { return CPrivateSendClientOptions::Get().nPrivateSendRounds; } + static int GetAmount() { return CPrivateSendClientOptions::Get().nPrivateSendAmount; } + static int GetDenomsGoal() { return CPrivateSendClientOptions::Get().nPrivateSendDenomsGoal; } + static int GetDenomsHardCap() { return CPrivateSendClientOptions::Get().nPrivateSendDenomsHardCap; } + + static void SetEnabled(bool fEnabled); + static void SetMultiSessionEnabled(bool fEnabled); + static void SetRounds(int nRounds); + static void SetAmount(CAmount amount); + + static int IsEnabled() { return CPrivateSendClientOptions::Get().fEnablePrivateSend; } + static int IsMultiSessionEnabled() { return CPrivateSendClientOptions::Get().fPrivateSendMultiSession; } + + static void GetJsonInfo(UniValue& obj); + +private: + static CPrivateSendClientOptions* _instance; + static std::once_flag onceFlag; + + CCriticalSection cs_ps_options; int nPrivateSendSessions; int nPrivateSendRounds; int nPrivateSendAmount; @@ -299,7 +317,11 @@ class CPrivateSendClientOptions { } - void GetJsonInfo(UniValue& obj) const; + CPrivateSendClientOptions(const CPrivateSendClientOptions& other) = delete; + CPrivateSendClientOptions& operator=(const CPrivateSendClientOptions&) = delete; + + static CPrivateSendClientOptions& Get(); + static void Init(); }; void DoPrivateSendMaintenance(CConnman& connman); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 7ec28b45fcc7..c0f3d3dfb0ec 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -780,8 +780,8 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) sendCoinsAction->setEnabled(enabled); sendCoinsMenuAction->setEnabled(enabled); #ifdef ENABLE_WALLET - privateSendCoinsAction->setEnabled(enabled && privateSendClientOptions.fEnablePrivateSend); - privateSendCoinsMenuAction->setEnabled(enabled && privateSendClientOptions.fEnablePrivateSend); + privateSendCoinsAction->setEnabled(enabled && CPrivateSendClientOptions::IsEnabled()); + privateSendCoinsMenuAction->setEnabled(enabled && CPrivateSendClientOptions::IsEnabled()); #else privateSendCoinsAction->setEnabled(enabled); privateSendCoinsMenuAction->setEnabled(enabled); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 28f8f3169a3f..0779892a584e 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -501,7 +501,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // unselect non-fully-mixed, this can happen when users switch from Send to PrivateSend if (coinControl()->IsUsingPrivateSend()) { int nRounds = model->getRealOutpointPrivateSendRounds(outpt); - if (nRounds < privateSendClientOptions.nPrivateSendRounds) { + if (nRounds < CPrivateSendClientOptions::GetRounds()) { coinControl()->UnSelect(outpt); fUnselectedNonMixed = true; continue; @@ -707,7 +707,7 @@ void CoinControlDialog::updateView() COutPoint outpoint = COutPoint(out.tx->tx->GetHash(), out.i); int nRounds = model->getRealOutpointPrivateSendRounds(outpoint); - if ((coinControl()->IsUsingPrivateSend() && nRounds >= privateSendClientOptions.nPrivateSendRounds) || !(coinControl()->IsUsingPrivateSend())) { + if ((coinControl()->IsUsingPrivateSend() && nRounds >= CPrivateSendClientOptions::GetRounds()) || !(coinControl()->IsUsingPrivateSend())) { nSum += out.tx->tx->vout[out.i].nValue; nChildren++; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 83465d330c82..463269a8fa91 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -138,7 +138,7 @@ void OptionsModel::Init(bool resetSettings) settings.setValue("nPrivateSendRounds", DEFAULT_PRIVATESEND_ROUNDS); if (!gArgs.SoftSetArg("-privatesendrounds", settings.value("nPrivateSendRounds").toString().toStdString())) addOverriddenOption("-privatesendrounds"); - privateSendClientOptions.nPrivateSendRounds = settings.value("nPrivateSendRounds").toInt(); + CPrivateSendClientOptions::SetRounds(settings.value("nPrivateSendRounds").toInt()); if (!settings.contains("nPrivateSendAmount")) { // for migration from old settings @@ -149,13 +149,13 @@ void OptionsModel::Init(bool resetSettings) } if (!gArgs.SoftSetArg("-privatesendamount", settings.value("nPrivateSendAmount").toString().toStdString())) addOverriddenOption("-privatesendamount"); - privateSendClientOptions.nPrivateSendAmount = settings.value("nPrivateSendAmount").toInt(); + CPrivateSendClientOptions::SetAmount(settings.value("nPrivateSendAmount").toInt()); if (!settings.contains("fPrivateSendMultiSession")) settings.setValue("fPrivateSendMultiSession", DEFAULT_PRIVATESEND_MULTISESSION); if (!gArgs.SoftSetBoolArg("-privatesendmultisession", settings.value("fPrivateSendMultiSession").toBool())) addOverriddenOption("-privatesendmultisession"); - privateSendClientOptions.fPrivateSendMultiSession = settings.value("fPrivateSendMultiSession").toBool(); + CPrivateSendClientOptions::SetMultiSessionEnabled(settings.value("fPrivateSendMultiSession").toBool()); #endif // Network @@ -470,24 +470,24 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in case PrivateSendRounds: if (settings.value("nPrivateSendRounds") != value) { - privateSendClientOptions.nPrivateSendRounds = value.toInt(); - settings.setValue("nPrivateSendRounds", privateSendClientOptions.nPrivateSendRounds); + CPrivateSendClientOptions::SetRounds(value.toInt()); + settings.setValue("nPrivateSendRounds", CPrivateSendClientOptions::GetRounds()); Q_EMIT privateSendRoundsChanged(); } break; case PrivateSendAmount: if (settings.value("nPrivateSendAmount") != value) { - privateSendClientOptions.nPrivateSendAmount = value.toInt(); - settings.setValue("nPrivateSendAmount", privateSendClientOptions.nPrivateSendAmount); + CPrivateSendClientOptions::SetAmount(value.toInt()); + settings.setValue("nPrivateSendAmount", CPrivateSendClientOptions::GetAmount()); Q_EMIT privateSentAmountChanged(); } break; case PrivateSendMultiSession: if (settings.value("fPrivateSendMultiSession") != value) { - privateSendClientOptions.fPrivateSendMultiSession = value.toBool(); - settings.setValue("fPrivateSendMultiSession", privateSendClientOptions.fPrivateSendMultiSession); + CPrivateSendClientOptions::SetMultiSessionEnabled(value.toBool()); + settings.setValue("fPrivateSendMultiSession", CPrivateSendClientOptions::IsMultiSessionEnabled()); } break; #endif diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 9b5df879df80..33e40c4cfa98 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -172,7 +172,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) // start with displaying the "out of sync" warnings showOutOfSyncWarning(true); - if(!privateSendClientOptions.fEnablePrivateSend) return; + if (!CPrivateSendClientOptions::IsEnabled()) return; // Disable any PS UI for masternode or when autobackup is disabled or failed for whatever reason if(fMasternodeMode || nWalletBackups <= 0){ @@ -310,7 +310,7 @@ void OverviewPage::setWalletModel(WalletModel *model) // Initialize PS UI privateSendStatus(true); - if(!privateSendClientOptions.fEnablePrivateSend) return; + if (!CPrivateSendClientOptions::IsEnabled()) return; connect(model->getOptionsModel(), SIGNAL(privateSendRoundsChanged()), this, SLOT(updatePrivateSendProgress())); connect(model->getOptionsModel(), SIGNAL(privateSentAmountChanged()), this, SLOT(updatePrivateSendProgress())); @@ -359,7 +359,7 @@ void OverviewPage::updatePrivateSendProgress() if(!walletModel) return; QString strAmountAndRounds; - QString strPrivateSendAmount = BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, privateSendClientOptions.nPrivateSendAmount * COIN, false, BitcoinUnits::separatorAlways); + QString strPrivateSendAmount = BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CPrivateSendClientOptions::GetAmount() * COIN, false, BitcoinUnits::separatorAlways); if(currentBalance == 0) { @@ -368,7 +368,7 @@ void OverviewPage::updatePrivateSendProgress() // when balance is zero just show info from settings strPrivateSendAmount = strPrivateSendAmount.remove(strPrivateSendAmount.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1); - strAmountAndRounds = strPrivateSendAmount + " / " + tr("%n Rounds", "", privateSendClientOptions.nPrivateSendRounds); + strAmountAndRounds = strPrivateSendAmount + " / " + tr("%n Rounds", "", CPrivateSendClientOptions::GetRounds()); ui->labelAmountRounds->setToolTip(tr("No inputs detected")); ui->labelAmountRounds->setText(strAmountAndRounds); @@ -380,15 +380,15 @@ void OverviewPage::updatePrivateSendProgress() CAmount nMaxToAnonymize = nAnonymizableBalance + currentAnonymizedBalance; // If it's more than the anon threshold, limit to that. - if(nMaxToAnonymize > privateSendClientOptions.nPrivateSendAmount*COIN) nMaxToAnonymize = privateSendClientOptions.nPrivateSendAmount*COIN; + if (nMaxToAnonymize > CPrivateSendClientOptions::GetAmount() * COIN) nMaxToAnonymize = CPrivateSendClientOptions::GetAmount() * COIN; if(nMaxToAnonymize == 0) return; - if(nMaxToAnonymize >= privateSendClientOptions.nPrivateSendAmount * COIN) { + if (nMaxToAnonymize >= CPrivateSendClientOptions::GetAmount() * COIN) { ui->labelAmountRounds->setToolTip(tr("Found enough compatible inputs to mix %1") .arg(strPrivateSendAmount)); strPrivateSendAmount = strPrivateSendAmount.remove(strPrivateSendAmount.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1); - strAmountAndRounds = strPrivateSendAmount + " / " + tr("%n Rounds", "", privateSendClientOptions.nPrivateSendRounds); + strAmountAndRounds = strPrivateSendAmount + " / " + tr("%n Rounds", "", CPrivateSendClientOptions::GetRounds()); } else { QString strMaxToAnonymize = BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, nMaxToAnonymize, false, BitcoinUnits::separatorAlways); ui->labelAmountRounds->setToolTip(tr("Not enough compatible inputs to mix %2,
" @@ -399,7 +399,7 @@ void OverviewPage::updatePrivateSendProgress() strMaxToAnonymize = strMaxToAnonymize.remove(strMaxToAnonymize.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1); strAmountAndRounds = "" + QString(BitcoinUnits::factor(nDisplayUnit) == 1 ? "" : "~") + strMaxToAnonymize + - " / " + tr("%n Rounds", "", privateSendClientOptions.nPrivateSendRounds) + ""; + " / " + tr("%n Rounds", "", CPrivateSendClientOptions::GetRounds()) + ""; } ui->labelAmountRounds->setText(strAmountAndRounds); @@ -438,7 +438,7 @@ void OverviewPage::updatePrivateSendProgress() // apply some weights to them ... float denomWeight = 1; - float anonNormWeight = privateSendClientOptions.nPrivateSendRounds; + float anonNormWeight = CPrivateSendClientOptions::GetRounds(); float anonFullWeight = 2; float fullWeight = denomWeight + anonNormWeight + anonFullWeight; // ... and calculate the whole progress @@ -454,7 +454,7 @@ void OverviewPage::updatePrivateSendProgress() tr("Denominated") + ": %2%
" + tr("Partially mixed") + ": %3%
" + tr("Mixed") + ": %4%
" + - tr("Denominated inputs have %5 of %n rounds on average", "", privateSendClientOptions.nPrivateSendRounds)) + tr("Denominated inputs have %5 of %n rounds on average", "", CPrivateSendClientOptions::GetRounds())) .arg(progress).arg(denomPart).arg(anonNormPart).arg(anonFullPart) .arg(nAverageAnonymizedRounds); ui->privateSendProgress->setToolTip(strToolPip); @@ -462,10 +462,10 @@ void OverviewPage::updatePrivateSendProgress() void OverviewPage::updateAdvancedPSUI(bool fShowAdvancedPSUI) { this->fShowAdvancedPSUI = fShowAdvancedPSUI; - int nNumItems = (!privateSendClientOptions.fEnablePrivateSend || !fShowAdvancedPSUI) ? NUM_ITEMS : NUM_ITEMS_ADV; + int nNumItems = (!CPrivateSendClientOptions::IsEnabled() || !fShowAdvancedPSUI) ? NUM_ITEMS : NUM_ITEMS_ADV; SetupTransactionList(nNumItems); - if (!privateSendClientOptions.fEnablePrivateSend) return; + if (!CPrivateSendClientOptions::IsEnabled()) return; ui->framePrivateSend->setVisible(true); ui->labelCompletitionText->setVisible(fShowAdvancedPSUI); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 6f1e9566b9e9..61d03c10cf57 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -155,13 +155,12 @@ void WalletModel::pollBalanceChanged() if(!lockWallet) return; - if(fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks || privateSendClientOptions.nPrivateSendRounds != cachedPrivateSendRounds) - { + if (fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks || CPrivateSendClientOptions::GetRounds() != cachedPrivateSendRounds) { fForceCheckBalanceChanged = false; // Balance and number of transactions might have changed cachedNumBlocks = chainActive.Height(); - cachedPrivateSendRounds = privateSendClientOptions.nPrivateSendRounds; + cachedPrivateSendRounds = CPrivateSendClientOptions::GetRounds(); checkBalanceChanged(); if(transactionTableModel) diff --git a/src/rpc/privatesend.cpp b/src/rpc/privatesend.cpp index 085cced8227a..f2dd6c011e77 100644 --- a/src/rpc/privatesend.cpp +++ b/src/rpc/privatesend.cpp @@ -32,7 +32,7 @@ UniValue privatesend(const JSONRPCRequest& request) if (fMasternodeMode) throw JSONRPCError(RPC_INTERNAL_ERROR, "Client-side mixing is not supported on masternodes"); - if (!privateSendClientOptions.fEnablePrivateSend) { + if (!CPrivateSendClientOptions::IsEnabled()) { if (!gArgs.GetBoolArg("-enableprivatesend", true)) { // otherwise it's on by default, unless cmd line option says otherwise throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing is disabled via -enableprivatesend=0 command line option, remove it to enable mixing again"); @@ -136,7 +136,7 @@ UniValue getprivatesendinfo(const JSONRPCRequest& request) #ifdef ENABLE_WALLET - privateSendClientOptions.GetJsonInfo(obj); + CPrivateSendClientOptions::GetJsonInfo(obj); obj.pushKV("queue_size", privateSendClientQueueManager.GetQueueSize()); diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 1cc4e10d9a6a..891bd240f79a 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -364,7 +364,7 @@ void WalletInit::Start(CScheduler& scheduler) // Run a thread to flush wallet periodically scheduler.scheduleEvery(MaybeCompactWalletDB, 500); - if (!fMasternodeMode && privateSendClientOptions.fEnablePrivateSend) { + if (!fMasternodeMode && CPrivateSendClientOptions::IsEnabled()) { scheduler.scheduleEvery(std::bind(&DoPrivateSendMaintenance, std::ref(*g_connman)), 1 * 1000); } } @@ -372,7 +372,7 @@ void WalletInit::Start(CScheduler& scheduler) void WalletInit::Flush() { for (CWallet* pwallet : GetWallets()) { - if (privateSendClientOptions.fEnablePrivateSend) { + if (CPrivateSendClientOptions::IsEnabled()) { // Stop PrivateSend, release keys auto it = privateSendClientManagers.find(pwallet->GetName()); it->second->ResetPool(); @@ -407,37 +407,24 @@ void WalletInit::AutoLockMasternodeCollaterals() void WalletInit::InitPrivateSendSettings() { - if (!HasWallets()) { - privateSendClientOptions.fEnablePrivateSend = false; - } else { - privateSendClientOptions.fEnablePrivateSend = gArgs.GetBoolArg("-enableprivatesend", true); + CPrivateSendClientOptions::SetEnabled(HasWallets() ? gArgs.GetBoolArg("-enableprivatesend", true) : false); + if (!CPrivateSendClientOptions::IsEnabled()) { + return; } bool fAutoStart = gArgs.GetBoolArg("-privatesendautostart", DEFAULT_PRIVATESEND_AUTOSTART); - if (privateSendClientOptions.fEnablePrivateSend) { - for (auto& pwallet : GetWallets()) { - if (pwallet->IsLocked()) { - privateSendClientManagers.at(pwallet->GetName())->StopMixing(); - } else if (fAutoStart) { - privateSendClientManagers.at(pwallet->GetName())->StartMixing(pwallet); - } + for (auto& pwallet : GetWallets()) { + if (pwallet->IsLocked()) { + privateSendClientManagers.at(pwallet->GetName())->StopMixing(); + } else if (fAutoStart) { + privateSendClientManagers.at(pwallet->GetName())->StartMixing(pwallet); } } - privateSendClientOptions.fPrivateSendMultiSession = gArgs.GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION); - privateSendClientOptions.nPrivateSendSessions = std::min(std::max((int)gArgs.GetArg("-privatesendsessions", DEFAULT_PRIVATESEND_SESSIONS), MIN_PRIVATESEND_SESSIONS), MAX_PRIVATESEND_SESSIONS); - privateSendClientOptions.nPrivateSendRounds = std::min(std::max((int)gArgs.GetArg("-privatesendrounds", DEFAULT_PRIVATESEND_ROUNDS), MIN_PRIVATESEND_ROUNDS), MAX_PRIVATESEND_ROUNDS); - privateSendClientOptions.nPrivateSendAmount = std::min(std::max((int)gArgs.GetArg("-privatesendamount", DEFAULT_PRIVATESEND_AMOUNT), MIN_PRIVATESEND_AMOUNT), MAX_PRIVATESEND_AMOUNT); - privateSendClientOptions.nPrivateSendDenomsGoal = std::min(std::max((int)gArgs.GetArg("-privatesenddenomsgoal", DEFAULT_PRIVATESEND_DENOMS_GOAL), MIN_PRIVATESEND_DENOMS_GOAL), MAX_PRIVATESEND_DENOMS_GOAL); - privateSendClientOptions.nPrivateSendDenomsHardCap = std::min(std::max((int)gArgs.GetArg("-privatesenddenomshardcap", DEFAULT_PRIVATESEND_DENOMS_HARDCAP), MIN_PRIVATESEND_DENOMS_HARDCAP), MAX_PRIVATESEND_DENOMS_HARDCAP); - - if (privateSendClientOptions.fEnablePrivateSend) { - LogPrintf("PrivateSend: autostart=%d, multisession=%d," /* Continued */ - "sessions=%d, rounds=%d, amount=%d, denoms_goal=%d, denoms_hardcap=%d\n", - fAutoStart, privateSendClientOptions.fPrivateSendMultiSession, - privateSendClientOptions.nPrivateSendSessions, privateSendClientOptions.nPrivateSendRounds, - privateSendClientOptions.nPrivateSendAmount, - privateSendClientOptions.nPrivateSendDenomsGoal, privateSendClientOptions.nPrivateSendDenomsHardCap); - } - + LogPrintf("PrivateSend: autostart=%d, multisession=%d," /* Continued */ + "sessions=%d, rounds=%d, amount=%d, denoms_goal=%d, denoms_hardcap=%d\n", + fAutoStart, CPrivateSendClientOptions::IsMultiSessionEnabled(), + CPrivateSendClientOptions::GetSessions(), CPrivateSendClientOptions::GetRounds(), + CPrivateSendClientOptions::GetAmount(), CPrivateSendClientOptions::GetDenomsGoal(), + CPrivateSendClientOptions::GetDenomsHardCap()); } void WalletInit::InitKeePass() diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5cb1340441a9..db4e100dd9e7 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2682,7 +2682,7 @@ UniValue setprivatesendrounds(const JSONRPCRequest& request) if (nRounds > MAX_PRIVATESEND_ROUNDS || nRounds < MIN_PRIVATESEND_ROUNDS) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid number of rounds"); - privateSendClientOptions.nPrivateSendRounds = nRounds; + CPrivateSendClientOptions::SetRounds(nRounds); return NullUniValue; } @@ -2710,7 +2710,7 @@ UniValue setprivatesendamount(const JSONRPCRequest& request) if (nAmount > MAX_PRIVATESEND_AMOUNT || nAmount < MIN_PRIVATESEND_AMOUNT) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount of " + CURRENCY_UNIT + " as mixing goal amount"); - privateSendClientOptions.nPrivateSendAmount = nAmount; + CPrivateSendClientOptions::SetAmount(nAmount); return NullUniValue; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index cf8663a09a92..470096ad9483 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1662,7 +1662,7 @@ int CWallet::GetCappedOutpointPrivateSendRounds(const COutPoint& outpoint) const { LOCK(cs_wallet); int realPrivateSendRounds = GetRealOutpointPrivateSendRounds(outpoint); - return realPrivateSendRounds > privateSendClientOptions.nPrivateSendRounds ? privateSendClientOptions.nPrivateSendRounds : realPrivateSendRounds; + return realPrivateSendRounds > CPrivateSendClientOptions::GetRounds() ? CPrivateSendClientOptions::GetRounds() : realPrivateSendRounds; } bool CWallet::IsDenominated(const COutPoint& outpoint) const @@ -2364,7 +2364,7 @@ CAmount CWalletTx::GetAnonymizedCredit(bool fUseCache) const if (pwallet->IsSpent(hashTx, i) || !CPrivateSend::IsDenominatedAmount(txout.nValue)) continue; const int nRounds = pwallet->GetCappedOutpointPrivateSendRounds(outpoint); - if (nRounds >= privateSendClientOptions.nPrivateSendRounds){ + if (nRounds >= CPrivateSendClientOptions::GetRounds()) { nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); if (!MoneyRange(nCredit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); @@ -2573,7 +2573,7 @@ CAmount CWallet::GetBalance() const CAmount CWallet::GetAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfirmed) const { - if(!privateSendClientOptions.fEnablePrivateSend) return 0; + if (!CPrivateSendClientOptions::IsEnabled()) return 0; std::vector vecTally; if(!SelectCoinsGroupedByAddresses(vecTally, fSkipDenominated, true, fSkipUnconfirmed)) return 0; @@ -2595,7 +2595,7 @@ CAmount CWallet::GetAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfi CAmount CWallet::GetAnonymizedBalance() const { - if(!privateSendClientOptions.fEnablePrivateSend) return 0; + if (!CPrivateSendClientOptions::IsEnabled()) return 0; CAmount nTotal = 0; @@ -2612,7 +2612,7 @@ CAmount CWallet::GetAnonymizedBalance() const // that's ok as long as we use it for informational purposes only float CWallet::GetAverageAnonymizedRounds() const { - if(!privateSendClientOptions.fEnablePrivateSend) return 0; + if (!CPrivateSendClientOptions::IsEnabled()) return 0; int nTotal = 0; int nCount = 0; @@ -2634,7 +2634,7 @@ float CWallet::GetAverageAnonymizedRounds() const // that's ok as long as we use it for informational purposes only CAmount CWallet::GetNormalizedAnonymizedBalance() const { - if(!privateSendClientOptions.fEnablePrivateSend) return 0; + if (!CPrivateSendClientOptions::IsEnabled()) return 0; CAmount nTotal = 0; @@ -2648,7 +2648,7 @@ CAmount CWallet::GetNormalizedAnonymizedBalance() const if (it->second.GetDepthInMainChain() < 0) continue; int nRounds = GetCappedOutpointPrivateSendRounds(outpoint); - nTotal += nValue * nRounds / privateSendClientOptions.nPrivateSendRounds; + nTotal += nValue * nRounds / CPrivateSendClientOptions::GetRounds(); } return nTotal; @@ -2656,7 +2656,7 @@ CAmount CWallet::GetNormalizedAnonymizedBalance() const CAmount CWallet::GetDenominatedBalance(bool unconfirmed) const { - if(!privateSendClientOptions.fEnablePrivateSend) return 0; + if (!CPrivateSendClientOptions::IsEnabled()) return 0; CAmount nTotal = 0; @@ -2831,11 +2831,11 @@ void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const if (nCoinType == CoinType::ONLY_FULLY_MIXED) { if (!CPrivateSend::IsDenominatedAmount(pcoin->tx->vout[i].nValue)) continue; int nRounds = GetCappedOutpointPrivateSendRounds(COutPoint(wtxid, i)); - found = nRounds >= privateSendClientOptions.nPrivateSendRounds; + found = nRounds >= CPrivateSendClientOptions::GetRounds(); } else if(nCoinType == CoinType::ONLY_READY_TO_MIX) { if (!CPrivateSend::IsDenominatedAmount(pcoin->tx->vout[i].nValue)) continue; int nRounds = GetCappedOutpointPrivateSendRounds(COutPoint(wtxid, i)); - found = nRounds < privateSendClientOptions.nPrivateSendRounds; + found = nRounds < CPrivateSendClientOptions::GetRounds(); } else if(nCoinType == CoinType::ONLY_NONDENOMINATED) { if (CPrivateSend::IsCollateralAmount(pcoin->tx->vout[i].nValue)) continue; // do not use collateral amounts found = !CPrivateSend::IsDenominatedAmount(pcoin->tx->vout[i].nValue); @@ -3217,7 +3217,7 @@ bool CWallet::SelectCoins(const std::vector& vAvailableCoins, const CAm // Make sure to include mixed preset inputs only, // even if some non-mixed inputs were manually selected via CoinControl int nRounds = GetRealOutpointPrivateSendRounds(outpoint); - if (nRounds < privateSendClientOptions.nPrivateSendRounds) continue; + if (nRounds < CPrivateSendClientOptions::GetRounds()) continue; } nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue; setPresetCoins.insert(CInputCoin(pcoin, outpoint.n)); @@ -3420,7 +3420,7 @@ bool CWallet::SelectCoinsGroupedByAddresses(std::vector& vecTa // otherwise they will just lead to higher fee / lower priority if(wtx.tx->vout[i].nValue <= nSmallestDenom/10) continue; // ignore mixed - if(GetCappedOutpointPrivateSendRounds(COutPoint(outpoint.hash, i)) >= privateSendClientOptions.nPrivateSendRounds) continue; + if (GetCappedOutpointPrivateSendRounds(COutPoint(outpoint.hash, i)) >= CPrivateSendClientOptions::GetRounds()) continue; } if (itTallyItem == mapTally.end()) { From 3d5c35cd77ab4c1b12ae77d1a3748f4f0df90f65 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Mon, 20 Jul 2020 19:21:34 +0300 Subject: [PATCH 12/13] Fix qt tests --- src/qt/overviewpage.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 33e40c4cfa98..53e25962bcb6 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -492,7 +492,12 @@ void OverviewPage::privateSendStatus(bool fForce) static int64_t nLastDSProgressBlockTime = 0; int nBestHeight = clientModel->getNumBlocks(); - CPrivateSendClientManager* privateSendClientManager = privateSendClientManagers.find(walletModel->getWallet()->GetName())->second; + auto it = privateSendClientManagers.find(walletModel->getWallet()->GetName()); + if (it == privateSendClientManagers.end()) { + // nothing to do + return; + } + CPrivateSendClientManager* privateSendClientManager = it->second; // We are processing more than 1 block per second, we'll just leave if(nBestHeight > privateSendClientManager->nCachedNumBlocks && GetTime() - nLastDSProgressBlockTime <= 1) return; @@ -605,7 +610,12 @@ void OverviewPage::togglePrivateSend(){ settings.setValue("hasMixed", "hasMixed"); } - CPrivateSendClientManager* privateSendClientManager = privateSendClientManagers.find(walletModel->getWallet()->GetName())->second; + auto it = privateSendClientManagers.find(walletModel->getWallet()->GetName()); + if (it == privateSendClientManagers.end()) { + // nothing to do + return; + } + CPrivateSendClientManager* privateSendClientManager = it->second; if (!privateSendClientManager->IsMixing()) { const CAmount nMinAmount = CPrivateSend::GetSmallestDenomination() + CPrivateSend::GetMaxCollateralAmount(); @@ -671,5 +681,10 @@ void OverviewPage::DisablePrivateSendCompletely() { if (nWalletBackups <= 0) { ui->labelPrivateSendEnabled->setText("(" + tr("Disabled") + ")"); } - privateSendClientManagers.at(walletModel->getWallet()->GetName())->StopMixing(); + auto it = privateSendClientManagers.find(walletModel->getWallet()->GetName()); + if (it == privateSendClientManagers.end()) { + // nothing to do + return; + } + it->second->StopMixing(); } From 449b4a8c4b430fe70d263af171ffe3714159c596 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Mon, 20 Jul 2020 18:58:44 +0200 Subject: [PATCH 13/13] qt: Hide m_wallet_selector until a second wallet gets added. Showing it instantly may lead to the selector showing up in an unexpected place because it only gets added to a proper layout when a second wallet gets added. --- src/qt/bitcoingui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index c0f3d3dfb0ec..b872b54fdad4 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -615,6 +615,7 @@ void BitcoinGUI::createToolBars() #ifdef ENABLE_WALLET m_wallet_selector = new QComboBox(this); + m_wallet_selector->setHidden(true); connect(m_wallet_selector, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(setCurrentWallet(const QString&))); #endif @@ -743,6 +744,7 @@ bool BitcoinGUI::addWallet(WalletModel *walletModel) setWalletActionsEnabled(true); m_wallet_selector->addItem(name); if (m_wallet_selector->count() == 2) { + m_wallet_selector->setHidden(false); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(m_wallet_selector); layout->setSpacing(0);