Browse Source

Call estimate(Smart)Fee directly from CBlockPolicyEstimator

tags/v0.15.1
Alex Morcos 4 years ago
parent
commit
14e10aa842

+ 3
- 3
src/policy/fees.cpp View File

@@ -77,7 +77,7 @@ void TxConfirmStats::UpdateMovingAverages()
// returns -1 on error conditions
double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
double successBreakPoint, bool requireGreater,
unsigned int nBlockHeight)
unsigned int nBlockHeight) const
{
// Counters for a bucket (or range of buckets)
double nConf = 0; // Number of tx's confirmed within the confTarget
@@ -411,7 +411,7 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
untrackedTxs = 0;
}

CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget)
CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) const
{
LOCK(cs_feeEstimator);
// Return failure if trying to analyze a target we're not tracking
@@ -427,7 +427,7 @@ CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget)
return CFeeRate(median);
}

CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) const
{
if (answerFoundAtTarget)
*answerFoundAtTarget = confTarget;

+ 4
- 4
src/policy/fees.h View File

@@ -150,10 +150,10 @@ public:
* @param nBlockHeight the current block height
*/
double EstimateMedianVal(int confTarget, double sufficientTxVal,
double minSuccess, bool requireGreater, unsigned int nBlockHeight);
double minSuccess, bool requireGreater, unsigned int nBlockHeight) const;

/** Return the max number of confirms we're tracking */
unsigned int GetMaxConfirms() { return confAvg.size(); }
unsigned int GetMaxConfirms() const { return confAvg.size(); }

/** Write state of estimation data to a file*/
void Write(CAutoFile& fileout);
@@ -217,13 +217,13 @@ public:
bool removeTx(uint256 hash);

/** Return a feerate estimate */
CFeeRate estimateFee(int confTarget);
CFeeRate estimateFee(int confTarget) const;

/** Estimate feerate needed to get be included in a block within
* confTarget blocks. If no answer can be given at confTarget, return an
* estimate at the lowest target where one can be given.
*/
CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) const;

/** Write estimation data to a file */
void Write(CAutoFile& fileout);

+ 3
- 2
src/qt/coincontroldialog.cpp View File

@@ -15,6 +15,7 @@

#include "wallet/coincontrol.h"
#include "init.h"
#include "policy/fees.h"
#include "policy/policy.h"
#include "validation.h" // For mempool
#include "wallet/wallet.h"
@@ -512,7 +513,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34;

// Fee
nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, ::mempool, ::feeEstimator);
if (nPayFee > 0 && coinControl->nMinimumTotalFee > nPayFee)
nPayFee = coinControl->nMinimumTotalFee;

@@ -592,7 +593,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (payTxFee.GetFeePerK() > 0)
dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), payTxFee.GetFeePerK()) / 1000;
else {
dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), mempool.estimateSmartFee(nTxConfirmTarget).GetFeePerK()) / 1000;
dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), ::feeEstimator.estimateSmartFee(nTxConfirmTarget, NULL, ::mempool).GetFeePerK()) / 1000;
}
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);


+ 2
- 1
src/qt/sendcoinsdialog.cpp View File

@@ -21,6 +21,7 @@
#include "validation.h" // mempool and minRelayTxFee
#include "ui_interface.h"
#include "txmempool.h"
#include "policy/fees.h"
#include "wallet/wallet.h"

#include <QFontMetrics>
@@ -660,7 +661,7 @@ void SendCoinsDialog::updateSmartFeeLabel()

int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
int estimateFoundAtBlocks = nBlocksToConfirm;
CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks);
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks, ::mempool);
if (feeRate <= CFeeRate(0)) // not enough data => minfee
{
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),

+ 3
- 2
src/rpc/mining.cpp View File

@@ -15,6 +15,7 @@
#include "validation.h"
#include "miner.h"
#include "net.h"
#include "policy/fees.h"
#include "pow.h"
#include "rpc/blockchain.h"
#include "rpc/server.h"
@@ -819,7 +820,7 @@ UniValue estimatefee(const JSONRPCRequest& request)
if (nBlocks < 1)
nBlocks = 1;

