From 284ac938197bd8c2ef84f8813c4f357dccd60a1f Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 19 Feb 2016 06:32:18 +0000 Subject: [PATCH 01/55] Qt/Options: Helper functions to build options programatically --- src/qt/optionsdialog.cpp | 48 ++++++++++++++++++++++++++++++++++++++++ src/qt/optionsdialog.h | 7 ++++++ 2 files changed, 55 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index c383b111e0..c3b190ee42 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -25,14 +25,60 @@ #include #include +#include #include #include #include +#include #include +#include #include #include +#include +#include +#include #include #include +#include + +void OptionsDialog::FixTabOrder(QWidget * const o) +{ + setTabOrder(prevwidget, o); + prevwidget = o; +} + +void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, const QString& text) +{ + QWidget * const parent = o->parentWidget(); + const QStringList text_parts = text.split("%s"); + + QHBoxLayout * const horizontalLayout = new QHBoxLayout(); + + QLabel * const labelBefore = new QLabel(parent); + labelBefore->setText(text_parts[0]); + labelBefore->setTextFormat(Qt::PlainText); + labelBefore->setBuddy(o); + labelBefore->setToolTip(o->toolTip()); + + horizontalLayout->addWidget(labelBefore); + horizontalLayout->addWidget(o); + + QLabel * const labelAfter = new QLabel(parent); + labelAfter->setText(text_parts[1]); + labelAfter->setTextFormat(Qt::PlainText); + labelAfter->setBuddy(o); + labelAfter->setToolTip(o->toolTip()); + + horizontalLayout->addWidget(labelAfter); + + QSpacerItem * const horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + horizontalLayout->addItem(horizontalSpacer); + + layout->addLayout(horizontalLayout); + + FixTabOrder(o); +} int setFontChoice(QComboBox* cb, const OptionsModel::FontChoice& fc) { @@ -140,6 +186,8 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) ui->maxuploadtarget->setMaximum(std::numeric_limits::max()); connect(ui->maxuploadtargetCheckbox, SIGNAL(toggled(bool)), ui->maxuploadtarget, SLOT(setEnabled(bool))); + prevwidget = ui->peerbloomfilters; + /* Window elements init */ #ifdef Q_OS_MACOS /* remove Window tab on Mac */ diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 5f29ae08ed..aad8417cc7 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -13,7 +13,10 @@ class OptionsModel; class QValidatedLineEdit; QT_BEGIN_NAMESPACE +class QBoxLayout; class QDataWidgetMapper; +class QString; +class QWidget; QT_END_NAMESPACE namespace Ui { @@ -78,6 +81,10 @@ private: ClientModel* m_client_model{nullptr}; OptionsModel* model{nullptr}; QDataWidgetMapper* mapper{nullptr}; + + QWidget *prevwidget{nullptr}; + void FixTabOrder(QWidget *); + void CreateOptionUI(QBoxLayout *, QWidget *, const QString& text); }; #endif // BITCOIN_QT_OPTIONSDIALOG_H From 41cf4b94e0ac8a931602100cc095aaf929349fde Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 19 Feb 2016 06:32:18 +0000 Subject: [PATCH 02/55] Qt/Options: Implement Mempool tab design in code --- src/qt/optionsdialog.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index c3b190ee42..acdbb53ec7 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include void OptionsDialog::FixTabOrder(QWidget * const o) @@ -188,6 +190,24 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) prevwidget = ui->peerbloomfilters; + /* Mempool tab */ + + QWidget * const tabMempool = new QWidget(); + QVBoxLayout * const verticalLayout_Mempool = new QVBoxLayout(tabMempool); + ui->tabWidget->insertTab(ui->tabWidget->indexOf(ui->tabWindow), tabMempool, tr("Mem&pool")); + + // TODO + + QGroupBox * const groupBox_Spamfiltering = new QGroupBox(tabMempool); + groupBox_Spamfiltering->setTitle(tr("Spam filtering")); + QVBoxLayout * const verticalLayout_Spamfiltering = new QVBoxLayout(groupBox_Spamfiltering); + + // TODO + + verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); + + verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); + /* Window elements init */ #ifdef Q_OS_MACOS /* remove Window tab on Mac */ From 654ee797d9e8ab705f192f507260f4129fa7aa46 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 18 Aug 2023 00:08:28 +0000 Subject: [PATCH 03/55] interfaces: Expose raw CTxMemPool via interfaces::Node --- src/interfaces/node.h | 3 +++ src/node/interfaces.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 3f0f85604a..74fc18a7f8 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -26,6 +26,7 @@ class BanMan; class CFeeRate; class CNodeStats; +class CTxMemPool; class Coin; class RPCTimerInterface; class UniValue; @@ -157,6 +158,8 @@ public: //! Get total bytes sent. virtual int64_t getTotalBytesSent() = 0; + virtual CTxMemPool& mempool() = 0; + //! Get mempool size. virtual size_t getMempoolSize() = 0; diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index c7bafa2617..2f87717736 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -425,6 +425,7 @@ public: } ArgsManager& args() { return *Assert(Assert(m_context)->args); } ChainstateManager& chainman() { return *Assert(m_context->chainman); } + CTxMemPool& mempool() override { return *Assert(m_context->mempool); } NodeContext* m_context{nullptr}; }; From 0892562e4343181d88c52bce6533e368a78c08fe Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 15 Feb 2016 06:38:09 +0000 Subject: [PATCH 04/55] Qt/Options: Configure mempoolreplacement using rwconf --- src/qt/optionsdialog.cpp | 18 +++++++++++++++++- src/qt/optionsdialog.h | 3 +++ src/qt/optionsmodel.cpp | 28 ++++++++++++++++++++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index acdbb53ec7..8982a79fbb 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -196,7 +196,11 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) QVBoxLayout * const verticalLayout_Mempool = new QVBoxLayout(tabMempool); ui->tabWidget->insertTab(ui->tabWidget->indexOf(ui->tabWindow), tabMempool, tr("Mem&pool")); - // TODO + mempoolreplacement = new QValueComboBox(tabMempool); + mempoolreplacement->addItem(QString("never"), QVariant("never")); + mempoolreplacement->addItem(QString("with a higher mining fee, and opt-in"), QVariant("fee,optin")); + mempoolreplacement->addItem(QString("with a higher mining fee (no opt-out)"), QVariant("fee,-optin")); + CreateOptionUI(verticalLayout_Mempool, mempoolreplacement, tr("Transaction &replacement: %s")); QGroupBox * const groupBox_Spamfiltering = new QGroupBox(tabMempool); groupBox_Spamfiltering->setTitle(tr("Spam filtering")); @@ -440,6 +444,16 @@ void OptionsDialog::setMapper() ui->peerblockfilters->setToolTip(ui->peerblockfilters->toolTip() + " " + tr("(only available if enabled at least once before turning on pruning)")); } + /* Mempool tab */ + + QVariant current_mempoolreplacement = model->data(model->index(OptionsModel::mempoolreplacement, 0), Qt::EditRole); + int current_mempoolreplacement_index = mempoolreplacement->findData(current_mempoolreplacement); + if (current_mempoolreplacement_index == -1) { + mempoolreplacement->addItem(current_mempoolreplacement.toString(), current_mempoolreplacement); + current_mempoolreplacement_index = mempoolreplacement->count() - 1; + } + mempoolreplacement->setCurrentIndex(current_mempoolreplacement_index); + /* Window */ #ifndef Q_OS_MACOS if (QSystemTrayIcon::isSystemTrayAvailable()) { @@ -556,6 +570,8 @@ void OptionsDialog::on_okButton_clicked() model->setData(model->index(OptionsModel::maxuploadtarget, 0), 0); } + model->setData(model->index(OptionsModel::mempoolreplacement, 0), mempoolreplacement->itemData(mempoolreplacement->currentIndex())); + mapper->submit(); accept(); updateDefaultProxyNets(); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index aad8417cc7..5811844404 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -16,6 +16,7 @@ QT_BEGIN_NAMESPACE class QBoxLayout; class QDataWidgetMapper; class QString; +class QValueComboBox; class QWidget; QT_END_NAMESPACE @@ -85,6 +86,8 @@ private: QWidget *prevwidget{nullptr}; void FixTabOrder(QWidget *); void CreateOptionUI(QBoxLayout *, QWidget *, const QString& text); + + QValueComboBox *mempoolreplacement; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index c4e484b454..d00d13a093 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include // for -dbcache defaults #include #include // For DEFAULT_SCRIPTCHECK_THREADS @@ -203,6 +204,16 @@ OptionsModel::FontChoice OptionsModel::FontChoiceFromString(const QString& s) } } +static QString CanonicalMempoolReplacement(const OptionsModel& model) +{ + switch (model.node().mempool().m_opts.rbf_policy) { + case RBFPolicy::Never: return "never"; + case RBFPolicy::OptIn: return "fee,optin"; + case RBFPolicy::Always: return "fee,-optin"; + } + assert(0); +} + OptionsModel::OptionsModel(interfaces::Node& node, QObject *parent) : QAbstractListModel(parent), m_node{node} { @@ -622,6 +633,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return f_peerbloomfilters; case peerblockfilters: return gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS); + case mempoolreplacement: + return CanonicalMempoolReplacement(*this); default: return QVariant(); } @@ -925,6 +938,21 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case mempoolreplacement: + { + if (changed()) { + QString nv = value.toString(); + if (nv == "never") { + node().mempool().m_opts.rbf_policy = RBFPolicy::Never; + } else if (nv == "fee,optin") { + node().mempool().m_opts.rbf_policy = RBFPolicy::OptIn; + } else { // "fee,-optin" + node().mempool().m_opts.rbf_policy = RBFPolicy::Always; + } + gArgs.ModifyRWConfigFile("mempoolreplacement", nv.toStdString()); + } + break; + } default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 3dfba8c1f0..2297c23fa2 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -80,6 +80,7 @@ public: maxuploadtarget, peerbloomfilters, // bool peerblockfilters, // bool + mempoolreplacement, OptionIDRowCount, }; From 4dff308dc74d7e51d2ced108284a12bf3daadbde Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 15 Feb 2016 07:09:36 +0000 Subject: [PATCH 05/55] Qt/Options: Configure maxorphantx using rwconf --- src/net_processing.cpp | 8 ++++++++ src/net_processing.h | 2 ++ src/qt/optionsdialog.cpp | 7 +++++++ src/qt/optionsdialog.h | 2 ++ src/qt/optionsmodel.cpp | 17 +++++++++++++++++ src/qt/optionsmodel.h | 1 + 6 files changed, 37 insertions(+) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index f5388971c4..d46800547e 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -520,6 +520,7 @@ public: bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); std::vector GetOrphanTransactions() override EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex); PeerManagerInfo GetInfo() const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void LimitOrphanTxSize(unsigned int nMaxOrphans) override EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex); void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void RelayTransaction(const uint256& txid, const uint256& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void SetBestBlock(int height, std::chrono::seconds time) override @@ -1952,6 +1953,13 @@ PeerManagerInfo PeerManagerImpl::GetInfo() const }; } +void PeerManagerImpl::LimitOrphanTxSize(unsigned int nMaxOrphans) +{ + LOCK(g_msgproc_mutex); + LOCK2(cs_main, m_tx_download_mutex); + m_orphanage.LimitOrphans(nMaxOrphans, m_rng); +} + int PeerManagerImpl::GetNumberOfPeersWithValidatedDownloads() const { AssertLockHeld(m_chainman.GetMutex()); diff --git a/src/net_processing.h b/src/net_processing.h index 7d6b5eb547..3aac9873f0 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -7,6 +7,7 @@ #define BITCOIN_NET_PROCESSING_H #include +#include #include #include @@ -95,6 +96,7 @@ public: /** Get statistics from node state */ virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const = 0; + virtual void LimitOrphanTxSize(unsigned int nMaxOrphans) = 0; virtual std::vector GetOrphanTransactions() = 0; diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 8982a79fbb..297b3fab1c 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -202,6 +202,11 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) mempoolreplacement->addItem(QString("with a higher mining fee (no opt-out)"), QVariant("fee,-optin")); CreateOptionUI(verticalLayout_Mempool, mempoolreplacement, tr("Transaction &replacement: %s")); + maxorphantx = new QSpinBox(tabMempool); + maxorphantx->setMinimum(0); + maxorphantx->setMaximum(std::numeric_limits::max()); + CreateOptionUI(verticalLayout_Mempool, maxorphantx, tr("Keep at most %s unconnected transactions in memory")); + QGroupBox * const groupBox_Spamfiltering = new QGroupBox(tabMempool); groupBox_Spamfiltering->setTitle(tr("Spam filtering")); QVBoxLayout * const verticalLayout_Spamfiltering = new QVBoxLayout(groupBox_Spamfiltering); @@ -454,6 +459,8 @@ void OptionsDialog::setMapper() } mempoolreplacement->setCurrentIndex(current_mempoolreplacement_index); + mapper->addMapping(maxorphantx, OptionsModel::maxorphantx); + /* Window */ #ifndef Q_OS_MACOS if (QSystemTrayIcon::isSystemTrayAvailable()) { diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 5811844404..aaa8f9a316 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -15,6 +15,7 @@ class QValidatedLineEdit; QT_BEGIN_NAMESPACE class QBoxLayout; class QDataWidgetMapper; +class QSpinBox; class QString; class QValueComboBox; class QWidget; @@ -88,6 +89,7 @@ private: void CreateOptionUI(QBoxLayout *, QWidget *, const QString& text); QValueComboBox *mempoolreplacement; + QSpinBox *maxorphantx; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index d00d13a093..926a95c48e 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -635,6 +635,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS); case mempoolreplacement: return CanonicalMempoolReplacement(*this); + case maxorphantx: + return qlonglong(gArgs.GetIntArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); default: return QVariant(); } @@ -953,6 +955,21 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case maxorphantx: + { + if (changed()) { + unsigned int nMaxOrphanTx = gArgs.GetIntArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS); + unsigned int nNv = value.toLongLong(); + std::string strNv = value.toString().toStdString(); + gArgs.ForceSetArg("-maxorphantx", strNv); + gArgs.ModifyRWConfigFile("maxorphantx", strNv); + if (nNv < nMaxOrphanTx) { + assert(node().context() && node().context()->peerman); + node().context()->peerman->LimitOrphanTxSize(nNv); + } + } + break; + } default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 2297c23fa2..38a984331a 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -81,6 +81,7 @@ public: peerbloomfilters, // bool peerblockfilters, // bool mempoolreplacement, + maxorphantx, OptionIDRowCount, }; From d6f4eb55f93ca687b47331db84961949b83e08be Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 15 Feb 2016 08:49:26 +0000 Subject: [PATCH 06/55] Qt/Options: Configure maxmempool using rwconf --- src/qt/optionsdialog.cpp | 10 +++++++++- src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 22 ++++++++++++++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 297b3fab1c..2bf01db8c6 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -20,8 +21,8 @@ #include #include #include +#include // for maxmempoolMinimum #include - #include #include @@ -207,6 +208,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) maxorphantx->setMaximum(std::numeric_limits::max()); CreateOptionUI(verticalLayout_Mempool, maxorphantx, tr("Keep at most %s unconnected transactions in memory")); + maxmempool = new QSpinBox(tabMempool); + const int64_t nMempoolSizeMinMB = maxmempoolMinimumBytes(gArgs.GetIntArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT_KVB) * 1'000) / 1'000'000; + maxmempool->setMinimum(nMempoolSizeMinMB); + maxmempool->setMaximum(std::numeric_limits::max()); + CreateOptionUI(verticalLayout_Mempool, maxmempool, tr("Keep the transaction memory pool below %s MB")); + QGroupBox * const groupBox_Spamfiltering = new QGroupBox(tabMempool); groupBox_Spamfiltering->setTitle(tr("Spam filtering")); QVBoxLayout * const verticalLayout_Spamfiltering = new QVBoxLayout(groupBox_Spamfiltering); @@ -460,6 +467,7 @@ void OptionsDialog::setMapper() mempoolreplacement->setCurrentIndex(current_mempoolreplacement_index); mapper->addMapping(maxorphantx, OptionsModel::maxorphantx); + mapper->addMapping(maxmempool, OptionsModel::maxmempool); /* Window */ #ifndef Q_OS_MACOS diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index aaa8f9a316..13cad80357 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -90,6 +90,7 @@ private: QValueComboBox *mempoolreplacement; QSpinBox *maxorphantx; + QSpinBox *maxmempool; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 926a95c48e..fd4ef110fe 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -14,6 +14,7 @@ #include #include #include +#include // for DEFAULT_MAX_MEMPOOL_SIZE_MB #include #include #include @@ -637,6 +638,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return CanonicalMempoolReplacement(*this); case maxorphantx: return qlonglong(gArgs.GetIntArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); + case maxmempool: + return qlonglong(node().mempool().m_opts.max_size_bytes / 1'000'000); default: return QVariant(); } @@ -970,6 +973,25 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case maxmempool: + { + if (changed()) { + long long nOldValue = node().mempool().m_opts.max_size_bytes; + long long nNv = value.toLongLong(); + std::string strNv = value.toString().toStdString(); + node().mempool().m_opts.max_size_bytes = nNv * 1'000'000; + gArgs.ForceSetArg("-maxmempool", strNv); + gArgs.ModifyRWConfigFile("maxmempool", strNv); + if (nNv < nOldValue) { + LOCK(cs_main); + auto node_ctx = node().context(); + assert(node_ctx && node_ctx->mempool && node_ctx->chainman); + auto& active_chainstate = node_ctx->chainman->ActiveChainstate(); + LimitMempoolSize(*node_ctx->mempool, active_chainstate.CoinsTip()); + } + } + break; + } default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 38a984331a..a5a32ff662 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -82,6 +82,7 @@ public: peerblockfilters, // bool mempoolreplacement, maxorphantx, + maxmempool, OptionIDRowCount, }; From 8ae6db8db19234dccbad87074db10ef23017e38e Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 15 Feb 2016 08:56:08 +0000 Subject: [PATCH 07/55] Qt/Options: Configure mempoolexpiry using rwconf --- src/qt/optionsdialog.cpp | 6 ++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 24 +++++++++++++++++++++++- src/qt/optionsmodel.h | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 2bf01db8c6..9b86281d46 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -214,6 +214,11 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) maxmempool->setMaximum(std::numeric_limits::max()); CreateOptionUI(verticalLayout_Mempool, maxmempool, tr("Keep the transaction memory pool below %s MB")); + mempoolexpiry = new QSpinBox(tabMempool); + mempoolexpiry->setMinimum(1); + mempoolexpiry->setMaximum(std::numeric_limits::max()); + CreateOptionUI(verticalLayout_Mempool, mempoolexpiry, tr("Do not keep transactions in memory more than %s hours")); + QGroupBox * const groupBox_Spamfiltering = new QGroupBox(tabMempool); groupBox_Spamfiltering->setTitle(tr("Spam filtering")); QVBoxLayout * const verticalLayout_Spamfiltering = new QVBoxLayout(groupBox_Spamfiltering); @@ -468,6 +473,7 @@ void OptionsDialog::setMapper() mapper->addMapping(maxorphantx, OptionsModel::maxorphantx); mapper->addMapping(maxmempool, OptionsModel::maxmempool); + mapper->addMapping(mempoolexpiry, OptionsModel::mempoolexpiry); /* Window */ #ifndef Q_OS_MACOS diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 13cad80357..dd3042a721 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -91,6 +91,7 @@ private: QValueComboBox *mempoolreplacement; QSpinBox *maxorphantx; QSpinBox *maxmempool; + QSpinBox *mempoolexpiry; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index fd4ef110fe..ea68aa6a67 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -14,7 +14,7 @@ #include #include #include -#include // for DEFAULT_MAX_MEMPOOL_SIZE_MB +#include // for DEFAULT_MAX_MEMPOOL_SIZE_MB, DEFAULT_MEMPOOL_EXPIRY_HOURS #include #include #include @@ -32,6 +32,7 @@ #include #endif +#include #include #include @@ -640,6 +641,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(gArgs.GetIntArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); case maxmempool: return qlonglong(node().mempool().m_opts.max_size_bytes / 1'000'000); + case mempoolexpiry: + return qlonglong(std::chrono::duration_cast(node().mempool().m_opts.expiry).count()); default: return QVariant(); } @@ -992,6 +995,25 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case mempoolexpiry: + { + if (changed()) { + const auto old_value = node().mempool().m_opts.expiry; + const std::chrono::hours new_value{value.toLongLong()}; + std::string strNv = value.toString().toStdString(); + node().mempool().m_opts.expiry = new_value; + gArgs.ForceSetArg("-mempoolexpiry", strNv); + gArgs.ModifyRWConfigFile("mempoolexpiry", strNv); + if (new_value < old_value) { + LOCK(cs_main); + auto node_ctx = node().context(); + assert(node_ctx && node_ctx->mempool && node_ctx->chainman); + auto& active_chainstate = node_ctx->chainman->ActiveChainstate(); + LimitMempoolSize(*node_ctx->mempool, active_chainstate.CoinsTip()); + } + } + break; + } default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index a5a32ff662..df760517f7 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -83,6 +83,7 @@ public: mempoolreplacement, maxorphantx, maxmempool, + mempoolexpiry, OptionIDRowCount, }; From 5f4b95ab8e2436ee462391372abd0b440ef5e1cd Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 3 Feb 2025 23:20:03 +0000 Subject: [PATCH 08/55] Qt/Options: Configure acceptnonstdtxn using rwconf --- src/qt/optionsdialog.cpp | 8 +++++++- src/qt/optionsdialog.h | 3 +++ src/qt/optionsmodel.cpp | 12 ++++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 9b86281d46..2189b75438 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -223,7 +223,11 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) groupBox_Spamfiltering->setTitle(tr("Spam filtering")); QVBoxLayout * const verticalLayout_Spamfiltering = new QVBoxLayout(groupBox_Spamfiltering); - // TODO + rejectunknownscripts = new QCheckBox(groupBox_Spamfiltering); + rejectunknownscripts->setText(tr("Ignore unrecognised receiver scripts")); + rejectunknownscripts->setToolTip(tr("With this option enabled, unrecognised receiver (\"pubkey\") scripts will be ignored. Unrecognisable scripts could be used to bypass further spam filters. If your software is outdated, they may also be used to trick you into thinking you were sent bitcoins that will never confirm.")); + verticalLayout_Spamfiltering->addWidget(rejectunknownscripts); + FixTabOrder(rejectunknownscripts); verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); @@ -475,6 +479,8 @@ void OptionsDialog::setMapper() mapper->addMapping(maxmempool, OptionsModel::maxmempool); mapper->addMapping(mempoolexpiry, OptionsModel::mempoolexpiry); + mapper->addMapping(rejectunknownscripts, OptionsModel::rejectunknownscripts); + /* Window */ #ifndef Q_OS_MACOS if (QSystemTrayIcon::isSystemTrayAvailable()) { diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index dd3042a721..96ff7f6296 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -14,6 +14,7 @@ class QValidatedLineEdit; QT_BEGIN_NAMESPACE class QBoxLayout; +class QCheckBox; class QDataWidgetMapper; class QSpinBox; class QString; @@ -92,6 +93,8 @@ private: QSpinBox *maxorphantx; QSpinBox *maxmempool; QSpinBox *mempoolexpiry; + + QCheckBox *rejectunknownscripts; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index ea68aa6a67..b9bde2fa84 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -643,6 +643,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(node().mempool().m_opts.max_size_bytes / 1'000'000); case mempoolexpiry: return qlonglong(std::chrono::duration_cast(node().mempool().m_opts.expiry).count()); + case rejectunknownscripts: + return node().mempool().m_opts.require_standard; default: return QVariant(); } @@ -1014,6 +1016,16 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case rejectunknownscripts: + { + if (changed()) { + const bool fNewValue = value.toBool(); + node().mempool().m_opts.require_standard = fNewValue; + // This option is inverted in the config: + gArgs.ModifyRWConfigFile("acceptnonstdtxn", strprintf("%d", ! fNewValue)); + } + break; + } default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index df760517f7..35b8437703 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -84,6 +84,7 @@ public: maxorphantx, maxmempool, mempoolexpiry, + rejectunknownscripts, // bool OptionIDRowCount, }; From 75cd381042d9fa3a2a010142c4de257160a492dd Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 3 Feb 2025 23:22:35 +0000 Subject: [PATCH 09/55] Qt/Options: Configure bytespersigopstrict using rwconf --- src/qt/optionsdialog.cpp | 12 ++++++++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 17 +++++++++++++++++ src/qt/optionsmodel.h | 2 ++ 4 files changed, 32 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 2189b75438..5e473e3807 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -229,6 +229,16 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Spamfiltering->addWidget(rejectunknownscripts); FixTabOrder(rejectunknownscripts); + bytespersigop = new QSpinBox(groupBox_Spamfiltering); + bytespersigop->setMinimum(1); + bytespersigop->setMaximum(std::numeric_limits::max()); + CreateOptionUI(verticalLayout_Spamfiltering, bytespersigop, tr("Treat each consensus-counted sigop as at least %s bytes.")); + + bytespersigopstrict = new QSpinBox(groupBox_Spamfiltering); + bytespersigopstrict->setMinimum(1); + bytespersigopstrict->setMaximum(std::numeric_limits::max()); + CreateOptionUI(verticalLayout_Spamfiltering, bytespersigopstrict, tr("Ignore transactions with fewer than %s bytes per potentially-executed sigop.")); + verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); @@ -480,6 +490,8 @@ void OptionsDialog::setMapper() mapper->addMapping(mempoolexpiry, OptionsModel::mempoolexpiry); mapper->addMapping(rejectunknownscripts, OptionsModel::rejectunknownscripts); + mapper->addMapping(bytespersigop, OptionsModel::bytespersigop); + mapper->addMapping(bytespersigopstrict, OptionsModel::bytespersigopstrict); /* Window */ #ifndef Q_OS_MACOS diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 96ff7f6296..e4ff898fe4 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -95,6 +95,7 @@ private: QSpinBox *mempoolexpiry; QCheckBox *rejectunknownscripts; + QSpinBox *bytespersigop, *bytespersigopstrict; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index b9bde2fa84..aa63083f9b 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -16,6 +16,7 @@ #include #include // for DEFAULT_MAX_MEMPOOL_SIZE_MB, DEFAULT_MEMPOOL_EXPIRY_HOURS #include +#include #include #include #include @@ -645,6 +646,10 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(std::chrono::duration_cast(node().mempool().m_opts.expiry).count()); case rejectunknownscripts: return node().mempool().m_opts.require_standard; + case bytespersigop: + return nBytesPerSigOp; + case bytespersigopstrict: + return nBytesPerSigOpStrict; default: return QVariant(); } @@ -1026,6 +1031,18 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case bytespersigop: + if (changed()) { + gArgs.ModifyRWConfigFile("bytespersigop", value.toString().toStdString()); + nBytesPerSigOp = value.toLongLong(); + } + break; + case bytespersigopstrict: + if (changed()) { + gArgs.ModifyRWConfigFile("bytespersigopstrict", value.toString().toStdString()); + nBytesPerSigOpStrict = value.toLongLong(); + } + break; default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 35b8437703..e3eb6cba24 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -85,6 +85,8 @@ public: maxmempool, mempoolexpiry, rejectunknownscripts, // bool + bytespersigop, + bytespersigopstrict, OptionIDRowCount, }; From a9fa1302b3811ad49fa816862b3c5a7586b533fc Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 3 Feb 2025 23:26:20 +0000 Subject: [PATCH 10/55] Qt/Options: Configure limitancestorcount using rwconf --- src/qt/optionsdialog.cpp | 6 ++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 11 +++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 19 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 5e473e3807..2063294508 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -239,6 +239,11 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) bytespersigopstrict->setMaximum(std::numeric_limits::max()); CreateOptionUI(verticalLayout_Spamfiltering, bytespersigopstrict, tr("Ignore transactions with fewer than %s bytes per potentially-executed sigop.")); + limitancestorcount = new QSpinBox(groupBox_Spamfiltering); + limitancestorcount->setMinimum(1); + limitancestorcount->setMaximum(std::numeric_limits::max()); + CreateOptionUI(verticalLayout_Spamfiltering, limitancestorcount, tr("Ignore transactions with %s or more unconfirmed ancestors.")); + verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); @@ -492,6 +497,7 @@ void OptionsDialog::setMapper() mapper->addMapping(rejectunknownscripts, OptionsModel::rejectunknownscripts); mapper->addMapping(bytespersigop, OptionsModel::bytespersigop); mapper->addMapping(bytespersigopstrict, OptionsModel::bytespersigopstrict); + mapper->addMapping(limitancestorcount, OptionsModel::limitancestorcount); /* Window */ #ifndef Q_OS_MACOS diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index e4ff898fe4..0a8ec0164d 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -96,6 +96,7 @@ private: QCheckBox *rejectunknownscripts; QSpinBox *bytespersigop, *bytespersigopstrict; + QSpinBox *limitancestorcount; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index aa63083f9b..eaaea01163 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -650,6 +650,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return nBytesPerSigOp; case bytespersigopstrict: return nBytesPerSigOpStrict; + case limitancestorcount: + return qlonglong(node().mempool().m_opts.limits.ancestor_count); default: return QVariant(); } @@ -1043,6 +1045,15 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: nBytesPerSigOpStrict = value.toLongLong(); } break; + case limitancestorcount: + if (changed()) { + long long nNv = value.toLongLong(); + std::string strNv = value.toString().toStdString(); + node().mempool().m_opts.limits.ancestor_count = nNv; + gArgs.ForceSetArg("-limitancestorcount", strNv); + gArgs.ModifyRWConfigFile("limitancestorcount", strNv); + } + break; default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index e3eb6cba24..849acb8517 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -87,6 +87,7 @@ public: rejectunknownscripts, // bool bytespersigop, bytespersigopstrict, + limitancestorcount, OptionIDRowCount, }; From ba4c6041186ca586e869819120e5e8e30c2621e4 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 3 Feb 2025 23:29:17 +0000 Subject: [PATCH 11/55] Qt/Options: Configure limitancestorsize using rwconf --- src/qt/optionsdialog.cpp | 6 ++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 11 +++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 19 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 2063294508..ae69700ba3 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -244,6 +244,11 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) limitancestorcount->setMaximum(std::numeric_limits::max()); CreateOptionUI(verticalLayout_Spamfiltering, limitancestorcount, tr("Ignore transactions with %s or more unconfirmed ancestors.")); + limitancestorsize = new QSpinBox(groupBox_Spamfiltering); + limitancestorsize->setMinimum(1); + limitancestorsize->setMaximum(std::numeric_limits::max()); + CreateOptionUI(verticalLayout_Spamfiltering, limitancestorsize, tr("Ignore transactions whose size with all unconfirmed ancestors exceeds %s kilobytes.")); + verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); @@ -498,6 +503,7 @@ void OptionsDialog::setMapper() mapper->addMapping(bytespersigop, OptionsModel::bytespersigop); mapper->addMapping(bytespersigopstrict, OptionsModel::bytespersigopstrict); mapper->addMapping(limitancestorcount, OptionsModel::limitancestorcount); + mapper->addMapping(limitancestorsize, OptionsModel::limitancestorsize); /* Window */ #ifndef Q_OS_MACOS diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 0a8ec0164d..e5e6dee159 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -97,6 +97,7 @@ private: QCheckBox *rejectunknownscripts; QSpinBox *bytespersigop, *bytespersigopstrict; QSpinBox *limitancestorcount; + QSpinBox *limitancestorsize; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index eaaea01163..4c275e6cc2 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -652,6 +652,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return nBytesPerSigOpStrict; case limitancestorcount: return qlonglong(node().mempool().m_opts.limits.ancestor_count); + case limitancestorsize: + return qlonglong(node().mempool().m_opts.limits.ancestor_size_vbytes / 1'000); default: return QVariant(); } @@ -1054,6 +1056,15 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: gArgs.ModifyRWConfigFile("limitancestorcount", strNv); } break; + case limitancestorsize: + if (changed()) { + long long nNv = value.toLongLong(); + std::string strNv = value.toString().toStdString(); + node().mempool().m_opts.limits.ancestor_size_vbytes = nNv * 1'000; + gArgs.ForceSetArg("-limitancestorsize", strNv); + gArgs.ModifyRWConfigFile("limitancestorsize", strNv); + } + break; default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 849acb8517..d8af8d68b4 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -88,6 +88,7 @@ public: bytespersigop, bytespersigopstrict, limitancestorcount, + limitancestorsize, OptionIDRowCount, }; From c72a0b21003d2bb7a7b92d89c098f409e68a8674 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 3 Feb 2025 23:32:39 +0000 Subject: [PATCH 12/55] Qt/Options: Configure limitdescendant{count,size} using rwconf --- src/qt/optionsdialog.cpp | 12 ++++++++++++ src/qt/optionsdialog.h | 2 ++ src/qt/optionsmodel.cpp | 22 ++++++++++++++++++++++ src/qt/optionsmodel.h | 2 ++ 4 files changed, 38 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index ae69700ba3..775785d10f 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -249,6 +249,16 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) limitancestorsize->setMaximum(std::numeric_limits::max()); CreateOptionUI(verticalLayout_Spamfiltering, limitancestorsize, tr("Ignore transactions whose size with all unconfirmed ancestors exceeds %s kilobytes.")); + limitdescendantcount = new QSpinBox(groupBox_Spamfiltering); + limitdescendantcount->setMinimum(1); + limitdescendantcount->setMaximum(std::numeric_limits::max()); + CreateOptionUI(verticalLayout_Spamfiltering, limitdescendantcount, tr("Ignore transactions if any ancestor would have %s or more unconfirmed descendants.")); + + limitdescendantsize = new QSpinBox(groupBox_Spamfiltering); + limitdescendantsize->setMinimum(1); + limitdescendantsize->setMaximum(std::numeric_limits::max()); + CreateOptionUI(verticalLayout_Spamfiltering, limitdescendantsize, tr("Ignore transactions if any ancestor would have more than %s kilobytes of unconfirmed descendants.")); + verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); @@ -504,6 +514,8 @@ void OptionsDialog::setMapper() mapper->addMapping(bytespersigopstrict, OptionsModel::bytespersigopstrict); mapper->addMapping(limitancestorcount, OptionsModel::limitancestorcount); mapper->addMapping(limitancestorsize, OptionsModel::limitancestorsize); + mapper->addMapping(limitdescendantcount, OptionsModel::limitdescendantcount); + mapper->addMapping(limitdescendantsize, OptionsModel::limitdescendantsize); /* Window */ #ifndef Q_OS_MACOS diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index e5e6dee159..5137334c66 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -98,6 +98,8 @@ private: QSpinBox *bytespersigop, *bytespersigopstrict; QSpinBox *limitancestorcount; QSpinBox *limitancestorsize; + QSpinBox *limitdescendantcount; + QSpinBox *limitdescendantsize; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 4c275e6cc2..6e550419e4 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -654,6 +654,10 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(node().mempool().m_opts.limits.ancestor_count); case limitancestorsize: return qlonglong(node().mempool().m_opts.limits.ancestor_size_vbytes / 1'000); + case limitdescendantcount: + return qlonglong(node().mempool().m_opts.limits.descendant_count); + case limitdescendantsize: + return qlonglong(node().mempool().m_opts.limits.descendant_size_vbytes / 1'000); default: return QVariant(); } @@ -1065,6 +1069,24 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: gArgs.ModifyRWConfigFile("limitancestorsize", strNv); } break; + case limitdescendantcount: + if (changed()) { + long long nNv = value.toLongLong(); + std::string strNv = value.toString().toStdString(); + node().mempool().m_opts.limits.descendant_count = nNv; + gArgs.ForceSetArg("-limitdescendantcount", strNv); + gArgs.ModifyRWConfigFile("limitdescendantcount", strNv); + } + break; + case limitdescendantsize: + if (changed()) { + long long nNv = value.toLongLong(); + std::string strNv = value.toString().toStdString(); + node().mempool().m_opts.limits.descendant_size_vbytes = nNv * 1'000; + gArgs.ForceSetArg("-limitdescendantsize", strNv); + gArgs.ModifyRWConfigFile("limitdescendantsize", strNv); + } + break; default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index d8af8d68b4..cd974bf06a 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -89,6 +89,8 @@ public: bytespersigopstrict, limitancestorcount, limitancestorsize, + limitdescendantcount, + limitdescendantsize, OptionIDRowCount, }; From f1ab51a4915fa7dffedf9a9a07276ae9edffcd35 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 3 Feb 2025 23:36:06 +0000 Subject: [PATCH 13/55] Qt/Options: Configure permitbaremultisig using rwconf --- src/qt/optionsdialog.cpp | 7 +++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 10 ++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 19 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 775785d10f..2f9985c009 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -259,6 +259,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) limitdescendantsize->setMaximum(std::numeric_limits::max()); CreateOptionUI(verticalLayout_Spamfiltering, limitdescendantsize, tr("Ignore transactions if any ancestor would have more than %s kilobytes of unconfirmed descendants.")); + rejectbaremultisig = new QCheckBox(groupBox_Spamfiltering); + rejectbaremultisig->setText(tr("Ignore bare/exposed \"multisig\" scripts")); + rejectbaremultisig->setToolTip(tr("Spam is sometimes disguised to appear as if it is an old-style N-of-M multi-party transaction, where most of the keys are really bogus. At the same time, legitimate multi-party transactions typically have always used P2SH format (which is not filtered by this option), which is more secure.")); + verticalLayout_Spamfiltering->addWidget(rejectbaremultisig); + FixTabOrder(rejectbaremultisig); + verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); @@ -516,6 +522,7 @@ void OptionsDialog::setMapper() mapper->addMapping(limitancestorsize, OptionsModel::limitancestorsize); mapper->addMapping(limitdescendantcount, OptionsModel::limitdescendantcount); mapper->addMapping(limitdescendantsize, OptionsModel::limitdescendantsize); + mapper->addMapping(rejectbaremultisig, OptionsModel::rejectbaremultisig); /* Window */ #ifndef Q_OS_MACOS diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 5137334c66..cf5b63c3cb 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -100,6 +100,7 @@ private: QSpinBox *limitancestorsize; QSpinBox *limitdescendantcount; QSpinBox *limitdescendantsize; + QCheckBox *rejectbaremultisig; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 6e550419e4..61957c3545 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -658,6 +658,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(node().mempool().m_opts.limits.descendant_count); case limitdescendantsize: return qlonglong(node().mempool().m_opts.limits.descendant_size_vbytes / 1'000); + case rejectbaremultisig: + return !node().mempool().m_opts.permit_bare_multisig; default: return QVariant(); } @@ -1087,6 +1089,14 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: gArgs.ModifyRWConfigFile("limitdescendantsize", strNv); } break; + case rejectbaremultisig: + if (changed()) { + // The config and internal option is inverted + const bool fNewValue = ! value.toBool(); + node().mempool().m_opts.permit_bare_multisig = fNewValue; + gArgs.ModifyRWConfigFile("permitbaremultisig", strprintf("%d", fNewValue)); + } + break; default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index cd974bf06a..8e362fd2db 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -91,6 +91,7 @@ public: limitancestorsize, limitdescendantcount, limitdescendantsize, + rejectbaremultisig, // bool OptionIDRowCount, }; From 80196bad5c5fc83a822bc8d49d6c84a32afe968e Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 3 Feb 2025 23:38:54 +0000 Subject: [PATCH 14/55] Qt/Options: Configure datacarrier[size] using rwconf --- src/qt/optionsdialog.cpp | 7 +++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 18 ++++++++++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 27 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 2f9985c009..7b7b2f882b 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -265,6 +265,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Spamfiltering->addWidget(rejectbaremultisig); FixTabOrder(rejectbaremultisig); + datacarriersize = new QSpinBox(groupBox_Spamfiltering); + datacarriersize->setMinimum(0); + datacarriersize->setMaximum(std::numeric_limits::max()); + datacarriersize->setToolTip(tr("Since 2014, a specific method for attaching arbitrary data to transactions has been recognised as not requiring space in the coin database. Since it is sometimes impractical to detect small spam disguised as ordinary transactions, it is sometimes considered beneficial to treat these less harmful data attachments as equals to legitimate usage.")); + CreateOptionUI(verticalLayout_Spamfiltering, datacarriersize, tr("Ignore transactions with additional data larger than %s bytes.")); + verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); @@ -523,6 +529,7 @@ void OptionsDialog::setMapper() mapper->addMapping(limitdescendantcount, OptionsModel::limitdescendantcount); mapper->addMapping(limitdescendantsize, OptionsModel::limitdescendantsize); mapper->addMapping(rejectbaremultisig, OptionsModel::rejectbaremultisig); + mapper->addMapping(datacarriersize, OptionsModel::datacarriersize); /* Window */ #ifndef Q_OS_MACOS diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index cf5b63c3cb..1487b2162d 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -101,6 +101,7 @@ private: QSpinBox *limitdescendantcount; QSpinBox *limitdescendantsize; QCheckBox *rejectbaremultisig; + QSpinBox *datacarriersize; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 61957c3545..31bc00d249 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -660,6 +660,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(node().mempool().m_opts.limits.descendant_size_vbytes / 1'000); case rejectbaremultisig: return !node().mempool().m_opts.permit_bare_multisig; + case datacarriersize: + return qlonglong(node().mempool().m_opts.max_datacarrier_bytes.value_or(0)); default: return QVariant(); } @@ -1097,6 +1099,22 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: gArgs.ModifyRWConfigFile("permitbaremultisig", strprintf("%d", fNewValue)); } break; + case datacarriersize: + if (changed()) { + const int nNewSize = value.toInt(); + const bool fNewEn = (nNewSize > 0); + if (fNewEn) { + if (!node().mempool().m_opts.max_datacarrier_bytes.has_value()) { + gArgs.ModifyRWConfigFile("datacarrier", strprintf("%d", fNewEn)); + } + gArgs.ModifyRWConfigFile("datacarriersize", value.toString().toStdString()); + node().mempool().m_opts.max_datacarrier_bytes = nNewSize; + } else { + gArgs.ModifyRWConfigFile("datacarrier", "0"); + node().mempool().m_opts.max_datacarrier_bytes = std::nullopt; + } + } + break; default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 8e362fd2db..ad79045ce0 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -92,6 +92,7 @@ public: limitdescendantcount, limitdescendantsize, rejectbaremultisig, // bool + datacarriersize, OptionIDRowCount, }; From b67e66bcde1203068f41ce55f632ec2e11e35710 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 16 Feb 2016 07:22:10 +0000 Subject: [PATCH 15/55] Qt/Options: Implement Mining tab design in code --- src/qt/optionsdialog.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 7b7b2f882b..26c9fcecaa 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -275,6 +275,18 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); + /* Mining tab */ + + QWidget * const tabMining = new QWidget(); + QVBoxLayout * const verticalLayout_Mining = new QVBoxLayout(tabMining); + ui->tabWidget->insertTab(ui->tabWidget->indexOf(ui->tabWindow), tabMining, tr("M&ining")); + + verticalLayout_Mining->addWidget(new QLabel(tr("Note that mining is heavily influenced by the settings on the Mempool tab."))); + + // TODO + + verticalLayout_Mining->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); + /* Window elements init */ #ifdef Q_OS_MACOS /* remove Window tab on Mac */ From 9568978fd5d2fa3628065c87a87cac6ed068b9ab Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 3 Feb 2025 23:43:26 +0000 Subject: [PATCH 16/55] Qt/Options: Configure blockmaxsize, blockprioritysize, and blockmaxweight using rwconf --- src/qt/optionsdialog.cpp | 55 +++++++++++++++++++++++++++++++++++++++- src/qt/optionsdialog.h | 6 +++++ src/qt/optionsmodel.cpp | 29 +++++++++++++++++++++ src/qt/optionsmodel.h | 3 +++ 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 26c9fcecaa..998a5ea882 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -15,11 +15,13 @@ #include #include +#include // for MAX_BLOCK_SERIALIZED_SIZE #include #include #include #include #include +#include // for WITNESS_SCALE_FACTOR #include #include // for maxmempoolMinimum #include @@ -283,7 +285,23 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Mining->addWidget(new QLabel(tr("Note that mining is heavily influenced by the settings on the Mempool tab."))); - // TODO + blockmaxsize = new QSpinBox(tabMining); + blockmaxsize->setMinimum(1); + blockmaxsize->setMaximum((MAX_BLOCK_SERIALIZED_SIZE - 1000) / 1000); + connect(blockmaxsize, SIGNAL(valueChanged(int)), this, SLOT(blockmaxsize_changed(int))); + CreateOptionUI(verticalLayout_Mining, blockmaxsize, tr("Never mine a block larger than %s kB.")); + + blockprioritysize = new QSpinBox(tabMining); + blockprioritysize->setMinimum(0); + blockprioritysize->setMaximum(blockmaxsize->maximum()); + connect(blockprioritysize, SIGNAL(valueChanged(int)), this, SLOT(blockmaxsize_increase(int))); + CreateOptionUI(verticalLayout_Mining, blockprioritysize, tr("Mine first %s kB of transactions sorted by coin-age priority.")); + + blockmaxweight = new QSpinBox(tabMining); + blockmaxweight->setMinimum(1); + blockmaxweight->setMaximum((MAX_BLOCK_WEIGHT-4000) / 1000); + connect(blockmaxweight, SIGNAL(valueChanged(int)), this, SLOT(blockmaxweight_changed(int))); + CreateOptionUI(verticalLayout_Mining, blockmaxweight, tr("Never mine a block weighing more than %s kWU.")); verticalLayout_Mining->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); @@ -543,6 +561,12 @@ void OptionsDialog::setMapper() mapper->addMapping(rejectbaremultisig, OptionsModel::rejectbaremultisig); mapper->addMapping(datacarriersize, OptionsModel::datacarriersize); + /* Mining tab */ + + mapper->addMapping(blockmaxsize, OptionsModel::blockmaxsize); + mapper->addMapping(blockprioritysize, OptionsModel::blockprioritysize); + mapper->addMapping(blockmaxweight, OptionsModel::blockmaxweight); + /* Window */ #ifndef Q_OS_MACOS if (QSystemTrayIcon::isSystemTrayAvailable()) { @@ -575,6 +599,35 @@ void OptionsDialog::setOkButtonState(bool fState) ui->okButton->setEnabled(fState); } +void OptionsDialog::blockmaxsize_changed(int i) +{ + if (blockprioritysize->value() > i) { + blockprioritysize->setValue(i); + } + + if (blockmaxweight->value() < i) { + blockmaxweight->setValue(i); + } else if (blockmaxweight->value() > i * WITNESS_SCALE_FACTOR) { + blockmaxweight->setValue(i * WITNESS_SCALE_FACTOR); + } +} + +void OptionsDialog::blockmaxsize_increase(int i) +{ + if (blockmaxsize->value() < i) { + blockmaxsize->setValue(i); + } +} + +void OptionsDialog::blockmaxweight_changed(int i) +{ + if (blockmaxsize->value() < i / WITNESS_SCALE_FACTOR) { + blockmaxsize->setValue(i / WITNESS_SCALE_FACTOR); + } else if (blockmaxsize->value() > i) { + blockmaxsize->setValue(i); + } +} + void OptionsDialog::on_resetButton_clicked() { if (model) { diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 1487b2162d..e60f023535 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -75,6 +75,10 @@ private Q_SLOTS: void updateDefaultProxyNets(); void checkLineEdit(); + void blockmaxsize_changed(int); + void blockmaxsize_increase(int); + void blockmaxweight_changed(int); + Q_SIGNALS: void proxyIpChecks(QValidatedLineEdit *pUiProxyIp, uint16_t nProxyPort); void quitOnReset(); @@ -102,6 +106,8 @@ private: QSpinBox *limitdescendantsize; QCheckBox *rejectbaremultisig; QSpinBox *datacarriersize; + + QSpinBox *blockmaxsize, *blockprioritysize, *blockmaxweight; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 31bc00d249..f25ae7d419 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -662,6 +662,12 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return !node().mempool().m_opts.permit_bare_multisig; case datacarriersize: return qlonglong(node().mempool().m_opts.max_datacarrier_bytes.value_or(0)); + case blockmaxsize: + return qlonglong(gArgs.GetIntArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE) / 1000); + case blockprioritysize: + return qlonglong(gArgs.GetIntArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE) / 1000); + case blockmaxweight: + return qlonglong(gArgs.GetIntArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT) / 1000); default: return QVariant(); } @@ -1115,6 +1121,29 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } } break; + case blockmaxsize: + case blockprioritysize: + case blockmaxweight: + if (changed()) { + const int nNewValue_kB = value.toInt(); + std::string strNv = strprintf("%d000", nNewValue_kB); + std::string strKey; + switch (option) { + case blockmaxsize: + strKey = "blockmaxsize"; + break; + case blockprioritysize: + strKey = "blockprioritysize"; + break; + case blockmaxweight: + strKey = "blockmaxweight"; + break; + default: assert(0); + } + gArgs.ForceSetArg("-" + strKey, strNv); + gArgs.ModifyRWConfigFile(strKey, strNv); + } + break; default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index ad79045ce0..337bc3f228 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -93,6 +93,9 @@ public: limitdescendantsize, rejectbaremultisig, // bool datacarriersize, + blockmaxsize, + blockprioritysize, + blockmaxweight, OptionIDRowCount, }; From 63eee421030c026690bbba8bfd5350d5f11785bd Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 3 Feb 2025 23:45:32 +0000 Subject: [PATCH 17/55] Qt/Options: Configure minrelaytxfee using rwconf --- src/qt/optionsdialog.cpp | 5 +++++ src/qt/optionsdialog.h | 2 ++ src/qt/optionsmodel.cpp | 10 ++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 18 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 998a5ea882..7811c2ffdb 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -231,6 +232,9 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Spamfiltering->addWidget(rejectunknownscripts); FixTabOrder(rejectunknownscripts); + minrelaytxfee = new BitcoinAmountField(groupBox_Spamfiltering); + CreateOptionUI(verticalLayout_Spamfiltering, minrelaytxfee, tr("Ignore transactions offering miners less than %s per kvB in transaction fees.")); + bytespersigop = new QSpinBox(groupBox_Spamfiltering); bytespersigop->setMinimum(1); bytespersigop->setMaximum(std::numeric_limits::max()); @@ -552,6 +556,7 @@ void OptionsDialog::setMapper() mapper->addMapping(mempoolexpiry, OptionsModel::mempoolexpiry); mapper->addMapping(rejectunknownscripts, OptionsModel::rejectunknownscripts); + mapper->addMapping(minrelaytxfee, OptionsModel::minrelaytxfee); mapper->addMapping(bytespersigop, OptionsModel::bytespersigop); mapper->addMapping(bytespersigopstrict, OptionsModel::bytespersigopstrict); mapper->addMapping(limitancestorcount, OptionsModel::limitancestorcount); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index e60f023535..ffcdcf1b73 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -8,6 +8,7 @@ #include #include +class BitcoinAmountField; class ClientModel; class OptionsModel; class QValidatedLineEdit; @@ -99,6 +100,7 @@ private: QSpinBox *mempoolexpiry; QCheckBox *rejectunknownscripts; + BitcoinAmountField *minrelaytxfee; QSpinBox *bytespersigop, *bytespersigopstrict; QSpinBox *limitancestorcount; QSpinBox *limitancestorsize; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index f25ae7d419..b4b7435eff 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -25,6 +25,7 @@ #include #include #include // for -dbcache defaults +#include // for FormatMoney #include #include // For DEFAULT_SCRIPTCHECK_THREADS #include // For DEFAULT_SPEND_ZEROCONF_CHANGE @@ -646,6 +647,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(std::chrono::duration_cast(node().mempool().m_opts.expiry).count()); case rejectunknownscripts: return node().mempool().m_opts.require_standard; + case minrelaytxfee: + return qlonglong(node().mempool().m_opts.min_relay_feerate.GetFeePerK()); case bytespersigop: return nBytesPerSigOp; case bytespersigopstrict: @@ -1049,6 +1052,13 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case minrelaytxfee: + if (changed()) { + CAmount nNv = value.toLongLong(); + gArgs.ModifyRWConfigFile("minrelaytxfee", FormatMoney(nNv)); + node().mempool().m_opts.min_relay_feerate = CFeeRate(nNv); + } + break; case bytespersigop: if (changed()) { gArgs.ModifyRWConfigFile("bytespersigop", value.toString().toStdString()); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 337bc3f228..afe4a0bb91 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -85,6 +85,7 @@ public: maxmempool, mempoolexpiry, rejectunknownscripts, // bool + minrelaytxfee, bytespersigop, bytespersigopstrict, limitancestorcount, From 8102b5aa39855450dc12bb62087c0318fb9f7e4b Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 7 Feb 2017 22:41:52 +0000 Subject: [PATCH 18/55] Qt/Options: Configure walletrbf using rwconf --- src/qt/optionsdialog.cpp | 9 +++++++++ src/qt/optionsdialog.h | 2 ++ src/qt/optionsmodel.cpp | 22 ++++++++++++++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 34 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 7811c2ffdb..d910d7285b 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -192,6 +192,14 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) ui->maxuploadtarget->setMaximum(std::numeric_limits::max()); connect(ui->maxuploadtargetCheckbox, SIGNAL(toggled(bool)), ui->maxuploadtarget, SLOT(setEnabled(bool))); + prevwidget = ui->tabWidget; + + walletrbf = new QCheckBox(ui->tabWallet); + walletrbf->setText(tr("Request Replace-By-Fee")); + walletrbf->setToolTip(tr("Indicates that the sender may wish to replace this transaction with a new one paying higher fees (prior to being confirmed). Can be overridden per send.")); + ui->verticalLayout_Wallet->insertWidget(0, walletrbf); + FixTabOrder(walletrbf); + prevwidget = ui->peerbloomfilters; /* Mempool tab */ @@ -495,6 +503,7 @@ void OptionsDialog::setMapper() mapper->addMapping(ui->pruneSizeMiB, OptionsModel::PruneSizeMiB); /* Wallet */ + mapper->addMapping(walletrbf, OptionsModel::walletrbf); mapper->addMapping(ui->addressType, OptionsModel::addresstype); mapper->addMapping(ui->spendZeroConfChange, OptionsModel::SpendZeroConfChange); mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index ffcdcf1b73..e0bec76e3e 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -94,6 +94,8 @@ private: void FixTabOrder(QWidget *); void CreateOptionUI(QBoxLayout *, QWidget *, const QString& text); + QCheckBox *walletrbf; + QValueComboBox *mempoolreplacement; QSpinBox *maxorphantx; QSpinBox *maxmempool; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index b4b7435eff..07a6455b24 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -611,6 +611,10 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return QVariant::fromValue(m_font_qrcodes); case PeersTabAlternatingRowColors: return m_peers_tab_alternating_row_colors; +#ifdef ENABLE_WALLET + case walletrbf: + return gArgs.GetBoolArg("-walletrbf", wallet::DEFAULT_WALLET_RBF); +#endif case CoinControlFeatures: return fCoinControlFeatures; case EnablePSBTControls: @@ -886,6 +890,24 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: settings.setValue("PeersTabAlternatingRowColors", m_peers_tab_alternating_row_colors); Q_EMIT peersTabAlternatingRowColorsChanged(m_peers_tab_alternating_row_colors); break; +#ifdef ENABLE_WALLET + case walletrbf: + if (changed()) { + const bool fNewValue = value.toBool(); + const std::string newvalue_str = strprintf("%d", fNewValue); + gArgs.ModifyRWConfigFile("walletrbf", newvalue_str); + gArgs.ForceSetArg("-walletrbf", newvalue_str); + for (auto& wallet_interface : m_node.walletLoader().getWallets()) { + wallet::CWallet *wallet; + if (wallet_interface && (wallet = wallet_interface->wallet())) { + wallet->m_signal_rbf = fNewValue; + } else { + setRestartRequired(true); + } + } + } + break; +#endif case CoinControlFeatures: fCoinControlFeatures = value.toBool(); settings.setValue("fCoinControlFeatures", fCoinControlFeatures); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index afe4a0bb91..bfb9c45131 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -64,6 +64,7 @@ public: FontForMoney, // FontChoice FontForQRCodes, // FontChoice PeersTabAlternatingRowColors, // bool + walletrbf, // bool CoinControlFeatures, // bool SubFeeFromAmount, // bool ThreadsScriptVerif, // int From e8f3dbeb28cb84f81a54ac847ef48eaa2612755e Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 7 Feb 2017 23:28:03 +0000 Subject: [PATCH 19/55] Qt/Options: Configure blockreconstructionextratxn using rwconf --- src/qt/optionsdialog.cpp | 13 +++++++++++++ src/qt/optionsdialog.h | 2 ++ src/qt/optionsmodel.cpp | 9 +++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 25 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index d910d7285b..881a7bf5fe 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -200,6 +200,17 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) ui->verticalLayout_Wallet->insertWidget(0, walletrbf); FixTabOrder(walletrbf); + /* Network tab */ + QLayoutItem *spacer = ui->verticalLayout_Network->takeAt(ui->verticalLayout_Network->count() - 1); + prevwidget = dynamic_cast(ui->verticalLayout_Network->itemAt(ui->verticalLayout_Network->count() - 1))->widget(); + + blockreconstructionextratxn = new QSpinBox(ui->tabNetwork); + blockreconstructionextratxn->setMinimum(0); + blockreconstructionextratxn->setMaximum(std::numeric_limits::max()); + CreateOptionUI(ui->verticalLayout_Network, blockreconstructionextratxn, tr("Keep at most %s extra transactions in memory for compact block reconstruction")); + + ui->verticalLayout_Network->addItem(spacer); + prevwidget = ui->peerbloomfilters; /* Mempool tab */ @@ -550,6 +561,8 @@ void OptionsDialog::setMapper() ui->peerblockfilters->setToolTip(ui->peerblockfilters->toolTip() + " " + tr("(only available if enabled at least once before turning on pruning)")); } + mapper->addMapping(blockreconstructionextratxn, OptionsModel::blockreconstructionextratxn); + /* Mempool tab */ QVariant current_mempoolreplacement = model->data(model->index(OptionsModel::mempoolreplacement, 0), Qt::EditRole); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index e0bec76e3e..e99ca735d4 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -96,6 +96,8 @@ private: QCheckBox *walletrbf; + QSpinBox *blockreconstructionextratxn; + QValueComboBox *mempoolreplacement; QSpinBox *maxorphantx; QSpinBox *maxmempool; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 07a6455b24..28a8d013b7 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -675,6 +675,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(gArgs.GetIntArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE) / 1000); case blockmaxweight: return qlonglong(gArgs.GetIntArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT) / 1000); + case blockreconstructionextratxn: + return qlonglong(gArgs.GetIntArg("-blockreconstructionextratxn", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN)); default: return QVariant(); } @@ -1176,6 +1178,13 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: gArgs.ModifyRWConfigFile(strKey, strNv); } break; + case blockreconstructionextratxn: + if (changed()) { + std::string strNv = value.toString().toStdString(); + gArgs.ForceSetArg("-blockreconstructionextratxn", strNv); + gArgs.ModifyRWConfigFile("blockreconstructionextratxn", strNv); + } + break; default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index bfb9c45131..5b3ba871f9 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -98,6 +98,7 @@ public: blockmaxsize, blockprioritysize, blockmaxweight, + blockreconstructionextratxn, OptionIDRowCount, }; From 1fa73518834b63a7104636e99aaa3bfc3f0fb432 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 3 Feb 2025 23:56:51 +0000 Subject: [PATCH 20/55] Qt/Options: Configure incrementalrelayfee using rwconf --- src/qt/optionsdialog.cpp | 19 ++++++++++++++++++- src/qt/optionsdialog.h | 2 ++ src/qt/optionsmodel.cpp | 9 +++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 881a7bf5fe..fb6e4127c1 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -49,7 +49,12 @@ void OptionsDialog::FixTabOrder(QWidget * const o) { - setTabOrder(prevwidget, o); + BitcoinAmountField * const af = qobject_cast(o); + if (af) { + af->setupTabChain(prevwidget); + } else { + setTabOrder(prevwidget, o); + } prevwidget = o; } @@ -236,6 +241,10 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) maxmempool->setMaximum(std::numeric_limits::max()); CreateOptionUI(verticalLayout_Mempool, maxmempool, tr("Keep the transaction memory pool below %s MB")); + incrementalrelayfee = new BitcoinAmountField(tabMempool); + connect(incrementalrelayfee, SIGNAL(valueChanged()), this, SLOT(incrementalrelayfee_changed())); + CreateOptionUI(verticalLayout_Mempool, incrementalrelayfee, tr("Require transaction fees to be at least %s per kvB higher than transactions they are replacing.")); + mempoolexpiry = new QSpinBox(tabMempool); mempoolexpiry->setMinimum(1); mempoolexpiry->setMaximum(std::numeric_limits::max()); @@ -575,6 +584,7 @@ void OptionsDialog::setMapper() mapper->addMapping(maxorphantx, OptionsModel::maxorphantx); mapper->addMapping(maxmempool, OptionsModel::maxmempool); + mapper->addMapping(incrementalrelayfee, OptionsModel::incrementalrelayfee); mapper->addMapping(mempoolexpiry, OptionsModel::mempoolexpiry); mapper->addMapping(rejectunknownscripts, OptionsModel::rejectunknownscripts); @@ -626,6 +636,13 @@ void OptionsDialog::setOkButtonState(bool fState) ui->okButton->setEnabled(fState); } +void OptionsDialog::incrementalrelayfee_changed() +{ + if (incrementalrelayfee->value() > minrelaytxfee->value()) { + minrelaytxfee->setValue(incrementalrelayfee->value()); + } +} + void OptionsDialog::blockmaxsize_changed(int i) { if (blockprioritysize->value() > i) { diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index e99ca735d4..6ffaf9ebb6 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -76,6 +76,7 @@ private Q_SLOTS: void updateDefaultProxyNets(); void checkLineEdit(); + void incrementalrelayfee_changed(); void blockmaxsize_changed(int); void blockmaxsize_increase(int); void blockmaxweight_changed(int); @@ -100,6 +101,7 @@ private: QValueComboBox *mempoolreplacement; QSpinBox *maxorphantx; + BitcoinAmountField *incrementalrelayfee; QSpinBox *maxmempool; QSpinBox *mempoolexpiry; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 28a8d013b7..94425265af 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -647,6 +647,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(gArgs.GetIntArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); case maxmempool: return qlonglong(node().mempool().m_opts.max_size_bytes / 1'000'000); + case incrementalrelayfee: + return qlonglong(node().mempool().m_opts.incremental_relay_feerate.GetFeePerK()); case mempoolexpiry: return qlonglong(std::chrono::duration_cast(node().mempool().m_opts.expiry).count()); case rejectunknownscripts: @@ -1047,6 +1049,13 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case incrementalrelayfee: + if (changed()) { + CAmount nNv = value.toLongLong(); + gArgs.ModifyRWConfigFile("incrementalrelayfee", FormatMoney(nNv)); + node().mempool().m_opts.incremental_relay_feerate = CFeeRate(nNv); + } + break; case mempoolexpiry: { if (changed()) { diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 5b3ba871f9..911111fe6d 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -84,6 +84,7 @@ public: mempoolreplacement, maxorphantx, maxmempool, + incrementalrelayfee, mempoolexpiry, rejectunknownscripts, // bool minrelaytxfee, From dc03e92c4e6527a921e6bcf8f59628213092ef23 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 4 Feb 2025 00:02:27 +0000 Subject: [PATCH 21/55] Qt/Options: Configure dustrelayfee using rwconf --- src/qt/optionsdialog.cpp | 4 ++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 15 +++++++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 21 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index fb6e4127c1..e66e767c85 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -305,6 +305,9 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) datacarriersize->setToolTip(tr("Since 2014, a specific method for attaching arbitrary data to transactions has been recognised as not requiring space in the coin database. Since it is sometimes impractical to detect small spam disguised as ordinary transactions, it is sometimes considered beneficial to treat these less harmful data attachments as equals to legitimate usage.")); CreateOptionUI(verticalLayout_Spamfiltering, datacarriersize, tr("Ignore transactions with additional data larger than %s bytes.")); + dustrelayfee = new BitcoinAmountField(groupBox_Spamfiltering); + CreateOptionUI(verticalLayout_Spamfiltering, dustrelayfee, tr("Ignore transactions with values that would cost more to spend at a fee rate of %s per kvB.")); + verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); @@ -597,6 +600,7 @@ void OptionsDialog::setMapper() mapper->addMapping(limitdescendantsize, OptionsModel::limitdescendantsize); mapper->addMapping(rejectbaremultisig, OptionsModel::rejectbaremultisig); mapper->addMapping(datacarriersize, OptionsModel::datacarriersize); + mapper->addMapping(dustrelayfee, OptionsModel::dustrelayfee); /* Mining tab */ diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 6ffaf9ebb6..94cf45ba3d 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -114,6 +114,7 @@ private: QSpinBox *limitdescendantsize; QCheckBox *rejectbaremultisig; QSpinBox *datacarriersize; + BitcoinAmountField *dustrelayfee; QSpinBox *blockmaxsize, *blockprioritysize, *blockmaxweight; }; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 94425265af..da9e0dd088 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -671,6 +671,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return !node().mempool().m_opts.permit_bare_multisig; case datacarriersize: return qlonglong(node().mempool().m_opts.max_datacarrier_bytes.value_or(0)); + case dustrelayfee: + return qlonglong(node().mempool().m_opts.dust_relay_feerate_floor.GetFeePerK()); case blockmaxsize: return qlonglong(gArgs.GetIntArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE) / 1000); case blockprioritysize: @@ -1164,6 +1166,19 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } } break; + case dustrelayfee: + if (changed()) { + CAmount nNv = value.toLongLong(); + gArgs.ModifyRWConfigFile("dustrelayfee", FormatMoney(nNv)); + CFeeRate feerate{nNv}; + node().mempool().m_opts.dust_relay_feerate_floor = feerate; + if (node().mempool().m_opts.dust_relay_feerate < feerate || !node().mempool().m_opts.dust_relay_target) { + node().mempool().m_opts.dust_relay_feerate = feerate; + } else { + node().mempool().UpdateDynamicDustFeerate(); + } + } + break; case blockmaxsize: case blockprioritysize: case blockmaxweight: diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 911111fe6d..143ce6cbaa 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -96,6 +96,7 @@ public: limitdescendantsize, rejectbaremultisig, // bool datacarriersize, + dustrelayfee, blockmaxsize, blockprioritysize, blockmaxweight, From d15608edced13af4f052445b0e76595c572b5f78 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 4 Feb 2025 00:05:22 +0000 Subject: [PATCH 22/55] Qt/Options: Configure blockmintxfee using rwconf --- src/qt/optionsdialog.cpp | 4 ++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 13 +++++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 19 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index e66e767c85..fca06369a6 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -320,6 +320,9 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Mining->addWidget(new QLabel(tr("Note that mining is heavily influenced by the settings on the Mempool tab."))); + blockmintxfee = new BitcoinAmountField(tabMining); + CreateOptionUI(verticalLayout_Mining, blockmintxfee, tr("Only mine transactions paying a fee of at least %s per kvB.")); + blockmaxsize = new QSpinBox(tabMining); blockmaxsize->setMinimum(1); blockmaxsize->setMaximum((MAX_BLOCK_SERIALIZED_SIZE - 1000) / 1000); @@ -604,6 +607,7 @@ void OptionsDialog::setMapper() /* Mining tab */ + mapper->addMapping(blockmintxfee, OptionsModel::blockmintxfee); mapper->addMapping(blockmaxsize, OptionsModel::blockmaxsize); mapper->addMapping(blockprioritysize, OptionsModel::blockprioritysize); mapper->addMapping(blockmaxweight, OptionsModel::blockmaxweight); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 94cf45ba3d..642ceabfae 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -116,6 +116,7 @@ private: QSpinBox *datacarriersize; BitcoinAmountField *dustrelayfee; + BitcoinAmountField *blockmintxfee; QSpinBox *blockmaxsize, *blockprioritysize, *blockmaxweight; }; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index da9e0dd088..20cb8a6c91 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -673,6 +673,12 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(node().mempool().m_opts.max_datacarrier_bytes.value_or(0)); case dustrelayfee: return qlonglong(node().mempool().m_opts.dust_relay_feerate_floor.GetFeePerK()); + case blockmintxfee: + if (gArgs.IsArgSet("-blockmintxfee")) { + return qlonglong(ParseMoney(gArgs.GetArg("-blockmintxfee", "")).value_or(0)); + } else { + return qlonglong(DEFAULT_BLOCK_MIN_TX_FEE); + } case blockmaxsize: return qlonglong(gArgs.GetIntArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE) / 1000); case blockprioritysize: @@ -1179,6 +1185,13 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } } break; + case blockmintxfee: + if (changed()) { + std::string strNv = FormatMoney(value.toLongLong()); + gArgs.ForceSetArg("-blockmintxfee", strNv); + gArgs.ModifyRWConfigFile("blockmintxfee", strNv); + } + break; case blockmaxsize: case blockprioritysize: case blockmaxweight: diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 143ce6cbaa..333c0ea256 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -97,6 +97,7 @@ public: rejectbaremultisig, // bool datacarriersize, dustrelayfee, + blockmintxfee, blockmaxsize, blockprioritysize, blockmaxweight, From 0551bcd0ff9f219229a782a3280a42b39b25f681 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 4 Feb 2025 00:08:02 +0000 Subject: [PATCH 23/55] Qt/Options: Configure spkreuse using rwconf --- src/qt/optionsdialog.cpp | 9 +++++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 12 ++++++++++++ src/qt/optionsmodel.h | 2 ++ 4 files changed, 24 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index fca06369a6..d3ce3e529a 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -260,6 +260,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Spamfiltering->addWidget(rejectunknownscripts); FixTabOrder(rejectunknownscripts); + rejectspkreuse = new QCheckBox(groupBox_Spamfiltering); + rejectspkreuse->setText(tr("Disallow most address reuse")); + rejectspkreuse->setToolTip(tr("With this option enabled, your memory pool will only allow each unique payment destination to be used once, effectively deprioritising address reuse. Address reuse is not technically supported, and harms the privacy of all Bitcoin users. It also has limited real-world utility, and has been known to be common with spam.")); + verticalLayout_Spamfiltering->addWidget(rejectspkreuse); + FixTabOrder(rejectspkreuse); + minrelaytxfee = new BitcoinAmountField(groupBox_Spamfiltering); CreateOptionUI(verticalLayout_Spamfiltering, minrelaytxfee, tr("Ignore transactions offering miners less than %s per kvB in transaction fees.")); @@ -499,6 +505,8 @@ void OptionsDialog::setModel(OptionsModel *_model) connect(ui->connectSocksTor, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); connect(ui->peerbloomfilters, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); connect(ui->peerblockfilters, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); + /* Mempool */ + connect(rejectspkreuse, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); /* Display */ connect(ui->lang, qOverload<>(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); }); connect(ui->thirdPartyTxUrls, &QLineEdit::textChanged, [this]{ showRestartWarning(); }); @@ -594,6 +602,7 @@ void OptionsDialog::setMapper() mapper->addMapping(mempoolexpiry, OptionsModel::mempoolexpiry); mapper->addMapping(rejectunknownscripts, OptionsModel::rejectunknownscripts); + mapper->addMapping(rejectspkreuse, OptionsModel::rejectspkreuse); mapper->addMapping(minrelaytxfee, OptionsModel::minrelaytxfee); mapper->addMapping(bytespersigop, OptionsModel::bytespersigop); mapper->addMapping(bytespersigopstrict, OptionsModel::bytespersigopstrict); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 642ceabfae..cd7051b885 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -106,6 +106,7 @@ private: QSpinBox *mempoolexpiry; QCheckBox *rejectunknownscripts; + QCheckBox *rejectspkreuse; BitcoinAmountField *minrelaytxfee; QSpinBox *bytespersigop, *bytespersigopstrict; QSpinBox *limitancestorcount; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 20cb8a6c91..7a04fbf2ad 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -350,7 +350,9 @@ bool OptionsModel::Init(bilingual_str& error) addOverriddenOption("-port"); // rwconf settings that require a restart + // Caution: This is before general initialisation occurs! f_peerbloomfilters = gArgs.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS); + f_rejectspkreuse = !(gArgs.GetArg("-spkreuse", DEFAULT_SPKREUSE) == "allow" || gArgs.GetBoolArg("-spkreuse", false)); // Display if (settings.contains("FontForMoney")) { @@ -653,6 +655,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(std::chrono::duration_cast(node().mempool().m_opts.expiry).count()); case rejectunknownscripts: return node().mempool().m_opts.require_standard; + case rejectspkreuse: + return f_rejectspkreuse; case minrelaytxfee: return qlonglong(node().mempool().m_opts.min_relay_feerate.GetFeePerK()); case bytespersigop: @@ -1093,6 +1097,14 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case rejectspkreuse: + if (changed()) { + const bool fNewValue = value.toBool(); + gArgs.ModifyRWConfigFile("spkreuse", fNewValue ? "conflict" : "allow"); + f_rejectspkreuse = fNewValue; + setRestartRequired(true); + } + break; case minrelaytxfee: if (changed()) { CAmount nNv = value.toLongLong(); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 333c0ea256..b04e1dd098 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -87,6 +87,7 @@ public: incrementalrelayfee, mempoolexpiry, rejectunknownscripts, // bool + rejectspkreuse, // bool minrelaytxfee, bytespersigop, bytespersigopstrict, @@ -178,6 +179,7 @@ private: /* rwconf settings that require a restart */ bool f_peerbloomfilters; + bool f_rejectspkreuse; // Add option to list of GUI options overridden through command line/config file void addOverriddenOption(const std::string &option); From 1b37b2d605b646a590275fe0dba0039ecef421c3 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 25 Feb 2016 15:51:43 +0000 Subject: [PATCH 24/55] test_IsStandard: Work with any MAX_OP_RETURN_RELAY --- src/test/transaction_tests.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index fc9a61e624..9823c6a3c3 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -873,12 +873,15 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) g_mempool_opts.reject_tokens = false; // MAX_OP_RETURN_RELAY-byte TxoutType::NULL_DATA (standard) - t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[0].scriptPubKey = CScript() << OP_RETURN; + while (t.vout[0].scriptPubKey.size() < MAX_OP_RETURN_RELAY) { + t.vout[0].scriptPubKey << OP_0; + } BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size()); CheckIsStandard(t); // MAX_OP_RETURN_RELAY+1-byte TxoutType::NULL_DATA (non-standard) - t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"); + t.vout[0].scriptPubKey << OP_0; BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size()); CheckIsNotStandard(t, "scriptpubkey"); From b67adadb9a8a0d7e0bbd029882e6ef40c0219653 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 25 Feb 2016 10:51:29 +0000 Subject: [PATCH 25/55] Adjust default policy for Knots and add -corepolicy option to undo --- src/init.cpp | 13 +++++++++++++ src/node/miner.cpp | 6 +++--- src/policy/policy.h | 14 +++++++------- src/qt/optionsdialog.cpp | 18 +++++++++++++++--- src/qt/optionsmodel.cpp | 3 +++ src/qt/optionsmodel.h | 1 + src/test/fuzz/mini_miner.cpp | 1 + src/test/miner_tests.cpp | 2 ++ test/functional/test_framework/test_node.py | 1 + 9 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 7abdedf417..f6f72eb89a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -140,6 +140,7 @@ using util::Join; using util::ReplaceAll; using util::ToString; +static constexpr bool DEFAULT_COREPOLICY{false}; static constexpr bool DEFAULT_PROXYRANDOMIZE{true}; static constexpr bool DEFAULT_REST_ENABLE{false}; static constexpr bool DEFAULT_I2P_ACCEPT_INCOMING{true}; @@ -494,6 +495,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-coinstatsindex", strprintf("Maintain coinstats index used by the gettxoutsetinfo RPC (default: %u)", DEFAULT_COINSTATSINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-conf=", strprintf("Specify path to read-only configuration file. Relative paths will be prefixed by datadir location (only useable from command line, not configuration file) (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-confrw=", strprintf("Specify read/write configuration file. Relative paths will be prefixed by the network-specific datadir location (default: %s)", BITCOIN_RW_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-corepolicy", strprintf("Use Bitcoin Core policy defaults (default: %u)", DEFAULT_COREPOLICY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-datadir=", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); argsman.AddArg("-dbcache=", strprintf("Maximum database cache size MiB (%d to %d, default: %d). In addition, unused mempool memory is shared for this cache (see -maxmempool).", nMinDbCache, nMaxDbCache, nDefaultDbCache), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -801,6 +803,17 @@ static bool AppInitServers(NodeContext& node) // Parameter interaction based on rules void InitParameterInteraction(ArgsManager& args) { + if (args.GetBoolArg("-corepolicy", DEFAULT_COREPOLICY)) { + args.SoftSetArg("-bytespersigopstrict", "0"); + args.SoftSetArg("-permitbaremultisig", "1"); + args.SoftSetArg("-datacarriersize", "83"); + + args.SoftSetArg("-spkreuse", "allow"); + args.SoftSetArg("-blockprioritysize", "0"); + args.SoftSetArg("-blockmaxsize", "4000000"); + args.SoftSetArg("-blockmaxweight", "3996000"); + } + // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified if (args.IsArgSet("-bind")) { diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 33c3ce0a1a..4b50012362 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -73,14 +73,14 @@ BlockCreateOptions BlockCreateOptions::Clamped() const constexpr size_t theoretical_min_gentx_sz = 1+4+1+36+1+1+4+1+4; constexpr size_t theoretical_min_gentx_weight = theoretical_min_gentx_sz * WITNESS_SCALE_FACTOR; CHECK_NONFATAL(options.coinbase_max_additional_size <= MAX_BLOCK_SERIALIZED_SIZE - 1000); - CHECK_NONFATAL(options.coinbase_max_additional_weight <= DEFAULT_BLOCK_MAX_WEIGHT); + CHECK_NONFATAL(options.coinbase_max_additional_weight <= MAX_BLOCK_WEIGHT - 4000); CHECK_NONFATAL(options.coinbase_max_additional_weight >= theoretical_min_gentx_weight); CHECK_NONFATAL(options.coinbase_output_max_additional_sigops <= MAX_BLOCK_SIGOPS_COST); // Limit size to between coinbase_max_additional_size and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity: options.nBlockMaxSize = std::clamp(options.nBlockMaxSize, options.coinbase_max_additional_size, MAX_BLOCK_SERIALIZED_SIZE - 1000); - // Limit weight to between coinbase_max_additional_weight and DEFAULT_BLOCK_MAX_WEIGHT for sanity: + // Limit weight to between coinbase_max_additional_weight and MAX_BLOCK_WEIGHT for sanity: // Coinbase (reserved) outputs can safely exceed -blockmaxweight, but the rest of the block template will be empty. - options.nBlockMaxWeight = std::clamp(options.nBlockMaxWeight, options.coinbase_max_additional_weight, DEFAULT_BLOCK_MAX_WEIGHT); + options.nBlockMaxWeight = std::clamp(options.nBlockMaxWeight, options.coinbase_max_additional_weight, MAX_BLOCK_WEIGHT); return options; } diff --git a/src/policy/policy.h b/src/policy/policy.h index 99efc581b1..c369875fef 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -25,13 +25,13 @@ struct MemPoolOptions; }; /** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/ -static const unsigned int DEFAULT_BLOCK_MAX_SIZE = MAX_BLOCK_SERIALIZED_SIZE; +static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 300000; /** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ -static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 0; +static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 100000; /** Minimum priority for transactions to be accepted into the priority area **/ static const double MINIMUM_TX_PRIORITY = COIN * 144 / 250; /** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/ -static constexpr unsigned int DEFAULT_BLOCK_MAX_WEIGHT{MAX_BLOCK_WEIGHT - 4000}; +static constexpr unsigned int DEFAULT_BLOCK_MAX_WEIGHT{DEFAULT_BLOCK_MAX_SIZE * WITNESS_SCALE_FACTOR}; /** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/ static constexpr unsigned int DEFAULT_BLOCK_MIN_TX_FEE{1000}; /** The maximum weight for transactions we're willing to relay/mine */ @@ -57,7 +57,7 @@ static constexpr bool DEFAULT_REJECT_TOKENS{false}; /** Default for -permitbarepubkey */ static constexpr bool DEFAULT_PERMIT_BAREPUBKEY{true}; /** Default for -permitbaremultisig */ -static constexpr bool DEFAULT_PERMIT_BAREMULTISIG{true}; +static constexpr bool DEFAULT_PERMIT_BAREMULTISIG{false}; /** Default for -rejectparasites */ static constexpr bool DEFAULT_REJECT_PARASITES{false}; /** The maximum number of witness stack items in a standard P2WSH script */ @@ -92,10 +92,10 @@ static constexpr unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT_KVB{101}; /** Default for -datacarrier */ static const bool DEFAULT_ACCEPT_DATACARRIER = true; /** - * Default setting for -datacarriersize. 80 bytes of data, +1 for OP_RETURN, - * +2 for the pushdata opcodes. + * Default setting for -datacarriersize. 40 bytes of data, +1 for OP_RETURN, + * +1 for the pushdata opcode. */ -static const unsigned int MAX_OP_RETURN_RELAY = 83; +static constexpr unsigned int MAX_OP_RETURN_RELAY{42}; /** Default for -datacarrierfullcount */ static constexpr bool DEFAULT_DATACARRIER_FULLCOUNT{false}; /** diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index d3ce3e529a..8c0cc52d15 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -704,14 +705,25 @@ void OptionsDialog::on_resetButton_clicked() with a client shutdown. */ reset_dialog_text.append(tr("Client will be shut down. Do you want to proceed?")); //: Window title text of pop-up window shown when the user has chosen to reset options. - QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"), - reset_dialog_text, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); + QStringList items; + QString strPrefix = tr("Use policy defaults for %1"); + items << strPrefix.arg(tr(PACKAGE_NAME)); + items << strPrefix.arg(tr("Bitcoin Core")+" "); - if (btnRetVal == QMessageBox::Cancel) + QInputDialog dialog(this); + dialog.setWindowTitle(tr("Confirm options reset")); + dialog.setLabelText(reset_dialog_text); + dialog.setComboBoxItems(items); + dialog.setTextValue(items[0]); + dialog.setComboBoxEditable(false); + + if (!dialog.exec()) { return; + } /* reset all options and close GUI */ model->Reset(); + model->setData(model->index(OptionsModel::corepolicy, 0), items.indexOf(dialog.textValue())); close(); Q_EMIT quitOnReset(); } diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 7a04fbf2ad..2c78529792 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -1234,6 +1234,9 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: gArgs.ModifyRWConfigFile("blockreconstructionextratxn", strNv); } break; + case corepolicy: + gArgs.ModifyRWConfigFile("corepolicy", value.toString().toStdString()); + break; default: break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index b04e1dd098..0e6986a5c1 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -103,6 +103,7 @@ public: blockprioritysize, blockmaxweight, blockreconstructionextratxn, + corepolicy, OptionIDRowCount, }; diff --git a/src/test/fuzz/mini_miner.cpp b/src/test/fuzz/mini_miner.cpp index 24cee28112..e6115e54a3 100644 --- a/src/test/fuzz/mini_miner.cpp +++ b/src/test/fuzz/mini_miner.cpp @@ -30,6 +30,7 @@ void initialize_miner() for (uint32_t i = 0; i < uint32_t{100}; ++i) { g_available_coins.emplace_back(Txid::FromUint256(uint256::ZERO), i); } + g_setup->m_node.args->ForceSetArg("-blockprioritysize", "0"); } // Test that the MiniMiner can run with various outpoints and feerates. diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 6ff08aec86..801d49bdba 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -607,6 +607,8 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { + gArgs.ForceSetArg("-blockprioritysize", "0"); + // Note that by default, these tests run with size accounting enabled. CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; std::shared_ptr pblocktemplate; diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 9c2b613778..2fa829b038 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -131,6 +131,7 @@ class TestNode(): if self.version is None: self.args += [ + "-corepolicy", "-softwareexpiry=0", "-walletimplicitsegwit", ] From 708fbd4e0f7be8855a0ae06a76b325c8ce90744f Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 19 Aug 2023 14:38:33 +0000 Subject: [PATCH 26/55] GUI/Options: When changing mempoolreplacement, update settings.json with mempoolfullrbf too --- src/qt/optionsmodel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 2c78529792..0505264fdf 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -1018,10 +1018,13 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: QString nv = value.toString(); if (nv == "never") { node().mempool().m_opts.rbf_policy = RBFPolicy::Never; + node().updateRwSetting("mempoolfullrbf", "0"); } else if (nv == "fee,optin") { node().mempool().m_opts.rbf_policy = RBFPolicy::OptIn; + node().updateRwSetting("mempoolfullrbf", "0"); } else { // "fee,-optin" node().mempool().m_opts.rbf_policy = RBFPolicy::Always; + node().updateRwSetting("mempoolfullrbf", "1"); } gArgs.ModifyRWConfigFile("mempoolreplacement", nv.toStdString()); } From 69bcc02d5f4e1799b414736bff6b140ae7d0aa9b Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 5 Sep 2023 00:56:34 +0000 Subject: [PATCH 27/55] Default to more reasonable datacarriercost=1 datacarrierfullcount=1 --- src/init.cpp | 2 ++ src/policy/policy.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index f6f72eb89a..4d72151e50 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -806,6 +806,8 @@ void InitParameterInteraction(ArgsManager& args) if (args.GetBoolArg("-corepolicy", DEFAULT_COREPOLICY)) { args.SoftSetArg("-bytespersigopstrict", "0"); args.SoftSetArg("-permitbaremultisig", "1"); + args.SoftSetArg("-datacarriercost", "0.25"); + args.SoftSetArg("-datacarrierfullcount", "0"); args.SoftSetArg("-datacarriersize", "83"); args.SoftSetArg("-spkreuse", "allow"); diff --git a/src/policy/policy.h b/src/policy/policy.h index c369875fef..9c5ee9f05c 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -51,7 +51,7 @@ static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP{20}; /** Default for -bytespersigopstrict */ static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP_STRICT{20}; /** Default for -datacarriercost (multiplied by WITNESS_SCALE_FACTOR) */ -static constexpr unsigned int DEFAULT_WEIGHT_PER_DATA_BYTE{1}; +static constexpr unsigned int DEFAULT_WEIGHT_PER_DATA_BYTE{4}; /** Default for -rejecttokens */ static constexpr bool DEFAULT_REJECT_TOKENS{false}; /** Default for -permitbarepubkey */ @@ -97,7 +97,7 @@ static const bool DEFAULT_ACCEPT_DATACARRIER = true; */ static constexpr unsigned int MAX_OP_RETURN_RELAY{42}; /** Default for -datacarrierfullcount */ -static constexpr bool DEFAULT_DATACARRIER_FULLCOUNT{false}; +static constexpr bool DEFAULT_DATACARRIER_FULLCOUNT{true}; /** * An extra transaction can be added to a package, as long as it only has one * ancestor and is no larger than this. Not really any reason to make this From 60dea73864b799e0305d2e1e34af3322331870f9 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 6 Sep 2023 03:05:29 +0000 Subject: [PATCH 28/55] GUI/Options: Rewrite datacarriersize tooltip in light of match_more_datacarrier --- src/qt/optionsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 8c0cc52d15..447a6e13e8 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -309,7 +309,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) datacarriersize = new QSpinBox(groupBox_Spamfiltering); datacarriersize->setMinimum(0); datacarriersize->setMaximum(std::numeric_limits::max()); - datacarriersize->setToolTip(tr("Since 2014, a specific method for attaching arbitrary data to transactions has been recognised as not requiring space in the coin database. Since it is sometimes impractical to detect small spam disguised as ordinary transactions, it is sometimes considered beneficial to treat these less harmful data attachments as equals to legitimate usage.")); + datacarriersize->setToolTip(tr("While Bitcoin itself does not support attaching arbitrary data to transactions, despite that various methods for disguising it have been devised over the years. Since it is sometimes impractical to detect small spam disguised as ordinary transactions, it is sometimes considered beneficial to tolerate certain kinds of less harmful data attachments.")); CreateOptionUI(verticalLayout_Spamfiltering, datacarriersize, tr("Ignore transactions with additional data larger than %s bytes.")); dustrelayfee = new BitcoinAmountField(groupBox_Spamfiltering); From 3e1b343fef409f75a87d9b2ca4a9ab3ec3013e6b Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 4 Feb 2025 01:31:27 +0000 Subject: [PATCH 29/55] GUI/Options: Configure datacarriercost using settings --- src/qt/optionsdialog.cpp | 16 ++++++++++++++++ src/qt/optionsdialog.h | 2 ++ src/qt/optionsmodel.cpp | 11 +++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 30 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 447a6e13e8..0726d506d8 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -312,6 +313,20 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) datacarriersize->setToolTip(tr("While Bitcoin itself does not support attaching arbitrary data to transactions, despite that various methods for disguising it have been devised over the years. Since it is sometimes impractical to detect small spam disguised as ordinary transactions, it is sometimes considered beneficial to tolerate certain kinds of less harmful data attachments.")); CreateOptionUI(verticalLayout_Spamfiltering, datacarriersize, tr("Ignore transactions with additional data larger than %s bytes.")); + datacarriercost = new QDoubleSpinBox(groupBox_Spamfiltering); + datacarriercost->setDecimals(2); + datacarriercost->setStepType(QAbstractSpinBox::DefaultStepType); + datacarriercost->setSingleStep(0.25); + datacarriercost->setMinimum(0.25); + datacarriercost->setMaximum(MAX_BLOCK_SERIALIZED_SIZE); + datacarriercost->setToolTip(tr("As an alternative to, or in addition to, limiting the size of disguised data, you can also configure how it is accounted for in comparison to legitimate transaction data. For example, 1 vbyte per actual byte would count it as equivalent to ordinary transaction data; 0.25 vB/B would allow it to benefit from the so-called \"segwit discount\"; or 2 vB/B would establish a bias toward legitimate transactions.")); + CreateOptionUI(verticalLayout_Spamfiltering, datacarriercost, tr("Weigh embedded data as %s virtual bytes per actual byte.")); + connect(datacarriercost, QOverload::of(&QDoubleSpinBox::valueChanged), [&](double d){ + const double w = d * 4; + const double wf = floor(w); + if (w != wf) datacarriercost->setValue(wf / 4); + }); + dustrelayfee = new BitcoinAmountField(groupBox_Spamfiltering); CreateOptionUI(verticalLayout_Spamfiltering, dustrelayfee, tr("Ignore transactions with values that would cost more to spend at a fee rate of %s per kvB.")); @@ -612,6 +627,7 @@ void OptionsDialog::setMapper() mapper->addMapping(limitdescendantcount, OptionsModel::limitdescendantcount); mapper->addMapping(limitdescendantsize, OptionsModel::limitdescendantsize); mapper->addMapping(rejectbaremultisig, OptionsModel::rejectbaremultisig); + mapper->addMapping(datacarriercost, OptionsModel::datacarriercost); mapper->addMapping(datacarriersize, OptionsModel::datacarriersize); mapper->addMapping(dustrelayfee, OptionsModel::dustrelayfee); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index cd7051b885..47c7146256 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -17,6 +17,7 @@ QT_BEGIN_NAMESPACE class QBoxLayout; class QCheckBox; class QDataWidgetMapper; +class QDoubleSpinBox; class QSpinBox; class QString; class QValueComboBox; @@ -115,6 +116,7 @@ private: QSpinBox *limitdescendantsize; QCheckBox *rejectbaremultisig; QSpinBox *datacarriersize; + QDoubleSpinBox *datacarriercost; BitcoinAmountField *dustrelayfee; BitcoinAmountField *blockmintxfee; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 0505264fdf..4219134ede 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include // for DEFAULT_MAX_MEMPOOL_SIZE_MB, DEFAULT_MEMPOOL_EXPIRY_HOURS @@ -75,6 +76,7 @@ static const char* SettingName(OptionsModel::OptionID option) case OptionsModel::maxuploadtarget: return "maxuploadtarget"; case OptionsModel::peerbloomfilters: return "peerbloomfilters"; case OptionsModel::peerblockfilters: return "peerblockfilters"; + case OptionsModel::datacarriercost: return "datacarriercost"; default: throw std::logic_error(strprintf("GUI option %i has no corresponding node setting.", option)); } } @@ -673,6 +675,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(node().mempool().m_opts.limits.descendant_size_vbytes / 1'000); case rejectbaremultisig: return !node().mempool().m_opts.permit_bare_multisig; + case datacarriercost: + return double(::g_weight_per_data_byte) / WITNESS_SCALE_FACTOR; case datacarriersize: return qlonglong(node().mempool().m_opts.max_datacarrier_bytes.value_or(0)); case dustrelayfee: @@ -1171,6 +1175,13 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: gArgs.ModifyRWConfigFile("permitbaremultisig", strprintf("%d", fNewValue)); } break; + case datacarriercost: + if (changed()) { + const double nNewSize = value.toDouble(); + update(nNewSize); + ::g_weight_per_data_byte = nNewSize * WITNESS_SCALE_FACTOR; + } + break; case datacarriersize: if (changed()) { const int nNewSize = value.toInt(); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 0e6986a5c1..f6f7cc3c3c 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -96,6 +96,7 @@ public: limitdescendantcount, limitdescendantsize, rejectbaremultisig, // bool + datacarriercost, // double datacarriersize, dustrelayfee, blockmintxfee, From 57fadfa0360d079bfefd401d0a2873f336fe6674 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 4 Feb 2025 01:53:39 +0000 Subject: [PATCH 30/55] Set maxscriptsize policy option default to 1650 (like MAX_STANDARD_SCRIPTSIG_SIZE) --- src/init.cpp | 2 +- src/policy/policy.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 4d72151e50..68075f841b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -809,7 +809,7 @@ void InitParameterInteraction(ArgsManager& args) args.SoftSetArg("-datacarriercost", "0.25"); args.SoftSetArg("-datacarrierfullcount", "0"); args.SoftSetArg("-datacarriersize", "83"); - + args.SoftSetArg("-maxscriptsize", strprintf("%s", std::numeric_limits::max())); args.SoftSetArg("-spkreuse", "allow"); args.SoftSetArg("-blockprioritysize", "0"); args.SoftSetArg("-blockmaxsize", "4000000"); diff --git a/src/policy/policy.h b/src/policy/policy.h index 9c5ee9f05c..6903866da0 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -45,7 +45,7 @@ static constexpr unsigned int MAX_STANDARD_TX_SIGOPS_COST{MAX_BLOCK_SIGOPS_COST/ /** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or replacement **/ static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE{1000}; /** Default for -maxscriptsize */ -static constexpr unsigned int DEFAULT_SCRIPT_SIZE_POLICY_LIMIT{std::numeric_limits::max()}; +static constexpr unsigned int DEFAULT_SCRIPT_SIZE_POLICY_LIMIT{1650}; /** Default for -bytespersigop */ static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP{20}; /** Default for -bytespersigopstrict */ From 0b0757569184c94d9a436845b358e5a11bdfc51a Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 4 Feb 2025 01:55:22 +0000 Subject: [PATCH 31/55] GUI/Options: Configure maxscriptsize using settings --- src/qt/optionsdialog.cpp | 7 +++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 9 +++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 18 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 0726d506d8..d0de145f8f 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -307,6 +307,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Spamfiltering->addWidget(rejectbaremultisig); FixTabOrder(rejectbaremultisig); + maxscriptsize = new QSpinBox(groupBox_Spamfiltering); + maxscriptsize->setMinimum(0); + maxscriptsize->setMaximum(std::numeric_limits::max()); + maxscriptsize->setToolTip(tr("There may be rare smart contracts that require a large amount of code, but more often a larger code segment is actually just spam finding new ways to try to evade filtering. 1650 bytes is sometimes considered the high end of what might be normal, usually for N-of-20 multisig.")); + CreateOptionUI(verticalLayout_Spamfiltering, maxscriptsize, tr("Ignore transactions with smart contract code larger than %s bytes.")); + datacarriersize = new QSpinBox(groupBox_Spamfiltering); datacarriersize->setMinimum(0); datacarriersize->setMaximum(std::numeric_limits::max()); @@ -627,6 +633,7 @@ void OptionsDialog::setMapper() mapper->addMapping(limitdescendantcount, OptionsModel::limitdescendantcount); mapper->addMapping(limitdescendantsize, OptionsModel::limitdescendantsize); mapper->addMapping(rejectbaremultisig, OptionsModel::rejectbaremultisig); + mapper->addMapping(maxscriptsize, OptionsModel::maxscriptsize); mapper->addMapping(datacarriercost, OptionsModel::datacarriercost); mapper->addMapping(datacarriersize, OptionsModel::datacarriersize); mapper->addMapping(dustrelayfee, OptionsModel::dustrelayfee); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 47c7146256..0cc3c2c4a7 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -115,6 +115,7 @@ private: QSpinBox *limitdescendantcount; QSpinBox *limitdescendantsize; QCheckBox *rejectbaremultisig; + QSpinBox *maxscriptsize; QSpinBox *datacarriersize; QDoubleSpinBox *datacarriercost; BitcoinAmountField *dustrelayfee; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 4219134ede..c435fc395e 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -675,6 +675,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(node().mempool().m_opts.limits.descendant_size_vbytes / 1'000); case rejectbaremultisig: return !node().mempool().m_opts.permit_bare_multisig; + case maxscriptsize: + return ::g_script_size_policy_limit; case datacarriercost: return double(::g_weight_per_data_byte) / WITNESS_SCALE_FACTOR; case datacarriersize: @@ -1175,6 +1177,13 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: gArgs.ModifyRWConfigFile("permitbaremultisig", strprintf("%d", fNewValue)); } break; + case maxscriptsize: + if (changed()) { + const auto nv = value.toLongLong(); + update(nv); + ::g_script_size_policy_limit = nv; + } + break; case datacarriercost: if (changed()) { const double nNewSize = value.toDouble(); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index f6f7cc3c3c..8263c3bbb2 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -96,6 +96,7 @@ public: limitdescendantcount, limitdescendantsize, rejectbaremultisig, // bool + maxscriptsize, datacarriercost, // double datacarriersize, dustrelayfee, From 4d0469fad965876f42583a02ff16b33199f06907 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 4 Feb 2025 02:08:49 +0000 Subject: [PATCH 32/55] QA: Adapt unit tests to not care about permitbarepubkey default --- src/test/script_p2sh_tests.cpp | 2 ++ src/test/transaction_tests.cpp | 2 ++ src/test/txvalidationcache_tests.cpp | 2 +- src/wallet/test/wallet_tests.cpp | 4 ++-- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index dd9317e965..76cda2680f 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -22,6 +22,7 @@ static bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, std::string& reason) { const kernel::MemPoolOptions opts{ + .permit_bare_pubkey = true, .permit_bare_multisig = permit_bare_multisig, }; return IsStandardTx(tx, opts, reason); @@ -30,6 +31,7 @@ static bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, std: static bool IsStandardTx(const CTransaction& tx, std::string& reason) { kernel::MemPoolOptions opts{ + .permit_bare_pubkey = true, .permit_bare_multisig = true, }; if (!IsStandardTx(tx, opts, reason)) return false; diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 9823c6a3c3..d45f911e95 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -796,6 +796,8 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) CKey key = GenerateRandomKey(); t.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); + g_mempool_opts.permit_bare_pubkey = true; + constexpr auto CheckIsStandard = [](const auto& t) { std::string reason; BOOST_CHECK(IsStandardTx(CTransaction{t}, g_mempool_opts, reason)); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index af36a95693..d22b815fcd 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -54,7 +54,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup) spends[i].vin[0].prevout.n = 0; spends[i].vout.resize(1); spends[i].vout[0].nValue = 11*CENT; - spends[i].vout[0].scriptPubKey = scriptPubKey; + spends[i].vout[0].scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey())); // Sign: std::vector vchSig; diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index e5bfa7bad6..264276f2e2 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -864,7 +864,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup) m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); auto block_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); - auto mempool_tx = TestSimpleSpend(*m_coinbase_txns[1], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); + auto mempool_tx = TestSimpleSpend(*m_coinbase_txns[1], 0, coinbaseKey, GetScriptForDestination(PKHash(key.GetPubKey()))); BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error)); @@ -906,7 +906,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup) m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); block_tx = TestSimpleSpend(*m_coinbase_txns[2], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); - mempool_tx = TestSimpleSpend(*m_coinbase_txns[3], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); + mempool_tx = TestSimpleSpend(*m_coinbase_txns[3], 0, coinbaseKey, GetScriptForDestination(PKHash(key.GetPubKey()))); BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error)); m_node.validation_signals->SyncWithValidationInterfaceQueue(); }); From a933eb7cd8d54058fefbf30eca6462b855ee7c05 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 28 Feb 2024 18:54:23 +0000 Subject: [PATCH 33/55] Default policy: Set permitbarepubkey=0 (corepolicy resets to 1) --- src/init.cpp | 1 + src/policy/policy.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 68075f841b..d8dc4e8bec 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -805,6 +805,7 @@ void InitParameterInteraction(ArgsManager& args) { if (args.GetBoolArg("-corepolicy", DEFAULT_COREPOLICY)) { args.SoftSetArg("-bytespersigopstrict", "0"); + args.SoftSetArg("-permitbarepubkey", "1"); args.SoftSetArg("-permitbaremultisig", "1"); args.SoftSetArg("-datacarriercost", "0.25"); args.SoftSetArg("-datacarrierfullcount", "0"); diff --git a/src/policy/policy.h b/src/policy/policy.h index 6903866da0..612bef98bf 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -55,7 +55,7 @@ static constexpr unsigned int DEFAULT_WEIGHT_PER_DATA_BYTE{4}; /** Default for -rejecttokens */ static constexpr bool DEFAULT_REJECT_TOKENS{false}; /** Default for -permitbarepubkey */ -static constexpr bool DEFAULT_PERMIT_BAREPUBKEY{true}; +static constexpr bool DEFAULT_PERMIT_BAREPUBKEY{false}; /** Default for -permitbaremultisig */ static constexpr bool DEFAULT_PERMIT_BAREMULTISIG{false}; /** Default for -rejectparasites */ From 73fed175b71d25624069e796887e8c84863186a6 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 4 Feb 2025 02:45:23 +0000 Subject: [PATCH 34/55] Qt/Options: Configure permitbarepubkey using settings --- src/qt/optionsdialog.cpp | 7 +++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 10 ++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 19 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index d0de145f8f..9243b97edc 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -301,6 +301,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) limitdescendantsize->setMaximum(std::numeric_limits::max()); CreateOptionUI(verticalLayout_Spamfiltering, limitdescendantsize, tr("Ignore transactions if any ancestor would have more than %s kilobytes of unconfirmed descendants.")); + rejectbarepubkey = new QCheckBox(groupBox_Spamfiltering); + rejectbarepubkey->setText(tr("Ignore bare/exposed public keys (pay-to-IP)")); + rejectbarepubkey->setToolTip(tr("Spam is sometimes disguised to appear as if it is a deprecated pay-to-IP (bare pubkey) transaction, where the \"key\" is actually arbitrary data (not a real key) instead. Support for pay-to-IP was only ever supported by Satoshi's early Bitcoin wallet, which has been abandoned since 2011.")); + verticalLayout_Spamfiltering->addWidget(rejectbarepubkey); + FixTabOrder(rejectbarepubkey); + rejectbaremultisig = new QCheckBox(groupBox_Spamfiltering); rejectbaremultisig->setText(tr("Ignore bare/exposed \"multisig\" scripts")); rejectbaremultisig->setToolTip(tr("Spam is sometimes disguised to appear as if it is an old-style N-of-M multi-party transaction, where most of the keys are really bogus. At the same time, legitimate multi-party transactions typically have always used P2SH format (which is not filtered by this option), which is more secure.")); @@ -632,6 +638,7 @@ void OptionsDialog::setMapper() mapper->addMapping(limitancestorsize, OptionsModel::limitancestorsize); mapper->addMapping(limitdescendantcount, OptionsModel::limitdescendantcount); mapper->addMapping(limitdescendantsize, OptionsModel::limitdescendantsize); + mapper->addMapping(rejectbarepubkey, OptionsModel::rejectbarepubkey); mapper->addMapping(rejectbaremultisig, OptionsModel::rejectbaremultisig); mapper->addMapping(maxscriptsize, OptionsModel::maxscriptsize); mapper->addMapping(datacarriercost, OptionsModel::datacarriercost); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 0cc3c2c4a7..698990770b 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -114,6 +114,7 @@ private: QSpinBox *limitancestorsize; QSpinBox *limitdescendantcount; QSpinBox *limitdescendantsize; + QCheckBox *rejectbarepubkey; QCheckBox *rejectbaremultisig; QSpinBox *maxscriptsize; QSpinBox *datacarriersize; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index c435fc395e..27acaf06f4 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -673,6 +673,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(node().mempool().m_opts.limits.descendant_count); case limitdescendantsize: return qlonglong(node().mempool().m_opts.limits.descendant_size_vbytes / 1'000); + case rejectbarepubkey: + return !node().mempool().m_opts.permit_bare_pubkey; case rejectbaremultisig: return !node().mempool().m_opts.permit_bare_multisig; case maxscriptsize: @@ -1169,6 +1171,14 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: gArgs.ModifyRWConfigFile("limitdescendantsize", strNv); } break; + case rejectbarepubkey: + if (changed()) { + // The config and internal option is inverted + const bool nv = ! value.toBool(); + node().mempool().m_opts.permit_bare_pubkey = nv; + node().updateRwSetting("permitbaremultisig", nv); + } + break; case rejectbaremultisig: if (changed()) { // The config and internal option is inverted diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 8263c3bbb2..77df89f3ce 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -95,6 +95,7 @@ public: limitancestorsize, limitdescendantcount, limitdescendantsize, + rejectbarepubkey, // bool rejectbaremultisig, // bool maxscriptsize, datacarriercost, // double From e1e3b8137f67f83b15126c0f009fca69f84fcc91 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 6 Mar 2024 04:02:06 +0000 Subject: [PATCH 35/55] Default policy: Set acceptnonstddatacarrier=0 (corepolicy resets to 1) --- src/init.cpp | 1 + src/kernel/mempool_options.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index d8dc4e8bec..a3376767cf 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -804,6 +804,7 @@ static bool AppInitServers(NodeContext& node) void InitParameterInteraction(ArgsManager& args) { if (args.GetBoolArg("-corepolicy", DEFAULT_COREPOLICY)) { + args.SoftSetArg("-acceptnonstddatacarrier", "1"); args.SoftSetArg("-bytespersigopstrict", "0"); args.SoftSetArg("-permitbarepubkey", "1"); args.SoftSetArg("-permitbaremultisig", "1"); diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h index 23313b224d..26bd29818a 100644 --- a/src/kernel/mempool_options.h +++ b/src/kernel/mempool_options.h @@ -33,7 +33,7 @@ static constexpr TRUCPolicy DEFAULT_MEMPOOL_TRUC_POLICY{TRUCPolicy::Enforce}; /** Whether to fall back to legacy V1 serialization when writing mempool.dat */ static constexpr bool DEFAULT_PERSIST_V1_DAT{false}; /** Default for -acceptnonstddatacarrier */ -static constexpr bool DEFAULT_ACCEPT_NON_STD_DATACARRIER{true}; +static constexpr bool DEFAULT_ACCEPT_NON_STD_DATACARRIER{false}; /** Default for -acceptnonstdtxn */ static constexpr bool DEFAULT_ACCEPT_NON_STD_TXN{false}; From 057943b59b71a3fbc006f2b0fde44d96735c97d2 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 19 Mar 2024 05:06:22 +0000 Subject: [PATCH 36/55] GUI: Let CreateOptionUI caller pre-initialise the QLayout --- src/qt/optionsdialog.cpp | 4 ++-- src/qt/optionsdialog.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 9243b97edc..cf8a5fb3c4 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -60,12 +60,12 @@ void OptionsDialog::FixTabOrder(QWidget * const o) prevwidget = o; } -void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, const QString& text) +void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, const QString& text, QLayout *horizontalLayout) { QWidget * const parent = o->parentWidget(); const QStringList text_parts = text.split("%s"); - QHBoxLayout * const horizontalLayout = new QHBoxLayout(); + if (!horizontalLayout) horizontalLayout = new QHBoxLayout(); QLabel * const labelBefore = new QLabel(parent); labelBefore->setText(text_parts[0]); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 698990770b..1ba3d1be4c 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -18,6 +18,7 @@ class QBoxLayout; class QCheckBox; class QDataWidgetMapper; class QDoubleSpinBox; +class QLayout; class QSpinBox; class QString; class QValueComboBox; @@ -94,7 +95,7 @@ private: QWidget *prevwidget{nullptr}; void FixTabOrder(QWidget *); - void CreateOptionUI(QBoxLayout *, QWidget *, const QString& text); + void CreateOptionUI(QBoxLayout *, QWidget *, const QString& text, QLayout *horizontalLayout = nullptr); QCheckBox *walletrbf; From 46897eda0e9dcfd9a4f0bc0423a916908b9dc918 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 4 Feb 2025 03:03:22 +0000 Subject: [PATCH 37/55] GUI/Options: Configure dustdynamic using settings --- src/qt/optionsdialog.cpp | 107 ++++++++++++++++++++++++++++++++++++--- src/qt/optionsdialog.h | 7 +++ src/qt/optionsmodel.cpp | 16 ++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 124 insertions(+), 7 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index cf8a5fb3c4..4955f6fbda 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -21,12 +21,14 @@ #include #include #include +#include // for ParseDustDynamicOpt #include #include // for WITNESS_SCALE_FACTOR #include #include // for maxmempoolMinimum #include #include +#include #include #include @@ -41,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -67,13 +70,15 @@ void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, if (!horizontalLayout) horizontalLayout = new QHBoxLayout(); - QLabel * const labelBefore = new QLabel(parent); - labelBefore->setText(text_parts[0]); - labelBefore->setTextFormat(Qt::PlainText); - labelBefore->setBuddy(o); - labelBefore->setToolTip(o->toolTip()); + if (!text_parts[0].isEmpty()) { + QLabel * const labelBefore = new QLabel(parent); + labelBefore->setText(text_parts[0]); + labelBefore->setTextFormat(Qt::PlainText); + labelBefore->setBuddy(o); + labelBefore->setToolTip(o->toolTip()); + horizontalLayout->addWidget(labelBefore); + } - horizontalLayout->addWidget(labelBefore); horizontalLayout->addWidget(o); QLabel * const labelAfter = new QLabel(parent); @@ -340,7 +345,67 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) }); dustrelayfee = new BitcoinAmountField(groupBox_Spamfiltering); - CreateOptionUI(verticalLayout_Spamfiltering, dustrelayfee, tr("Ignore transactions with values that would cost more to spend at a fee rate of %s per kvB.")); + CreateOptionUI(verticalLayout_Spamfiltering, dustrelayfee, tr("Ignore transactions with values that would cost more to spend at a fee rate of %s per kvB (\"dust\").")); + + + auto hlayout = new QHBoxLayout(); + dustdynamic_enable = new QCheckBox(groupBox_Spamfiltering); + dustdynamic_enable->setText(tr("Automatically adjust the dust limit upward to")); + hlayout->addWidget(dustdynamic_enable); + dustdynamic_multiplier = new QDoubleSpinBox(groupBox_Spamfiltering); + dustdynamic_multiplier->setDecimals(3); + dustdynamic_multiplier->setStepType(QAbstractSpinBox::DefaultStepType); + dustdynamic_multiplier->setSingleStep(1); + dustdynamic_multiplier->setMinimum(0.001); + dustdynamic_multiplier->setMaximum(65); + dustdynamic_multiplier->setValue(DEFAULT_DUST_RELAY_MULTIPLIER / 1000.0); + CreateOptionUI(verticalLayout_Spamfiltering, dustdynamic_multiplier, tr("%s times:"), hlayout); + + QStyleOptionButton styleoptbtn; + const auto checkbox_indent = dustdynamic_enable->style()->subElementRect(QStyle::SE_CheckBoxIndicator, &styleoptbtn, dustdynamic_enable).width(); + + hlayout = new QHBoxLayout(); + hlayout->addSpacing(checkbox_indent); + dustdynamic_target = new QRadioButton(groupBox_Spamfiltering); + hlayout->addWidget(dustdynamic_target); + dustdynamic_target_blocks = new QSpinBox(groupBox_Spamfiltering); + dustdynamic_target_blocks->setMinimum(2); + dustdynamic_target_blocks->setMaximum(1008); // FIXME: Get this from the fee estimator + dustdynamic_target_blocks->setValue(1008); + CreateOptionUI(verticalLayout_Spamfiltering, dustdynamic_target_blocks, tr("fee estimate for %s blocks."), hlayout); + // FIXME: Make it possible to click labels to select + focus spinbox + + hlayout = new QHBoxLayout(); + hlayout->addSpacing(checkbox_indent); + dustdynamic_mempool = new QRadioButton(groupBox_Spamfiltering); + hlayout->addWidget(dustdynamic_mempool); + dustdynamic_mempool_kvB = new QSpinBox(groupBox_Spamfiltering); + dustdynamic_mempool_kvB->setMinimum(1); + dustdynamic_mempool_kvB->setMaximum(std::numeric_limits::max()); + dustdynamic_mempool_kvB->setValue(3024000); + CreateOptionUI(verticalLayout_Spamfiltering, dustdynamic_mempool_kvB, tr("the lowest fee of the best known %s kvB of unconfirmed transactions."), hlayout); + + connect(dustdynamic_enable, &QAbstractButton::toggled, [this](const bool state){ + dustdynamic_multiplier->setEnabled(state); + dustdynamic_target->setEnabled(state); + dustdynamic_mempool->setEnabled(state); + if (state) { + if (!dustdynamic_mempool->isChecked()) dustdynamic_target->setChecked(true); + dustdynamic_target_blocks->setEnabled(dustdynamic_target->isChecked()); + dustdynamic_mempool_kvB->setEnabled(dustdynamic_mempool->isChecked()); + } else { + dustdynamic_target_blocks->setEnabled(false); + dustdynamic_mempool_kvB->setEnabled(false); + } + }); + dustdynamic_enable->toggled(dustdynamic_enable->isChecked()); + connect(dustdynamic_target, &QAbstractButton::toggled, [this](const bool state){ + dustdynamic_target_blocks->setEnabled(state); + }); + connect(dustdynamic_mempool, &QAbstractButton::toggled, [this](const bool state){ + dustdynamic_mempool_kvB->setEnabled(state); + }); + verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); @@ -645,6 +710,24 @@ void OptionsDialog::setMapper() mapper->addMapping(datacarriersize, OptionsModel::datacarriersize); mapper->addMapping(dustrelayfee, OptionsModel::dustrelayfee); + QVariant current_dustdynamic = model->data(model->index(OptionsModel::dustdynamic, 0), Qt::EditRole); + const util::Result> parsed_dustdynamic = ParseDustDynamicOpt(current_dustdynamic.toString().toStdString(), std::numeric_limits::max()); + if (parsed_dustdynamic) { + if (parsed_dustdynamic->first == 0) { + dustdynamic_enable->setChecked(false); + } else { + dustdynamic_multiplier->setValue(parsed_dustdynamic->second / 1000.0); + if (parsed_dustdynamic->first < 0) { + dustdynamic_target->setChecked(true); + dustdynamic_target_blocks->setValue(-parsed_dustdynamic->first); + } else { + dustdynamic_mempool->setChecked(true); + dustdynamic_mempool_kvB->setValue(parsed_dustdynamic->first); + } + dustdynamic_enable->setChecked(true); + } + } + /* Mining tab */ mapper->addMapping(blockmintxfee, OptionsModel::blockmintxfee); @@ -817,6 +900,16 @@ void OptionsDialog::on_okButton_clicked() model->setData(model->index(OptionsModel::mempoolreplacement, 0), mempoolreplacement->itemData(mempoolreplacement->currentIndex())); + if (dustdynamic_enable->isChecked()) { + if (dustdynamic_target->isChecked()) { + model->setData(model->index(OptionsModel::dustdynamic, 0), QStringLiteral("%2*target:%1").arg(dustdynamic_target_blocks->value()).arg(dustdynamic_multiplier->value())); + } else if (dustdynamic_mempool->isChecked()) { + model->setData(model->index(OptionsModel::dustdynamic, 0), QStringLiteral("%2*mempool:%1").arg(dustdynamic_mempool_kvB->value()).arg(dustdynamic_multiplier->value())); + } + } else { + model->setData(model->index(OptionsModel::dustdynamic, 0), "off"); + } + mapper->submit(); accept(); updateDefaultProxyNets(); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 1ba3d1be4c..606e78f486 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -19,6 +19,7 @@ class QCheckBox; class QDataWidgetMapper; class QDoubleSpinBox; class QLayout; +class QRadioButton; class QSpinBox; class QString; class QValueComboBox; @@ -121,6 +122,12 @@ private: QSpinBox *datacarriersize; QDoubleSpinBox *datacarriercost; BitcoinAmountField *dustrelayfee; + QCheckBox *dustdynamic_enable; + QDoubleSpinBox *dustdynamic_multiplier; + QRadioButton *dustdynamic_target; + QSpinBox *dustdynamic_target_blocks; + QRadioButton *dustdynamic_mempool; + QSpinBox *dustdynamic_mempool_kvB; BitcoinAmountField *blockmintxfee; QSpinBox *blockmaxsize, *blockprioritysize, *blockmaxweight; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 27acaf06f4..4963476c87 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -23,6 +23,7 @@ #include #include #include +#include // for ParseDustDynamicOpt #include #include #include // for -dbcache defaults @@ -38,6 +39,7 @@ #include #include #include +#include #include #include @@ -77,6 +79,7 @@ static const char* SettingName(OptionsModel::OptionID option) case OptionsModel::peerbloomfilters: return "peerbloomfilters"; case OptionsModel::peerblockfilters: return "peerblockfilters"; case OptionsModel::datacarriercost: return "datacarriercost"; + case OptionsModel::dustdynamic: return "dustdynamic"; default: throw std::logic_error(strprintf("GUI option %i has no corresponding node setting.", option)); } } @@ -685,6 +688,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(node().mempool().m_opts.max_datacarrier_bytes.value_or(0)); case dustrelayfee: return qlonglong(node().mempool().m_opts.dust_relay_feerate_floor.GetFeePerK()); + case dustdynamic: + return QString::fromStdString(SettingToString(setting(), DEFAULT_DUST_DYNAMIC)); case blockmintxfee: if (gArgs.IsArgSet("-blockmintxfee")) { return qlonglong(ParseMoney(gArgs.GetArg("-blockmintxfee", "")).value_or(0)); @@ -1230,6 +1235,17 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } } break; + case dustdynamic: + if (changed()) { + const std::string newvalue_str = value.toString().toStdString(); + const util::Result> parsed = ParseDustDynamicOpt(newvalue_str, 1008 /* FIXME: get from estimator */); + assert(parsed); // FIXME: what to do if it fails to parse? + // FIXME: save -prev- for each type + update(newvalue_str); + node().mempool().m_opts.dust_relay_target = parsed->first; + node().mempool().m_opts.dust_relay_multiplier = parsed->second; + } + break; case blockmintxfee: if (changed()) { std::string strNv = FormatMoney(value.toLongLong()); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 77df89f3ce..73397368f4 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -101,6 +101,7 @@ public: datacarriercost, // double datacarriersize, dustrelayfee, + dustdynamic, // QString blockmintxfee, blockmaxsize, blockprioritysize, From f19978f20db5fd1c4b4fc6dc295d33e52f98fb74 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 4 Feb 2025 03:09:47 +0000 Subject: [PATCH 38/55] GUI/Options: Configure acceptnonstddatacarrier using settings --- src/qt/optionsdialog.cpp | 7 +++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 10 ++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 19 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 4955f6fbda..e67519513a 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -344,6 +344,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) if (w != wf) datacarriercost->setValue(wf / 4); }); + rejectnonstddatacarrier = new QCheckBox(groupBox_Spamfiltering); + rejectnonstddatacarrier->setText(tr("Ignore data embedded with non-standard formats")); + rejectnonstddatacarrier->setToolTip(tr("Some attempts to spam Bitcoin intentionally use non-standard formats in an attempt to bypass the datacarrier limits. Without this option, %1 will attempt to detect these and enforce the intended limits. By enabling this option, your node will ignore these transactions entirely (when detected) even if they fall within the configured limits otherwise.")); + verticalLayout_Spamfiltering->addWidget(rejectnonstddatacarrier); + FixTabOrder(rejectnonstddatacarrier); + dustrelayfee = new BitcoinAmountField(groupBox_Spamfiltering); CreateOptionUI(verticalLayout_Spamfiltering, dustrelayfee, tr("Ignore transactions with values that would cost more to spend at a fee rate of %s per kvB (\"dust\").")); @@ -708,6 +714,7 @@ void OptionsDialog::setMapper() mapper->addMapping(maxscriptsize, OptionsModel::maxscriptsize); mapper->addMapping(datacarriercost, OptionsModel::datacarriercost); mapper->addMapping(datacarriersize, OptionsModel::datacarriersize); + mapper->addMapping(rejectnonstddatacarrier, OptionsModel::rejectnonstddatacarrier); mapper->addMapping(dustrelayfee, OptionsModel::dustrelayfee); QVariant current_dustdynamic = model->data(model->index(OptionsModel::dustdynamic, 0), Qt::EditRole); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 606e78f486..97bd22c1b7 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -121,6 +121,7 @@ private: QSpinBox *maxscriptsize; QSpinBox *datacarriersize; QDoubleSpinBox *datacarriercost; + QCheckBox *rejectnonstddatacarrier; BitcoinAmountField *dustrelayfee; QCheckBox *dustdynamic_enable; QDoubleSpinBox *dustdynamic_multiplier; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 4963476c87..eca6206a97 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -686,6 +686,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return double(::g_weight_per_data_byte) / WITNESS_SCALE_FACTOR; case datacarriersize: return qlonglong(node().mempool().m_opts.max_datacarrier_bytes.value_or(0)); + case rejectnonstddatacarrier: + return !node().mempool().m_opts.accept_non_std_datacarrier; case dustrelayfee: return qlonglong(node().mempool().m_opts.dust_relay_feerate_floor.GetFeePerK()); case dustdynamic: @@ -1222,6 +1224,14 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } } break; + case rejectnonstddatacarrier: + if (changed()) { + // This option is inverted + const bool new_value = ! value.toBool(); + node().updateRwSetting("acceptnonstddatacarrier" + suffix, new_value); + node().mempool().m_opts.accept_non_std_datacarrier = new_value; + } + break; case dustrelayfee: if (changed()) { CAmount nNv = value.toLongLong(); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 73397368f4..ea0e7d5fe0 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -100,6 +100,7 @@ public: maxscriptsize, datacarriercost, // double datacarriersize, + rejectnonstddatacarrier, // bool dustrelayfee, dustdynamic, // QString blockmintxfee, From 4daa4fe59997baa16f272fc200dcce5dc4e8b97d Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 6 May 2024 20:39:23 +0000 Subject: [PATCH 39/55] GUI/Options: Configure rejecttokens using settings --- src/qt/optionsdialog.cpp | 7 +++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 11 +++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 20 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index e67519513a..acf2f0c0d7 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -267,6 +267,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Spamfiltering->addWidget(rejectunknownscripts); FixTabOrder(rejectunknownscripts); + rejecttokens = new QCheckBox(groupBox_Spamfiltering); + rejecttokens->setText(tr("Ignore transactions involving non-bitcoin token/asset overlay protocols")); + rejecttokens->setToolTip(tr("With this option enabled, transactions involving non-bitcoin tokens/assets will not be relayed or mined by your node. Due to not having value, and some technical design flaws, token mints and transfers are often spammy and can bog down the network.")); + verticalLayout_Spamfiltering->addWidget(rejecttokens); + FixTabOrder(rejecttokens); + rejectspkreuse = new QCheckBox(groupBox_Spamfiltering); rejectspkreuse->setText(tr("Disallow most address reuse")); rejectspkreuse->setToolTip(tr("With this option enabled, your memory pool will only allow each unique payment destination to be used once, effectively deprioritising address reuse. Address reuse is not technically supported, and harms the privacy of all Bitcoin users. It also has limited real-world utility, and has been known to be common with spam.")); @@ -701,6 +707,7 @@ void OptionsDialog::setMapper() mapper->addMapping(mempoolexpiry, OptionsModel::mempoolexpiry); mapper->addMapping(rejectunknownscripts, OptionsModel::rejectunknownscripts); + mapper->addMapping(rejecttokens, OptionsModel::rejecttokens); mapper->addMapping(rejectspkreuse, OptionsModel::rejectspkreuse); mapper->addMapping(minrelaytxfee, OptionsModel::minrelaytxfee); mapper->addMapping(bytespersigop, OptionsModel::bytespersigop); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 97bd22c1b7..e51bc57744 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -109,6 +109,7 @@ private: QSpinBox *mempoolexpiry; QCheckBox *rejectunknownscripts; + QCheckBox *rejecttokens; QCheckBox *rejectspkreuse; BitcoinAmountField *minrelaytxfee; QSpinBox *bytespersigop, *bytespersigopstrict; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index eca6206a97..9dc60d65d5 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -660,6 +660,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(std::chrono::duration_cast(node().mempool().m_opts.expiry).count()); case rejectunknownscripts: return node().mempool().m_opts.require_standard; + case rejecttokens: + return node().mempool().m_opts.reject_tokens; case rejectspkreuse: return f_rejectspkreuse; case minrelaytxfee: @@ -1115,6 +1117,15 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case rejecttokens: + { + if (changed()) { + const bool nv = value.toBool(); + node().mempool().m_opts.reject_tokens = nv; + node().updateRwSetting("rejecttokens", nv); + } + break; + } case rejectspkreuse: if (changed()) { const bool fNewValue = value.toBool(); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index ea0e7d5fe0..0c61962a90 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -87,6 +87,7 @@ public: incrementalrelayfee, mempoolexpiry, rejectunknownscripts, // bool + rejecttokens, // bool rejectspkreuse, // bool minrelaytxfee, bytespersigop, From 4f3ea9f6ee91ee39dc8524c3e00a803648469ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=CC=81o=20Haf?= Date: Mon, 6 May 2024 18:14:19 +0200 Subject: [PATCH 40/55] GUI/Options: Configure rejectparasites using settings Co-authored-by: Luke Dashjr Github-Pull: knots#78 Rebased-From: 78f1ec0f8ddd912778f3c712f08c3412a6d3afb6 --- src/qt/optionsdialog.cpp | 7 +++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 11 +++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 20 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index acf2f0c0d7..ebb1d67e06 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -267,6 +267,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Spamfiltering->addWidget(rejectunknownscripts); FixTabOrder(rejectunknownscripts); + rejectparasites = new QCheckBox(groupBox_Spamfiltering); + rejectparasites->setText(tr("Reject parasite transactions")); + rejectparasites->setToolTip(tr("With this option enabled, transactions related to parasitic overlay protocols will be ignored. Parasites are transactions using Bitcoin as a technical infrastructure to animate other protocols, unrelated to ordinary money transfers.")); + verticalLayout_Spamfiltering->addWidget(rejectparasites); + FixTabOrder(rejectparasites); + rejecttokens = new QCheckBox(groupBox_Spamfiltering); rejecttokens->setText(tr("Ignore transactions involving non-bitcoin token/asset overlay protocols")); rejecttokens->setToolTip(tr("With this option enabled, transactions involving non-bitcoin tokens/assets will not be relayed or mined by your node. Due to not having value, and some technical design flaws, token mints and transfers are often spammy and can bog down the network.")); @@ -707,6 +713,7 @@ void OptionsDialog::setMapper() mapper->addMapping(mempoolexpiry, OptionsModel::mempoolexpiry); mapper->addMapping(rejectunknownscripts, OptionsModel::rejectunknownscripts); + mapper->addMapping(rejectparasites, OptionsModel::rejectparasites); mapper->addMapping(rejecttokens, OptionsModel::rejecttokens); mapper->addMapping(rejectspkreuse, OptionsModel::rejectspkreuse); mapper->addMapping(minrelaytxfee, OptionsModel::minrelaytxfee); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index e51bc57744..550e1f7a7d 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -109,6 +109,7 @@ private: QSpinBox *mempoolexpiry; QCheckBox *rejectunknownscripts; + QCheckBox *rejectparasites; QCheckBox *rejecttokens; QCheckBox *rejectspkreuse; BitcoinAmountField *minrelaytxfee; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 9dc60d65d5..e8013c08a2 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -660,6 +660,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return qlonglong(std::chrono::duration_cast(node().mempool().m_opts.expiry).count()); case rejectunknownscripts: return node().mempool().m_opts.require_standard; + case rejectparasites: + return node().mempool().m_opts.reject_parasites; case rejecttokens: return node().mempool().m_opts.reject_tokens; case rejectspkreuse: @@ -1117,6 +1119,15 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case rejectparasites: + { + if (changed()) { + const bool nv = value.toBool(); + node().mempool().m_opts.reject_parasites = nv; + node().updateRwSetting("rejectparasites", nv); + } + break; + } case rejecttokens: { if (changed()) { diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 0c61962a90..7b502f1b14 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -87,6 +87,7 @@ public: incrementalrelayfee, mempoolexpiry, rejectunknownscripts, // bool + rejectparasites, // bool rejecttokens, // bool rejectspkreuse, // bool minrelaytxfee, From fdfc57bd1ab2def68ab4f115e31ede2c3d1cafb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=CC=81o=20Haf?= Date: Wed, 8 May 2024 21:44:57 +0200 Subject: [PATCH 41/55] Default policy: Set rejectparasites=1 (corepolicy resets to 0) Github-Pull: knots#78 Rebased-From: 535155bfb212d916fafa4c1351dbc856fd829d57 --- src/init.cpp | 1 + src/policy/policy.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index a3376767cf..26e5f1c9a5 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -808,6 +808,7 @@ void InitParameterInteraction(ArgsManager& args) args.SoftSetArg("-bytespersigopstrict", "0"); args.SoftSetArg("-permitbarepubkey", "1"); args.SoftSetArg("-permitbaremultisig", "1"); + args.SoftSetArg("-rejectparasites", "0"); args.SoftSetArg("-datacarriercost", "0.25"); args.SoftSetArg("-datacarrierfullcount", "0"); args.SoftSetArg("-datacarriersize", "83"); diff --git a/src/policy/policy.h b/src/policy/policy.h index 612bef98bf..83195a588d 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -59,7 +59,7 @@ static constexpr bool DEFAULT_PERMIT_BAREPUBKEY{false}; /** Default for -permitbaremultisig */ static constexpr bool DEFAULT_PERMIT_BAREMULTISIG{false}; /** Default for -rejectparasites */ -static constexpr bool DEFAULT_REJECT_PARASITES{false}; +static constexpr bool DEFAULT_REJECT_PARASITES{true}; /** The maximum number of witness stack items in a standard P2WSH script */ static constexpr unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS{100}; /** The maximum size in bytes of each witness stack item in a standard P2WSH script */ From b399472de8f16c419b2ad79b64ed57fc33153ccd Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 6 Jun 2024 13:17:55 +0000 Subject: [PATCH 42/55] GUI/Options: Configure mempooltruc using settings --- src/qt/optionsdialog.cpp | 16 ++++++++++++++++ src/qt/optionsdialog.h | 1 + src/qt/optionsmodel.cpp | 27 +++++++++++++++++++++++++++ src/qt/optionsmodel.h | 1 + 4 files changed, 45 insertions(+) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index ebb1d67e06..7ac188cc24 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -237,6 +237,13 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) mempoolreplacement->addItem(QString("with a higher mining fee (no opt-out)"), QVariant("fee,-optin")); CreateOptionUI(verticalLayout_Mempool, mempoolreplacement, tr("Transaction &replacement: %s")); + mempooltruc = new QValueComboBox(tabMempool); + mempooltruc->addItem(QString("do not relay or mine at all"), QVariant("reject")); + mempooltruc->addItem(QString("handle the same as other transactions"), QVariant("accept")); + mempooltruc->addItem(QString("impose stricter limits requested (DRAFT)"), QVariant("enforce")); + mempooltruc->setToolTip(tr("Some transactions signal a request to limit both themselves and other related transactions to more restrictive expectations. Specifically, this would disallow more than 1 unconfirmed predecessor or spending transaction, as well as smaller size limits (see BIP 431 for details), regardless of what policy you have configured.")); + CreateOptionUI(verticalLayout_Mempool, mempooltruc, tr("Transactions requesting more restrictive policy limits (TRUC): %s")); + maxorphantx = new QSpinBox(tabMempool); maxorphantx->setMinimum(0); maxorphantx->setMaximum(std::numeric_limits::max()); @@ -707,6 +714,14 @@ void OptionsDialog::setMapper() } mempoolreplacement->setCurrentIndex(current_mempoolreplacement_index); + QVariant current_mempooltruc = model->data(model->index(OptionsModel::mempooltruc, 0), Qt::EditRole); + int current_mempooltruc_index = mempooltruc->findData(current_mempooltruc); + if (current_mempooltruc_index == -1) { + mempooltruc->addItem(current_mempooltruc.toString(), current_mempooltruc); + current_mempooltruc_index = mempooltruc->count() - 1; + } + mempooltruc->setCurrentIndex(current_mempooltruc_index); + mapper->addMapping(maxorphantx, OptionsModel::maxorphantx); mapper->addMapping(maxmempool, OptionsModel::maxmempool); mapper->addMapping(incrementalrelayfee, OptionsModel::incrementalrelayfee); @@ -920,6 +935,7 @@ void OptionsDialog::on_okButton_clicked() } model->setData(model->index(OptionsModel::mempoolreplacement, 0), mempoolreplacement->itemData(mempoolreplacement->currentIndex())); + model->setData(model->index(OptionsModel::mempooltruc, 0), mempooltruc->itemData(mempooltruc->currentIndex())); if (dustdynamic_enable->isChecked()) { if (dustdynamic_target->isChecked()) { diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 550e1f7a7d..f6001fe3c5 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -103,6 +103,7 @@ private: QSpinBox *blockreconstructionextratxn; QValueComboBox *mempoolreplacement; + QValueComboBox *mempooltruc; QSpinBox *maxorphantx; BitcoinAmountField *incrementalrelayfee; QSpinBox *maxmempool; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index e8013c08a2..86214e4fd2 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -223,6 +223,16 @@ static QString CanonicalMempoolReplacement(const OptionsModel& model) assert(0); } +static QString CanonicalMempoolTRUC(const OptionsModel& model) +{ + switch (model.node().mempool().m_opts.truc_policy) { + case TRUCPolicy::Reject: return "reject"; + case TRUCPolicy::Accept: return "accept"; + case TRUCPolicy::Enforce: return "enforce"; + } + assert(0); +} + OptionsModel::OptionsModel(interfaces::Node& node, QObject *parent) : QAbstractListModel(parent), m_node{node} { @@ -650,6 +660,8 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con return gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS); case mempoolreplacement: return CanonicalMempoolReplacement(*this); + case mempooltruc: + return CanonicalMempoolTRUC(*this); case maxorphantx: return qlonglong(gArgs.GetIntArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); case maxmempool: @@ -1049,6 +1061,21 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std:: } break; } + case mempooltruc: + { + if (changed()) { + QString nv = value.toString(); + if (nv == "reject") { + node().mempool().m_opts.truc_policy = TRUCPolicy::Reject; + } else if (nv == "accept") { + node().mempool().m_opts.truc_policy = TRUCPolicy::Accept; + } else if (nv == "enforce") { + node().mempool().m_opts.truc_policy = TRUCPolicy::Enforce; + } + node().updateRwSetting("mempooltruc", nv.toStdString()); + } + break; + } case maxorphantx: { if (changed()) { diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 7b502f1b14..46f812f808 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -82,6 +82,7 @@ public: peerbloomfilters, // bool peerblockfilters, // bool mempoolreplacement, + mempooltruc, maxorphantx, maxmempool, incrementalrelayfee, From 2c0de119a07ef458ced9598d616a05869fcd2cf8 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 5 Feb 2025 00:50:15 +0000 Subject: [PATCH 43/55] Default policy: Set mempooltruc=accept (corepolicy resets to enforce) --- src/init.cpp | 3 ++- src/kernel/mempool_options.h | 2 +- src/test/util/txmempool.cpp | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 26e5f1c9a5..64ed601bc1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -696,7 +696,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-maxscriptsize", strprintf("Maximum size of scripts we relay and mine, in bytes (default: %s)", DEFAULT_SCRIPT_SIZE_POLICY_LIMIT), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-mempoolfullrbf", strprintf("Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", (DEFAULT_MEMPOOL_RBF_POLICY == RBFPolicy::Always)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-mempoolreplacement", strprintf("Set to 0 to disable RBF entirely, \"fee,optin\" to honour RBF opt-out signal, or \"fee,-optin\" to always RBF aka full RBF (default: %s)", "fee,-optin"), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); - argsman.AddArg("-mempooltruc", strprintf("Behaviour for transactions requesting TRUC limits: \"reject\" the transactions entirely, \"accept\" them just like any other, or \"enforce\" to impose their requested restrictions (default: %s)", "enforce"), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); + argsman.AddArg("-mempooltruc", strprintf("Behaviour for transactions requesting TRUC limits: \"reject\" the transactions entirely, \"accept\" them just like any other, or \"enforce\" to impose their requested restrictions (default: %s)", "accept"), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-permitbarepubkey", strprintf("Relay legacy pubkey outputs (default: %u)", DEFAULT_PERMIT_BAREPUBKEY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-permitbaremultisig", strprintf("Relay transactions creating non-P2SH multisig outputs (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, @@ -813,6 +813,7 @@ void InitParameterInteraction(ArgsManager& args) args.SoftSetArg("-datacarrierfullcount", "0"); args.SoftSetArg("-datacarriersize", "83"); args.SoftSetArg("-maxscriptsize", strprintf("%s", std::numeric_limits::max())); + args.SoftSetArg("-mempooltruc", "enforce"); args.SoftSetArg("-spkreuse", "allow"); args.SoftSetArg("-blockprioritysize", "0"); args.SoftSetArg("-blockmaxsize", "4000000"); diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h index 26bd29818a..8fab5d2ec3 100644 --- a/src/kernel/mempool_options.h +++ b/src/kernel/mempool_options.h @@ -29,7 +29,7 @@ static constexpr unsigned int DEFAULT_MEMPOOL_EXPIRY_HOURS{336}; /** Default for -mempoolreplacement; must update docs in init.cpp manually */ static constexpr RBFPolicy DEFAULT_MEMPOOL_RBF_POLICY{RBFPolicy::Always}; /** Default for -mempooltruc; must update docs in init.cpp manually */ -static constexpr TRUCPolicy DEFAULT_MEMPOOL_TRUC_POLICY{TRUCPolicy::Enforce}; +static constexpr TRUCPolicy DEFAULT_MEMPOOL_TRUC_POLICY{TRUCPolicy::Accept}; /** Whether to fall back to legacy V1 serialization when writing mempool.dat */ static constexpr bool DEFAULT_PERSIST_V1_DAT{false}; /** Default for -acceptnonstddatacarrier */ diff --git a/src/test/util/txmempool.cpp b/src/test/util/txmempool.cpp index 9ee5fd1ae0..989a57ad17 100644 --- a/src/test/util/txmempool.cpp +++ b/src/test/util/txmempool.cpp @@ -23,6 +23,7 @@ CTxMemPool::Options MemPoolOptionsForTest(const NodeContext& node) // Default to always checking mempool regardless of // chainparams.DefaultConsistencyChecks for tests .check_ratio = 1, + .truc_policy = TRUCPolicy::Enforce, .signals = node.validation_signals.get(), }; const auto result{ApplyArgsManOptions(*node.args, ::Params(), mempool_opts)}; From b0e0651b378b3b14a7b1662de0100a103c76e5c6 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 11 Jun 2024 16:12:42 +0000 Subject: [PATCH 44/55] Bugfix: GUI: Check for overridden options of many settings --- src/qt/optionsmodel.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 86214e4fd2..ee6c1b11c3 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -65,6 +65,7 @@ static const char* SettingName(OptionsModel::OptionID option) case OptionsModel::MapPortNatpmp: return "natpmp"; case OptionsModel::Listen: return "listen"; case OptionsModel::Server: return "server"; + case OptionsModel::walletrbf: return "walletrbf"; case OptionsModel::addresstype: return "addresstype"; case OptionsModel::PruneSizeMiB: return "prune"; case OptionsModel::PruneTristate: return "prune"; @@ -78,8 +79,36 @@ static const char* SettingName(OptionsModel::OptionID option) case OptionsModel::maxuploadtarget: return "maxuploadtarget"; case OptionsModel::peerbloomfilters: return "peerbloomfilters"; case OptionsModel::peerblockfilters: return "peerblockfilters"; + case OptionsModel::mempoolreplacement: return "mempoolreplacement"; + case OptionsModel::mempooltruc: return "mempooltruc"; + case OptionsModel::maxorphantx: return "maxorphantx"; + case OptionsModel::maxmempool: return "maxmempool"; + case OptionsModel::incrementalrelayfee: return "incrementalrelayfee"; + case OptionsModel::mempoolexpiry: return "mempoolexpiry"; + case OptionsModel::rejectunknownscripts: return "rejectunknownscripts"; + case OptionsModel::rejectparasites: return "rejectparasites"; + case OptionsModel::rejecttokens: return "rejecttokens"; + case OptionsModel::rejectspkreuse: return "rejectspkreuse"; + case OptionsModel::minrelaytxfee: return "minrelaytxfee"; + case OptionsModel::bytespersigop: return "bytespersigop"; + case OptionsModel::bytespersigopstrict: return "bytespersigopstrict"; + case OptionsModel::limitancestorcount: return "limitancestorcount"; + case OptionsModel::limitancestorsize: return "limitancestorsize"; + case OptionsModel::limitdescendantcount: return "limitdescendantcount"; + case OptionsModel::limitdescendantsize: return "limitdescendantsize"; + case OptionsModel::rejectbarepubkey: return "rejectbarepubkey"; + case OptionsModel::rejectbaremultisig: return "rejectbaremultisig"; + case OptionsModel::maxscriptsize: return "maxscriptsize"; case OptionsModel::datacarriercost: return "datacarriercost"; + case OptionsModel::datacarriersize: return "datacarriersize"; + case OptionsModel::rejectnonstddatacarrier: return "rejectnonstddatacarrier"; + case OptionsModel::dustrelayfee: return "dustrelayfee"; case OptionsModel::dustdynamic: return "dustdynamic"; + case OptionsModel::blockmintxfee: return "blockmintxfee"; + case OptionsModel::blockmaxsize: return "blockmaxsize"; + case OptionsModel::blockprioritysize: return "blockprioritysize"; + case OptionsModel::blockmaxweight: return "blockmaxweight"; + case OptionsModel::blockreconstructionextratxn: return "blockreconstructionextratxn"; default: throw std::logic_error(strprintf("GUI option %i has no corresponding node setting.", option)); } } From 1648442c33a79616c8d552069b26323e8569f837 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 19 Jun 2024 03:53:54 +0000 Subject: [PATCH 45/55] GUI/OptionsDialog: Split spam filtering to a new tab --- src/qt/optionsdialog.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 7ac188cc24..420be122f6 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -264,8 +264,13 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) mempoolexpiry->setMaximum(std::numeric_limits::max()); CreateOptionUI(verticalLayout_Mempool, mempoolexpiry, tr("Do not keep transactions in memory more than %s hours")); - QGroupBox * const groupBox_Spamfiltering = new QGroupBox(tabMempool); - groupBox_Spamfiltering->setTitle(tr("Spam filtering")); + verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); + + /* Filters tab */ + + QWidget * const tabFilters = new QWidget(); + auto& groupBox_Spamfiltering = tabFilters; + ui->tabWidget->insertTab(ui->tabWidget->indexOf(ui->tabWindow), tabFilters, tr("Spam &filtering")); QVBoxLayout * const verticalLayout_Spamfiltering = new QVBoxLayout(groupBox_Spamfiltering); rejectunknownscripts = new QCheckBox(groupBox_Spamfiltering); @@ -432,9 +437,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) }); - verticalLayout_Mempool->addWidget(groupBox_Spamfiltering); - - verticalLayout_Mempool->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); + verticalLayout_Spamfiltering->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); /* Mining tab */ From c5ccb1fe6043a0bd35dbf711936522dcb3c00802 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 19 Jun 2024 04:06:53 +0000 Subject: [PATCH 46/55] GUI/OptionsDialog: Move rejectspkreuse back to Mempool tab --- src/qt/optionsdialog.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 420be122f6..89b7c0c3e6 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -237,6 +237,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) mempoolreplacement->addItem(QString("with a higher mining fee (no opt-out)"), QVariant("fee,-optin")); CreateOptionUI(verticalLayout_Mempool, mempoolreplacement, tr("Transaction &replacement: %s")); + rejectspkreuse = new QCheckBox(tabMempool); + rejectspkreuse->setText(tr("Disallow most address reuse")); + rejectspkreuse->setToolTip(tr("With this option enabled, your memory pool will only allow each unique payment destination to be used once, effectively deprioritising address reuse. Address reuse is not technically supported, and harms the privacy of all Bitcoin users. It also has limited real-world utility, and has been known to be common with spam.")); + verticalLayout_Mempool->addWidget(rejectspkreuse); + FixTabOrder(rejectspkreuse); + mempooltruc = new QValueComboBox(tabMempool); mempooltruc->addItem(QString("do not relay or mine at all"), QVariant("reject")); mempooltruc->addItem(QString("handle the same as other transactions"), QVariant("accept")); @@ -291,12 +297,6 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) verticalLayout_Spamfiltering->addWidget(rejecttokens); FixTabOrder(rejecttokens); - rejectspkreuse = new QCheckBox(groupBox_Spamfiltering); - rejectspkreuse->setText(tr("Disallow most address reuse")); - rejectspkreuse->setToolTip(tr("With this option enabled, your memory pool will only allow each unique payment destination to be used once, effectively deprioritising address reuse. Address reuse is not technically supported, and harms the privacy of all Bitcoin users. It also has limited real-world utility, and has been known to be common with spam.")); - verticalLayout_Spamfiltering->addWidget(rejectspkreuse); - FixTabOrder(rejectspkreuse); - minrelaytxfee = new BitcoinAmountField(groupBox_Spamfiltering); CreateOptionUI(verticalLayout_Spamfiltering, minrelaytxfee, tr("Ignore transactions offering miners less than %s per kvB in transaction fees.")); From 1e529858e26b720bcf6277d5560fdee90a49648c Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 19 Jun 2024 04:08:19 +0000 Subject: [PATCH 47/55] GUI/OptionsDialog: Move incrementalrelayfee directly below mempoolreplacement --- src/qt/optionsdialog.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 89b7c0c3e6..6bc799d3fb 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -237,6 +237,10 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) mempoolreplacement->addItem(QString("with a higher mining fee (no opt-out)"), QVariant("fee,-optin")); CreateOptionUI(verticalLayout_Mempool, mempoolreplacement, tr("Transaction &replacement: %s")); + incrementalrelayfee = new BitcoinAmountField(tabMempool); + connect(incrementalrelayfee, SIGNAL(valueChanged()), this, SLOT(incrementalrelayfee_changed())); + CreateOptionUI(verticalLayout_Mempool, incrementalrelayfee, tr("Require transaction fees to be at least %s per kvB higher than transactions they are replacing.")); + rejectspkreuse = new QCheckBox(tabMempool); rejectspkreuse->setText(tr("Disallow most address reuse")); rejectspkreuse->setToolTip(tr("With this option enabled, your memory pool will only allow each unique payment destination to be used once, effectively deprioritising address reuse. Address reuse is not technically supported, and harms the privacy of all Bitcoin users. It also has limited real-world utility, and has been known to be common with spam.")); @@ -261,10 +265,6 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) maxmempool->setMaximum(std::numeric_limits::max()); CreateOptionUI(verticalLayout_Mempool, maxmempool, tr("Keep the transaction memory pool below %s MB")); - incrementalrelayfee = new BitcoinAmountField(tabMempool); - connect(incrementalrelayfee, SIGNAL(valueChanged()), this, SLOT(incrementalrelayfee_changed())); - CreateOptionUI(verticalLayout_Mempool, incrementalrelayfee, tr("Require transaction fees to be at least %s per kvB higher than transactions they are replacing.")); - mempoolexpiry = new QSpinBox(tabMempool); mempoolexpiry->setMinimum(1); mempoolexpiry->setMaximum(std::numeric_limits::max()); From a38caffcd0e5648f9f142976f0932f831a8ebdaf Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 19 Jun 2024 14:47:47 +0000 Subject: [PATCH 48/55] Bugfix: GUI/OptionsDialog: Properly disable dustdynamic labels when appropriate --- src/qt/optionsdialog.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 6bc799d3fb..59c27fe62a 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -26,6 +26,7 @@ #include // for WITNESS_SCALE_FACTOR #include #include // for maxmempoolMinimum +#include #include #include #include @@ -95,9 +96,24 @@ void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, layout->addLayout(horizontalLayout); + o->setProperty("L", QVariant::fromValue((QLayout*)horizontalLayout)); + FixTabOrder(o); } +static void setSiblingsEnabled(QWidget * const o, const bool state) +{ + auto layout = o->property("L").value(); + Assert(layout); + // NOTE: QLayout::children does not do what we need here + for (int i = layout->count(); i-- > 0; ) { + QLayoutItem * const layoutitem = layout->itemAt(i); + QWidget * const childwidget = layoutitem->widget(); + if (!childwidget) continue; + childwidget->setEnabled(state); + } +} + int setFontChoice(QComboBox* cb, const OptionsModel::FontChoice& fc) { int i; @@ -417,15 +433,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) connect(dustdynamic_enable, &QAbstractButton::toggled, [this](const bool state){ dustdynamic_multiplier->setEnabled(state); - dustdynamic_target->setEnabled(state); - dustdynamic_mempool->setEnabled(state); + setSiblingsEnabled(dustdynamic_target_blocks, state); + setSiblingsEnabled(dustdynamic_mempool_kvB, state); if (state) { if (!dustdynamic_mempool->isChecked()) dustdynamic_target->setChecked(true); dustdynamic_target_blocks->setEnabled(dustdynamic_target->isChecked()); dustdynamic_mempool_kvB->setEnabled(dustdynamic_mempool->isChecked()); - } else { - dustdynamic_target_blocks->setEnabled(false); - dustdynamic_mempool_kvB->setEnabled(false); } }); dustdynamic_enable->toggled(dustdynamic_enable->isChecked()); From 5fdea54c90b0ad1088370f86d557780162e63c4d Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 19 Jun 2024 14:48:19 +0000 Subject: [PATCH 49/55] Bugfix: GUI/OptionsDialog: Disable policy options that require rejectunknownscripts when the latter is disabled --- src/qt/optionsdialog.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 59c27fe62a..67af311c49 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -431,7 +431,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) dustdynamic_mempool_kvB->setValue(3024000); CreateOptionUI(verticalLayout_Spamfiltering, dustdynamic_mempool_kvB, tr("the lowest fee of the best known %s kvB of unconfirmed transactions."), hlayout); - connect(dustdynamic_enable, &QAbstractButton::toggled, [this](const bool state){ + const auto dustdynamic_enable_toggled = [this](const bool state){ dustdynamic_multiplier->setEnabled(state); setSiblingsEnabled(dustdynamic_target_blocks, state); setSiblingsEnabled(dustdynamic_mempool_kvB, state); @@ -440,8 +440,9 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) dustdynamic_target_blocks->setEnabled(dustdynamic_target->isChecked()); dustdynamic_mempool_kvB->setEnabled(dustdynamic_mempool->isChecked()); } - }); - dustdynamic_enable->toggled(dustdynamic_enable->isChecked()); + }; + connect(dustdynamic_enable, &QAbstractButton::toggled, dustdynamic_enable_toggled); + dustdynamic_enable_toggled(dustdynamic_enable->isChecked()); connect(dustdynamic_target, &QAbstractButton::toggled, [this](const bool state){ dustdynamic_target_blocks->setEnabled(state); }); @@ -450,6 +451,18 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) }); + connect(rejectunknownscripts, &QAbstractButton::toggled, [this, dustdynamic_enable_toggled](const bool state){ + rejectbarepubkey->setEnabled(state); + rejectbaremultisig->setEnabled(state); + rejectparasites->setEnabled(state); + rejecttokens->setEnabled(state); + setSiblingsEnabled(dustrelayfee, state); + setSiblingsEnabled(maxscriptsize, state); + setSiblingsEnabled(dustdynamic_multiplier, state); + dustdynamic_enable_toggled(state && dustdynamic_enable->isChecked()); + }); + + verticalLayout_Spamfiltering->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); /* Mining tab */ From 7e53e5dc5b7bb486c80f77fdbc973e825c2963fc Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 5 Jul 2024 15:24:39 +0000 Subject: [PATCH 50/55] Bugfix: GUI/OptionsDialog: Set stretch factor on spacers so window resizes avoid weird spacing --- src/qt/optionsdialog.cpp | 6 ++---- src/qt/optionsdialog.h | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 67af311c49..1d43cf7fde 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -64,7 +64,7 @@ void OptionsDialog::FixTabOrder(QWidget * const o) prevwidget = o; } -void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, const QString& text, QLayout *horizontalLayout) +void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, const QString& text, QBoxLayout *horizontalLayout) { QWidget * const parent = o->parentWidget(); const QStringList text_parts = text.split("%s"); @@ -90,9 +90,7 @@ void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, horizontalLayout->addWidget(labelAfter); - QSpacerItem * const horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - horizontalLayout->addItem(horizontalSpacer); + horizontalLayout->addStretch(1); layout->addLayout(horizontalLayout); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index f6001fe3c5..fbf9fc82c8 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -18,7 +18,7 @@ class QBoxLayout; class QCheckBox; class QDataWidgetMapper; class QDoubleSpinBox; -class QLayout; +class QBoxLayout; class QRadioButton; class QSpinBox; class QString; @@ -96,7 +96,7 @@ private: QWidget *prevwidget{nullptr}; void FixTabOrder(QWidget *); - void CreateOptionUI(QBoxLayout *, QWidget *, const QString& text, QLayout *horizontalLayout = nullptr); + void CreateOptionUI(QBoxLayout *, QWidget *, const QString& text, QBoxLayout *horizontalLayout = nullptr); QCheckBox *walletrbf; From 78aeaaceaf6c7c05c42edca31ed277d34b4da1b1 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 6 Jul 2024 15:07:06 +0000 Subject: [PATCH 51/55] GUI/OptionsDialog: Make Spam filtering tab scrollable at smaller screen sizes --- src/qt/optionsdialog.cpp | 38 ++++++++++++++++++++++++++++++++++++-- src/qt/optionsdialog.h | 14 ++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 1d43cf7fde..68cc106722 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include #include #include @@ -53,6 +55,36 @@ #include #include +ModScrollArea::ModScrollArea() +{ + setWidgetResizable(true); + setFrameShape(QFrame::NoFrame); + setObjectName(QStringLiteral("scroll")); + setStyleSheet("QScrollArea#scroll, QScrollArea#scroll > QWidget > QWidget { background: transparent; } QScrollArea#scroll > QWidget > QScrollBar { background: palette(base); }"); +} + +ModScrollArea *ModScrollArea::fromWidget(QWidget * const parent, QWidget * const o) +{ + auto * const scroll = new ModScrollArea; + scroll->setWidget(o); + return scroll; +} + +QSize ModScrollArea::minimumSizeHint() const +{ + auto w = widget()->minimumSizeHint().width(); + w += verticalScrollBar()->sizeHint().width(); + const auto h = fontMetrics().height() * 2; + return QSize(w, h); +} + +QSize ModScrollArea::sizeHint() const +{ + QSize sz = widget()->sizeHint(); + sz.rwidth() += verticalScrollBar()->sizeHint().width(); + return sz; +} + void OptionsDialog::FixTabOrder(QWidget * const o) { BitcoinAmountField * const af = qobject_cast(o); @@ -290,7 +322,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) QWidget * const tabFilters = new QWidget(); auto& groupBox_Spamfiltering = tabFilters; - ui->tabWidget->insertTab(ui->tabWidget->indexOf(ui->tabWindow), tabFilters, tr("Spam &filtering")); + ui->tabWidget->insertTab(ui->tabWidget->indexOf(ui->tabWindow), ModScrollArea::fromWidget(this, groupBox_Spamfiltering), tr("Spam &filtering")); QVBoxLayout * const verticalLayout_Spamfiltering = new QVBoxLayout(groupBox_Spamfiltering); rejectunknownscripts = new QCheckBox(groupBox_Spamfiltering); @@ -461,7 +493,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) }); - verticalLayout_Spamfiltering->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); + verticalLayout_Spamfiltering->addStretch(1); /* Mining tab */ @@ -587,6 +619,8 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) ui->qrFont_preview->setVisible(false); #endif + adjustSize(); + GUIUtil::handleCloseWindowShortcut(this); } diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index fbf9fc82c8..a1b4c2f4e5 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -6,6 +6,7 @@ #define BITCOIN_QT_OPTIONSDIALOG_H #include +#include #include class BitcoinAmountField; @@ -26,6 +27,19 @@ class QValueComboBox; class QWidget; QT_END_NAMESPACE +/** QScrollArea, but returning reasonable size hints. + */ +class ModScrollArea : public QScrollArea { + Q_OBJECT + +public: + ModScrollArea(); + static ModScrollArea *fromWidget(QWidget *parent, QWidget *o); + + QSize minimumSizeHint() const override; + QSize sizeHint() const override; +}; + namespace Ui { class OptionsDialog; } From 4b4f6eae2ae9290595621cdf5a69c69d3624d854 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 16 Aug 2024 13:51:50 +0000 Subject: [PATCH 52/55] GUI/Options: Update informational notice to reflect new Spam filtering tab --- src/qt/optionsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 68cc106722..f9079f904e 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -501,7 +501,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) QVBoxLayout * const verticalLayout_Mining = new QVBoxLayout(tabMining); ui->tabWidget->insertTab(ui->tabWidget->indexOf(ui->tabWindow), tabMining, tr("M&ining")); - verticalLayout_Mining->addWidget(new QLabel(tr("Note that mining is heavily influenced by the settings on the Mempool tab."))); + verticalLayout_Mining->addWidget(new QLabel(tr("Note that mining is heavily influenced by the settings on the Mempool and Spam filtering tabs."))); blockmintxfee = new BitcoinAmountField(tabMining); CreateOptionUI(verticalLayout_Mining, blockmintxfee, tr("Only mine transactions paying a fee of at least %s per kvB.")); From 50feba09b815800452c132e14f27cb06541a0275 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 16 Aug 2024 19:42:41 +0000 Subject: [PATCH 53/55] Bugfix: GUI/Options: Set prevwidget correctly in FixTabOrder --- src/qt/optionsdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index f9079f904e..80e8172240 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -89,11 +89,11 @@ void OptionsDialog::FixTabOrder(QWidget * const o) { BitcoinAmountField * const af = qobject_cast(o); if (af) { - af->setupTabChain(prevwidget); + prevwidget = af->setupTabChain(prevwidget); } else { setTabOrder(prevwidget, o); + prevwidget = o; } - prevwidget = o; } void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, const QString& text, QBoxLayout *horizontalLayout) From d9f0785d471852539e1423e8a2389836dee2a3f0 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 16 Aug 2024 19:01:02 +0000 Subject: [PATCH 54/55] GUI/Options: Make CreateOptionUI even more flexible --- src/qt/optionsdialog.cpp | 87 +++++++++++++++++++++++++++++----------- src/qt/optionsdialog.h | 4 ++ 2 files changed, 67 insertions(+), 24 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 80e8172240..db0160b599 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -96,39 +96,78 @@ void OptionsDialog::FixTabOrder(QWidget * const o) } } -void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, const QString& text, QBoxLayout *horizontalLayout) +struct CreateOptionUIOpts { + QBoxLayout *horizontal_layout{nullptr}; + int stretch{1}; + int indent{0}; +}; + +void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, const QString& text, const std::vector& objs, const CreateOptionUIOpts& opts) { - QWidget * const parent = o->parentWidget(); - const QStringList text_parts = text.split("%s"); + Assert(!objs.empty()); - if (!horizontalLayout) horizontalLayout = new QHBoxLayout(); + auto& first_o = objs[0]; + QWidget * const parent = first_o->parentWidget(); - if (!text_parts[0].isEmpty()) { - QLabel * const labelBefore = new QLabel(parent); - labelBefore->setText(text_parts[0]); - labelBefore->setTextFormat(Qt::PlainText); - labelBefore->setBuddy(o); - labelBefore->setToolTip(o->toolTip()); - horizontalLayout->addWidget(labelBefore); + QBoxLayout * const horizontalLayout = opts.horizontal_layout ? opts.horizontal_layout : (new QHBoxLayout); + + if (opts.indent) horizontalLayout->addSpacing(opts.indent); + + int processed{0}, index_start{0}; + QWidget *last_widget{nullptr}; + while (true) { + int pos = text.indexOf('%', index_start); + int idx; + if (pos == -1) { + pos = text.size(); + idx = -1; + } else { + const int pos_next{pos + 1}; + const auto char_next = text[pos_next]; + idx = (char_next == 's') ? 0 : (char_next.digitValue() - 1); + if (pos_next == text.size() || idx < 0 || idx > 8 || (unsigned)idx >= objs.size()) { + index_start = pos_next; + continue; + } + } + if (processed != pos) { + auto label_text = text.mid(processed, pos - processed); + if (auto last_widget_as_qcheckbox = qobject_cast(last_widget)) { + if (label_text[0].isSpace()) label_text = label_text.mid(1); + last_widget_as_qcheckbox->setText(label_text); + } else { + const auto label = new QLabel(parent); + label->setText(label_text); + label->setTextFormat(Qt::PlainText); + label->setBuddy(first_o); + label->setToolTip(first_o->toolTip()); + horizontalLayout->addWidget(label); + } + } + if (idx == -1) break; + last_widget = objs[idx]; + horizontalLayout->addWidget(last_widget); + index_start = processed = pos + 2; } - horizontalLayout->addWidget(o); - - QLabel * const labelAfter = new QLabel(parent); - labelAfter->setText(text_parts[1]); - labelAfter->setTextFormat(Qt::PlainText); - labelAfter->setBuddy(o); - labelAfter->setToolTip(o->toolTip()); - - horizontalLayout->addWidget(labelAfter); - - horizontalLayout->addStretch(1); + if (opts.stretch) horizontalLayout->addStretch(opts.stretch); layout->addLayout(horizontalLayout); - o->setProperty("L", QVariant::fromValue((QLayout*)horizontalLayout)); + for (auto& o : objs) { + o->setProperty("L", QVariant::fromValue((QLayout*)horizontalLayout)); + FixTabOrder(o); + } +} - FixTabOrder(o); +void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, const QString& text, const std::vector& objs) +{ + CreateOptionUI(layout, text, objs, {}); +} + +void OptionsDialog::CreateOptionUI(QBoxLayout * const layout, QWidget * const o, const QString& text, QBoxLayout *horizontalLayout) +{ + CreateOptionUI(layout, text, {o}, { .horizontal_layout = horizontalLayout, }); } static void setSiblingsEnabled(QWidget * const o, const bool state) diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index a1b4c2f4e5..6640a0704a 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -27,6 +27,8 @@ class QValueComboBox; class QWidget; QT_END_NAMESPACE +struct CreateOptionUIOpts; + /** QScrollArea, but returning reasonable size hints. */ class ModScrollArea : public QScrollArea { @@ -110,6 +112,8 @@ private: QWidget *prevwidget{nullptr}; void FixTabOrder(QWidget *); + void CreateOptionUI(QBoxLayout *, const QString& text, const std::vector&, const CreateOptionUIOpts&); + void CreateOptionUI(QBoxLayout *, const QString& text, const std::vector&); void CreateOptionUI(QBoxLayout *, QWidget *, const QString& text, QBoxLayout *horizontalLayout = nullptr); QCheckBox *walletrbf; From 2b7871d02fb79146ebf40e166c64abec89b89935 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 16 Aug 2024 19:43:39 +0000 Subject: [PATCH 55/55] Bugfix: GUI/Options: Refactor dustdynamic to use new CreateOptionUI (which calls FixTabOrder for all widgets) --- src/qt/optionsdialog.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index db0160b599..eecdd8f52e 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -463,10 +463,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) CreateOptionUI(verticalLayout_Spamfiltering, dustrelayfee, tr("Ignore transactions with values that would cost more to spend at a fee rate of %s per kvB (\"dust\").")); - auto hlayout = new QHBoxLayout(); dustdynamic_enable = new QCheckBox(groupBox_Spamfiltering); - dustdynamic_enable->setText(tr("Automatically adjust the dust limit upward to")); - hlayout->addWidget(dustdynamic_enable); dustdynamic_multiplier = new QDoubleSpinBox(groupBox_Spamfiltering); dustdynamic_multiplier->setDecimals(3); dustdynamic_multiplier->setStepType(QAbstractSpinBox::DefaultStepType); @@ -474,31 +471,25 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) dustdynamic_multiplier->setMinimum(0.001); dustdynamic_multiplier->setMaximum(65); dustdynamic_multiplier->setValue(DEFAULT_DUST_RELAY_MULTIPLIER / 1000.0); - CreateOptionUI(verticalLayout_Spamfiltering, dustdynamic_multiplier, tr("%s times:"), hlayout); + CreateOptionUI(verticalLayout_Spamfiltering, tr("%1 Automatically adjust the dust limit upward to %2 times:"), {dustdynamic_enable, dustdynamic_multiplier}); QStyleOptionButton styleoptbtn; const auto checkbox_indent = dustdynamic_enable->style()->subElementRect(QStyle::SE_CheckBoxIndicator, &styleoptbtn, dustdynamic_enable).width(); - hlayout = new QHBoxLayout(); - hlayout->addSpacing(checkbox_indent); dustdynamic_target = new QRadioButton(groupBox_Spamfiltering); - hlayout->addWidget(dustdynamic_target); dustdynamic_target_blocks = new QSpinBox(groupBox_Spamfiltering); dustdynamic_target_blocks->setMinimum(2); dustdynamic_target_blocks->setMaximum(1008); // FIXME: Get this from the fee estimator dustdynamic_target_blocks->setValue(1008); - CreateOptionUI(verticalLayout_Spamfiltering, dustdynamic_target_blocks, tr("fee estimate for %s blocks."), hlayout); + CreateOptionUI(verticalLayout_Spamfiltering, tr("%1 fee estimate for %2 blocks."), {dustdynamic_target, dustdynamic_target_blocks}, { .indent = checkbox_indent, }); // FIXME: Make it possible to click labels to select + focus spinbox - hlayout = new QHBoxLayout(); - hlayout->addSpacing(checkbox_indent); dustdynamic_mempool = new QRadioButton(groupBox_Spamfiltering); - hlayout->addWidget(dustdynamic_mempool); dustdynamic_mempool_kvB = new QSpinBox(groupBox_Spamfiltering); dustdynamic_mempool_kvB->setMinimum(1); dustdynamic_mempool_kvB->setMaximum(std::numeric_limits::max()); dustdynamic_mempool_kvB->setValue(3024000); - CreateOptionUI(verticalLayout_Spamfiltering, dustdynamic_mempool_kvB, tr("the lowest fee of the best known %s kvB of unconfirmed transactions."), hlayout); + CreateOptionUI(verticalLayout_Spamfiltering, tr("%1 the lowest fee of the best known %2 kvB of unconfirmed transactions."), {dustdynamic_mempool, dustdynamic_mempool_kvB}, { .indent = checkbox_indent, }); const auto dustdynamic_enable_toggled = [this](const bool state){ dustdynamic_multiplier->setEnabled(state);