Skip to content

Commit 29a7374

Browse files
committed
Merge #241: fix(wallet): fix into_descriptor_key for DescriptorPublicKey
469cfd0 fix(wallet): fix `into_descriptor_key` for DescriptorPublicKey (valued mammal) Pull request description: Fix `into_descriptor_key` for `DescriptorPublicKey` 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. fixes #10 ### 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 `cargo +nightly fmt` and `cargo clippy` before committing #### New Features: * [ ] I've added tests for the new feature * [ ] I've added docs for the new feature #### Bugfixes: * [ ] This pull request breaks the existing API * [x] I've added tests to reproduce the issue which are now passing * [x] I'm linking the issue being fixed by this PR ACKs for top commit: notmandatory: ACK 469cfd0 oleonardolima: ACK 469cfd0 Tree-SHA512: e5b26b5e52308500e57a322fbe94b294adef605afc9aab93b649cdc2c930e7c043170b531fd5fb0da560f384d4574ac3bc86adb4d6a6d52b10db7694b3667fe4
2 parents 54d4028 + 469cfd0 commit 29a7374

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed

wallet/src/descriptor/mod.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,4 +917,48 @@ mod test {
917917
assert_eq!(psbt_input.redeem_script, Some(script.to_p2wsh()));
918918
assert_eq!(psbt_input.witness_script, Some(script));
919919
}
920+
921+
#[test]
922+
fn test_into_wallet_descriptor_multi() -> anyhow::Result<()> {
923+
// See <https://github.com/bitcoindevkit/bdk_wallet/issues/10>
924+
let secp = Secp256k1::new();
925+
926+
// multipath tpub
927+
let descriptor_str = "wpkh([9a6a2580/84'/1'/0']tpubDDnGNapGEY6AZAdQbfRJgMg9fvz8pUBrLwvyvUqEgcUfgzM6zc2eVK4vY9x9L5FJWdX8WumXuLEDV5zDZnTfbn87vLe9XceCFwTu9so9Kks/<0;1>/*)";
928+
let (descriptor, _key_map) = descriptor_str
929+
.into_wallet_descriptor(&secp, Network::Testnet)
930+
.expect("should parse multipath tpub");
931+
932+
assert!(descriptor.is_multipath());
933+
934+
// invalid network for descriptor
935+
let descriptor_str = "wpkh([9a6a2580/84'/0'/0']xpub6DEzNop46vmxR49zYWFnMwmEfawSNmAMf6dLH5YKDY463twtvw1XD7ihwJRLPRGZJz799VPFzXHpZu6WdhT29WnaeuChS6aZHZPFmqczR5K/<0;1>/*)";
936+
let res = descriptor_str.into_wallet_descriptor(&secp, Network::Testnet);
937+
938+
assert!(matches!(
939+
res,
940+
Err(DescriptorError::Key(KeyError::InvalidNetwork))
941+
));
942+
943+
// multipath xpub
944+
let descriptor_str = "wpkh([9a6a2580/84'/0'/0']xpub6DEzNop46vmxR49zYWFnMwmEfawSNmAMf6dLH5YKDY463twtvw1XD7ihwJRLPRGZJz799VPFzXHpZu6WdhT29WnaeuChS6aZHZPFmqczR5K/<0;1>/*)";
945+
let (descriptor, _key_map) = descriptor_str
946+
.into_wallet_descriptor(&secp, Network::Bitcoin)
947+
.expect("should parse multipath xpub");
948+
949+
assert!(descriptor.is_multipath());
950+
951+
// Miniscript can't make an extended private key with multiple paths into a public key.
952+
// ref: <https://docs.rs/miniscript/12.3.2/miniscript/descriptor/enum.DescriptorSecretKey.html#method.to_public>
953+
let descriptor_str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/<0;1>/*)";
954+
assert!(matches!(
955+
Descriptor::parse_descriptor(&secp, descriptor_str),
956+
Err(miniscript::Error::Unexpected(..)),
957+
));
958+
let _ = descriptor_str
959+
.into_wallet_descriptor(&secp, Network::Testnet)
960+
.unwrap_err();
961+
962+
Ok(())
963+
}
920964
}

wallet/src/keys/mod.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use bitcoin::secp256k1::{self, Secp256k1, Signing};
2727
use bitcoin::bip32;
2828
use bitcoin::{key::XOnlyPublicKey, Network, PrivateKey, PublicKey};
2929

30-
use miniscript::descriptor::{Descriptor, DescriptorXKey, Wildcard};
30+
use miniscript::descriptor::{Descriptor, DescriptorMultiXKey, DescriptorXKey, Wildcard};
3131
pub use miniscript::descriptor::{
3232
DescriptorPublicKey, DescriptorSecretKey, KeyMap, SinglePriv, SinglePub, SinglePubKey,
3333
SortedMultiVec,
@@ -880,10 +880,20 @@ impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorPublicKey {
880880
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
881881
let networks = match self {
882882
DescriptorPublicKey::Single(_) => any_network(),
883-
DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. }) if xkey.network.is_mainnet() => {
884-
mainnet_network()
883+
DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. }) => {
884+
if xkey.network.is_mainnet() {
885+
mainnet_network()
886+
} else {
887+
test_networks()
888+
}
889+
}
890+
DescriptorPublicKey::MultiXPub(DescriptorMultiXKey { xkey, .. }) => {
891+
if xkey.network.is_mainnet() {
892+
mainnet_network()
893+
} else {
894+
test_networks()
895+
}
885896
}
886-
_ => test_networks(),
887897
};
888898

889899
Ok(DescriptorKey::from_public(self, networks))

0 commit comments

Comments
 (0)