Skip to content

Commit 4be00e1

Browse files
author
Scott Robinson
committed
Extract specialised DescriptorPublicKey functionality into DescriptorExtendedPublicKey
1 parent 4b63ba4 commit 4be00e1

File tree

1 file changed

+105
-58
lines changed

1 file changed

+105
-58
lines changed

src/descriptor/key.rs

Lines changed: 105 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ use crate::prelude::*;
1818
use crate::serde::{Deserialize, Deserializer, Serialize, Serializer};
1919
use crate::{hash256, MiniscriptKey, ToPublicKey};
2020

21+
type DescriptorExtendedPublicKey = DescriptorXKey<bip32::ExtendedPubKey>;
22+
2123
/// The descriptor pubkey, either a single pubkey or an xpub.
2224
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
2325
pub enum DescriptorPublicKey {
2426
/// Single public key.
2527
Single(SinglePub),
2628
/// Extended public key (xpub).
27-
XPub(DescriptorXKey<bip32::ExtendedPubKey>),
29+
XPub(DescriptorExtendedPublicKey),
2830
/// Multiple extended public keys.
2931
MultiXPub(DescriptorMultiXKey<bip32::ExtendedPubKey>),
3032
}
@@ -283,6 +285,20 @@ impl error::Error for DescriptorKeyParseError {
283285
}
284286
}
285287

