Introduce a fee estimate mode.

GetMinimumFee now passes the conservative argument into estimateSmartFee.
Call CalculateEstimateType(mode) before calling GetMinimumFee or estimateSmartFee to determine the value of this argument.
CCoinControl can now be used to control this mode.
This commit is contained in:
Alex Morcos 2017-06-13 11:28:30 -04:00
parent cfaef69ace
commit d507c301bc
8 changed files with 42 additions and 8 deletions

View File

@ -90,6 +90,13 @@ enum class FeeReason {
std::string StringForFeeReason(FeeReason reason); std::string StringForFeeReason(FeeReason reason);
/* Used to determine type of fee estimation requested */
enum class FeeEstimateMode {
UNSET, //! Use default settings based on other criteria
ECONOMICAL, //! Force estimateSmartFee to use non-conservative estimates
CONSERVATIVE, //! Force estimateSmartFee to use conservative estimates
};
/* Used to return detailed information about a feerate bucket */ /* Used to return detailed information about a feerate bucket */
struct EstimatorBucket struct EstimatorBucket
{ {

View File

@ -490,6 +490,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
else nBytesInputs += 148; else nBytesInputs += 148;
} }
bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET);
// calculation // calculation
if (nQuantity > 0) if (nQuantity > 0)
{ {
@ -510,7 +512,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34; nBytes -= 34;
// Fee // Fee
nPayFee = CWallet::GetMinimumFee(nBytes, coinControl->nConfirmTarget, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */, false /* ignoreGlobalPayTxFee */); nPayFee = CWallet::GetMinimumFee(nBytes, coinControl->nConfirmTarget, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */, false /* ignoreGlobalPayTxFee */, conservative_estimate);
if (nPayAmount > 0) if (nPayAmount > 0)
{ {
@ -585,7 +587,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (payTxFee.GetFeePerK() > 0) if (payTxFee.GetFeePerK() > 0)
dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), payTxFee.GetFeePerK()) / 1000; dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), payTxFee.GetFeePerK()) / 1000;
else { else {
dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), ::feeEstimator.estimateSmartFee(coinControl->nConfirmTarget, NULL, ::mempool).GetFeePerK()) / 1000; dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), ::feeEstimator.estimateSmartFee(coinControl->nConfirmTarget, NULL, ::mempool, conservative_estimate).GetFeePerK()) / 1000;
} }
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary); QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);

View File

@ -652,7 +652,8 @@ void SendCoinsDialog::updateSmartFeeLabel()
int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2; int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
FeeCalculation feeCalc; FeeCalculation feeCalc;
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool); bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET);
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool, conservative_estimate);
if (feeRate <= CFeeRate(0)) // not enough data => minfee if (feeRate <= CFeeRate(0)) // not enough data => minfee
{ {
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),

View File

@ -19,6 +19,7 @@
#include "keystore.h" #include "keystore.h"
#include "validation.h" #include "validation.h"
#include "net.h" // for g_connman #include "net.h" // for g_connman
#include "policy/fees.h"
#include "policy/rbf.h" #include "policy/rbf.h"
#include "sync.h" #include "sync.h"
#include "ui_interface.h" #include "ui_interface.h"

View File

@ -6,6 +6,7 @@
#define BITCOIN_WALLET_COINCONTROL_H #define BITCOIN_WALLET_COINCONTROL_H
#include "policy/feerate.h" #include "policy/feerate.h"
#include "policy/fees.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "wallet/wallet.h" #include "wallet/wallet.h"
@ -26,6 +27,8 @@ public:
int nConfirmTarget; int nConfirmTarget;
//! Signal BIP-125 replace by fee. //! Signal BIP-125 replace by fee.
bool signalRbf; bool signalRbf;
//! Fee estimation mode to control arguments to estimateSmartFee
FeeEstimateMode m_fee_mode;
CCoinControl() CCoinControl()
{ {
@ -42,6 +45,7 @@ public:
fOverrideFeeRate = false; fOverrideFeeRate = false;
nConfirmTarget = 0; nConfirmTarget = 0;
signalRbf = fWalletRbf; signalRbf = fWalletRbf;
m_fee_mode = FeeEstimateMode::UNSET;
} }
bool HasSelected() const bool HasSelected() const

View File

@ -165,7 +165,8 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
nNewFee = totalFee; nNewFee = totalFee;
nNewFeeRate = CFeeRate(totalFee, maxNewTxSize); nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
} else { } else {
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr, ignoreGlobalPayTxFee); bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET);
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr /* FeeCalculation */, ignoreGlobalPayTxFee, conservative_estimate);
nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize); nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
// New fee rate must be at least old rate + minimum incremental relay rate // New fee rate must be at least old rate + minimum incremental relay rate

