Skip to content

Commit 104f5f2

Browse files
committed
Merge #10589: More economical fee estimates for RBF and RPC options to control
f135923 Add RPC options for RBF, confirmation target, and conservative fee estimation. (Alex Morcos) f0bf33d Change default fee estimation mode. (Alex Morcos) e0738e3 remove default argument from estimateSmartFee (Alex Morcos) d507c30 Introduce a fee estimate mode. (Alex Morcos) cfaef69 remove default argument from GetMinimumFee (Alex Morcos) Tree-SHA512: 49c3a49a6893790a7e8b4e93a48f123dd5307af26c2017800683b76b4df8fc904ba73402917878676242c7440e3e04288d0c1ff3c2c907418724efc03cedab50
2 parents 379aed0 + f135923 commit 104f5f2

File tree

13 files changed

+157
-28
lines changed

13 files changed

+157
-28
lines changed

src/policy/fees.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ std::string StringForFeeReason(FeeReason reason) {
3636
return reason_string->second;
3737
}
3838

39+
bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) {
40+
static const std::map<std::string, FeeEstimateMode> fee_modes = {
41+
{"UNSET", FeeEstimateMode::UNSET},
42+
{"ECONOMICAL", FeeEstimateMode::ECONOMICAL},
43+
{"CONSERVATIVE", FeeEstimateMode::CONSERVATIVE},
44+
};
45+
auto mode = fee_modes.find(mode_string);
46+
47+
if (mode == fee_modes.end()) return false;
48+
49+
fee_estimate_mode = mode->second;
50+
return true;
51+
}
52+
3953
/**
4054
* We will instantiate an instance of this class to track transactions that were
4155
* included in a block. We will lump transactions into a bucket according to their

src/policy/fees.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ enum class FeeReason {
9090

9191
std::string StringForFeeReason(FeeReason reason);
9292

93+
/* Used to determine type of fee estimation requested */
94+
enum class FeeEstimateMode {
95+
UNSET, //! Use default settings based on other criteria
96+
ECONOMICAL, //! Force estimateSmartFee to use non-conservative estimates
97+
CONSERVATIVE, //! Force estimateSmartFee to use conservative estimates
98+
};
99+
100+
bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode);
101+
93102
/* Used to return detailed information about a feerate bucket */
94103
struct EstimatorBucket
95104
{
@@ -197,7 +206,7 @@ class CBlockPolicyEstimator
197206
* the closest target where one can be given. 'conservative' estimates are
198207
* valid over longer time horizons also.
199208
*/
200-
CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, const CTxMemPool& pool, bool conservative = true) const;
209+
CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, const CTxMemPool& pool, bool conservative) const;
201210

202211
/** Return a specific fee estimate calculation with a given success
203212
* threshold and time horizon, and optionally return detailed data about

src/qt/coincontroldialog.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
490490
else nBytesInputs += 148;
491491
}
492492

493+
bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET, coinControl->signalRbf);
494+
493495
// calculation
494496
if (nQuantity > 0)
495497
{
@@ -510,7 +512,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
510512
nBytes -= 34;
511513

512514
// Fee
513-
nPayFee = CWallet::GetMinimumFee(nBytes, coinControl->nConfirmTarget, ::mempool, ::feeEstimator);
515+
nPayFee = CWallet::GetMinimumFee(nBytes, coinControl->nConfirmTarget, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */, false /* ignoreGlobalPayTxFee */, conservative_estimate);
514516

515517
if (nPayAmount > 0)
516518
{
@@ -585,7 +587,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
585587
if (payTxFee.GetFeePerK() > 0)
586588
dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), payTxFee.GetFeePerK()) / 1000;
587589
else {
588-
dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), ::feeEstimator.estimateSmartFee(coinControl->nConfirmTarget, NULL, ::mempool).GetFeePerK()) / 1000;
590+
dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), ::feeEstimator.estimateSmartFee(coinControl->nConfirmTarget, NULL, ::mempool, conservative_estimate).GetFeePerK()) / 1000;
589591
}
590592
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
591593

src/qt/sendcoinsdialog.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ void SendCoinsDialog::setModel(WalletModel *_model)
166166
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls()));
167167
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables()));
168168
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
169+
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel()));
170+
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
169171
ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000));
170172
updateFeeSectionControls();
171173
updateMinFeeLabel();
@@ -652,7 +654,8 @@ void SendCoinsDialog::updateSmartFeeLabel()
652654

653655
int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
654656
FeeCalculation feeCalc;
655-
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool);
657+
bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET, ui->optInRBF->isChecked());
658+
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool, conservative_estimate);
656659
if (feeRate <= CFeeRate(0)) // not enough data => minfee
657660
{
658661
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
@@ -827,6 +830,7 @@ void SendCoinsDialog::coinControlUpdateLabels()
827830
} else {
828831
CoinControlDialog::coinControl->nConfirmTarget = model->getDefaultConfirmTarget();
829832
}
833+
CoinControlDialog::coinControl->signalRbf = ui->optInRBF->isChecked();
830834