288+
impl fmt::Display for DescriptorExtendedPublicKey {
289+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290+
maybe_fmt_master_id(f, &self.origin)?;
291+
self.xkey.fmt(f)?;
292+
fmt_derivation_path(f, &self.derivation_path)?;
293+
match self.wildcard {
294+
Wildcard::None => {}
295+
Wildcard::Unhardened => write!(f, "/*")?,
296+
Wildcard::Hardened => write!(f, "/*h")?,
297+
}
298+
Ok(())
299+
}
300+
}
301+
286302
impl fmt::Display for DescriptorPublicKey {
287303
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
288304
match *self {
@@ -294,17 +310,7 @@ impl fmt::Display for DescriptorPublicKey {
294310
}?;
295311
Ok(())
296312
}
297-
DescriptorPublicKey::XPub(ref xpub) => {
298-
maybe_fmt_master_id(f, &xpub.origin)?;
299-
xpub.xkey.fmt(f)?;
300-
fmt_derivation_path(f, &xpub.derivation_path)?;
301-
match xpub.wildcard {
302-
Wildcard::None => {}
303-
Wildcard::Unhardened => write!(f, "/*")?,
304-
Wildcard::Hardened => write!(f, "/*h")?,
305-
}
306-
Ok(())
307-
}
313+
DescriptorPublicKey::XPub(ref xpub) => xpub.fmt(f),
308314
DescriptorPublicKey::MultiXPub(ref xpub) => {
309315
maybe_fmt_master_id(f, &xpub.origin)?;
310316
xpub.xkey.fmt(f)?;
@@ -558,17 +564,86 @@ pub trait DescriptorInnerKey {
558564
/// Whether or not this key has multiple derivation paths.
559565
fn is_multipath(&self) -> bool;
560566
}
567+
568+
impl DescriptorInnerKey for DescriptorExtendedPublicKey {
569+
/// The fingerprint of the master key associated with this key, `0x00000000` if none.
570+
fn master_fingerprint(&self) -> bip32::Fingerprint {
571+
if let Some((fingerprint, _)) = self.origin {
572+
fingerprint
573+
} else {
574+
self.xkey.fingerprint()
575+
}
576+
}
577+
578+
/// Full path, from the master key
579+
///
580+
/// For wildcard keys this will return the path up to the wildcard, so you
581+
/// can get full paths by appending one additional derivation step, according
582+
/// to the wildcard type (hardened or normal).
583+
///
584+
/// For multipath extended keys, this returns `None`.
585+
fn full_derivation_path(&self) -> Option<bip32::DerivationPath> {
586+
let origin_path = if let Some((_, ref path)) = self.origin {
587+
path.clone()
588+
} else {
589+
bip32::DerivationPath::from(vec![])
590+
};
591+
Some(origin_path.extend(&self.derivation_path))
592+
}
593+
594+
/// Whether or not the key has a wildcard
595+
fn has_wildcard(&self) -> bool {
596+
self.wildcard != Wildcard::None
597+
}
598+
599+
/// Replaces any wildcard (i.e. `/*`) in the key with a particular derivation index, turning it into a
600+
/// *definite* key (i.e. one where all the derivation paths are set).
601+
///
602+
/// # Returns
603+
///
604+
/// - If this key is not an xpub, returns `self`.
605+
/// - If this key is an xpub but does not have a wildcard, returns `self`.
606+
/// - Otherwise, returns the xpub at derivation `index` (removing the wildcard).
607+
///
608+
/// # Errors
609+
///
610+
/// - If `index` is hardened.
611+
fn at_derivation_index(self, index: u32) -> Result<DefiniteDescriptorKey, ConversionError> {
612+
let derivation_path = match self.wildcard {
613+
Wildcard::None => self.derivation_path,
614+
Wildcard::Unhardened => self.derivation_path.into_child(
615+
bip32::ChildNumber::from_normal_idx(index)
616+
.ok()
617+
.ok_or(ConversionError::HardenedChild)?,
618+
),
619+
Wildcard::Hardened => self.derivation_path.into_child(
620+
bip32::ChildNumber::from_hardened_idx(index)
621+
.ok()
622+
.ok_or(ConversionError::HardenedChild)?,
623+
),
624+
};
625+
let definite = DescriptorPublicKey::XPub(DescriptorXKey {
626+
origin: self.origin,
627+
xkey: self.xkey,
628+
derivation_path,
629+
wildcard: Wildcard::None,
630+
});
631+
632+
Ok(DefiniteDescriptorKey::new(definite)
633+
.expect("The key should not contain any wildcards at this point"))
634+
}
635+
636+
/// Whether or not this key has multiple derivation paths.
637+
fn is_multipath(&self) -> bool {
638+
false
639+
}
640+
}
641+
561642
impl DescriptorPublicKey {
562643
/// The fingerprint of the master key associated with this key, `0x00000000` if none.
563644
pub fn master_fingerprint(&self) -> bip32::Fingerprint {
564645
match *self {
565-
DescriptorPublicKey::XPub(ref xpub) => {
566-
if let Some((fingerprint, _)) = xpub.origin {
567-
fingerprint
568-
} else {
569-
xpub.xkey.fingerprint()
570-
}
571-
}
646+
DescriptorPublicKey::XPub(ref xpub) => xpub.master_fingerprint(),
572647
DescriptorPublicKey::MultiXPub(ref xpub) => {
573648
if let Some((fingerprint, _)) = xpub.origin {
574649
fingerprint
@@ -606,14 +681,7 @@ impl DescriptorPublicKey {
606681
/// For multipath extended keys, this returns `None`.
607682
pub fn full_derivation_path(&self) -> Option<bip32::DerivationPath> {
608683
match *self {
609-
DescriptorPublicKey::XPub(ref xpub) => {
610-
let origin_path = if let Some((_, ref path)) = xpub.origin {
611-
path.clone()
612-
} else {
613-
bip32::DerivationPath::from(vec![])
614-
};
615-
Some(origin_path.extend(&xpub.derivation_path))
616-
}
684+
DescriptorPublicKey::XPub(ref xpub) => xpub.full_derivation_path(),
617685
DescriptorPublicKey::Single(ref single) => {
618686
Some(if let Some((_, ref path)) = single.origin {
619687
path.clone()
@@ -635,7 +703,7 @@ impl DescriptorPublicKey {
635703
pub fn has_wildcard(&self) -> bool {
636704
match *self {
637705
DescriptorPublicKey::Single(..) => false,
638-
DescriptorPublicKey::XPub(ref xpub) => xpub.wildcard != Wildcard::None,
706+
DescriptorPublicKey::XPub(ref xpub) => xpub.has_wildcard(),
639707
DescriptorPublicKey::MultiXPub(ref xpub) => xpub.wildcard != Wildcard::None,
640708
}
641709
}
@@ -659,40 +727,19 @@ impl DescriptorPublicKey {
659727
///
660728
/// - If `index` is hardened.
661729
pub fn at_derivation_index(self, index: u32) -> Result<DefiniteDescriptorKey, ConversionError> {
662-
let definite = match self {
663-
DescriptorPublicKey::Single(_) => self,
664-
DescriptorPublicKey::XPub(xpub) => {
665-
let derivation_path = match xpub.wildcard {
666-
Wildcard::None => xpub.derivation_path,
667-
Wildcard::Unhardened => xpub.derivation_path.into_child(
668-
bip32::ChildNumber::from_normal_idx(index)
669-
.ok()
670-
.ok_or(ConversionError::HardenedChild)?,
671-
),
672-
Wildcard::Hardened => xpub.derivation_path.into_child(
673-
bip32::ChildNumber::from_hardened_idx(index)
674-
.ok()
675-
.ok_or(ConversionError::HardenedChild)?,
676-
),
677-
};
678-
DescriptorPublicKey::XPub(DescriptorXKey {
679-
origin: xpub.origin,
680-
xkey: xpub.xkey,
681-
derivation_path,
682-
wildcard: Wildcard::None,
683-
})
684-
}
685-
DescriptorPublicKey::MultiXPub(_) => return Err(ConversionError::MultiKey),
686-
};
687-
688-
Ok(DefiniteDescriptorKey::new(definite)
689-
.expect("The key should not contain any wildcards at this point"))
730+
match self {
731+
DescriptorPublicKey::Single(_) => Ok(DefiniteDescriptorKey::new(self)
732+
.expect("The key should not contain any wildcards at this point")),
733+
DescriptorPublicKey::XPub(xpub) => xpub.at_derivation_index(index),
734+
DescriptorPublicKey::MultiXPub(_) => Err(ConversionError::MultiKey),
735+
}
690736
}
691737

692738
/// Whether or not this key has multiple derivation paths.
693739
pub fn is_multipath(&self) -> bool {
694-
match *self {
695-
DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => false,
740+
match self {
741+
DescriptorPublicKey::Single(..) => false,
742+
DescriptorPublicKey::XPub(xpub) => xpub.is_multipath(),
696743
DescriptorPublicKey::MultiXPub(_) => true,
697744
}
698745
}

0 commit comments

Comments
 (0)