View File

@ -2724,7 +2724,10 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
if (coinControl && coinControl->nConfirmTarget > 0) if (coinControl && coinControl->nConfirmTarget > 0)
currentConfirmationTarget = coinControl->nConfirmTarget; currentConfirmationTarget = coinControl->nConfirmTarget;
CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator, &feeCalc, false /* ignoreGlobalPayTxFee */); // Allow to override the default fee estimate mode over the CoinControl instance
bool conservative_estimate = CalculateEstimateType(coinControl ? coinControl->m_fee_mode : FeeEstimateMode::UNSET);
CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator, &feeCalc, false /* ignoreGlobalPayTxFee */, conservative_estimate);
if (coinControl && coinControl->fOverrideFeeRate) if (coinControl && coinControl->fOverrideFeeRate)
nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes); nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes);
@ -2905,13 +2908,13 @@ CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes)); return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
} }
CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc, bool ignoreGlobalPayTxFee) CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc, bool ignoreGlobalPayTxFee, bool conservative_estimate)
{ {
// payTxFee is the user-set global for desired feerate // payTxFee is the user-set global for desired feerate
CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes); CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
// User didn't set: use -txconfirmtarget to estimate... // User didn't set: use -txconfirmtarget to estimate...
if (nFeeNeeded == 0 || ignoreGlobalPayTxFee) { if (nFeeNeeded == 0 || ignoreGlobalPayTxFee) {
nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, feeCalc, pool, true).GetFee(nTxBytes); nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, feeCalc, pool, conservative_estimate).GetFee(nTxBytes);
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee // ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
if (nFeeNeeded == 0) { if (nFeeNeeded == 0) {
nFeeNeeded = fallbackFee.GetFee(nTxBytes); nFeeNeeded = fallbackFee.GetFee(nTxBytes);
@ -4154,3 +4157,14 @@ bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState&
{ {
return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, NULL, false, nAbsurdFee); return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, NULL, false, nAbsurdFee);
} }
bool CalculateEstimateType(FeeEstimateMode mode) {
switch (mode) {
case FeeEstimateMode::UNSET:
case FeeEstimateMode::CONSERVATIVE:
return true;
case FeeEstimateMode::ECONOMICAL:
return false;
}
return true;
}

View File

@ -80,6 +80,7 @@ class CTxMemPool;
class CBlockPolicyEstimator; class CBlockPolicyEstimator;
class CWalletTx; class CWalletTx;
struct FeeCalculation; struct FeeCalculation;
enum class FeeEstimateMode;
/** (client) version numbers for particular wallet features */ /** (client) version numbers for particular wallet features */
enum WalletFeature enum WalletFeature
@ -963,7 +964,7 @@ public:
* Estimate the minimum fee considering user set parameters * Estimate the minimum fee considering user set parameters
* and the required fee * and the required fee
*/ */
static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc, bool ignoreGlobalPayTxFee); static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc, bool ignoreGlobalPayTxFee, bool conservative_estimate);
/** /**
* Return the minimum required fee taking into account the * Return the minimum required fee taking into account the
* floating relay fee and user set minimum transaction fee * floating relay fee and user set minimum transaction fee
@ -1211,4 +1212,7 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const ContainerType &coins
} }
return true; return true;
} }
bool CalculateEstimateType(FeeEstimateMode mode);
#endif // BITCOIN_WALLET_WALLET_H #endif // BITCOIN_WALLET_WALLET_H