This is a first pass at always logging a single line of information whenever CreateTransaction is invoked which will help debug any problems in fee calculation or estimation.
Built on top of #10199 and #10283, only the last commit is new.
159 | @@ -160,7 +160,7 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf 160 | } else { 161 | // if user specified a confirm target then don't consider any global payTxFee 162 | if (specifiedConfirmTarget) { 163 | - nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, true); 164 | + nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, nullptr, true);
Would logging the fee estimation details during bumpfee (all call to GetMinimumFee) be possible?
I think this is possible, but it wasn't clear to me we wanted it here. Perhaps that could be added later
2799 | + nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, feeCalc, pool, true).GetFee(nTxBytes); 2800 | // ... unless we don't have enough mempool data for estimatefee, then use fallbackFee 2801 | - if (nFeeNeeded == 0) 2802 | + if (nFeeNeeded == 0) { 2803 | nFeeNeeded = fallbackFee.GetFee(nTxBytes); 2804 | + if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
supernit: use brackets if (feeCalc) { feeCalc->reason = FeeReason::FALLBACK; }
No. From https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md:
If an if only has a single-statement then-clause, it can appear on the same line as the if, without braces. In every other case, braces are required, and the then and else clauses must appear correctly indented on a new line.
Okay. Fair point.
rebased
73 | @@ -74,6 +74,33 @@ enum FeeEstimateHorizon { 74 | LONG_HALFLIFE = 2 75 | }; 76 | 77 | +/* Enumeration of reason for returned fee estimate */ 78 | +enum FeeReason {
shouldn't this be "enum class" to avoid the enum values from leaking into global scope?
2734 | @@ -2734,6 +2735,15 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT 2735 | return false; 2736 | } 2737 | } 2738 | + 2739 | + LogPrintf("Fee Calculation: Fee:%s 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",
Nice! That should give a lot of info for troubleshooting this.
Should Fee:%s be Fee:%d? (maybe it doesn't matter)
Should this be LogPrint(BCLog::ESTIMATEFEE... (ie only log if estimatefee logs are enabled)?
It's meant to get logged even if you have not selected any debug log categories
678 | @@ -679,7 +679,7 @@ void SendCoinsDialog::updateSmartFeeLabel() 679 | ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 680 | std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB"); 681 | ui->labelSmartFee2->hide(); 682 | - ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks)); 683 | + ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", feeCalc.desiredTarget));
Should this be returnedTarget?
damn, i made that same bug elsewhere. thx
73 | @@ -74,6 +74,33 @@ enum FeeEstimateHorizon { 74 | LONG_HALFLIFE = 2 75 | }; 76 | 77 | +/* Enumeration of reason for returned fee estimate */ 78 | +enum FeeReason { 79 | + NONE = 0, 80 | + HALF_ESTIMATE = 1,
Could drop all these = 1, = 2.
86 | + FALLBACK = 7, 87 | + REQUIRED = 8, 88 | + MAXTXFEE = 9 89 | +}; 90 | + 91 | +static std::map<FeeReason, std::string> FeeReasonString = {
Should make this const. Also maybe prefer to declare this as a const char*[] array, or as a function mapping enum values to strings, or as a function returning a static map. Global objects like this have constructors that need to run before main() and will cumulatively slow down program startup. Also because this is a static global in a header file, the constructor will run once for every .cpp file that includes this.
Addressed comments and squashed/rebased debugEstimates.ver2 --> debugEstimates.ver2.squash --> debugEstimates.ver2.rebased
86 | + FALLBACK, 87 | + REQUIRED, 88 | + MAXTXFEE, 89 | +}; 90 | + 91 | +const std::string StringForFeeReason(FeeReason reason);
I don't think there's any benefit to making this const (cases where you do want this are pretty rare https://stackoverflow.com/questions/8716330/purpose-of-returning-by-const-value).
done
Const is actually still here (you removed it from the definition but not declaration)
utACK 436207ef833dfdd6dc2e664799a68516cb3249a8. Looks good. Changes since previous review were rebase, cleaned up feereason enum/strings, fixed ui target string.
addressed nit
utACK 7c287a7b5df6f33f3b7723496590e72cdd7fed2e. Only change is removed const.
oops, actually addressed nit this time.
utACK 1bebfc8d3aa615dfdd0221f21b87319e36821b71, const is gone
utACK 1bebfc8