From ef02e2bb7f990b26b06919bb2c41e9d5c2bc992d Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Wed, 24 Jun 2026 16:01:14 -0400 Subject: [PATCH] docs: fix API docs for LoadParams::two_path_descriptor method --- src/test_utils.rs | 7 ++++++- src/wallet/params.rs | 10 +++++----- tests/persisted_wallet.rs | 20 +++++++++++++++++++- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/test_utils.rs b/src/test_utils.rs index c0a514647..b89ef3ee1 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -147,11 +147,16 @@ pub fn get_test_wpkh_and_change_desc() -> (&'static str, &'static str) { "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)") } -/// `wpkh` two-path descriptor +/// `wpkh` public two-path descriptor pub fn get_test_two_path_wpkh() -> &'static str { "wpkh(tpubDDks68wKK1xKaVVVbNmXUAx68K1K817M6KwjvjEyCrjdU7xMvjKnfYAtZjfZcrfPfGFzqmibuVqMzKJGbBnK7mo7WSJri8Y9QgM7aNQ3fCp/<0;1>/*)" } +/// `wpkh` private two-path descriptor +pub fn get_test_two_path_private_wpkh() -> &'static str { + "tr(tprv8ZgxMBicQKsPdfqH2fGKQkBAMXpqCpC6v6WhYnEZC7TbpcEavC1N27tHbFP16eLm9XdFDW6cqnGChit8gWXyyT1zQ3xFqUWgHTS9XBQw3j5/<0;1>/*)" +} + /// `wsh` descriptor with policy `and(pk(A),older(6))` pub fn get_test_single_sig_csv() -> &'static str { "wsh(and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),older(6)))" diff --git a/src/wallet/params.rs b/src/wallet/params.rs index 388d67c51..a0b9a1c73 100644 --- a/src/wallet/params.rs +++ b/src/wallet/params.rs @@ -271,12 +271,12 @@ impl LoadParams { } /// Checks that the provided two-path descriptor matches exactly what is loaded for both the - /// external and internal keychains. + /// external and internal keychains. Note that you can only use this method with public extended + /// keys (`xpub` prefix) to create watch-only wallets. /// - /// # Note - /// - /// You must also specify [`extract_keys`](Self::extract_keys) if you wish to add a signer - /// for an expected descriptor containing secrets. + /// # Errors + /// Returns an error if the descriptor is invalid, not a 2-path multipath descriptor, or if + /// the descriptor provided contains an extended private key (`xprv` prefix). pub fn two_path_descriptor(mut self, expected_descriptor: D) -> Self where D: IntoWalletDescriptor + Send + Clone + 'static, diff --git a/tests/persisted_wallet.rs b/tests/persisted_wallet.rs index bc1375948..1d260a97d 100644 --- a/tests/persisted_wallet.rs +++ b/tests/persisted_wallet.rs @@ -8,7 +8,7 @@ use bdk_chain::{ keychain_txout::DEFAULT_LOOKAHEAD, ChainPosition, ConfirmationBlockTime, DescriptorExt, }; use bdk_wallet::coin_selection::InsufficientFunds; -use bdk_wallet::descriptor::IntoWalletDescriptor; +use bdk_wallet::descriptor::{DescriptorError, IntoWalletDescriptor}; use bdk_wallet::error::CreateTxError; use bdk_wallet::test_utils::*; use bdk_wallet::{ @@ -450,6 +450,24 @@ fn two_path_descriptor_wallet_persist_and_recover() { .unwrap() .expect("wallet must exist"); assert_eq!(loaded.derivation_index(KeychainKind::External), Some(2)); + + // A private multipath descriptor can't be converted to a public key, so loading fails. + // You get a Miniscript(Unexpected("Can't make an extended private key with multiple paths into + // a public key.")) error. + let private_two_path_descriptor = get_test_two_path_private_wpkh(); + let err = Wallet::load() + .two_path_descriptor(private_two_path_descriptor) + .check_network(Network::Testnet4) + .load_wallet(&mut db); + assert_matches!( + err, + Err(LoadWithPersistError::InvalidChangeSet( + LoadError::Descriptor(DescriptorError::Miniscript(miniscript::Error::Unexpected( + _ + ))) + )), + "private multipath descriptor should fail with a Miniscript Unexpected error" + ); } #[test]