Merge #12909: wallet: Make fee settings to be non-static members

fac0db0 wallet: Make fee settings non-static members (MarcoFalke)

Pull request description:

  The wallet header defined some globals (they were called "settings"), that should be class members instead.

  This commit is hopefully only refactoring, apart from a multiwallet bugfix: Calling the rpc `settxfee` for one wallet, would set (and change) the fee rate for all loaded wallets. (See added test case)

Tree-SHA512: 4ab6ec2f5c714742396ded5e451ec3b1ceb771e3696492de29889d866de4365b3fbe4a2784d085c8b8bd11b1ebb8a1fec99ab2c62eee716791cfc67c0cf29e1b
This commit is contained in:
Wladimir J. van der Laan 2021-04-09 11:26:57 +03:00 committed by UdjinM6
parent 716d0cd696
commit 4aca43e24a
No known key found for this signature in database
GPG Key ID: 83592BD1400D58D9
15 changed files with 165 additions and 159 deletions

View File

@ -112,9 +112,9 @@ CTransactionBuilder::CTransactionBuilder(std::shared_ptr<CWallet> pwalletIn, con
tallyItem(tallyItemIn)
{
// Generate a feerate which will be used to consider if the remainder is dust and will go into fees or not
coinControl.m_discard_feerate = ::GetDiscardRate(::feeEstimator);
coinControl.m_discard_feerate = ::GetDiscardRate(*pwallet.get(), ::feeEstimator);
// Generate a feerate which will be used by calculations of this class and also by CWallet::CreateTransaction
coinControl.m_feerate = std::max(::feeEstimator.estimateSmartFee((int)::nTxConfirmTarget, nullptr, true), payTxFee);
coinControl.m_feerate = std::max(::feeEstimator.estimateSmartFee((int)pwallet->m_confirm_target, nullptr, true), pwallet->m_pay_tx_fee);
// Change always goes back to origin
coinControl.destChange = tallyItemIn.txdest;
// Only allow tallyItems inputs for tx creation
@ -239,7 +239,7 @@ CAmount CTransactionBuilder::GetAmountUsed() const
CAmount CTransactionBuilder::GetFee(unsigned int nBytes) const
{
CAmount nFeeCalc = coinControl.m_feerate->GetFee(nBytes);
CAmount nRequiredFee = GetRequiredFee(nBytes);
CAmount nRequiredFee = GetRequiredFee(*pwallet.get(), nBytes);
if (nRequiredFee > nFeeCalc) {
nFeeCalc = nRequiredFee;
}

View File

@ -311,20 +311,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
{

View File

@ -26,11 +26,9 @@ class Coin;
class RPCTimerInterface;
class UniValue;
class proxyType;
enum class FeeReason;
struct CNodeStateStats;
namespace interfaces {
class Handler;
class Wallet;
@ -209,18 +207,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;

View File

@ -10,6 +10,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>
@ -21,6 +23,7 @@
#include <ui_interface.h>
#include <uint256.h>
#include <validation.h>
#include <wallet/fees.h>
#include <wallet/wallet.h>
#include <memory>
@ -482,6 +485,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(); }
CoinJoin::Client& coinJoin() override { return m_coinjoin; }
std::unique_ptr<Handler> handleUnload(UnloadFn fn) override

View File

@ -23,8 +23,10 @@
#include <vector>
class CCoinControl;
class CFeeRate;
class CKey;
class CWallet;
enum class FeeReason;
struct CRecipient;
namespace interfaces {
@ -244,6 +246,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;

View File

@ -536,7 +536,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *
nBytes -= 34;
// Fee
nPayFee = model->node().getMinimumFee(nBytes, m_coin_control, nullptr /* returned_target */, nullptr /* reason */);
nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control, nullptr /* returned_target */, nullptr /* reason */);
if (nPayAmount > 0)
{

View File

@ -128,7 +128,7 @@ SendCoinsDialog::SendCoinsDialog(bool _fCoinJoin, QWidget* parent) :
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);
@ -213,7 +213,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()));
}
@ -707,7 +707,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()
@ -739,7 +739,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")
);
}
@ -763,7 +763,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
m_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, *m_coin_control, &returned_target, &reason));
CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, *m_coin_control, &returned_target, &reason));
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");

View File

@ -39,7 +39,7 @@ 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 discard feerate estimation with m_discard_feerate in CreateTransaction if set
boost::optional<CFeeRate> m_discard_feerate;

View File

@ -13,14 +13,14 @@
#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;
@ -29,34 +29,34 @@ 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
bool conservative_estimate = true;
// Allow to override the default fee estimate mode over the CoinControl instance
@ -65,8 +65,8 @@ CFeeRate GetMinimumFeeRate(const CCoinControl& coin_control, const CTxMemPool& p
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;
}
// Obey mempool min fee when using smart fee estimation
@ -77,8 +77,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;
@ -86,12 +86,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;

