Skip to content

Commit 6d1da92

Browse files
committed
Merge #818: Add helpers to convert to DescriptorPublicKey and Descriptor<DefinitePublicKey> data structures
a00c993 Add helpers to convert from PublicKey & XOnlyPublicKey to Descriptor Keys (Philip Robinson) Pull request description: closes #817 I added the common cases of converting from `Descriptor<PublicKey>` and `Descriptor<XOnlyPublicKey>` to `Descriptor<DefinitePublicKey>`. Not sure if this is considered too specific but it feels like a use case that will be very common. ACKs for top commit: apoelstra: ACK a00c993; successfully ran local tests Tree-SHA512: 151296fbeca3ccb3e7e76138cb0ba874de8250e5139f0eae5e407a16573ed312af2e25d8c5b79d7ca59c8d673bd819087381287d6551a08a64fea51d7ddd9f9e
2 parents 9bf3f10 + a00c993 commit 6d1da92

File tree

2 files changed

+69
-3
lines changed

2 files changed

+69
-3
lines changed

src/descriptor/key.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::error;
88

99
use bitcoin::bip32::{self, XKeyIdentifier};
1010
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash, HashEngine};
11-
use bitcoin::key::XOnlyPublicKey;
11+
use bitcoin::key::{PublicKey, XOnlyPublicKey};
1212
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
1313

1414
use crate::prelude::*;
@@ -670,6 +670,18 @@ impl FromStr for DescriptorPublicKey {
670670
}
671671
}
672672

673+
impl From<XOnlyPublicKey> for DescriptorPublicKey {
674+
fn from(key: XOnlyPublicKey) -> Self {
675+
DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::XOnly(key) })
676+
}
677+
}
678+
679+
impl From<PublicKey> for DescriptorPublicKey {
680+
fn from(key: PublicKey) -> Self {
681+
DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::FullKey(key) })
682+
}
683+
}
684+
673685
/// Descriptor key conversion error
674686
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
675687
pub enum ConversionError {
@@ -1260,7 +1272,7 @@ impl DefiniteDescriptorKey {
12601272
/// Construct an instance from a descriptor key and a derivation index
12611273
///
12621274
/// Returns `None` if the key contains a wildcard
1263-
fn new(key: DescriptorPublicKey) -> Option<Self> {
1275+
pub fn new(key: DescriptorPublicKey) -> Option<Self> {
12641276
if key.has_wildcard() {
12651277
None
12661278
} else {

src/descriptor/mod.rs

+55-1
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ mod tests {
10511051
use bitcoin::hashes::Hash;
10521052
use bitcoin::script::PushBytes;
10531053
use bitcoin::sighash::EcdsaSighashType;
1054-
use bitcoin::{bip32, PublicKey, Sequence};
1054+
use bitcoin::{bip32, PublicKey, Sequence, XOnlyPublicKey};
10551055

10561056
use super::{checksum, *};
10571057
use crate::hex_script;
@@ -2183,4 +2183,58 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
21832183
)
21842184
.unwrap_err();
21852185
}
2186+
2187+
#[test]
2188+
fn convert_public_key_descriptor_to_definite_key() {
2189+
let descriptor_str = "wsh(or_d(pk(021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b),pk(0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6)))";
2190+
let full_pk_descriptor: Descriptor<PublicKey> =
2191+
Descriptor::from_str(descriptor_str).unwrap();
2192+
2193+
struct TranslateFullPk;
2194+
2195+
impl Translator<bitcoin::PublicKey> for TranslateFullPk {
2196+
type TargetPk = DefiniteDescriptorKey;
2197+
type Error = core::convert::Infallible;
2198+
2199+
fn pk(
2200+
&mut self,
2201+
pk: &bitcoin::PublicKey,
2202+
) -> Result<DefiniteDescriptorKey, Self::Error> {
2203+
Ok(DefiniteDescriptorKey::new(DescriptorPublicKey::from(*pk))
2204+
.expect("DescriptorPublicKey from PublicKey has no wildcards"))
2205+
}
2206+
2207+
translate_hash_clone!(bitcoin::PublicKey, DefiniteDescriptorKey, Self::Error);
2208+
}
2209+
2210+
let converted_descriptor = full_pk_descriptor
2211+
.translate_pk(&mut TranslateFullPk)
2212+
.expect("infallible");
2213+
2214+
assert_eq!(full_pk_descriptor.to_string(), converted_descriptor.to_string());
2215+
2216+
let xonly_descriptor_str = "tr(1d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b,pk(02c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6))";
2217+
let xonly_pk_descriptor: Descriptor<XOnlyPublicKey> =
2218+
Descriptor::from_str(xonly_descriptor_str).unwrap();
2219+
2220+
struct TranslateXOnlyPk;
2221+
2222+
impl Translator<XOnlyPublicKey> for TranslateXOnlyPk {
2223+
type TargetPk = DefiniteDescriptorKey;
2224+
type Error = core::convert::Infallible;
2225+
2226+
fn pk(&mut self, pk: &XOnlyPublicKey) -> Result<DefiniteDescriptorKey, Self::Error> {
2227+
Ok(DefiniteDescriptorKey::new(DescriptorPublicKey::from(*pk))
2228+
.expect("DescriptorPublicKey from XOnlyPublicKey has no wildcards"))
2229+
}
2230+
2231+
translate_hash_clone!(XOnlyPublicKey, DefiniteDescriptorKey, Self::Error);
2232+
}
2233+
2234+
let xonly_converted_descriptor = xonly_pk_descriptor
2235+
.translate_pk(&mut TranslateXOnlyPk)
2236+
.expect("infallible");
2237+
2238+
assert_eq!(xonly_pk_descriptor.to_string(), xonly_converted_descriptor.to_string());
2239+
}
21862240
}

0 commit comments

Comments
 (0)