-
Notifications
You must be signed in to change notification settings - Fork 37.7k
wallet: introduce fee_rate sat/vB param/option #20305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
How does this differ/compare to #20250 ? |
I guess this one is adding a new separate option, #20250 is adding named aliases and keeping the existing options. |
Yes, this one removes the conf_target/estimate_mode overloading and introduces a standard fee rate param. #20250 keeps the current overloading and makes it more consistent between the six RPCs. Some of what it does (feeRate -> fee_rate) is compatible or orthogonal. ISTM the question is, do we want to release with the overloading or with a standard feerate param. (It would be simpler if we decide before the branch-off. After, this PR would need to be changed as we would have to support both.) |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
078b8fb
to
2b8d681
Compare
AFAICT, the only "fee_rate" in 0.20 was bumpfee. Specifying BTC/vkB (current value) in place of the new sat/vB would always be a much lower feerate. So it'd most likely be too low and error, or worst case lower than you intended and you can just bump it again to fix. With that in mind, I think the option here should just be renamed to "fee_rate" and break the compatibility for bumpfee. |
@luke-jr SGTM and that would further simplify the implementation too. |
Agree with renaming to Concept ACK. |
Concept ACK for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why fee_rate_sat_vb
and not just fee_rate
? Also, should not change verbose
parameter index?
I initially began with
For sendtoaddress and sendmany, I hesitated on this because I thought that users are used to seeing the |
Has |
Per d5863c0 it looks like |
2b8d681
to
9c680e7
Compare
9c680e7
to
5660dd3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial review up to ~3/4 of 53b35be. Will continue in approx 60 minutes.
src/wallet/rpcwallet.cpp
Outdated
|
||
cc.m_feerate = CFeeRate(fee_rate); | ||
CAmount feerate{AmountFromValue(estimate_param)}; | ||
cc.m_feerate = cc.m_fee_mode == FeeEstimateMode::SAT_B ? CFeeRate(feerate, COIN) : CFeeRate(feerate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not immediately obvious to me why CFeeRate(feerate, COIN)
is equivalent to fee_rate /= WALLET_BTC_KB_TO_SAT_B; CFeeRate(fee_rate)
. As far as I see, COIN
equals 1e8, but WALLET_BTC_KB_TO_SAT_B
equals 1e5.
Upon inspection of ./src/policy/feerate.cpp
and ./src/policy/feerate.h
, CFeeRate(…)
with two arguments appears to construct a fee rate in sat/kvB
from fees paid in sats divided by transaction weight in vB:
/** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/
CFeeRate(const CAmount& nFeePaid, size_t nBytes);
CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_)
{
assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
int64_t nSize = int64_t(nBytes_);
if (nSize > 0)
nSatoshisPerK = nFeePaid * 1000 / nSize;
else
nSatoshisPerK = 0;
}
and either results in the feerate having been divided by 100,000 (1e5). ✔️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes 👍 and I was more confident about making this change after all the test coverage we added in #20220.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have a comment explaining this because it is not immediately clear why this works and future work on this code may not see this explanation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, added Doxygen documentation in a3eac6e
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like a hack, unless I misunderstand the original purpose of this constructor. Maybe it's better to add a separate constructor with a boolean to distinguish SAT_VB
from BTC/kvB
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I asked myself why else the two-argument ctor might have been written and didn't come up with an answer...I'm not against reviewing a refactoring of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at settxfee in wallet/rpcwallet.cpp
, it uses this ctor in a similar manner.
CAmount nAmount = AmountFromValue(request.params[0]);
CFeeRate tx_fee_rate(nAmount, 1000);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert_raises_rpc_error(-8, "Invalid fee_rate 0.00000000 BTC/kB (must be greater than 0)", | ||
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"feeRate": 0, "add_inputs": True}) | ||
for param, value in {("fee_rate", 100000), ("feeRate", 1.1)}: | ||
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably out of scope, but it would be kinda nice if an error like this told the user what said limit is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree--punting on this for the next push but would be good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great to me! Gonna circle back tomorrow after I get up. :)
assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, rbfid, options) | ||
# Bumping to just above minrelay should fail to increase the total fee enough. | ||
assert_raises_rpc_error(-8, "Insufficient total fee 0.00000141, must be at least 0.00001704 (oldFee 0.00000999 + incrementalFee 0.00000705)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting hung up on all the wrong things, but if minRelayTxFee × txsize is 141 sats, I'm surprised that the incrementalFee is 705
. I thought that minimum increments are equal to minRelayTxFee
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's from wallet/wallet.h
, though the different fee constants and config options are a bit confusing to me.
//! minimum recommended increment for BIP 125 replacement txs
static const CAmount WALLET_INCREMENTAL_RELAY_FEE = 5000;
and wallet/feebumper.cpp
if (new_total_fee < minTotalFee) {
errors.push_back(strprintf(Untranslated("Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)"),
FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxTxSize)), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for tracking that down!
self.log.info("Test invalid fee rate settings") | ||
assert_raises_rpc_error(-8, "Invalid fee_rate 0.00000000 BTC/kB (must be greater than 0)", | ||
rbf_node.bumpfee, rbfid, {"fee_rate": 0}) | ||
assert_raises_rpc_error(-4, "Specified or calculated fee 0.141 is too high (cannot be higher than -maxtxfee 0.10", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
woah, damn. I think we may want to have a look at the maxtxfee
that's a lot of money.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be a good follow-up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I proposed that once: #16539
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I proposed that once: #16539
TIL, thanks. Interesting discussion in that PR.
"At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n" | ||
"returned by getnetworkinfo) to enter the node's mempool.\n", | ||
"returned by getnetworkinfo) to enter the node's mempool.\n" | ||
"* WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB. *\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Luckily, this is very benign. In the worst case, someone is going to get upped to the minRelayTxFee
silently and sends at 1 sat/vB. Since RBF is on by default, they should be able to bump when they notice. 👍
@@ -4369,8 +4363,7 @@ static RPCHelpMan walletcreatefundedpsbt() | |||
}, | |||
{"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n" | |||
"Allows this transaction to be replaced by a transaction with higher fees"}, | |||
{"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target (in blocks)\n" | |||
"or fee rate (for " + CURRENCY_UNIT + "/kB and " + CURRENCY_ATOM + "/B estimate modes)"}, | |||
{"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overloading, begone! 🎆
@@ -2303,7 +2303,7 @@ static RPCHelpMan settxfee() | |||
"\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n" | |||
"Can be deactivated by passing 0 as the fee. In that case automatic fee selection will be used by default.\n", | |||
{ | |||
{"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee in " + CURRENCY_UNIT + "/kB"}, | |||
{"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee in " + CURRENCY_UNIT + "/kvB"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume that you considered and deliberately passed on also replacing these. I would surmise that it's it just too much of a can of worms? Otherwise it would be kinda odd that we are using sat/vB
for the fee rate in all the send variants, but then use BTC/kvB
for settxfee
.
Nit: settxfee
sets not a fee, but a feerate. ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, scope creep on an already-wide PR. Could be a next step.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in #20391.
ACK 5660dd3 |
5660dd3
to
bcb8e0d
Compare
tACK 05e82d8 |
If there's still block explorers (that people use) using real bytes instead of virtual bytes in their fee calculation, then indeed adding the |
Block explorer websites have been confusing users with bogus "information" forever. Trying to match them doesn't make sense. |
review ACK 05e82d8 did not test and found a few style nits, which can be fixed later 🍯 Show signature and timestampSignature:
python: error while loading shared libraries: libpython3.8.so.1.0: cannot open shared object file: No such file or directory |
I contacted one such explorer and nagged them to switch from bytes to vbytes :-) |
This probably needs release notes? |
Btw, the first commit adds tests that pass without the code changes. I haven't tried the other added tests, but as a general rule, I'd prefer if new tests were added in a separate commit and not in the same commit that also changes behaviour. |
Yes, will update the wiki. |
Turns out the style nits are regressions. See https://github.com/bitcoin/bitcoin/pull/20305/files#r525406176 and #20410 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Release notes added to the wiki at https://github.com/bitcoin-core/bitcoin-devwiki/wiki/0.21.0-Release-Notes-Draft. The |
in RPCs fundrawtransaction and walletcreatefundedpsbt only. This provides the existing feeRate (BTC/kvB) behavior in these two RPCs to the new fee_rate (sat/vB) param also. See these two GitHub review discussions for more info: bitcoin/bitcoin#10706 bitcoin/bitcoin#20305 (comment)
This PR builds on #11413 and #20220 to address #19543.
replace overloading the conf_target and estimate_mode params with
fee_rate
in sat/vB in the sendtoaddress, sendmany, send, fundrawtransaction, walletcreatefundedpsbt, and bumpfee RPCsallow non-actionable conf_target value of
0
and estimate_mode value of""
to be passed to usefee_rate
as a positional argument, in addition to as a named argumentfix a bug in the experimental send RPC described in wallet, rpc: explicit fee rate follow-ups/fixes for 0.21 #20220 (comment) where args were not being passed correctly into the options values
update the feerate error message units for these RPCs from BTC/kB to sat/vB
update the test coverage, help docs, doxygen docs, and some of the RPC examples
other changes to address the excellent review feedback
See this wallet meeting log for more context: http://www.erisian.com.au/bitcoin-core-dev/log-2020-11-06.html#l-309