Skip to content

Commit 740c8c9

Browse files
committed
Merge #306: Add docs + test on required use of xpub for multipath constructor
e647ed2 docs: add wording on required use of xpub for multipath constructor (thunderbiscuit) Pull request description: This PR makes explicit a limitation of the `Wallet::create_from_two_path_descriptor` method, in that you must use public descriptors to build the wallet using this constructor, meaning you can only build watch-only wallets. I also added a test to showcase this and the error returned. See [my comment here](#275 (comment)) for more: From what I can tell the issue is that miniscript cannot parse an xprv (I saw a comment from Sanket about this somewhere but now I can't find it anymore) if the multipath contains hardened derivation paths, and therefore miniscipt cannot ensure the xprv will be parsable into public keys in all cases? Something like that. But our arguments for bdk wallet constructors require the `IntoWalletDescriptor` trait: ```rust pub trait IntoWalletDescriptor { /// Convert to wallet descriptor fn into_wallet_descriptor( self, secp: &SecpCtx, network: Network, ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError>; } pub type ExtendedDescriptor = Descriptor<DescriptorPublicKey>; ``` In other words, upon creation, the wallet will always try to parse the descriptor string into its public form, and here since it cannot be done by miniscript we fail to build. ### Changelog notice No changelog notice. ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `just p` before pushing ACKs for top commit: ValuedMammal: ACK e647ed2 oleonardolima: utACK e647ed2 Tree-SHA512: 15085dedc07c69f9e04876c174c4a8d54d186f0b04c6d1bf8ea76829cccdbf3f3644b7169392be5d03f0b983e4db6fd01afda6fb97ae348438f585cdde3fc08b
2 parents 0cf9f28 + e647ed2 commit 740c8c9

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

wallet/src/wallet/mod.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,15 +399,17 @@ impl Wallet {
399399
/// Build a new [`Wallet`] from a two-path descriptor.
400400
///
401401
/// This function parses a multipath descriptor with exactly 2 paths and creates a wallet
402-
/// using the existing receive and change wallet creation logic.
402+
/// using the existing receive and change wallet creation logic. Note that you can only use this
403+
/// method with public extended keys (`xpub` prefix) to create watch-only wallets.
403404
///
404405
/// Multipath descriptors follow [BIP 389] and allow defining both receive and change
405406
/// derivation paths in a single descriptor using the `<0;1>` syntax.
406407
///
407408
/// If you have previously created a wallet, use [`load`](Self::load) instead.
408409
///
409410
/// # Errors
410-
/// Returns an error if the descriptor is invalid or not a 2-path multipath descriptor.
411+
/// Returns an error if the descriptor is invalid, not a 2-path multipath descriptor, or if
412+
/// the descriptor provided contains an extended private key (`xprv` prefix).
411413
///
412414
/// # Synopsis
413415
///
@@ -1224,7 +1226,7 @@ impl Wallet {
12241226
txs
12251227
}
12261228

1227-
/// Return the balance, separated into available, trusted-pending, untrusted-pending and
1229+
/// Return the balance, separated into available, trusted-pending, untrusted-pending, and
12281230
/// immature values.
12291231
pub fn balance(&self) -> Balance {
12301232
self.indexed_graph.graph().balance(
@@ -2794,6 +2796,7 @@ macro_rules! doctest_wallet {
27942796
#[cfg(test)]
27952797
mod test {
27962798
use super::*;
2799+
use crate::miniscript::Error::Unexpected;
27972800
use crate::test_utils::get_test_tr_single_sig_xprv_and_change_desc;
27982801
use crate::test_utils::insert_tx;
27992802

@@ -2894,6 +2897,17 @@ mod test {
28942897
let wallet = params.network(Network::Testnet).create_wallet_no_persist();
28952898
assert!(matches!(wallet, Err(DescriptorError::MultiPath)));
28962899

2900+
// Test with a private descriptor
2901+
// You get a Miniscript(Unexpected("Can't make an extended private key with multiple paths
2902+
// into a public key.")) error.
2903+
let private_multipath_descriptor = "wpkh(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/84'/1'/0'/<0;1>/*)";
2904+
let params = Wallet::create_from_two_path_descriptor(private_multipath_descriptor);
2905+
let wallet = params.network(Network::Testnet).create_wallet_no_persist();
2906+
assert!(matches!(
2907+
wallet,
2908+
Err(DescriptorError::Miniscript(Unexpected(..)))
2909+
));
2910+
28972911
// Test with invalid 3-path multipath descriptor
28982912
let three_path_descriptor = "wpkh([9a6a2580/84'/1'/0']tpubDDnGNapGEY6AZAdQbfRJgMg9fvz8pUBrLwvyvUqEgcUfgzM6zc2eVK4vY9x9L5FJWdX8WumXuLEDV5zDZnTfbn87vLe9XceCFwTu9so9Kks/<0;1;2>/*)";
28992913
let params = Wallet::create_from_two_path_descriptor(three_path_descriptor);

0 commit comments

Comments
 (0)