831835
for(int i = 0; i < ui->entries->count(); ++i)
832836
{

src/qt/walletmodel.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "keystore.h"
2020
#include "validation.h"
2121
#include "net.h" // for g_connman
22+
#include "policy/fees.h"
2223
#include "policy/rbf.h"
2324
#include "sync.h"
2425
#include "ui_interface.h"
@@ -667,7 +668,7 @@ bool WalletModel::bumpFee(uint256 hash)
667668
std::unique_ptr<CFeeBumper> feeBump;
668669
{
669670
LOCK2(cs_main, wallet->cs_wallet);
670-
feeBump.reset(new CFeeBumper(wallet, hash, nTxConfirmTarget, false, 0, true));
671+
feeBump.reset(new CFeeBumper(wallet, hash, nTxConfirmTarget, false, 0, true, FeeEstimateMode::UNSET));
671672
}
672673
if (feeBump->getResult() != BumpFeeResult::OK)
673674
{

src/rpc/client.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
3737
{ "getnetworkhashps", 1, "height" },
3838
{ "sendtoaddress", 1, "amount" },
3939
{ "sendtoaddress", 4, "subtractfeefromamount" },
40+
{ "sendtoaddress", 5 , "replaceable" },
41+
{ "sendtoaddress", 6 , "conf_target" },
4042
{ "settxfee", 0, "amount" },
4143
{ "getreceivedbyaddress", 1, "minconf" },
4244
{ "getreceivedbyaccount", 1, "minconf" },
@@ -69,6 +71,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
6971
{ "sendmany", 1, "amounts" },
7072
{ "sendmany", 2, "minconf" },
7173
{ "sendmany", 4, "subtractfeefrom" },
74+
{ "sendmany", 5 , "replaceable" },
75+
{ "sendmany", 6 , "conf_target" },
7276
{ "addmultisigaddress", 0, "nrequired" },
7377
{ "addmultisigaddress", 1, "keys" },
7478
{ "createmultisig", 0, "nrequired" },

src/test/policyestimator_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,8 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
184184
mpool.TrimToSize(1);
185185
BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
186186
for (int i = 1; i < 10; i++) {
187-
BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= feeEst.estimateRawFee(i, 0.85, FeeEstimateHorizon::MED_HALFLIFE).GetFeePerK());
188-
BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
187+
BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool, true).GetFeePerK() >= feeEst.estimateRawFee(i, 0.85, FeeEstimateHorizon::MED_HALFLIFE).GetFeePerK());
188+
BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool, true).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
189189
}
190190
}
191191

src/wallet/coincontrol.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define BITCOIN_WALLET_COINCONTROL_H
77

88
#include "policy/feerate.h"
9+
#include "policy/fees.h"
910
#include "primitives/transaction.h"
1011
#include "wallet/wallet.h"
1112

@@ -26,6 +27,8 @@ class CCoinControl
2627
int nConfirmTarget;
2728
//! Signal BIP-125 replace by fee.
2829
bool signalRbf;
30+
//! Fee estimation mode to control arguments to estimateSmartFee
31+
FeeEstimateMode m_fee_mode;
2932

3033
CCoinControl()
3134
{
@@ -42,6 +45,7 @@ class CCoinControl
4245
fOverrideFeeRate = false;
4346
nConfirmTarget = 0;
4447
signalRbf = fWalletRbf;
48+
m_fee_mode = FeeEstimateMode::UNSET;
4549
}
4650

4751
bool HasSelected() const

src/wallet/feebumper.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ bool CFeeBumper::preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx
6666
return true;
6767
}
6868

69-
CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable)
69+
CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable, FeeEstimateMode fee_mode)
7070
:
7171
txid(std::move(txidIn)),
7272
nOldFee(0),
@@ -165,7 +165,8 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
165165
nNewFee = totalFee;
166166
nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
167167
} else {
168-
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr, ignoreGlobalPayTxFee);
168+
bool conservative_estimate = CalculateEstimateType(fee_mode, newTxReplaceable);
169+
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr /* FeeCalculation */, ignoreGlobalPayTxFee, conservative_estimate);
169170
nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
170171

171172
// New fee rate must be at least old rate + minimum incremental relay rate

src/wallet/feebumper.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
class CWallet;
1111
class CWalletTx;
1212
class uint256;
13+
enum class FeeEstimateMode;
1314

1415
enum class BumpFeeResult
1516
{
@@ -24,7 +25,7 @@ enum class BumpFeeResult
2425
class CFeeBumper
2526
{
2627
public:
27-
CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable);
28+
CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable, FeeEstimateMode fee_mode);
2829
BumpFeeResult getResult() const { return currentResult; }
2930
const std::vector<std::string>& getErrors() const { return vErrors; }
3031
CAmount getOldFee() const { return nOldFee; }

0 commit comments

Comments
 (0)