Have createwalletdescriptor auto-detect an unused(KEY) - #32861
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32861. ReviewsSee the guideline and AI policy for information on the review process.
If your review is incorrectly listed, please copy-paste 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. |
Once the unused(KEY) descriptor is used, doesn't it become used? Keeping it as an unused descriptor later might come across as confusing. |
There was a problem hiding this comment.
In e8b1440aa3ed7efe3a9c2d10afb05e7247fff1f6 "rpc: make createwalletdescriptor smarter"
Though this check here seems more thorough, but the presence of more than one spkm also seems sufficient to throw this error?
I agree, and it was also brought up here: #29136 (comment). It's orthogonal to this PR. |
|
Thanks, I recall reading this comment earlier but forgot about it later. If I am not missing anything, I don't suppose this point is orthogonal to this PR? The linked comment also states that any RPC using the unused descriptor should delete it immediately afterwords.
I don't believe diff --git a/test/functional/wallet_createwalletdescriptor.py b/test/functional/wallet_createwalletdescriptor.py
index 6de0ca4782..a7086c5b9e 100755
--- a/test/functional/wallet_createwalletdescriptor.py
+++ b/test/functional/wallet_createwalletdescriptor.py
@@ -125,7 +125,11 @@ class WalletCreateDescriptorTest(BitcoinTestFramework):
# Create unused(KEY) descriptor and try again
w1.addhdkey()
+ print("listdescriptors: ", w1.listdescriptors())
+ print("gethdkeys: ", w1.gethdkeys())
w1.createwalletdescriptor(type="bech32")
+ print("listdescriptors: ", w1.listdescriptors())
+ print("gethdkeys: ", w1.gethdkeys())
self.nodes[0].createwallet("w2", blank=True)
w2 = self.nodes[0].get_wallet_rpc("w2")
(END) |
e8b1440 to
6049553
Compare
That should be done in #29136 which introduces |
6049553 to
f2752ef
Compare
f2752ef to
c8b6d4e
Compare
| // Check both only have one pubkey | ||
| std::set<CPubKey> prv_pubkeys; | ||
| std::set<CExtPubKey> prv_extpubs; | ||
| parse_pub->GetPubKeys(prv_pubkeys, prv_extpubs); |
There was a problem hiding this comment.
Should this call use parse_priv instead of parse_pub?
There was a problem hiding this comment.
Thanks, fixed in a new commit (even though it pertains to #29136).
| } | ||
| } | ||
|
|
||
| LOCK(wallet->cs_wallet); |
There was a problem hiding this comment.
I think a duplicate check is needed. What if the wallet already has this xprv through an active descriptor and user calls addhdkey with the same xprv? The descriptor check would not catch that, because unused(xprv) is a different descriptor string. A check is needed here to prevent adding the same private key twice.
const CExtPubKey hd_xpub{hdkey.Nexuter()};
if (wallet->GetKey(hd_xpub.pubkey.GetID())) {
throw JSONRPCError(RPC_WALLET_ERROR, "HD key already exists");
}
| wallet = self.nodes[0].get_wallet_rpc("hdkey") | ||
|
|
||
| assert_equal(len(wallet.gethdkeys()), 1) | ||
|
|
There was a problem hiding this comment.
Cover the case where addhdkey is called with existing xprv. Expected behavior is to reject it as "HD key already exists"
existing_wallet_xprv = wallet.gethdkeys(private=True)[0]["xprv"]
assert_raises_rpc_error(-4, "HD key already exists", wallet.addhdkey, existing_wallet_xprv)
|
Review and tested c8b6d4ee2abbd1271e44aa66da6079cee6323529 Concept ACK, Approach ACK. I think I have found a small issue where a xprv already in wallet via active descriptors, and addhdkey(xprv) is called from RPC with the same xprv. Suggested a fix in the review comments. |
fb57795 to
13d807e
Compare
|
Rebased after #28333. |
|
Concept ACK |
13d807e to
c4249c0
Compare
…tor' into HEAD Resolve the createwalletdescriptor conflict between bitcoin#32784 and bitcoin#32861 by keeping bitcoin#32861's fallback to unused KEY descriptors, but adapting the active descriptor lookup to bitcoin#32784's GetHDPubKeys(HDKeyFilter::Active) API and extracting the xpub from the map key.
c4249c0 to
fe1a296
Compare
|
Rebased after #32784. |
fe1a296 to
d46c58d
Compare
d46c58d to
9d8e530
Compare
jeanpablojp
left a comment
There was a problem hiding this comment.
Concept ACK
I noticed that on a wallet with two active keys plus one from addhdkey, derivehdkey uses the unused one while createwalletdescriptor errors with "Unable to determine which HD key to use from active descriptors". Master does the same. But now that this RPC knows about unused(KEY), shouldn't that lookup also apply when there's more than one active key?
The hdkey hint is stale now too. It still says "The HD key used by all other active descriptors", where derivehdkey's mentions both cases.
| throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to determine which HD key to use from active descriptors. Please specify with 'hdkey'"); | ||
| } else { | ||
| // Look for an unused(KEY) descriptor | ||
| std::set<DescriptorScriptPubKeyMan*> spkms{pwallet->GetScriptlessSPKMs()}; |
There was a problem hiding this comment.
GetHDPubKeys(HDKeyFilter::UnusedKey) already returns this set, and derivehdkey uses it further down in this same file. I swapped this block for a call to it, the wallet tests still pass and GetScriptlessSPKMs() goes away entirely. Is there a reason for the separate helper that I'm missing?
Co-authored-by: adyshimony <6388409+adyshimony@users.noreply.github.com>
Co-authored-by: adyshimony <6388409+adyshimony@users.noreply.github.com>
When a wallet contains only an unused(KEY) descriptor, use it. Previously the user would have to call listdescriptors and manually specify it.
The participant wallets are only used to derive an xpub and sign PSBTs for the multisig wallet. Creating them blank and adding just the legacy descriptor avoids handing the reader singlesig addresses they are not supposed to use. The legacy descriptor can't be dropped entirely because the signing code only considers descriptors whose derivation paths cover the input. To further discourage use of the singlesig descriptors, the PSBT example now pays a separate recipient wallet rather than participant_1.
9d8e530 to
9d4eb1f
Compare
|
The rule and help text is now:
In the ambiguous case @jeanpablojp describes, it's better to err on the side of failing, because descriptors can't be deleted. In that sense it's different from
Fixed I also added a commit to use improve the multisig tutorial. |
The
createwalletdescriptorwas introduced in #29130 to let users add atr()descriptor to an existing SegWit wallet. The newaddhdkeymethod from #29136 introduces a new potential workflow: start from a blank wallet, generate an HD and then add only the descriptors you need, e.g.:Before this PR the last line would fail, requiring the user to call
gethdkeysand copy-paste the xpub.This PR makes
createwalletdescriptora bit smarter so it just finds theunused(KEY)generated byhdkeyand uses that.If multiple
unused(KEY)descriptors are present the user still has to pick one.A potential followup is to make our multisig tutorial slightly safer to use. Rather than creating a full wallet, the instruction could be changed to start with a blank wallet and only generate the default legacy descriptor. This avoids accidental use of single sig
p2sh-segwitandbech32addresses.--
The first two commits are quick followups for #29136.