View File

@ -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

View File

@ -88,7 +88,7 @@ void WalletInit::AddWalletOptions() const
gArgs.AddArg("-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)), false, OptionsCategory::WALLET_FEE);
gArgs.AddArg("-paytxfee=<amt>", strprintf("Fee (in %s/kB) to add to transactions you send (default: %s)",
CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())), false, OptionsCategory::WALLET_FEE);
CURRENCY_UNIT, FormatMoney(CFeeRate{DEFAULT_PAY_TX_FEE}.GetFeePerK())), false, OptionsCategory::WALLET_FEE);
gArgs.AddArg("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", DEFAULT_TX_CONFIRM_TARGET), false, OptionsCategory::WALLET_FEE);
gArgs.AddArg("-hdseed=<hex>", "User defined seed for HD wallet (should be in hex). Only has effect during wallet creation/first start (default: randomly generated)", false, OptionsCategory::WALLET_HD);
@ -184,52 +184,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);
}
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);
}
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;
@ -244,8 +198,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);
if (gArgs.IsArgSet("-walletbackupsdir")) {
if (!fs::is_directory(gArgs.GetArg("-walletbackupsdir", ""))) {

View File

@ -2912,10 +2912,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"
@ -2924,13 +2924,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;
}
@ -3067,7 +3067,7 @@ UniValue getwalletinfo(const JSONRPCRequest& request)
obj.pushKV("keys_left", pwallet->nKeysLeftSinceAutoBackup);
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 (fHDEnabled) {
obj.pushKV("hdchainid", hdChainCurrent.GetID().GetHex());
obj.pushKV("hdaccountcount", (int64_t)hdChainCurrent.CountAccounts());

View File

@ -92,24 +92,6 @@ std::shared_ptr<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;
/**
* Fees smaller than this (in duffs) 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);
// Custom deleter for shared_ptr<CWallet>.
static void ReleaseWallet(CWallet* wallet)
@ -2587,7 +2569,7 @@ bool CWalletTx::IsTrusted() const
return false;
if (IsLockedByInstantSend())
return true;
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.
@ -3134,10 +3116,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)
@ -3250,11 +3232,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, nCoinType) ||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(1, 1, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType) ||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) ||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) ||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) ||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) ||
(bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max()), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType));
(m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) ||
(m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) ||
(m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) ||
(m_spend_zero_conf_change && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) ||
(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, nCoinType));
// because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
@ -3615,7 +3597,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
FeeCalculation feeCalc;
CFeeRate discard_rate = coin_control.m_discard_feerate ? *coin_control.m_discard_feerate : GetDiscardRate(::feeEstimator);
CFeeRate discard_rate = coin_control.m_discard_feerate ? *coin_control.m_discard_feerate : GetDiscardRate(*this, ::feeEstimator);
unsigned int nBytes;
{
std::vector<CInputCoin> vecCoins;
@ -3776,7 +3758,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
txin.scriptSig = CScript();
}
nFee = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc);
nFee = GetMinimumFee(*this, nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc);
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
@ -5143,6 +5125,66 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const WalletLocation& loc
InitWarning(_("Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works!"));
}
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);
}
// TODO: enable when IsFallbackFeeEnabled is backported
// 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);
LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
// Try to top up keypool. No-op if the wallet is locked.

View File

@ -44,19 +44,12 @@ bool HasWallets();
std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> GetWallet(const std::string& name);
/**
* Settings
*/
extern CFeeRate payTxFee;
extern unsigned int nTxConfirmTarget;
extern bool bSpendZeroConfChange;
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 = 1000;
//! -m_discard_rate default
//! -discardfee default
static const CAmount DEFAULT_DISCARD_FEE = 10000;
//! -mintxfee default
static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000;
@ -1082,9 +1075,18 @@ 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_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};
bool NewKeyPool();
size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);

View File

@ -163,6 +163,12 @@ class MultiWalletTest(BitcoinTestFramework):
assert_equal(batch[0]["result"]["chain"], self.chain)
assert_equal(batch[1]["result"]["walletname"], "w1")
self.log.info('Check for per-wallet settxfee call')
assert_equal(w1.getwalletinfo()['paytxfee'], 0)
assert_equal(w2.getwalletinfo()['paytxfee'], 0)
w2.settxfee(4.0)
assert_equal(w1.getwalletinfo()['paytxfee'], 0)
assert_equal(w2.getwalletinfo()['paytxfee'], 4.0)
self.log.info("Test dynamic wallet loading")