This PR:
- Adds release notes for #30275
- Describe fee estimation modes in RPC help texts
This PR:
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--006a51241073e994b41acfe9ec718e94-->
For detailed information about the code coverage, see the test coverage report.
<!--021abf342d371248e50ceaed478a90ca-->
See the guideline for information on the review process.
| Type | Reviewers |
|---|---|
| ACK | glozow, willcl-ark, tdb3, achow101 |
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.
75 | + assert(false); 76 | + } 77 | + return strprintf("\"%s\" \n%s", mode.first, info); 78 | +} 79 | + 80 | +std::string FeeModesDetail()
I think this new format is a little difficult to read with the modes interleaved with their descriptions:
2. estimate_mode (string, optional, default="economical") The fee estimate mode.
"unset"
no mode set
"economical"
Economical estimates use a shorter time horizon, making them more
responsive to short-term drops in the prevailing fee market. This mode
potentially returns a lower fee rate estimate.
"conservative"
Conservative estimates use a longer time horizon, making them
less responsive to short-term drops in the prevailing fee market. This mode
potentially returns a higher fee rate estimate.
IMO it may be clearer to switch to something more like this:
2. estimate_mode (string, optional, default="economical") The fee estimate mode.
Available modes: "economical", "conservative", "unset"
Economical estimates use a shorter time horizon, making them more
responsive to short-term drops in the prevailing fee market. This mode
potentially returns a lower fee rate estimate.
Conservative estimates use a longer time horizon, making them
less responsive to short-term drops in the prevailing fee market. This mode
potentially returns a higher fee rate estimate.
Taken
51 | - "The request target will be clamped between 2 and the highest target\n" 52 | + {RPCResult::Type::NUM, "blocks", "The returned fee rate estimate will likely make transaction begin\n" 53 | + "confirming confirm within this value. If an estimate for the exact\n" 54 | + "conf_target cannot be provided, the closest possible target\n" 55 | + "for which an estimate can be provided will be returned.\n" 56 | + "The requested conf_target will be clamped between 2 and the highest target\n"
Might it make more sense to change this to something simpler:
The number of blocks from the current tip where the estimate was found.
And amend the doc on L38 about the confirmation target range from 1 to 2 to avoid having to explain it in blocks:
{"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (2 - 1008)"},
The error could be moved to the error description string:
{RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing. An error is returned if not enough transactions and blocks have been observed to make an estimate for any number of blocks."
Taken with some modification.
Release note looks good to me.
Left a few thoughts on the RPC help strings for consideration.
<!--85328a0da195eb286784d51f73fa0af9-->
🚧 At least one of the CI tasks failed. <sub>Debug: https://github.com/bitcoin/bitcoin/runs/27925476433</sub>
<details><summary>Hints</summary>
Make sure to run all tests locally, according to the documentation.
The failure may happen due to a number of reasons, for example:
Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.
A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.
An intermittent issue.
Leave a comment here, if you need help tracking down a confusing failure.
</details>
59 | - {RPCResult::Type::NUM, "blocks", "block number where estimate was found\n" 60 | - "The request target will be clamped between 2 and the highest target\n" 61 | - "fee estimation is able to return based on how long it has been running.\n" 62 | - "An error is returned if not enough transactions and blocks\n" 63 | - "have been observed to make an estimate for any number of blocks."}, 64 | + {RPCResult::Type::NUM, "blocks", "The returned fee rate estimate will likely result transaction\n"
Seems like there might be missing words here.
likely result in the transaction starting to...
fixed, thanks.
79 | + for (const auto& fee_mode : FeeModeMap()) { 80 | + modes += strprintf("\"%s\", ", fee_mode.first); 81 | + info += FeeModeInfo(fee_mode); 82 | + } 83 | + if (!FeeModeMap().empty()) { 84 | + modes = modes.substr(0, modes.size() - 2) + "\n";
nitty nit (feel free to ignore): If changing this file, could add a comment for clarity, although it's a small enough function for a reader to pick up on the meaning of the magic number 2.
modes = modes.substr(0, modes.size() - 2) + "\n"; // remove the ", " delimiter
Alternatively, could add a string to name the delimiter. Something like:
diff --git a/src/common/messages.cpp b/src/common/messages.cpp
index bf41d09bbd..76777dd8cd 100644
--- a/src/common/messages.cpp
+++ b/src/common/messages.cpp
@@ -76,12 +76,13 @@ std::string FeeModesDetail()
{
std::string modes{"Available modes: "};
std::string info;
+ std::string delimiter{", "};
for (const auto& fee_mode : FeeModeMap()) {
- modes += strprintf("\"%s\", ", fee_mode.first);
+ modes += "\"" + fee_mode.first + "\"" + delimiter;
info += FeeModeInfo(fee_mode);
}
if (!FeeModeMap().empty()) {
- modes = modes.substr(0, modes.size() - 2) + "\n";
+ modes = modes.substr(0, modes.size() - delimiter.length()) + "\n";
}
return modes + info;
}
Taken.
Approach ACK Nice follow-up. Left a couple of small comments. Also manually ran "help <RPC>" for each change and didn't notice any rendering issues.
52 | @@ -53,6 +53,40 @@ const std::vector<std::pair<std::string, FeeEstimateMode>>& FeeModeMap() 53 | return FEE_MODES; 54 | } 55 | 56 | +std::string FeeModeInfo(const std::pair<std::string, FeeEstimateMode>& mode) 57 | +{ 58 | + switch (mode.second) { 59 | + case FeeEstimateMode::UNSET: 60 | + return std::string("unset: no mode set; default mode will be used.\n");
it might be useful to let the user know what the default is here
unset: no mode set; default mode (economical) will be used.
When using bitcoin-cli sendtoaddress I see the following snippit
8. estimate_mode (string, optional, default="unset") The fee estimate mode, must be one of (case insensitive):
Available modes: "unset", "economical", "conservative"
unset: no mode set; default mode will be used.
Economical estimates use a shorter time horizon, making them more
responsive to short-term drops in the prevailing fee market. This mode
potentially returns a lower fee rate estimate.
Conservative estimates use a longer time horizon, making them
less responsive to short-term drops in the prevailing fee market. This mode
potentially returns a higher fee rate estimate.
This might not be a good idea because the wallet RPC sendtoaddress and friends default depends on whether the RPC call signals RBF or not. If it doesn’t, conservative will be used.
see
I will update the documentation to indicate the "unset" behavior for estimatesmartfee is economical whereas on wallet RPC's it's economical but will be changed to conservative if the user did not to opt into RBF.
pushed in https://github.com/bitcoin/bitcoin/pull/30525/commits/d38a4d1f61f6b8c523f690eeb8f3a2671afaf9da, thanks for review
ACK f38aaefbbfbc3be3751eff61ea3995ce30d303ba
76 | +{ 77 | + std::string info; 78 | + for (const auto& fee_mode : FeeModeMap()) { 79 | + info += FeeModeInfo(fee_mode, default_info); 80 | + } 81 | + return strprintf("%s \n %s", FeeModes(", "), info);
nitty nit: Any reason for the spaces around the newline here?
will remove the space, If there is need to retouch.
fixed.
ACK 4f5ded6905ff7a425aabe53c1a4124f2cb7b5365
Nice cleanup
Re-inspected "help" for each changed RPC and didn't notice any rendering issues. Seems ok to remove Available modes: text.
8 | + to short-term drops in the prevailing fee market. 9 | + 10 | +- Since users typically rely on the default mode, this change is expected to reduce overestimation for many users. 11 | + The `economical` mode aligns with current users behavior, where users often opt-in to Replace-by-Fee (RBF), 12 | + prefer not to overestimate fees, and use fee bumping when necessary. For users requiring high confidence 13 | + in their fee estimates at the cost of potentially overestimating, the `conservative` mode remains available.
Seems like some duplicate information? The user can use help estimatesmartfee
- The default mode for the `estimatesmartfee` RPC has been updated from `conservative` to `economical`,
which is expected to reduce overestimation for many users, particularly if Replace-by-Fee is an option.
For users that require high confidence
in their fee estimates at the cost of potentially overestimating, the `conservative` mode remains available.
taken
57 | - "have been observed to make an estimate for any number of blocks."}, 58 | + {RPCResult::Type::NUM, "blocks", "The returned fee rate estimate will likely result in the\n" 59 | + "transaction starting to confirm within the returned \"blocks\" value.\n" 60 | + "If an estimate for the exact conf_target cannot be provided,\n" 61 | + "the nearest possible target for which an estimate can be given will be returned.\n" 62 | + "Fee estimation is able to return based on how long it has been running."},
Not really sure if this is better. The last sentence seems to be fragmented off?
https://github.com/bitcoin/bitcoin/pull/30525/commits/e387642f36ba01e45656875d8bde7b021ed28556 is an attempt to clarify the blocks returned value help text since I am modifying the file.
On master:
"blocks" : n (numeric) Block number where the estimate was found.
The request target will be clamped between 2 and the highest target
fee estimation can return based on how long it has been running.
An error is returned if not enough transactions and blocks
have been observed to make an estimate for any number of blocks.
With this PR:
"blocks" : n (numeric) The returned fee rate estimate will likely result in the
transaction starting to confirm within the returned "blocks" value.
If an estimate for the exact conf_target cannot be provided, the
nearest possible target for which an estimate can be given
will be returned.
I removed the last sentence, I think thats covered in the errors part.
I think the previous text is clear and not inaccurate, so I'm wondering whether this last commit is necessary.
Thanks I removed the last commit to focus this PR on #30275 follow-up.
- Add description that indicates the fee estimation modes behaviour.
- This description will be returned in the RPC's help texts.
76 | +{ 77 | + std::string info; 78 | + for (const auto& fee_mode : FeeModeMap()) { 79 | + info += FeeModeInfo(fee_mode, default_info); 80 | + } 81 | + return strprintf("%s \n%s", FeeModes(", "), info);
nitty nit: If this file ends up being changed again, could remove the extra space between the first %s and the newline.
Thank you. I will address this and @willcl-ark nit if there is need to retouch.
ACK fa2f26960ee084971ab09959b213a9b8104482e5
ACK fa2f26960ee
This changes the help text from
2. estimate_mode (string, optional, default="conservative") The fee estimate mode.
Whether to return a more conservative estimate which also satisfies
a longer history. A conservative estimate potentially returns a
higher feerate and is more likely to be sufficient for the desired
target, but is not as responsive to short term drops in the
prevailing fee market. Must be one of (case insensitive):
"unset"
"economical"
"conservative"
to
2. estimate_mode (string, optional, default="economical") The fee estimate mode.
unset, economical, conservative
unset means no mode set (default mode will be used).
economical estimates use a shorter time horizon, making them more
responsive to short-term drops in the prevailing fee market. This mode
potentially returns a lower fee rate estimate.
conservative estimates use a longer time horizon, making them
less responsive to short-term drops in the prevailing fee market. This mode
potentially returns a higher fee rate estimate.
Not a blocker for me but IMO a patch to fa2f26960ee could make this slightly clearer by wrapping modes in quotes and helping to break up the large block of text:
<details> <summary>Patch</summary>
diff --git a/src/common/messages.cpp b/src/common/messages.cpp
index da464106777..3666d4953b3 100644
--- a/src/common/messages.cpp
+++ b/src/common/messages.cpp
@@ -46,9 +46,9 @@ std::string StringForFeeReason(FeeReason reason)
const std::vector<std::pair<std::string, FeeEstimateMode>>& FeeModeMap()
{
static const std::vector<std::pair<std::string, FeeEstimateMode>> FEE_MODES = {
- {"unset", FeeEstimateMode::UNSET},
- {"economical", FeeEstimateMode::ECONOMICAL},
- {"conservative", FeeEstimateMode::CONSERVATIVE},
+ {"'unset'", FeeEstimateMode::UNSET},
+ {"'economical'", FeeEstimateMode::ECONOMICAL},
+ {"'conservative'", FeeEstimateMode::CONSERVATIVE},
};
return FEE_MODES;
}
@@ -83,7 +83,9 @@ std::string FeeModesDetail(std::string default_info)
std::string FeeModes(const std::string& delimiter)
{
- return Join(FeeModeMap(), delimiter, [&](const std::pair<std::string, FeeEstimateMode>& i) { return i.first; });
+ std::string modes = "Available modes: ";
+ modes += Join(FeeModeMap(), delimiter, [&](const std::pair<std::string, FeeEstimateMode>& i) { return i.first; });
+ return modes;
}
std::string InvalidEstimateModeErrorMessage()
</details>
which would render as:
2. estimate_mode (string, optional, default="economical") The fee estimate mode.
Available modes: 'unset', 'economical', 'conservative'
'unset' means no mode set (default mode will be used).
'economical' estimates use a shorter time horizon, making them more
responsive to short-term drops in the prevailing fee market. This mode
potentially returns a lower fee rate estimate.
'conservative' estimates use a longer time horizon, making them
less responsive to short-term drops in the prevailing fee market. This mode
potentially returns a higher fee rate estimate.
re ACK fa2f26960ee084971ab09959b213a9b8104482e5
ACK fa2f26960ee084971ab09959b213a9b8104482e5