CFeeRate feeRate = mempool.estimateFee(nBlocks);
CFeeRate feeRate = ::feeEstimator.estimateFee(nBlocks);
if (feeRate == CFeeRate(0))
return -1.0;

@@ -857,7 +858,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)

UniValue result(UniValue::VOBJ);
int answerFound;
CFeeRate feeRate = mempool.estimateSmartFee(nBlocks, &answerFound);
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &answerFound, ::mempool);
result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
result.push_back(Pair("blocks", answerFound));
return result;

+ 21
- 21
src/test/policyestimator_tests.cpp View File

@@ -79,16 +79,16 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// At this point we should need to combine 5 buckets to get enough data points
// So estimateFee(1,2,3) should fail and estimateFee(4) should return somewhere around
// 8*baserate. estimateFee(4) %'s are 100,100,100,100,90 = average 98%
BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
BOOST_CHECK(mpool.estimateFee(2) == CFeeRate(0));
BOOST_CHECK(mpool.estimateFee(3) == CFeeRate(0));
BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee);
BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
BOOST_CHECK(feeEst.estimateFee(2) == CFeeRate(0));
BOOST_CHECK(feeEst.estimateFee(3) == CFeeRate(0));
BOOST_CHECK(feeEst.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
BOOST_CHECK(feeEst.estimateFee(4).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee);
int answerFound;
BOOST_CHECK(mpool.estimateSmartFee(1, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
BOOST_CHECK(mpool.estimateSmartFee(3, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
BOOST_CHECK(mpool.estimateSmartFee(4, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
BOOST_CHECK(mpool.estimateSmartFee(8, &answerFound) == mpool.estimateFee(8) && answerFound == 8);
BOOST_CHECK(feeEst.estimateSmartFee(1, &answerFound, mpool) == feeEst.estimateFee(4) && answerFound == 4);
BOOST_CHECK(feeEst.estimateSmartFee(3, &answerFound, mpool) == feeEst.estimateFee(4) && answerFound == 4);
BOOST_CHECK(feeEst.estimateSmartFee(4, &answerFound, mpool) == feeEst.estimateFee(4) && answerFound == 4);
BOOST_CHECK(feeEst.estimateSmartFee(8, &answerFound, mpool) == feeEst.estimateFee(8) && answerFound == 8);
}
}

@@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// Second highest feerate has 100% chance of being included by 2 blocks,
// so estimateFee(2) should return 9*baseRate etc...
for (int i = 1; i < 10;i++) {
origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
origFeeEst.push_back(feeEst.estimateFee(i).GetFeePerK());
if (i > 2) { // Fee estimates should be monotonically decreasing
BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
}
@@ -119,10 +119,10 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
while (blocknum < 250)
mpool.removeForBlock(block, ++blocknum);

BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
for (int i = 2; i < 10;i++) {
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
}


@@ -142,8 +142,8 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)

int answerFound;
for (int i = 1; i < 10;i++) {
BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(0) || mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
BOOST_CHECK(mpool.estimateSmartFee(i, &answerFound).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee);
BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
BOOST_CHECK(feeEst.estimateSmartFee(i, &answerFound, mpool).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee);
}

// Mine all those transactions
@@ -158,9 +158,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
}
mpool.removeForBlock(block, 265);
block.clear();
BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
for (int i = 2; i < 10;i++) {
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
}

// Mine 200 more blocks where everything is mined every block
@@ -180,9 +180,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
mpool.removeForBlock(block, ++blocknum);
block.clear();
}
BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
for (int i = 2; i < 10; i++) {
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
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
@@ -191,8 +191,8 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
mpool.TrimToSize(1);
BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
for (int i = 1; i < 10; i++) {
BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK());
BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= feeEst.estimateFee(i).GetFeePerK());
BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
}
}


+ 0
- 9
src/txmempool.cpp View File

@@ -843,15 +843,6 @@ TxMempoolInfo CTxMemPool::info(const uint256& hash) const
return GetInfo(i);
}

