Browse Source

Merge #9239: Disable fee estimates for 1 block target

e878689 Make GUI incapable of setting tx confirm target of 1 (Alex Morcos)
d824ad0 Disable fee estimates for a confirm target of 1 block (Alex Morcos)
0.14
Wladimir J. van der Laan 8 years ago
parent
commit
3fbf079262
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 7
      src/policy/fees.cpp
  2. 2
      src/qt/forms/sendcoinsdialog.ui
  3. 8
      src/qt/sendcoinsdialog.cpp
  4. 2
      src/rpc/mining.cpp
  5. 22
      src/test/policyestimator_tests.cpp

7
src/policy/fees.cpp

@ -404,7 +404,8 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget)
{ {
// Return failure if trying to analyze a target we're not tracking // Return failure if trying to analyze a target we're not tracking
if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms()) // It's not possible to get reasonable estimates for confTarget of 1
if (confTarget <= 1 || (unsigned int)confTarget > feeStats.GetMaxConfirms())
return CFeeRate(0); return CFeeRate(0);
double median = feeStats.EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); double median = feeStats.EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
@ -423,6 +424,10 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms()) if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms())
return CFeeRate(0); return CFeeRate(0);
// It's not possible to get reasonable estimates for confTarget of 1
if (confTarget == 1)
confTarget = 2;
double median = -1; double median = -1;
while (median < 0 && (unsigned int)confTarget <= feeStats.GetMaxConfirms()) { while (median < 0 && (unsigned int)confTarget <= feeStats.GetMaxConfirms()) {
median = feeStats.EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); median = feeStats.EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);

2
src/qt/forms/sendcoinsdialog.ui

@ -1064,7 +1064,7 @@
<number>0</number> <number>0</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>24</number> <number>23</number>
</property> </property>
<property name="pageStep"> <property name="pageStep">
<number>1</number> <number>1</number>

8
src/qt/sendcoinsdialog.cpp

@ -175,7 +175,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
// set the smartfee-sliders default value (wallets default conf.target or last stored value) // set the smartfee-sliders default value (wallets default conf.target or last stored value)
QSettings settings; QSettings settings;
if (settings.value("nSmartFeeSliderPosition").toInt() == 0) if (settings.value("nSmartFeeSliderPosition").toInt() == 0)
ui->sliderSmartFee->setValue(ui->sliderSmartFee->maximum() - model->getDefaultConfirmTarget() + 1); ui->sliderSmartFee->setValue(ui->sliderSmartFee->maximum() - model->getDefaultConfirmTarget() + 2);
else else
ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt()); ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt());
} }
@ -241,7 +241,7 @@ void SendCoinsDialog::on_sendButton_clicked()
if (model->getOptionsModel()->getCoinControlFeatures()) if (model->getOptionsModel()->getCoinControlFeatures())
ctrl = *CoinControlDialog::coinControl; ctrl = *CoinControlDialog::coinControl;
if (ui->radioSmartFee->isChecked()) if (ui->radioSmartFee->isChecked())
ctrl.nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 1; ctrl.nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
else else
ctrl.nConfirmTarget = 0; ctrl.nConfirmTarget = 0;
@ -601,7 +601,7 @@ void SendCoinsDialog::updateGlobalFeeVariables()
{ {
if (ui->radioSmartFee->isChecked()) if (ui->radioSmartFee->isChecked())
{ {
int nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 1; int nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
payTxFee = CFeeRate(0); payTxFee = CFeeRate(0);
// set nMinimumTotalFee to 0 to not accidentally pay a custom fee // set nMinimumTotalFee to 0 to not accidentally pay a custom fee
@ -646,7 +646,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
if(!model || !model->getOptionsModel()) if(!model || !model->getOptionsModel())
return; return;
int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 1; int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
int estimateFoundAtBlocks = nBlocksToConfirm; int estimateFoundAtBlocks = nBlocksToConfirm;
CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks); CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks);
if (feeRate <= CFeeRate(0)) // not enough data => minfee if (feeRate <= CFeeRate(0)) // not enough data => minfee

2
src/rpc/mining.cpp

@ -785,6 +785,8 @@ UniValue estimatefee(const JSONRPCRequest& request)
"\n" "\n"
"A negative value is returned if not enough transactions and blocks\n" "A negative value is returned if not enough transactions and blocks\n"
"have been observed to make an estimate.\n" "have been observed to make an estimate.\n"
"-1 is always returned for nblocks == 1 as it is impossible to calculate\n"
"a fee that is high enough to get reliably included in the next block.\n"
"\nExample:\n" "\nExample:\n"
+ HelpExampleCli("estimatefee", "6") + HelpExampleCli("estimatefee", "6")
); );

22
src/test/policyestimator_tests.cpp

@ -95,17 +95,22 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// Highest feerate is 10*baseRate and gets in all blocks, // Highest feerate is 10*baseRate and gets in all blocks,
// second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%, // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,
// third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%, // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,
// so estimateFee(1) should return 10*baseRate. // so estimateFee(1) would return 10*baseRate but is hardcoded to return failure
// Second highest feerate has 100% chance of being included by 2 blocks, // Second highest feerate has 100% chance of being included by 2 blocks,
// so estimateFee(2) should return 9*baseRate etc... // so estimateFee(2) should return 9*baseRate etc...
for (int i = 1; i < 10;i++) { for (int i = 1; i < 10;i++) {
origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK()); origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
if (i > 1) { // Fee estimates should be monotonically decreasing if (i > 2) { // Fee estimates should be monotonically decreasing
BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]); BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
} }
int mult = 11-i; int mult = 11-i;
BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee); if (i > 1) {
BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee); BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee);
BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee);
}
else {
BOOST_CHECK(origFeeEst[i-1] == CFeeRate(0).GetFeePerK());
}
} }
// Mine 50 more blocks with no transactions happening, estimates shouldn't change // Mine 50 more blocks with no transactions happening, estimates shouldn't change
@ -113,7 +118,8 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
while (blocknum < 250) while (blocknum < 250)
mpool.removeForBlock(block, ++blocknum); mpool.removeForBlock(block, ++blocknum);
for (int i = 1; i < 10;i++) { BOOST_CHECK(mpool.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(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
} }
@ -151,7 +157,8 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
} }
mpool.removeForBlock(block, 265); mpool.removeForBlock(block, 265);
block.clear(); block.clear();
for (int i = 1; i < 10;i++) { BOOST_CHECK(mpool.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);
} }
@ -172,7 +179,8 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
mpool.removeForBlock(block, ++blocknum); mpool.removeForBlock(block, ++blocknum);
block.clear(); block.clear();
} }
for (int i = 1; i < 10; i++) { BOOST_CHECK(mpool.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);
} }

Loading…
Cancel
Save