aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/policy/fees.cpp110
-rw-r--r--src/policy/fees.h2
-rw-r--r--src/rpc/mining.cpp3
-rw-r--r--src/test/policyestimator_tests.cpp10
-rw-r--r--src/wallet/wallet.cpp8
5 files changed, 60 insertions, 73 deletions
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 03fe11a0d8..45f9765231 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -826,8 +826,10 @@ double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget,
* estimates, however, required the 95% threshold at 2 * target be met for any
* longer time horizons also.
*/
-CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, const CTxMemPool& pool, bool conservative) const
+CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
{
+ LOCK(cs_feeEstimator);
+
if (feeCalc) {
feeCalc->desiredTarget = confTarget;
feeCalc->returnedTarget = confTarget;
@@ -835,80 +837,70 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
double median = -1;
EstimationResult tempResult;
- {
- LOCK(cs_feeEstimator);
- // Return failure if trying to analyze a target we're not tracking
- if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms())
- return CFeeRate(0);
+ // Return failure if trying to analyze a target we're not tracking
+ if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms())
+ return CFeeRate(0);
- // It's not possible to get reasonable estimates for confTarget of 1
- if (confTarget == 1)
- confTarget = 2;
+ // It's not possible to get reasonable estimates for confTarget of 1
+ if (confTarget == 1)
+ confTarget = 2;
- unsigned int maxUsableEstimate = MaxUsableEstimate();
- if (maxUsableEstimate <= 1)
- return CFeeRate(0);
+ unsigned int maxUsableEstimate = MaxUsableEstimate();
+ if (maxUsableEstimate <= 1)
+ return CFeeRate(0);
- if ((unsigned int)confTarget > maxUsableEstimate) {
- confTarget = maxUsableEstimate;
- }
+ if ((unsigned int)confTarget > maxUsableEstimate) {
+ confTarget = maxUsableEstimate;
+ }
- assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
- /** true is passed to estimateCombined fee for target/2 and target so
- * that we check the max confirms for shorter time horizons as well.
- * This is necessary to preserve monotonically increasing estimates.
- * For non-conservative estimates we do the same thing for 2*target, but
- * for conservative estimates we want to skip these shorter horizons
- * checks for 2*target because we are taking the max over all time
- * horizons so we already have monotonically increasing estimates and
- * the purpose of conservative estimates is not to let short term
- * fluctuations lower our estimates by too much.
- */
- double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true, &tempResult);
+ assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
+ /** true is passed to estimateCombined fee for target/2 and target so
+ * that we check the max confirms for shorter time horizons as well.
+ * This is necessary to preserve monotonically increasing estimates.
+ * For non-conservative estimates we do the same thing for 2*target, but
+ * for conservative estimates we want to skip these shorter horizons
+ * checks for 2*target because we are taking the max over all time
+ * horizons so we already have monotonically increasing estimates and
+ * the purpose of conservative estimates is not to let short term
+ * fluctuations lower our estimates by too much.
+ */
+ double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true, &tempResult);
+ if (feeCalc) {
+ feeCalc->est = tempResult;
+ feeCalc->reason = FeeReason::HALF_ESTIMATE;
+ }
+ median = halfEst;
+ double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true, &tempResult);
+ if (actualEst > median) {
+ median = actualEst;
if (feeCalc) {
feeCalc->est = tempResult;
- feeCalc->reason = FeeReason::HALF_ESTIMATE;
+ feeCalc->reason = FeeReason::FULL_ESTIMATE;
}
- median = halfEst;
- double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true, &tempResult);
- if (actualEst > median) {
- median = actualEst;
- if (feeCalc) {
- feeCalc->est = tempResult;
- feeCalc->reason = FeeReason::FULL_ESTIMATE;
- }
+ }
+ double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative, &tempResult);
+ if (doubleEst > median) {
+ median = doubleEst;
+ if (feeCalc) {
+ feeCalc->est = tempResult;
+ feeCalc->reason = FeeReason::DOUBLE_ESTIMATE;
}
- double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative, &tempResult);
- if (doubleEst > median) {
- median = doubleEst;
+ }
+
+ if (conservative || median == -1) {
+ double consEst = estimateConservativeFee(2 * confTarget, &tempResult);
+ if (consEst > median) {
+ median = consEst;
if (feeCalc) {
feeCalc->est = tempResult;
- feeCalc->reason = FeeReason::DOUBLE_ESTIMATE;
+ feeCalc->reason = FeeReason::CONSERVATIVE;
}
}
-
- if (conservative || median == -1) {
- double consEst = estimateConservativeFee(2 * confTarget, &tempResult);
- if (consEst > median) {
- median = consEst;
- if (feeCalc) {
- feeCalc->est = tempResult;
- feeCalc->reason = FeeReason::CONSERVATIVE;
- }
- }
- }
- } // Must unlock cs_feeEstimator before taking mempool locks
+ }
if (feeCalc) feeCalc->returnedTarget = confTarget;
- // If mempool is limiting txs , return at least the min feerate from the mempool
- CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
- if (minPoolFee > 0 && minPoolFee > median) {
- if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
- return CFeeRate(minPoolFee);
- }
-
if (median < 0)
return CFeeRate(0);
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 4c80371c5c..f4ef793643 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -208,7 +208,7 @@ public:
* the closest target where one can be given. 'conservative' estimates are
* valid over longer time horizons also.
*/
- CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, const CTxMemPool& pool, bool conservative) const;
+ CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const;
/** Return a specific fee estimate calculation with a given success
* threshold and time horizon, and optionally return detailed data about
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 10bb341e54..5dc468e111 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -815,7 +815,6 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
"\n"
"A negative value is returned if not enough transactions and blocks\n"
"have been observed to make an estimate for any number of blocks.\n"
- "However it will not return a value below the mempool reject fee.\n"
"\nExample:\n"
+ HelpExampleCli("estimatesmartfee", "6")
);
@@ -831,7 +830,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
UniValue result(UniValue::VOBJ);
FeeCalculation feeCalc;
- CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &feeCalc, ::mempool, conservative);
+ CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &feeCalc, conservative);
result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
result.push_back(Pair("blocks", feeCalc.returnedTarget));
return result;
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 8cdd392109..fd8f7191f4 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -177,16 +177,6 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int i = 2; i < 9; i++) { // At 9, the original estimate was already at the bottom (b/c scale = 2)
BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
}
-
- // Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
- mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Height(blocknum).FromTx(tx));
- // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
- mpool.TrimToSize(1);
- BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
- for (int i = 1; i < 10; i++) {
- BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool, true).GetFeePerK() >= feeEst.estimateRawFee(i, 0.85, FeeEstimateHorizon::MED_HALFLIFE).GetFeePerK());
- BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool, true).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
- }
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index f7f296bd52..8c4f637306 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2951,12 +2951,18 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_c
if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true;
else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false;
- fee_needed = estimator.estimateSmartFee(target, feeCalc, pool, conservative_estimate).GetFee(nTxBytes);
+ fee_needed = estimator.estimateSmartFee(target, feeCalc, conservative_estimate).GetFee(nTxBytes);
if (fee_needed == 0) {
// if we don't have enough data for estimateSmartFee, then use fallbackFee
fee_needed = fallbackFee.GetFee(nTxBytes);
if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
}
+ // Obey mempool min fee when using smart fee estimation
+ CAmount min_mempool_fee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nTxBytes);
+ if (fee_needed < min_mempool_fee) {
+ fee_needed = min_mempool_fee;
+ if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
+ }
}
// prevent user from paying a fee below minRelayTxFee or minTxFee