diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/interfaces/node.cpp | 14 | ||||
-rw-r--r-- | src/interfaces/node.h | 14 | ||||
-rw-r--r-- | src/interfaces/wallet.cpp | 17 | ||||
-rw-r--r-- | src/interfaces/wallet.h | 14 | ||||
-rw-r--r-- | src/qt/coincontroldialog.cpp | 2 | ||||
-rw-r--r-- | src/qt/sendcoinsdialog.cpp | 14 | ||||
-rw-r--r-- | src/qt/walletmodel.cpp | 2 | ||||
-rw-r--r-- | src/wallet/coincontrol.h | 8 | ||||
-rw-r--r-- | src/wallet/feebumper.cpp | 8 | ||||
-rw-r--r-- | src/wallet/fees.cpp | 42 | ||||
-rw-r--r-- | src/wallet/fees.h | 17 | ||||
-rw-r--r-- | src/wallet/init.cpp | 54 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 22 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 109 | ||||
-rw-r--r-- | src/wallet/wallet.h | 29 |
15 files changed, 179 insertions, 187 deletions
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index e55cba3c65..55786c807f 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -191,20 +191,6 @@ class NodeImpl : public Node } } bool getNetworkActive() override { return g_connman && g_connman->GetNetworkActive(); } - unsigned int getTxConfirmTarget() override { CHECK_WALLET(return ::nTxConfirmTarget); } - CAmount getRequiredFee(unsigned int tx_bytes) override { CHECK_WALLET(return GetRequiredFee(tx_bytes)); } - CAmount getMinimumFee(unsigned int tx_bytes, - const CCoinControl& coin_control, - int* returned_target, - FeeReason* reason) override - { - FeeCalculation fee_calc; - CAmount result; - CHECK_WALLET(result = GetMinimumFee(tx_bytes, coin_control, ::mempool, ::feeEstimator, &fee_calc)); - if (returned_target) *returned_target = fee_calc.returnedTarget; - if (reason) *reason = fee_calc.reason; - return result; - } CAmount getMaxTxFee() override { return ::maxTxFee; } CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override { diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 84e869100a..3cebe53eb0 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -26,11 +26,9 @@ class Coin; class RPCTimerInterface; class UniValue; class proxyType; -enum class FeeReason; struct CNodeStateStats; namespace interfaces { - class Handler; class Wallet; @@ -152,18 +150,6 @@ public: //! Get network active. virtual bool getNetworkActive() = 0; - //! Get tx confirm target. - virtual unsigned int getTxConfirmTarget() = 0; - - //! Get required fee. - virtual CAmount getRequiredFee(unsigned int tx_bytes) = 0; - - //! Get minimum fee. - virtual CAmount getMinimumFee(unsigned int tx_bytes, - const CCoinControl& coin_control, - int* returned_target, - FeeReason* reason) = 0; - //! Get max tx fee. virtual CAmount getMaxTxFee() = 0; diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 3e6f0d6728..f4dfdae8ae 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -9,6 +9,8 @@ #include <consensus/validation.h> #include <interfaces/handler.h> #include <net.h> +#include <policy/feerate.h> +#include <policy/fees.h> #include <policy/policy.h> #include <primitives/transaction.h> #include <script/ismine.h> @@ -20,6 +22,7 @@ #include <uint256.h> #include <validation.h> #include <wallet/feebumper.h> +#include <wallet/fees.h> #include <wallet/wallet.h> namespace interfaces { @@ -403,6 +406,20 @@ public: } return result; } + CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(m_wallet, tx_bytes); } + CAmount getMinimumFee(unsigned int tx_bytes, + const CCoinControl& coin_control, + int* returned_target, + FeeReason* reason) override + { + FeeCalculation fee_calc; + CAmount result; + result = GetMinimumFee(m_wallet, tx_bytes, coin_control, ::mempool, ::feeEstimator, &fee_calc); + if (returned_target) *returned_target = fee_calc.returnedTarget; + if (reason) *reason = fee_calc.reason; + return result; + } + unsigned int getConfirmTarget() override { return m_wallet.m_confirm_target; } bool hdEnabled() override { return m_wallet.IsHDEnabled(); } OutputType getDefaultAddressType() override { return m_wallet.m_default_address_type; } OutputType getDefaultChangeType() override { return m_wallet.m_default_change_type; } diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 9d4830d189..2a03f6c60a 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -22,8 +22,10 @@ #include <vector> class CCoinControl; +class CFeeRate; class CKey; class CWallet; +enum class FeeReason; enum class OutputType; struct CRecipient; @@ -218,6 +220,18 @@ public: //! Return wallet transaction output information. virtual std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) = 0; + //! Get required fee. + virtual CAmount getRequiredFee(unsigned int tx_bytes) = 0; + + //! Get minimum fee. + virtual CAmount getMinimumFee(unsigned int tx_bytes, + const CCoinControl& coin_control, + int* returned_target, + FeeReason* reason) = 0; + + //! Get tx confirm target. + virtual unsigned int getConfirmTarget() = 0; + // Return whether HD enabled. virtual bool hdEnabled() = 0; diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 601a77fc85..b08de27041 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -509,7 +509,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) nBytes -= 34; // Fee - nPayFee = model->node().getMinimumFee(nBytes, *coinControl(), nullptr /* returned_target */, nullptr /* reason */); + nPayFee = model->wallet().getMinimumFee(nBytes, *coinControl(), nullptr /* returned_target */, nullptr /* reason */); if (nPayAmount > 0) { diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 0874a0ada4..261ab7a948 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -114,7 +114,7 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p if (!settings.contains("nSmartFeeSliderPosition")) settings.setValue("nSmartFeeSliderPosition", 0); if (!settings.contains("nTransactionFee")) - settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE); + settings.setValue("nTransactionFee", (qint64)DEFAULT_PAY_TX_FEE); if (!settings.contains("fPayOnlyMinFee")) settings.setValue("fPayOnlyMinFee", false); ui->groupFee->setId(ui->radioSmartFee, 0); @@ -175,7 +175,7 @@ void SendCoinsDialog::setModel(WalletModel *_model) connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel())); connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); - ui->customFee->setSingleStep(model->node().getRequiredFee(1000)); + ui->customFee->setSingleStep(model->wallet().getRequiredFee(1000)); updateFeeSectionControls(); updateMinFeeLabel(); updateSmartFeeLabel(); @@ -193,7 +193,7 @@ void SendCoinsDialog::setModel(WalletModel *_model) settings.remove("nSmartFeeSliderPosition"); } if (settings.value("nConfTarget").toInt() == 0) - ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->node().getTxConfirmTarget())); + ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->wallet().getConfirmTarget())); else ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(settings.value("nConfTarget").toInt())); } @@ -629,7 +629,7 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry) void SendCoinsDialog::setMinimumFee() { - ui->customFee->setValue(model->node().getRequiredFee(1000)); + ui->customFee->setValue(model->wallet().getRequiredFee(1000)); } void SendCoinsDialog::updateFeeSectionControls() @@ -661,7 +661,7 @@ void SendCoinsDialog::updateMinFeeLabel() { if (model && model->getOptionsModel()) ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg( - BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->node().getRequiredFee(1000)) + "/kB") + BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->wallet().getRequiredFee(1000)) + "/kB") ); } @@ -675,7 +675,7 @@ void SendCoinsDialog::updateCoinControlState(CCoinControl& ctrl) // Avoid using global defaults when sending money from the GUI // Either custom fee will be used or if not selected, the confirmation target from dropdown box ctrl.m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex()); - ctrl.signalRbf = ui->optInRBF->isChecked(); + ctrl.m_signal_bip125_rbf = ui->optInRBF->isChecked(); } void SendCoinsDialog::updateSmartFeeLabel() @@ -687,7 +687,7 @@ void SendCoinsDialog::updateSmartFeeLabel() coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels int returned_target; FeeReason reason; - CFeeRate feeRate = CFeeRate(model->node().getMinimumFee(1000, coin_control, &returned_target, &reason)); + CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, coin_control, &returned_target, &reason)); ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB"); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 00b98901c0..8f30a2a871 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -486,7 +486,7 @@ bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t bool WalletModel::bumpFee(uint256 hash) { CCoinControl coin_control; - coin_control.signalRbf = true; + coin_control.m_signal_bip125_rbf = true; std::vector<std::string> errors; CAmount old_fee; CAmount new_fee; diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index 52d6a291c9..2f08162ee4 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -26,12 +26,12 @@ public: bool fAllowWatchOnly; //! Override automatic min/max checks on fee, m_feerate must be set if true bool fOverrideFeeRate; - //! Override the default payTxFee if set + //! Override the wallet's m_pay_tx_fee if set boost::optional<CFeeRate> m_feerate; //! Override the default confirmation target if set boost::optional<unsigned int> m_confirm_target; - //! Signal BIP-125 replace by fee. - bool signalRbf; + //! Override the wallet's m_signal_rbf if set + boost::optional<bool> m_signal_bip125_rbf; //! Fee estimation mode to control arguments to estimateSmartFee FeeEstimateMode m_fee_mode; @@ -50,7 +50,7 @@ public: m_feerate.reset(); fOverrideFeeRate = false; m_confirm_target.reset(); - signalRbf = fWalletRbf; + m_signal_bip125_rbf.reset(); m_fee_mode = FeeEstimateMode::UNSET; } diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index 5c34b39ec8..4d70dde72a 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -134,7 +134,7 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(::incrementalRelayFee.GetFee(maxNewTxSize)))); return Result::INVALID_PARAMETER; } - CAmount requiredFee = GetRequiredFee(maxNewTxSize); + CAmount requiredFee = GetRequiredFee(*wallet, maxNewTxSize); if (total_fee < requiredFee) { errors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)", FormatMoney(requiredFee))); @@ -143,7 +143,7 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin new_fee = total_fee; nNewFeeRate = CFeeRate(total_fee, maxNewTxSize); } else { - new_fee = GetMinimumFee(maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */); + new_fee = GetMinimumFee(*wallet, maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */); nNewFeeRate = CFeeRate(new_fee, maxNewTxSize); // New fee rate must be at least old rate + minimum incremental relay rate @@ -194,14 +194,14 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin // If the output would become dust, discard it (converting the dust to fee) poutput->nValue -= nDelta; - if (poutput->nValue <= GetDustThreshold(*poutput, GetDiscardRate(::feeEstimator))) { + if (poutput->nValue <= GetDustThreshold(*poutput, GetDiscardRate(*wallet, ::feeEstimator))) { LogPrint(BCLog::RPC, "Bumping fee and discarding dust output\n"); new_fee += poutput->nValue; mtx.vout.erase(mtx.vout.begin() + nOutput); } // Mark new tx not replaceable, if requested. - if (!coin_control.signalRbf) { + if (!coin_control.m_signal_bip125_rbf.get_value_or(wallet->m_signal_rbf)) { for (auto& input : mtx.vin) { if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe; } diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp index 03c32d3b97..8d576a6689 100644 --- a/src/wallet/fees.cpp +++ b/src/wallet/fees.cpp @@ -13,15 +13,15 @@ #include <wallet/wallet.h> -CAmount GetRequiredFee(unsigned int nTxBytes) +CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes) { - return std::max(CWallet::minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes)); + return GetRequiredFeeRate(wallet).GetFee(nTxBytes); } -CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc) +CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation* feeCalc) { - CAmount fee_needed = GetMinimumFeeRate(coin_control, pool, estimator, feeCalc).GetFee(nTxBytes); + CAmount fee_needed = GetMinimumFeeRate(wallet, coin_control, pool, estimator, feeCalc).GetFee(nTxBytes); // Always obey the maximum if (fee_needed > maxTxFee) { fee_needed = maxTxFee; @@ -30,48 +30,48 @@ CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, c return fee_needed; } -CFeeRate GetRequiredFeeRate() +CFeeRate GetRequiredFeeRate(const CWallet& wallet) { - return std::max(CWallet::minTxFee, ::minRelayTxFee); + return std::max(wallet.m_min_fee, ::minRelayTxFee); } -CFeeRate GetMinimumFeeRate(const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc) +CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation* feeCalc) { /* User control of how to calculate fee uses the following parameter precedence: 1. coin_control.m_feerate 2. coin_control.m_confirm_target - 3. payTxFee (user-set global variable) - 4. nTxConfirmTarget (user-set global variable) + 3. m_pay_tx_fee (user-set member variable of wallet) + 4. m_confirm_target (user-set member variable of wallet) The first parameter that is set is used. */ - CFeeRate feerate_needed ; + CFeeRate feerate_needed; if (coin_control.m_feerate) { // 1. feerate_needed = *(coin_control.m_feerate); if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE; // Allow to override automatic min/max check over coin control instance if (coin_control.fOverrideFeeRate) return feerate_needed; } - else if (!coin_control.m_confirm_target && ::payTxFee != CFeeRate(0)) { // 3. TODO: remove magic value of 0 for global payTxFee - feerate_needed = ::payTxFee; + else if (!coin_control.m_confirm_target && wallet.m_pay_tx_fee != CFeeRate(0)) { // 3. TODO: remove magic value of 0 for wallet member m_pay_tx_fee + feerate_needed = wallet.m_pay_tx_fee; if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE; } else { // 2. or 4. // We will use smart fee estimation - unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : ::nTxConfirmTarget; + unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : wallet.m_confirm_target; // By default estimates are economical iff we are signaling opt-in-RBF - bool conservative_estimate = !coin_control.signalRbf; + bool conservative_estimate = !coin_control.m_signal_bip125_rbf.get_value_or(wallet.m_signal_rbf); // Allow to override the default fee estimate mode over the CoinControl instance if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true; else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false; feerate_needed = estimator.estimateSmartFee(target, feeCalc, conservative_estimate); if (feerate_needed == CFeeRate(0)) { - // if we don't have enough data for estimateSmartFee, then use fallbackFee - feerate_needed = CWallet::fallbackFee; + // if we don't have enough data for estimateSmartFee, then use fallback fee + feerate_needed = wallet.m_fallback_fee; if (feeCalc) feeCalc->reason = FeeReason::FALLBACK; // directly return if fallback fee is disabled (feerate 0 == disabled) - if (CWallet::fallbackFee == CFeeRate(0)) return feerate_needed; + if (wallet.m_fallback_fee == CFeeRate(0)) return feerate_needed; } // Obey mempool min fee when using smart fee estimation CFeeRate min_mempool_feerate = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); @@ -81,8 +81,8 @@ CFeeRate GetMinimumFeeRate(const CCoinControl& coin_control, const CTxMemPool& p } } - // prevent user from paying a fee below minRelayTxFee or minTxFee - CFeeRate required_feerate = GetRequiredFeeRate(); + // prevent user from paying a fee below the required fee rate + CFeeRate required_feerate = GetRequiredFeeRate(wallet); if (required_feerate > feerate_needed) { feerate_needed = required_feerate; if (feeCalc) feeCalc->reason = FeeReason::REQUIRED; @@ -90,12 +90,12 @@ CFeeRate GetMinimumFeeRate(const CCoinControl& coin_control, const CTxMemPool& p return feerate_needed; } -CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator) +CFeeRate GetDiscardRate(const CWallet& wallet, const CBlockPolicyEstimator& estimator) { unsigned int highest_target = estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); CFeeRate discard_rate = estimator.estimateSmartFee(highest_target, nullptr /* FeeCalculation */, false /* conservative */); // Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate - discard_rate = (discard_rate == CFeeRate(0)) ? CWallet::m_discard_rate : std::min(discard_rate, CWallet::m_discard_rate); + discard_rate = (discard_rate == CFeeRate(0)) ? wallet.m_discard_rate : std::min(discard_rate, wallet.m_discard_rate); // Discard rate must be at least dustRelayFee discard_rate = std::max(discard_rate, ::dustRelayFee); return discard_rate; diff --git a/src/wallet/fees.h b/src/wallet/fees.h index a627af70b0..b3cd064abc 100644 --- a/src/wallet/fees.h +++ b/src/wallet/fees.h @@ -12,35 +12,36 @@ class CBlockPolicyEstimator; class CCoinControl; class CFeeRate; class CTxMemPool; +class CWallet; struct FeeCalculation; /** - * Return the minimum required fee taking into account the - * floating relay fee and user set minimum transaction fee + * Return the minimum required absolute fee for this size + * based on the required fee rate */ -CAmount GetRequiredFee(unsigned int nTxBytes); +CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes); /** * Estimate the minimum fee considering user set parameters * and the required fee */ -CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc); +CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation* feeCalc); /** * Return the minimum required feerate taking into account the - * floating relay feerate and user set minimum transaction feerate + * minimum relay feerate and user set minimum transaction feerate */ -CFeeRate GetRequiredFeeRate(); +CFeeRate GetRequiredFeeRate(const CWallet& wallet); /** * Estimate the minimum fee rate considering user set parameters * and the required fee */ -CFeeRate GetMinimumFeeRate(const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc); +CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation* feeCalc); /** * Return the maximum feerate for discarding change. */ -CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator); +CFeeRate GetDiscardRate(const CWallet& wallet, const CBlockPolicyEstimator& estimator); #endif // BITCOIN_WALLET_FEES_H diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 5091477dfd..06f9c730c0 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -64,7 +64,7 @@ std::string WalletInit::GetHelpString(bool showDebug) const strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), - CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); + CURRENCY_UNIT, FormatMoney(CFeeRate{DEFAULT_PAY_TX_FEE}.GetFeePerK()))); strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup")); strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup")); strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE)); @@ -149,55 +149,6 @@ bool WalletInit::ParameterInteraction() const InitWarning(AmountHighWarn("-minrelaytxfee") + " " + _("The wallet will avoid paying less than the minimum relay fee.")); - if (gArgs.IsArgSet("-mintxfee")) - { - CAmount n = 0; - if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n) - return InitError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", ""))); - if (n > HIGH_TX_FEE_PER_KB) - InitWarning(AmountHighWarn("-mintxfee") + " " + - _("This is the minimum transaction fee you pay on every transaction.")); - CWallet::minTxFee = CFeeRate(n); - } - - g_wallet_allow_fallback_fee = Params().IsFallbackFeeEnabled(); - if (gArgs.IsArgSet("-fallbackfee")) - { - CAmount nFeePerK = 0; - if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) - return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", ""))); - if (nFeePerK > HIGH_TX_FEE_PER_KB) - InitWarning(AmountHighWarn("-fallbackfee") + " " + - _("This is the transaction fee you may pay when fee estimates are not available.")); - CWallet::fallbackFee = CFeeRate(nFeePerK); - g_wallet_allow_fallback_fee = nFeePerK != 0; //disable fallback fee in case value was set to 0, enable if non-null value - } - if (gArgs.IsArgSet("-discardfee")) - { - CAmount nFeePerK = 0; - if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK)) - return InitError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", ""))); - if (nFeePerK > HIGH_TX_FEE_PER_KB) - InitWarning(AmountHighWarn("-discardfee") + " " + - _("This is the transaction fee you may discard if change is smaller than dust at this level")); - CWallet::m_discard_rate = CFeeRate(nFeePerK); - } - if (gArgs.IsArgSet("-paytxfee")) - { - CAmount nFeePerK = 0; - if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK)) - return InitError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", ""))); - if (nFeePerK > HIGH_TX_FEE_PER_KB) - InitWarning(AmountHighWarn("-paytxfee") + " " + - _("This is the transaction fee you will pay if you send a transaction.")); - - payTxFee = CFeeRate(nFeePerK, 1000); - if (payTxFee < ::minRelayTxFee) - { - return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"), - gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString())); - } - } if (gArgs.IsArgSet("-maxtxfee")) { CAmount nMaxFee = 0; @@ -212,9 +163,6 @@ bool WalletInit::ParameterInteraction() const gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString())); } } - nTxConfirmTarget = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); - bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); - fWalletRbf = gArgs.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF); return true; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5bc8788c7c..c4c6701081 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -557,7 +557,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request) CCoinControl coin_control; if (!request.params[5].isNull()) { - coin_control.signalRbf = request.params[5].get_bool(); + coin_control.m_signal_bip125_rbf = request.params[5].get_bool(); } if (!request.params[6].isNull()) { @@ -1201,7 +1201,7 @@ UniValue sendmany(const JSONRPCRequest& request) CCoinControl coin_control; if (!request.params[5].isNull()) { - coin_control.signalRbf = request.params[5].get_bool(); + coin_control.m_signal_bip125_rbf = request.params[5].get_bool(); } if (!request.params[6].isNull()) { @@ -2915,10 +2915,10 @@ UniValue settxfee(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 1 || request.params.size() > 1) + if (request.fHelp || request.params.size() < 1 || request.params.size() > 1) { throw std::runtime_error( "settxfee amount\n" - "\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n" + "\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n" "\nArguments:\n" "1. amount (numeric or string, required) The transaction fee in " + CURRENCY_UNIT + "/kB\n" "\nResult\n" @@ -2927,13 +2927,13 @@ UniValue settxfee(const JSONRPCRequest& request) + HelpExampleCli("settxfee", "0.00001") + HelpExampleRpc("settxfee", "0.00001") ); + } LOCK2(cs_main, pwallet->cs_wallet); - // Amount CAmount nAmount = AmountFromValue(request.params[0]); - payTxFee = CFeeRate(nAmount, 1000); + pwallet->m_pay_tx_fee = CFeeRate(nAmount, 1000); return true; } @@ -2994,9 +2994,9 @@ UniValue getwalletinfo(const JSONRPCRequest& request) if (pwallet->IsCrypted()) { obj.pushKV("unlocked_until", pwallet->nRelockTime); } - obj.pushKV("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())); + obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK())); if (!masterKeyID.IsNull()) - obj.pushKV("hdmasterkeyid", masterKeyID.GetHex()); + obj.pushKV("hdmasterkeyid", masterKeyID.GetHex()); return obj; } @@ -3377,7 +3377,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) subtractFeeFromOutputs = options["subtractFeeFromOutputs"].get_array(); if (options.exists("replaceable")) { - coinControl.signalRbf = options["replaceable"].get_bool(); + coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool(); } if (options.exists("conf_target")) { if (options.exists("feeRate")) { @@ -3566,7 +3566,7 @@ UniValue bumpfee(const JSONRPCRequest& request) // optional parameters CAmount totalFee = 0; CCoinControl coin_control; - coin_control.signalRbf = true; + coin_control.m_signal_bip125_rbf = true; if (!request.params[1].isNull()) { UniValue options = request.params[1]; RPCTypeCheckObj(options, @@ -3590,7 +3590,7 @@ UniValue bumpfee(const JSONRPCRequest& request) } if (options.exists("replaceable")) { - coin_control.signalRbf = options["replaceable"].get_bool(); + coin_control.m_signal_bip125_rbf = options["replaceable"].get_bool(); } if (options.exists("estimate_mode")) { if (!FeeModeFromString(options["estimate_mode"].get_str(), coin_control.m_fee_mode)) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8c392434fc..ad3dd4cd2c 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -72,29 +72,8 @@ CWallet* GetWallet(const std::string& name) return nullptr; } -/** Transaction fee set by the user */ -CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); -unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; -bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE; -bool fWalletRbf = DEFAULT_WALLET_RBF; -bool g_wallet_allow_fallback_fee = true; //<! will be defined via chainparams - const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; -/** - * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) - * Override with -mintxfee - */ -CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE); -/** - * If fee estimation does not have enough data to provide estimates, use this fee instead. - * Has no effect if not using fee estimation - * Override with -fallbackfee - */ -CFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE); - -CFeeRate CWallet::m_discard_rate = CFeeRate(DEFAULT_DISCARD_FEE); - const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); /** @defgroup mapWallet @@ -2054,7 +2033,7 @@ bool CWalletTx::IsTrusted() const return true; if (nDepth < 0) return false; - if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit + if (!pwallet->m_spend_zero_conf_change || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit return false; // Don't trust unconfirmed transactions from us unless they are in the mempool. @@ -2490,10 +2469,10 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil FeeCalculation feeCalc; CCoinControl temp; temp.m_confirm_target = 1008; - CFeeRate long_term_feerate = GetMinimumFeeRate(temp, ::mempool, ::feeEstimator, &feeCalc); + CFeeRate long_term_feerate = GetMinimumFeeRate(*this, temp, ::mempool, ::feeEstimator, &feeCalc); // Calculate cost of change - CAmount cost_of_change = GetDiscardRate(::feeEstimator).GetFee(coin_selection_params.change_spend_size) + coin_selection_params.effective_fee.GetFee(coin_selection_params.change_output_size); + CAmount cost_of_change = GetDiscardRate(*this, ::feeEstimator).GetFee(coin_selection_params.change_spend_size) + coin_selection_params.effective_fee.GetFee(coin_selection_params.change_output_size); // Filter by the min conf specs and add to utxo_pool and calculate effective value for (const COutput &output : vCoins) @@ -2590,11 +2569,11 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm bool res = nTargetValue <= nValueFromPresetInputs || SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(1, 6, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used) || SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(1, 1, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used) || - (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) || - (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, std::min((size_t)4, nMaxChainLength/3)), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) || - (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, nMaxChainLength/2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) || - (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, nMaxChainLength), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) || - (bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max()), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); + (m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) || + (m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, std::min((size_t)4, nMaxChainLength/3)), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) || + (m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, nMaxChainLength/2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) || + (m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, nMaxChainLength), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) || + (m_spend_zero_conf_change && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max()), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end()); @@ -2813,10 +2792,10 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac CTxOut change_prototype_txout(0, scriptChange); coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout, SER_DISK, 0); - CFeeRate discard_rate = GetDiscardRate(::feeEstimator); + CFeeRate discard_rate = GetDiscardRate(*this, ::feeEstimator); // Get the fee rate to use effective values in coin selection - CFeeRate nFeeRateNeeded = GetMinimumFeeRate(coin_control, ::mempool, ::feeEstimator, &feeCalc); + CFeeRate nFeeRateNeeded = GetMinimumFeeRate(*this, coin_control, ::mempool, ::feeEstimator, &feeCalc); nFeeRet = 0; bool pick_new_inputs = true; @@ -2940,8 +2919,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac return false; } - nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc); - if (feeCalc.reason == FeeReason::FALLBACK && !g_wallet_allow_fallback_fee) { + nFeeNeeded = GetMinimumFee(*this, nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc); + if (feeCalc.reason == FeeReason::FALLBACK && !m_allow_fallback_fee) { // eventually allow a fallback fee strFailReason = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee."); return false; @@ -2968,7 +2947,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac // change output. Only try this once. if (nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) { unsigned int tx_size_with_change = nBytes + coin_selection_params.change_output_size + 2; // Add 2 as a buffer in case increasing # of outputs changes compact size - CAmount fee_needed_with_change = GetMinimumFee(tx_size_with_change, coin_control, ::mempool, ::feeEstimator, nullptr); + CAmount fee_needed_with_change = GetMinimumFee(*this, tx_size_with_change, coin_control, ::mempool, ::feeEstimator, nullptr); CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, discard_rate); if (nFeeRet >= fee_needed_with_change + minimum_value_for_change) { pick_new_inputs = false; @@ -3035,7 +3014,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac // to avoid conflicting with other possible uses of nSequence, // and in the spirit of "smallest possible change from prior // behavior." - const uint32_t nSequence = coin_control.signalRbf ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1); + const uint32_t nSequence = coin_control.m_signal_bip125_rbf.get_value_or(m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1); for (const auto& coin : selected_coins) { txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence)); } @@ -4080,6 +4059,66 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path& return nullptr; } + if (gArgs.IsArgSet("-mintxfee")) { + CAmount n = 0; + if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n) { + InitError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", ""))); + return nullptr; + } + if (n > HIGH_TX_FEE_PER_KB) { + InitWarning(AmountHighWarn("-mintxfee") + " " + + _("This is the minimum transaction fee you pay on every transaction.")); + } + walletInstance->m_min_fee = CFeeRate(n); + } + + walletInstance->m_allow_fallback_fee = Params().IsFallbackFeeEnabled(); + if (gArgs.IsArgSet("-fallbackfee")) { + CAmount nFeePerK = 0; + if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) { + InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", ""))); + return nullptr; + } + if (nFeePerK > HIGH_TX_FEE_PER_KB) { + InitWarning(AmountHighWarn("-fallbackfee") + " " + + _("This is the transaction fee you may pay when fee estimates are not available.")); + } + walletInstance->m_fallback_fee = CFeeRate(nFeePerK); + walletInstance->m_allow_fallback_fee = nFeePerK != 0; //disable fallback fee in case value was set to 0, enable if non-null value + } + if (gArgs.IsArgSet("-discardfee")) { + CAmount nFeePerK = 0; + if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK)) { + InitError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", ""))); + return nullptr; + } + if (nFeePerK > HIGH_TX_FEE_PER_KB) { + InitWarning(AmountHighWarn("-discardfee") + " " + + _("This is the transaction fee you may discard if change is smaller than dust at this level")); + } + walletInstance->m_discard_rate = CFeeRate(nFeePerK); + } + if (gArgs.IsArgSet("-paytxfee")) { + CAmount nFeePerK = 0; + if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK)) { + InitError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", ""))); + return nullptr; + } + if (nFeePerK > HIGH_TX_FEE_PER_KB) { + InitWarning(AmountHighWarn("-paytxfee") + " " + + _("This is the transaction fee you will pay if you send a transaction.")); + } + walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000); + if (walletInstance->m_pay_tx_fee < ::minRelayTxFee) { + InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"), + gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString())); + return nullptr; + } + } + walletInstance->m_confirm_target = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); + walletInstance->m_spend_zero_conf_change = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); + walletInstance->m_signal_rbf = gArgs.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF); + LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); // Try to top up keypool. No-op if the wallet is locked. diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index dd165de825..780c82ac36 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -38,22 +38,13 @@ bool HasWallets(); std::vector<CWallet*> GetWallets(); CWallet* GetWallet(const std::string& name); -/** - * Settings - */ -extern CFeeRate payTxFee; -extern unsigned int nTxConfirmTarget; -extern bool bSpendZeroConfChange; -extern bool fWalletRbf; -extern bool g_wallet_allow_fallback_fee; - //! Default for -keypool static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000; //! -paytxfee default -static const CAmount DEFAULT_TRANSACTION_FEE = 0; +constexpr CAmount DEFAULT_PAY_TX_FEE = 0; //! -fallbackfee default static const CAmount DEFAULT_FALLBACK_FEE = 20000; -//! -m_discard_rate default +//! -discardfee default static const CAmount DEFAULT_DISCARD_FEE = 10000; //! -mintxfee default static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000; @@ -968,9 +959,19 @@ public: bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts) const; bool DummySignInput(CTxIn &tx_in, const CTxOut &txout) const; - static CFeeRate minTxFee; - static CFeeRate fallbackFee; - static CFeeRate m_discard_rate; + CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE}; + unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET}; + bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE}; + bool m_signal_rbf{DEFAULT_WALLET_RBF}; + bool m_allow_fallback_fee{true}; //<! will be defined via chainparams + CFeeRate m_min_fee{DEFAULT_TRANSACTION_MINFEE}; //!< Override with -mintxfee + /** + * If fee estimation does not have enough data to provide estimates, use this fee instead. + * Has no effect if not using fee estimation + * Override with -fallbackfee + */ + CFeeRate m_fallback_fee{DEFAULT_FALLBACK_FEE}; + CFeeRate m_discard_rate{DEFAULT_DISCARD_FEE}; OutputType m_default_address_type{DEFAULT_ADDRESS_TYPE}; OutputType m_default_change_type{OutputType::NONE}; // Default to OutputType::NONE if not set by -changetype |