Output Fee Estimation Calculations in CreateTransaction
This commit is contained in:
parent
9c248e39f2
commit
1bebfc8d3a
7 changed files with 134 additions and 44 deletions
|
@ -16,6 +16,26 @@
|
|||
|
||||
static constexpr double INF_FEERATE = 1e99;
|
||||
|
||||
std::string StringForFeeReason(FeeReason reason) {
|
||||
static const std::map<FeeReason, std::string> fee_reason_strings = {
|
||||
{FeeReason::NONE, "None"},
|
||||
{FeeReason::HALF_ESTIMATE, "Half Target 60% Threshold"},
|
||||
{FeeReason::FULL_ESTIMATE, "Target 85% Threshold"},
|
||||
{FeeReason::DOUBLE_ESTIMATE, "Double Target 95% Threshold"},
|
||||
{FeeReason::CONSERVATIVE, "Conservative Double Target longer horizon"},
|
||||
{FeeReason::MEMPOOL_MIN, "Mempool Min Fee"},
|
||||
{FeeReason::PAYTXFEE, "PayTxFee set"},
|
||||
{FeeReason::FALLBACK, "Fallback fee"},
|
||||
{FeeReason::REQUIRED, "Minimum Required Fee"},
|
||||
{FeeReason::MAXTXFEE, "MaxTxFee limit"}
|
||||
};
|
||||
auto reason_string = fee_reason_strings.find(reason);
|
||||
|
||||
if (reason_string == fee_reason_strings.end()) return "Unknown";
|
||||
|
||||
return reason_string->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* We will instantiate an instance of this class to track transactions that were
|
||||
* included in a block. We will lump transactions into a bucket according to their
|
||||
|
@ -698,31 +718,36 @@ unsigned int CBlockPolicyEstimator::MaxUsableEstimate() const
|
|||
* time horizon which tracks confirmations up to the desired target. If
|
||||
* checkShorterHorizon is requested, also allow short time horizon estimates
|
||||
* for a lower target to reduce the given answer */
|
||||
double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon) const
|
||||
double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const
|
||||
{
|
||||
double estimate = -1;
|
||||
if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
|
||||
// Find estimate from shortest time horizon possible
|
||||
if (confTarget <= shortStats->GetMaxConfirms()) { // short horizon
|
||||
estimate = shortStats->EstimateMedianVal(confTarget, SUFFICIENT_TXS_SHORT, successThreshold, true, nBestSeenHeight);
|
||||
estimate = shortStats->EstimateMedianVal(confTarget, SUFFICIENT_TXS_SHORT, successThreshold, true, nBestSeenHeight, result);
|
||||
}
|
||||
else if (confTarget <= feeStats->GetMaxConfirms()) { // medium horizon
|
||||
estimate = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight);
|
||||
estimate = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight, result);
|
||||
}
|
||||
else { // long horizon
|
||||
estimate = longStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight);
|
||||
estimate = longStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight, result);
|
||||
}
|
||||
if (checkShorterHorizon) {
|
||||
EstimationResult tempResult;
|
||||
// If a lower confTarget from a more recent horizon returns a lower answer use it.
|
||||
if (confTarget > feeStats->GetMaxConfirms()) {
|
||||
double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(), SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight);
|
||||
if (medMax > 0 && (estimate == -1 || medMax < estimate))
|
||||
double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(), SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight, &tempResult);
|
||||
if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
|
||||
estimate = medMax;
|
||||
if (result) *result = tempResult;
|
||||
}
|
||||
}
|
||||
if (confTarget > shortStats->GetMaxConfirms()) {
|
||||
double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(), SUFFICIENT_TXS_SHORT, successThreshold, true, nBestSeenHeight);
|
||||
if (shortMax > 0 && (estimate == -1 || shortMax < estimate))
|
||||
double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(), SUFFICIENT_TXS_SHORT, successThreshold, true, nBestSeenHeight, &tempResult);
|
||||
if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
|
||||
estimate = shortMax;
|
||||
if (result) *result = tempResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -732,16 +757,18 @@ double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, doubl
|
|||
/** Ensure that for a conservative estimate, the DOUBLE_SUCCESS_PCT is also met
|
||||
* at 2 * target for any longer time horizons.
|
||||
*/
|
||||
double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget) const
|
||||
double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const
|
||||
{
|
||||
double estimate = -1;
|
||||
EstimationResult tempResult;
|
||||
if (doubleTarget <= shortStats->GetMaxConfirms()) {
|
||||
estimate = feeStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true, nBestSeenHeight);
|
||||
estimate = feeStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true, nBestSeenHeight, result);
|
||||
}
|
||||
if (doubleTarget <= feeStats->GetMaxConfirms()) {
|
||||
double longEstimate = longStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true, nBestSeenHeight);
|
||||
double longEstimate = longStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true, nBestSeenHeight, &tempResult);
|
||||
if (longEstimate > estimate) {
|
||||
estimate = longEstimate;
|
||||
if (result) *result = tempResult;
|
||||
}
|
||||
}
|
||||
return estimate;
|
||||
|
@ -754,12 +781,15 @@ 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, int *answerFoundAtTarget, const CTxMemPool& pool, bool conservative) const
|
||||
CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, const CTxMemPool& pool, bool conservative) const
|
||||
{
|
||||
if (answerFoundAtTarget)
|
||||
*answerFoundAtTarget = confTarget;
|
||||
if (feeCalc) {
|
||||
feeCalc->desiredTarget = confTarget;
|
||||
feeCalc->returnedTarget = confTarget;
|
||||
}
|
||||
|
||||
double median = -1;
|
||||
EstimationResult tempResult;
|
||||
{
|
||||
LOCK(cs_feeEstimator);
|
||||
|
||||
|
@ -780,7 +810,6 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
|
|||
}
|
||||
|
||||
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.
|
||||
|
@ -791,32 +820,49 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
|
|||
* 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);
|
||||
double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true);
|
||||
double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative);
|
||||
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::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;
|
||||
}
|
||||
}
|
||||
|
||||
if (conservative || median == -1) {
|
||||
double consEst = estimateConservativeFee(2 * confTarget);
|
||||
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 (answerFoundAtTarget)
|
||||
*answerFoundAtTarget = confTarget;
|
||||
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 (minPoolFee > 0 && minPoolFee > median) {
|
||||
if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
|
||||
return CFeeRate(minPoolFee);
|
||||
}
|
||||
|
||||
if (median < 0)
|
||||
return CFeeRate(0);
|
||||
|
|
|
@ -74,6 +74,22 @@ enum FeeEstimateHorizon {
|
|||
LONG_HALFLIFE = 2
|
||||
};
|
||||
|
||||
/* Enumeration of reason for returned fee estimate */
|
||||
enum class FeeReason {
|
||||
NONE,
|
||||
HALF_ESTIMATE,
|
||||
FULL_ESTIMATE,
|
||||
DOUBLE_ESTIMATE,
|
||||
CONSERVATIVE,
|
||||
MEMPOOL_MIN,
|
||||
PAYTXFEE,
|
||||
FALLBACK,
|
||||
REQUIRED,
|
||||
MAXTXFEE,
|
||||
};
|
||||
|
||||
std::string StringForFeeReason(FeeReason reason);
|
||||
|
||||
/* Used to return detailed information about a feerate bucket */
|
||||
struct EstimatorBucket
|
||||
{
|
||||
|
@ -90,8 +106,16 @@ struct EstimationResult
|
|||
{
|
||||
EstimatorBucket pass;
|
||||
EstimatorBucket fail;
|
||||
double decay;
|
||||
unsigned int scale;
|
||||
double decay = 0;
|
||||
unsigned int scale = 0;
|
||||
};
|
||||
|
||||
struct FeeCalculation
|
||||
{
|
||||
EstimationResult est;
|
||||
FeeReason reason = FeeReason::NONE;
|
||||
int desiredTarget = 0;
|
||||
int returnedTarget = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -173,7 +197,7 @@ public:
|
|||
* the closest target where one can be given. 'conservative' estimates are
|
||||
* valid over longer time horizons also.
|
||||
*/
|
||||
CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool, bool conservative = true) const;
|
||||
CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, const CTxMemPool& pool, bool conservative = true) const;
|
||||
|
||||
/** Return a specific fee estimate calculation with a given success
|
||||
* threshold and time horizon, and optionally return detailed data about
|
||||
|
@ -223,9 +247,9 @@ private:
|
|||
bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry);
|
||||
|
||||
/** Helper for estimateSmartFee */
|
||||
double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon) const;
|
||||
double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const;
|
||||
/** Helper for estimateSmartFee */
|
||||
double estimateConservativeFee(unsigned int doubleTarget) const;
|
||||
double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const;
|
||||
/** Number of blocks of data recorded while fee estimates have been running */
|
||||
unsigned int BlockSpan() const;
|
||||
/** Number of blocks of recorded fee estimate data represented in saved data file */
|
||||
|
|
|
@ -651,8 +651,8 @@ void SendCoinsDialog::updateSmartFeeLabel()
|
|||
return;
|
||||
|
||||
int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
|
||||
int estimateFoundAtBlocks = nBlocksToConfirm;
|
||||
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks, ::mempool);
|
||||
FeeCalculation feeCalc;
|
||||
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool);
|
||||
if (feeRate <= CFeeRate(0)) // not enough data => minfee
|
||||
{
|
||||
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
|
||||
|
@ -670,7 +670,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
|
|||
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
|
||||
std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
|
||||
ui->labelSmartFee2->hide();
|
||||
ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks));
|
||||
ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", feeCalc.returnedTarget));
|
||||
ui->fallbackFeeWarningLabel->setVisible(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -870,10 +870,10 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
|
|||
}
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
int answerFound;
|
||||
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &answerFound, ::mempool, conservative);
|
||||
FeeCalculation feeCalc;
|
||||
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &feeCalc, ::mempool, conservative);
|
||||
result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
|
||||
result.push_back(Pair("blocks", answerFound));
|
||||
result.push_back(Pair("blocks", feeCalc.returnedTarget));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
|
|||
nNewFee = totalFee;
|
||||
nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
|
||||
} else {
|
||||
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, ignoreGlobalPayTxFee);
|
||||
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr, ignoreGlobalPayTxFee);
|
||||
nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
|
||||
|
||||
// New fee rate must be at least old rate + minimum incremental relay rate
|
||||
|
|
|
@ -2524,7 +2524,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
|
|||
|
||||
assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
|
||||
assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
|
||||
|
||||
FeeCalculation feeCalc;
|
||||
unsigned int nBytes;
|
||||
{
|
||||
std::set<CInputCoin> setCoins;
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
|
@ -2696,7 +2697,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
|
|||
return false;
|
||||
}
|
||||
|
||||
unsigned int nBytes = GetVirtualTransactionSize(txNew);
|
||||
nBytes = GetVirtualTransactionSize(txNew);
|
||||
|
||||
CTransaction txNewConst(txNew);
|
||||
|
||||
|
@ -2711,7 +2712,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
|
|||
if (coinControl && coinControl->nConfirmTarget > 0)
|
||||
currentConfirmationTarget = coinControl->nConfirmTarget;
|
||||
|
||||
CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator);
|
||||
CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator, &feeCalc);
|
||||
if (coinControl && coinControl->fOverrideFeeRate)
|
||||
nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes);
|
||||
|
||||
|
@ -2808,6 +2809,15 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
|
||||
nFeeRet, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
|
||||
feeCalc.est.pass.start, feeCalc.est.pass.end,
|
||||
100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool),
|
||||
feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool,
|
||||
feeCalc.est.fail.start, feeCalc.est.fail.end,
|
||||
100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool),
|
||||
feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2882,23 +2892,32 @@ CAmount CWallet::GetRequiredFee(unsigned int 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, bool ignoreGlobalPayTxFee)
|
||||
CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc, bool ignoreGlobalPayTxFee)
|
||||
{
|
||||
// payTxFee is the user-set global for desired feerate
|
||||
CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
|
||||
// User didn't set: use -txconfirmtarget to estimate...
|
||||
if (nFeeNeeded == 0 || ignoreGlobalPayTxFee) {
|
||||
int estimateFoundTarget = nConfirmTarget;
|
||||
nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, &estimateFoundTarget, pool).GetFee(nTxBytes);
|
||||
nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, feeCalc, pool, true).GetFee(nTxBytes);
|
||||
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
|
||||
if (nFeeNeeded == 0)
|
||||
if (nFeeNeeded == 0) {
|
||||
nFeeNeeded = fallbackFee.GetFee(nTxBytes);
|
||||
if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
|
||||
}
|
||||
} else {
|
||||
if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
|
||||
}
|
||||
// prevent user from paying a fee below minRelayTxFee or minTxFee
|
||||
nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes));
|
||||
CAmount requiredFee = GetRequiredFee(nTxBytes);
|
||||
if (requiredFee > nFeeNeeded) {
|
||||
nFeeNeeded = requiredFee;
|
||||
if (feeCalc) feeCalc->reason = FeeReason::REQUIRED;
|
||||
}
|
||||
// But always obey the maximum
|
||||
if (nFeeNeeded > maxTxFee)
|
||||
if (nFeeNeeded > maxTxFee) {
|
||||
nFeeNeeded = maxTxFee;
|
||||
if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
|
||||
}
|
||||
return nFeeNeeded;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ class CScheduler;
|
|||
class CTxMemPool;
|
||||
class CBlockPolicyEstimator;
|
||||
class CWalletTx;
|
||||
class FeeCalculation;
|
||||
|
||||
/** (client) version numbers for particular wallet features */
|
||||
enum WalletFeature
|
||||
|
@ -956,7 +957,7 @@ public:
|
|||
* Estimate the minimum fee considering user set parameters
|
||||
* and the required fee
|
||||
*/
|
||||
static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, bool ignoreGlobalPayTxFee = false);
|
||||
static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc = nullptr, bool ignoreGlobalPayTxFee = false);
|
||||
/**
|
||||
* Return the minimum required fee taking into account the
|
||||
* floating relay fee and user set minimum transaction fee
|
||||
|
|
Loading…
Reference in a new issue