CFeeRate CTxMemPool::estimateFee(int nBlocks) const
{
return minerPolicyEstimator->estimateFee(nBlocks);
}
CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) const
{
return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, *this);
}

bool
CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
{

+ 0
- 9
src/txmempool.h View File

@@ -617,15 +617,6 @@ public:
TxMempoolInfo info(const uint256& hash) const;
std::vector<TxMempoolInfo> infoAll() const;

/** Estimate fee rate needed to get into the next nBlocks
* If no answer can be given at nBlocks, return an estimate
* at the lowest number of blocks where one can be given
*/
CFeeRate estimateSmartFee(int nBlocks, int *answerFoundAtBlocks = NULL) const;

/** Estimate fee rate needed to get into the next nBlocks */
CFeeRate estimateFee(int nBlocks) const;

/** Write/Read estimates to disk */
bool WriteFeeEstimates(CAutoFile& fileout) const;
bool ReadFeeEstimates(CAutoFile& filein);

+ 3
- 2
src/wallet/feebumper.cpp View File

@@ -5,6 +5,7 @@
#include "consensus/validation.h"
#include "wallet/feebumper.h"
#include "wallet/wallet.h"
#include "policy/fees.h"
#include "policy/policy.h"
#include "policy/rbf.h"
#include "validation.h" //for mempool access
@@ -159,11 +160,11 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
} else {
// if user specified a confirm target then don't consider any global payTxFee
if (specifiedConfirmTarget) {
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, CAmount(0));
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, CAmount(0));
}
// otherwise use the regular wallet logic to select payTxFee or default confirm target
else {
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool);
nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator);
}

nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);

+ 1
- 0
src/wallet/rpcwallet.cpp View File

@@ -11,6 +11,7 @@
#include "init.h"
#include "validation.h"
#include "net.h"
#include "policy/fees.h"
#include "policy/policy.h"
#include "policy/rbf.h"
#include "rpc/server.h"

+ 6
- 5
src/wallet/wallet.cpp View File

@@ -16,6 +16,7 @@
#include "keystore.h"
#include "validation.h"
#include "net.h"
#include "policy/fees.h"
#include "policy/policy.h"
#include "policy/rbf.h"
#include "primitives/block.h"
@@ -2575,7 +2576,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
if (coinControl && coinControl->nConfirmTarget > 0)
currentConfirmationTarget = coinControl->nConfirmTarget;

CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, mempool);
CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator);
if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) {
nFeeNeeded = coinControl->nMinimumTotalFee;
}
@@ -2749,19 +2750,19 @@ 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)
CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator)
{
// payTxFee is the user-set global for desired feerate
return GetMinimumFee(nTxBytes, nConfirmTarget, pool, payTxFee.GetFee(nTxBytes));
return GetMinimumFee(nTxBytes, nConfirmTarget, pool, estimator, payTxFee.GetFee(nTxBytes));
}

CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, CAmount targetFee)
CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, CAmount targetFee)
{
CAmount nFeeNeeded = targetFee;
// User didn't set: use -txconfirmtarget to estimate...
if (nFeeNeeded == 0) {
int estimateFoundTarget = nConfirmTarget;
nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes);
nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, &estimateFoundTarget, pool).GetFee(nTxBytes);
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
if (nFeeNeeded == 0)
nFeeNeeded = fallbackFee.GetFee(nTxBytes);

+ 3
- 2
src/wallet/wallet.h View File

@@ -75,6 +75,7 @@ class CReserveKey;
class CScript;
class CScheduler;
class CTxMemPool;
class CBlockPolicyEstimator;
class CWalletTx;

/** (client) version numbers for particular wallet features */
@@ -890,12 +891,12 @@ 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);
static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator);
/**
* Estimate the minimum fee considering required fee and targetFee or if 0
* then fee estimation for nConfirmTarget
*/
static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, CAmount targetFee);
static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, CAmount targetFee);
/**
* Return the minimum required fee taking into account the
* floating relay fee and user set minimum transaction fee

Loading…
Cancel
Save