feat(wallet): create_single accepts a multipath descriptor#1906
feat(wallet): create_single accepts a multipath descriptor#1906ValuedMammal wants to merge 3 commits intobitcoindevkit:masterfrom
create_single accepts a multipath descriptor#1906Conversation
..by including the missing match arm for `DescriptorPublicKey::MultiXPub` when initializing `networks`. Test that `into_wallet_descriptor` correctly parses a multipath descriptor and fails if passed a network that is invalid for the descriptor. Note that rust-miniscript doesn't support parsing a multipath descriptor containing extended private keys.
Test that creating a Wallet from a multipath descriptor returns a Wallet with two keychains. The first part of the multipath goes to the first (External) keychain and the second part goes to the Internal keychain. Fixup error message for `DescriptorError::Multipath` which previously indicated they weren't supported. The error can still be triggered by the appearance of a MultiXPub where not explicitly allowed.
| // In case of multipath we parse the descriptor into single descriptors and | ||
| // assign each one back to the `descriptor` and `change_descriptor`. | ||
| if descriptor.is_multipath() { | ||
| let mut desc_iter = descriptor.into_single_descriptors()?.into_iter(); | ||
| descriptor = desc_iter.next().expect("must have a descriptor"); | ||
| descriptor_keymap = Descriptor::parse_descriptor(&secp, &descriptor.to_string())?.1; | ||
| params.change_descriptor = desc_iter.next().map(params::make_descriptor_to_extract); | ||
| } |
There was a problem hiding this comment.
I think it should throw an error if there are more than 2 descriptors.
There was a problem hiding this comment.
Although you've explained that only the first 2 are used in the documentation, I also wonder if returning an error would be a better idea in order to prevent the user's unexpected behavior.
There was a problem hiding this comment.
Can you make a code suggestion (preferably non breaking)?
There was a problem hiding this comment.
I can't say I fully agree with throwing an error, and instead lean toward managing expectations through effective documentation. But I guess it can go either way.
| // assign each one back to the `descriptor` and `change_descriptor`. | ||
| if descriptor.is_multipath() { | ||
| let mut desc_iter = descriptor.into_single_descriptors()?.into_iter(); | ||
| descriptor = desc_iter.next().expect("must have a descriptor"); |
There was a problem hiding this comment.
Hi @ValuedMammal, your implementation is solid.
You can return this error gracefully, rather than panic here.
There was a problem hiding this comment.
What error to return though?
There was a problem hiding this comment.
Probably another variant like MissingDescriptor can be added to the error enum
There was a problem hiding this comment.
I would say the presence of a descriptor is invariant in the structure of CreateParams, meaning we've ruled out the possibility of a missing descriptor.
There was a problem hiding this comment.
Okay. I understand. That's a good development. I was initially concerned about the panic.
oleonardolima
left a comment
There was a problem hiding this comment.
cACK 4cf5537
Great work! I left a suggestion for a fix documentation typo, and another minor question. I agree with Schwab's, and wonder if we shouldn't return an error instead when multipath's with 3+ descriptors are used.
| // In case of multipath we parse the descriptor into single descriptors and | ||
| // assign each one back to the `descriptor` and `change_descriptor`. | ||
| if descriptor.is_multipath() { | ||
| let mut desc_iter = descriptor.into_single_descriptors()?.into_iter(); | ||
| descriptor = desc_iter.next().expect("must have a descriptor"); | ||
| descriptor_keymap = Descriptor::parse_descriptor(&secp, &descriptor.to_string())?.1; | ||
| params.change_descriptor = desc_iter.next().map(params::make_descriptor_to_extract); | ||
| } |
There was a problem hiding this comment.
Although you've explained that only the first 2 are used in the documentation, I also wonder if returning an error would be a better idea in order to prevent the user's unexpected behavior.
Co-authored-by: Leonardo L. <[email protected]>
|
Pardon me jumping here a bit late (and maybe with some missing information). One comment I have here is that once this feature is in, devs cannot expect that a wallet created with for a wallet with no internal (change) keychain, any methods requiring a [ I'm wondering where that certainty (around the number of keychains and hence reliance on certain APIs) should come from (and maybe relying on I initially thought of those as constructors that offer certainties about what types of wallets (i.e. single vs double keychains wallets) will come out of them ( Happy to hear everyone's thoughts. Again I'm coming in last minute a little bit on this, and I feel like I don't have complete knowledge on it so feel free to tell me I was wrong all along haha. |
Notes to the reviewers
We reuse
Wallet::create_singleto accommodate a wallet descriptor that parses as a MultiXPub. The documentation is updated to clarify the distinction between the single vs. dual-keychain use cases.The logical change happens in
create_with_paramswhere we now look for whether the external descriptoris_multipathand if so, use the parsed single descriptors to update thedescriptorandchange_descriptorand everything proceeds as normal. This means that the wallet change set still consists of the individually split descriptors.An alternative that was discussed was to make a new dedicated function such as
create_from_multipaththat enforces the provided input to be a multipath descriptor. However we arrived at the approach in this PR in order to promotecreate_singleas a more central API long term.This is based on #1902 as that seemed to be relatively non controversial.
fixes bitcoindevkit/bdk_wallet#11
Follow ups: Consider whether it might be needed to parse a multipath descriptor at load time bitcoindevkit/bdk_wallet#11
Changelog notice
Changed:
Wallet::create_singlecan be used to create a Wallet from a BIP389 multipath descriptorChecklists
All Submissions:
cargo fmtandcargo clippybefore committingNew Features: