Adds a new RPC psbtbumpfee
which always creates a psbt. bumpfee
will then only be able to create and broadcast fee bumping transactions instead of changing its behavior based on IsWalletSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)
.
Split from #18627
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
Reviewers, 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.
I wish there was a way to prevent duplicating walls of help text.
RPCHelpMan
can not be duplicated because it takes the RPC method’s name, but anything you pass to RPCHelpMan are basic C++11 structs that can be made const globals (or returned by helper functions like GetBumpFee{HelpText,Args,...}
.) and then passed into the rpc help man.
3564+ }},
3565+ }
3566+ },
3567+ RPCExamples{
3568+ "\nBump the fee, get the new transaction\'s psbt\n" +
3569+ HelpExampleCli("bumpfee", "<txid>")
psbtbumpfee
? And in the context of single signature hardware wallet setups, like #16546, can those still use bumpfee
, because PSBT is only used internally?
What’s your vision for (future) descriptor wallets with private keys as e.g. part of a multisig setup (or a coinjoin)? Should those use
psbtbumpfee
? And in the context of single signature hardware wallet setups, like #16546, can those still usebumpfee
, because PSBT is only used internally?
The idea is for bumpfee
to be used and available only when the wallet is actually able to create a complete transaction and broadcast it. So for multisigs and coinjoin, it would not be available. For single signature hardware wallets, it should be, but can give a generic error about the device not being available.
psbtbumpfee
is always available but also intended for use with wallets where bumpfee
is not available.
bumpfee
lines of code that need to be removed during deprecation (or wrap it in an if
statement, even though that’s currently redundant)? Maybe also clarify your intention in a source comment.
request.strMethod
to decide to bail out early?
Thoughts on using the same function for both calls, and simply checking
request.strMethod
to decide to bail out early?
That’s kind of what the first commit is doing. Most of the duplication is in the help text, which I don’t think can be really deduplicated since some differences are required.
3279@@ -3277,11 +3280,18 @@ static UniValue bumpfee(const JSONRPCRequest& request)
3280 }
3281 },
3282 RPCExamples{
3283- "\nBump the fee, get the new transaction\'s txid\n" +
3284+ "\nBump the fee, get the new transaction\'s" + std::string(want_psbt ? "psbt" : "txid\n") +
3279@@ -3277,11 +3280,18 @@ static UniValue bumpfee(const JSONRPCRequest& request)
3280 }
3281 },
3282 RPCExamples{
3283- "\nBump the fee, get the new transaction\'s txid\n" +
3284+ "\nBump the fee, get the new transaction\'s" + std::string(want_psbt ? "psbt" : "txid\n") +
3285 HelpExampleCli("bumpfee", "<txid>")
request.strMethod
3268@@ -3266,7 +3269,7 @@ static UniValue bumpfee(const JSONRPCRequest& request)
3269 },
3270 RPCResult{
3271 RPCResult::Type::OBJ, "", "", {
3272- {RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction. Only returned when wallet private keys are disabled."},
3273+ {RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction." + std::string(want_psbt ? "" : " Only returned when wallet private keys are disabled. (DEPRECATED)")},
3274 {RPCResult::Type::STR_HEX, "txid", "The id of the new transaction. Only returned when wallet private keys are enabled."},
RPCResult::Type::HIDDEN
to handle this.
3263@@ -3261,8 +3264,8 @@ static UniValue bumpfee(const JSONRPCRequest& request)
3264 },
3265 RPCResult{
3266 RPCResult::Type::OBJ, "", "", {
3267- {RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction. Only returned when wallet private keys are disabled."},
3268- {RPCResult::Type::STR_HEX, "txid", "The id of the new transaction. Only returned when wallet private keys are enabled."},
3269+ {RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction." + std::string(want_psbt ? "" : " Only returned when wallet private keys are disabled. (DEPRECATED)")},
3270+ {(want_psbt ? RPCResult::Type::HIDDEN : RPCResult::Type::STR_HEX), "txid", "The id of the new transaction. Only returned when wallet private keys are enabled."},
I think it doesn’t make sense to push an rpc result into the help manager and then tell the manager to discard it. Wouldn’t it make more sense to not push it in the first place? This should be trivial to achieve with Cat
0RPCResult::Type::OBJ, "", "", Cat(Cat({
1 {STR, "psbt", ...},
2 },
3 std::vector<RPCResult>{want_psbt ? {} : {STR_HEX, "txid", ...}}),
4 {
5 {STR_AMOUNT, "origfee" ...},
6 {STR_AMOUNT, "fee", ...},
7 ....
8 }),
(I didnt’ compile this to check)
I agree that it doesn’t make sense to push and then hide. I was originally trying to do something similar to this but couldn’t get it to work. I was also unable to get your suggestion to work. It fails with
0wallet/rpcwallet.cpp:3270:58: error: no matching function for call to ‘std::vector<RPCResult>::vector(<brace-enclosed initializer list>)’
1 3270 | std::vector<RPCResult>{want_psbt ? {} : {RPCResult::Type::STR_HEX, "txid", "The id of the new transaction. Only returned when wallet private keys are enabled."}
I tried a few different variations of this but nothing would work.
Ah, not your fault. That {}
means both “constructor” and “initializer list” is one of the countless design flaws of c++. {{}}
should work.
This diff compiles (haven’t tested what it doesn, though):
0diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
1index de21f23da3..e5ecc6a451 100644
2--- a/src/wallet/rpcwallet.cpp
3+++ b/src/wallet/rpcwallet.cpp
4@@ -3263,16 +3263,16 @@ static UniValue bumpfee(const JSONRPCRequest& request)
5 "options"},
6 },
7 RPCResult{
8- RPCResult::Type::OBJ, "", "", {
9+ RPCResult::Type::OBJ, "", "", Cat(Cat({
10 {RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction." + std::string(want_psbt ? "" : " Only returned when wallet private keys are disabled. (DEPRECATED)")},
11- {(want_psbt ? RPCResult::Type::HIDDEN : RPCResult::Type::STR_HEX), "txid", "The id of the new transaction. Only returned when wallet private keys are enabled."},
12+ },want_psbt ? std::vector<RPCResult>{} : std::vector<RPCResult>{{RPCResult::Type::STR_HEX, "txid", "The id of the new transaction. Only returned when wallet private keys are enabled."}}),{
13 {RPCResult::Type::STR_AMOUNT, "origfee", "The fee of the replaced transaction."},
14 {RPCResult::Type::STR_AMOUNT, "fee", "The fee of the new transaction."},
15 {RPCResult::Type::ARR, "errors", "Errors encountered during processing (may be empty).",
16 {
17 {RPCResult::Type::STR, "", ""},
18 }},
19- }
20+ })
21 },
22 RPCExamples{
23 "\nBump the fee, get the new transaction\'s" + std::string(want_psbt ? "psbt" : "txid") + "\n" +
HIDDEN
3225@@ -3226,8 +3226,11 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
3226
3227 static UniValue bumpfee(const JSONRPCRequest& request)
3228 {
3229- RPCHelpMan{"bumpfee",
3230+ bool want_psbt = request.strMethod == "psbtbumpfee";
3231+
3232+ RPCHelpMan{request.strMethod,
Reviewed 70e8422b585afa1ec623c62312764eb91dde4cd3
psbtbumpfee
doesn’t show up in the help list. You can fix that by adding a short wrapper and referencing that from CRPCCommand
, or perhaps @MarcoFalke has a better idea:
0static UniValue psbtbumpfee(const JSONRPCRequest& request)
1{
2 return bumpfee(request);
3}
When a wallet has private keys, the PSBT isn’t signed. That’s either a bug or something to document.
psbtbumpfee
doesn’t show up in the help list. You can fix that by adding a short wrapper and referencing that fromCRPCCommand
, or perhaps @MarcoFalke has a better idea:
That’s interesting. I’ve added the wrapper as you suggested.
When a wallet has private keys, the PSBT isn’t signed. That’s either a bug or something to document.
I think this is existing behavior.
utACK 39d39f7b77c5ef39ec9e877715a06ce962c442d6
I think this is existing behavior.
Not really; if your wallet had private keys, it would never create a PSBT, signed or otherwise. But it can wait for another PR.
With psbtbumpfee, we can deprecate bumpfee's psbt creation behavior.
So put that behind a -deprecatedrpc
Review this with -w to see that nothing actually changes.
utACK 79d6332e9e4fc01e6418247c31e31b4faa1b3b84
I wouldn’t call the lack of signing the PSBT a bug, but something to document maybe, sure.
That’s interesting. I’ve added the wrapper as you suggested.
Please at least add comments as to why it’s there?
That’s interesting. I’ve added the wrapper as you suggested.
Please at least add comments as to why it’s there?
Will do if I need to push again.
3392@@ -3382,7 +3393,7 @@ static UniValue bumpfee(const JSONRPCRequest& request)
3393
3394 // If wallet private keys are enabled, return the new transaction id,
3259- "Alternatively, the user can specify a fee_rate (" + CURRENCY_UNIT + " per kB) for the new transaction.\n"
3260- "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
3261- "returned by getnetworkinfo) to enter the node's mempool.\n",
3262+ RPCHelpMan{request.strMethod,
3263+ "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
3264+ + std::string(want_psbt ? "Returns a PSBT instead of creating and signing a new transaction.\n" : "") +
nit: Could be slightly improved if you have to retouch since the ‘creating a new transaction’ part is still true. It is just not signed and committed if I see that correctly.
0 + std::string(want_psbt ? "Returns a PSBT with the new, unsigned transaction.\n" : "") +
Code review ACK 79d6332e9e4fc01e6418247c31e31b4faa1b3b84
Feel free to ignore my nits, maybe consider them for a follow-up.