Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0010f1c

Browse files
committedApr 2, 2025··
Merge #804: Refactor: make descriptors::key::DescriptorKeyParseError an enum
497c5a3 refactor: make descriptors::key::DescriptorKeyParseError an enum (Chris Ricketts) Pull request description: This PR has a go at refactoring `DescriptorKeyParseError` into an enum, as suggested in the `FIXME` comment: https://github.com/rust-bitcoin/rust-miniscript/blob/d0da327417cb177884c5d77edffa0891ba9b6969/src/descriptor/key.rs#L327-L330 I have separated the error variants by different inner parse error types and result types (e.g, public key, private key, etc) where I think it made sense to retain the inner error. I left a variant that wraps a `&'static str` and its used for the various ad-hoc parsing errors instead of adding the boilerplate for variants only created once and without retained data. The generic `parse_xkey_deriv` function now takes a parse function as its first parameter to allow specific key parsing errors: https://github.com/chris-ricketts/rust-miniscript/blob/790b08fcf46f53ce6ee80355a7db8e5108ed860f/src/descriptor/key.rs#L935-L952 ACKs for top commit: apoelstra: ACK 497c5a3; successfully ran local tests; thanks! Tree-SHA512: c9fb26b6484c90124947912070e9cca4e93b4d3bdb674a07926fb1a1adc6fe2c272a1d38925b35fc4842a527651a45b00dc6381d057bb02f36006dbda653809b
2 parents d0da327 + 497c5a3 commit 0010f1c

File tree

2 files changed

+233
-79
lines changed

2 files changed

+233
-79
lines changed
 

‎src/descriptor/key.rs

Lines changed: 232 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ impl DescriptorXKey<bip32::Xpriv> {
223223
let xprv = self
224224
.xkey
225225
.derive_priv(secp, &hardened_path)
226-
.map_err(|_| DescriptorKeyParseError("Unable to derive the hardened steps"))?;
226+
.map_err(DescriptorKeyParseError::DeriveHardenedKey)?;
227+
227228
let xpub = bip32::Xpub::from_priv(secp, &xprv);
228229

229230
let origin = match &self.origin {
@@ -276,7 +277,9 @@ impl DescriptorMultiXKey<bip32::Xpriv> {
276277
if child_num.is_normal() {
277278
Ok(*child_num)
278279
} else {
279-
Err(DescriptorKeyParseError("Can't make a multi-xpriv with hardened derivation steps that are not shared among all paths into a public key."))
280+
Err(DescriptorKeyParseError::MalformedKeyData(
281+
MalformedKeyDataKind::InvalidMultiXKeyDerivation,
282+
))
280283
}
281284
})
282285
.collect()
@@ -295,7 +298,7 @@ impl DescriptorMultiXKey<bip32::Xpriv> {
295298
let xprv = self
296299
.xkey
297300
.derive_priv(secp, &hardened_path)
298-
.map_err(|_| DescriptorKeyParseError("Unable to derive the hardened steps"))?;
301+
.map_err(DescriptorKeyParseError::DeriveHardenedKey)?;
299302
let xpub = bip32::Xpub::from_priv(secp, &xprv);
300303

301304
let origin = match &self.origin {
@@ -324,18 +327,145 @@ impl DescriptorMultiXKey<bip32::Xpriv> {
324327
}
325328
}
326329

330+
/// Kinds of malformed key data
331+
#[derive(Debug, PartialEq, Clone)]
332+
#[non_exhaustive]
333+
#[allow(missing_docs)]
334+
pub enum MalformedKeyDataKind {
335+
EmptyKey,
336+
EncounteredUnprintableCharacter,
337+
InvalidFullPublicKeyPrefix,
338+
InvalidMasterFingerprintLength,
339+
InvalidMultiIndexStep,
340+
InvalidMultiXKeyDerivation,
341+
InvalidPublicKeyLength,
342+
InvalidWildcardInDerivationPath,
343+
KeyTooShort,
344+
MultipleFingerprintsInPublicKey,
345+
MultipleDerivationPathIndexSteps,
346+
NoKeyAfterOrigin,
347+
NoMasterFingerprintFound,
348+
UnclosedSquareBracket,
349+
WildcardAsDerivedDescriptorKey,
350+
}
351+
352+
impl fmt::Display for MalformedKeyDataKind {
353+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354+
use MalformedKeyDataKind::*;
355+
356+
let err = match self {
357+
EmptyKey => "empty key",
358+
EncounteredUnprintableCharacter => "encountered an unprintable character",
359+
InvalidFullPublicKeyPrefix => "only full public keys with prefixes '02', '03' or '04' are allowed",
360+
InvalidMasterFingerprintLength => "master fingerprint should be 8 characters long",
361+
InvalidMultiIndexStep => "invalid multi index step in multipath descriptor",
362+
InvalidMultiXKeyDerivation => "can't make a multi-xpriv with hardened derivation steps that are not shared among all paths into a public key",
363+
InvalidPublicKeyLength => "public keys must be 64, 66 or 130 characters in size",
364+
InvalidWildcardInDerivationPath => "'*' may only appear as last element in a derivation path",
365+
KeyTooShort => "key too short",
366+
MultipleFingerprintsInPublicKey => "multiple ']' in Descriptor Public Key",
367+
MultipleDerivationPathIndexSteps => "'<' may only appear once in a derivation path",
368+
NoKeyAfterOrigin => "no key after origin",
369+
NoMasterFingerprintFound => "no master fingerprint found after '['",
370+
UnclosedSquareBracket => "unclosed '['",
371+
WildcardAsDerivedDescriptorKey => "cannot parse key with a wilcard as a DerivedDescriptorKey",
372+
};
373+
374+
f.write_str(err)
375+
}
376+
}
377+
327378
/// Descriptor Key parsing errors
328-
// FIXME: replace with error enums
329-
#[derive(Debug, PartialEq, Clone, Copy)]
330-
pub struct DescriptorKeyParseError(&'static str);
379+
#[derive(Debug, PartialEq, Clone)]
380+
#[non_exhaustive]
381+
pub enum DescriptorKeyParseError {
382+
/// Error while parsing a BIP32 extended private key
383+
Bip32Xpriv(bip32::Error),
384+
/// Error while parsing a BIP32 extended public key
385+
Bip32Xpub(bip32::Error),
386+
/// Error while parsing a derivation index
387+
DerivationIndexError {
388+
/// The invalid index
389+
index: String,
390+
/// The underlying parse error
391+
err: bitcoin::bip32::Error,
392+
},
393+
/// Error deriving the hardened private key.
394+
DeriveHardenedKey(bip32::Error),
395+
/// Error indicating the key data was malformed
396+
MalformedKeyData(MalformedKeyDataKind),
397+
/// Error while parsing the master derivation path.
398+
MasterDerivationPath(bip32::Error),
399+
/// Error indicating a malformed master fingerprint (invalid hex).
400+
MasterFingerprint {
401+
/// The invalid fingerprint
402+
fingerprint: String,
403+
/// The underlying parse error
404+
err: bitcoin::hex::HexToArrayError,
405+
},
406+
/// Error while parsing a simple public key.
407+
FullPublicKey(bitcoin::key::ParsePublicKeyError),
408+
/// Error while parsing a WIF private key.
409+
WifPrivateKey(bitcoin::key::FromWifError),
410+
/// Error while parsing an X-only public key (Secp256k1 error).
411+
XonlyPublicKey(bitcoin::secp256k1::Error),
412+
}
331413

332414
impl fmt::Display for DescriptorKeyParseError {
333-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.0) }
415+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
416+
match self {
417+
DescriptorKeyParseError::Bip32Xpriv(err) => {
418+
write!(f, "error while parsing BIP32 Xpriv: {err}")
419+
}
420+
DescriptorKeyParseError::Bip32Xpub(err) => {
421+
write!(f, "error while parsing BIP32 Xpub: {err}")
422+
}
423+
DescriptorKeyParseError::DerivationIndexError { index, err } => {
424+
write!(f, "error while parsing derivation index '{index}': {err}")
425+
}
426+
DescriptorKeyParseError::DeriveHardenedKey(err) => {
427+
write!(f, "unable to derive the hardened steps: {err}")
428+
}
429+
DescriptorKeyParseError::MalformedKeyData(err) => {
430+
write!(f, "{err}")
431+
}
432+
DescriptorKeyParseError::MasterDerivationPath(err) => {
433+
write!(f, "error while parsing master derivation path: {err}")
434+
}
435+
DescriptorKeyParseError::MasterFingerprint { fingerprint, err } => {
436+
write!(f, "error while parsing master fingerprint '{fingerprint}': {err}")
437+
}
438+
DescriptorKeyParseError::FullPublicKey(err) => {
439+
write!(f, "error while parsing full public key: {err}")
440+
}
441+
DescriptorKeyParseError::WifPrivateKey(err) => {
442+
write!(f, "error while parsing WIF private key: {err}")
443+
}
444+
DescriptorKeyParseError::XonlyPublicKey(err) => {
445+
write!(f, "error while parsing xonly public key: {err}")
446+
}
447+
}
448+
}
334449
}
335450

336451
#[cfg(feature = "std")]
337452
impl error::Error for DescriptorKeyParseError {
338-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
453+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
454+
use DescriptorKeyParseError::*;
455+
456+
match self {
457+
Bip32Xpriv(err)
458+
| Bip32Xpub(err)
459+
| DerivationIndexError { err, .. }
460+
| DeriveHardenedKey(err)
461+
| MasterDerivationPath(err) => Some(err),
462+
MasterFingerprint { err, .. } => Some(err),
463+
FullPublicKey(err) => Some(err),
464+
WifPrivateKey(err) => Some(err),
465+
XonlyPublicKey(err) => Some(err),
466+
MalformedKeyData(_) => None,
467+
}
468+
}
339469
}
340470

341471
impl fmt::Display for DescriptorPublicKey {
@@ -485,16 +615,15 @@ impl FromStr for DescriptorPublicKey {
485615
fn from_str(s: &str) -> Result<Self, Self::Err> {
486616
// A "raw" public key without any origin is the least we accept.
487617
if s.len() < 64 {
488-
return Err(DescriptorKeyParseError(
489-
"Key too short (<64 characters); use parse_descriptor for parsing \
490-
descriptors with private keys.",
618+
return Err(DescriptorKeyParseError::MalformedKeyData(
619+
MalformedKeyDataKind::KeyTooShort,
491620
));
492621
}
493622

494623
let (key_part, origin) = parse_key_origin(s)?;
495624

496625
if key_part.contains("pub") {
497-
let (xpub, derivation_paths, wildcard) = parse_xkey_deriv::<bip32::Xpub>(key_part)?;
626+
let (xpub, derivation_paths, wildcard) = parse_xkey_deriv(parse_bip32_xpub, key_part)?;
498627
if derivation_paths.len() > 1 {
499628
Ok(DescriptorPublicKey::MultiXPub(DescriptorMultiXKey {
500629
origin,
@@ -513,28 +642,26 @@ impl FromStr for DescriptorPublicKey {
513642
} else {
514643
let key = match key_part.len() {
515644
64 => {
516-
let x_only_key = XOnlyPublicKey::from_str(key_part).map_err(|_| {
517-
DescriptorKeyParseError("Error while parsing simple xonly key")
518-
})?;
645+
let x_only_key = XOnlyPublicKey::from_str(key_part)
646+
.map_err(DescriptorKeyParseError::XonlyPublicKey)?;
519647
SinglePubKey::XOnly(x_only_key)
520648
}
521649
66 | 130 => {
522650
if !(&key_part[0..2] == "02"
523651
|| &key_part[0..2] == "03"
524652
|| &key_part[0..2] == "04")
525653
{
526-
return Err(DescriptorKeyParseError(
527-
"Only publickeys with prefixes 02/03/04 are allowed",
654+
return Err(DescriptorKeyParseError::MalformedKeyData(
655+
MalformedKeyDataKind::InvalidFullPublicKeyPrefix,
528656
));
529657
}
530-
let key = bitcoin::PublicKey::from_str(key_part).map_err(|_| {
531-
DescriptorKeyParseError("Error while parsing simple public key")
532-
})?;
658+
let key = bitcoin::PublicKey::from_str(key_part)
659+
.map_err(DescriptorKeyParseError::FullPublicKey)?;
533660
SinglePubKey::FullKey(key)
534661
}
535662
_ => {
536-
return Err(DescriptorKeyParseError(
537-
"Public keys must be 64/66/130 characters in size",
663+
return Err(DescriptorKeyParseError::MalformedKeyData(
664+
MalformedKeyDataKind::InvalidPublicKeyLength,
538665
))
539666
}
540667
};
@@ -772,10 +899,11 @@ impl FromStr for DescriptorSecretKey {
772899

773900
if key_part.len() <= 52 {
774901
let sk = bitcoin::PrivateKey::from_str(key_part)
775-
.map_err(|_| DescriptorKeyParseError("Error while parsing a WIF private key"))?;
902+
.map_err(DescriptorKeyParseError::WifPrivateKey)?;
776903
Ok(DescriptorSecretKey::Single(SinglePriv { key: sk, origin }))
777904
} else {
778-
let (xpriv, derivation_paths, wildcard) = parse_xkey_deriv::<bip32::Xpriv>(key_part)?;
905+
let (xpriv, derivation_paths, wildcard) =
906+
parse_xkey_deriv(parse_bip32_xpriv, key_part)?;
779907
if derivation_paths.len() > 1 {
780908
Ok(DescriptorSecretKey::MultiXPrv(DescriptorMultiXKey {
781909
origin,
@@ -799,42 +927,57 @@ impl FromStr for DescriptorSecretKey {
799927
fn parse_key_origin(s: &str) -> Result<(&str, Option<bip32::KeySource>), DescriptorKeyParseError> {
800928
for ch in s.as_bytes() {
801929
if *ch < 20 || *ch > 127 {
802-
return Err(DescriptorKeyParseError("Encountered an unprintable character"));
930+
return Err(DescriptorKeyParseError::MalformedKeyData(
931+
MalformedKeyDataKind::EncounteredUnprintableCharacter,
932+
));
803933
}
804934
}
805935

806936
if s.is_empty() {
807-
return Err(DescriptorKeyParseError("Empty key"));
937+
return Err(DescriptorKeyParseError::MalformedKeyData(MalformedKeyDataKind::EmptyKey));
808938
}
809939
let mut parts = s[1..].split(']');
810940

811941
if let Some('[') = s.chars().next() {
812942
let mut raw_origin = parts
813943
.next()
814-
.ok_or(DescriptorKeyParseError("Unclosed '['"))?
944+
.ok_or(DescriptorKeyParseError::MalformedKeyData(
945+
MalformedKeyDataKind::UnclosedSquareBracket,
946+
))?
815947
.split('/');
816948

817949
let origin_id_hex = raw_origin
818950
.next()
819-
.ok_or(DescriptorKeyParseError("No master fingerprint found after '['"))?;
951+
.ok_or(DescriptorKeyParseError::MalformedKeyData(
952+
MalformedKeyDataKind::NoMasterFingerprintFound,
953+
))?;
820954

821955
if origin_id_hex.len() != 8 {
822-
return Err(DescriptorKeyParseError("Master fingerprint should be 8 characters long"));
956+
return Err(DescriptorKeyParseError::MalformedKeyData(
957+
MalformedKeyDataKind::InvalidMasterFingerprintLength,
958+
));
823959
}
824-
let parent_fingerprint = bip32::Fingerprint::from_hex(origin_id_hex).map_err(|_| {
825-
DescriptorKeyParseError("Malformed master fingerprint, expected 8 hex chars")
960+
let parent_fingerprint = bip32::Fingerprint::from_hex(origin_id_hex).map_err(|err| {
961+
DescriptorKeyParseError::MasterFingerprint {
962+
fingerprint: origin_id_hex.to_owned(),
963+
err,
964+
}
826965
})?;
827966
let origin_path = raw_origin
828967
.map(bip32::ChildNumber::from_str)
829968
.collect::<Result<bip32::DerivationPath, bip32::Error>>()
830-
.map_err(|_| DescriptorKeyParseError("Error while parsing master derivation path"))?;
969+
.map_err(DescriptorKeyParseError::MasterDerivationPath)?;
831970

832971
let key = parts
833972
.next()
834-
.ok_or(DescriptorKeyParseError("No key after origin."))?;
973+
.ok_or(DescriptorKeyParseError::MalformedKeyData(
974+
MalformedKeyDataKind::NoKeyAfterOrigin,
975+
))?;
835976

836977
if parts.next().is_some() {
837-
Err(DescriptorKeyParseError("Multiple ']' in Descriptor Public Key"))
978+
Err(DescriptorKeyParseError::MalformedKeyData(
979+
MalformedKeyDataKind::MultipleFingerprintsInPublicKey,
980+
))
838981
} else {
839982
Ok((key, Some((parent_fingerprint, origin_path))))
840983
}
@@ -843,16 +986,26 @@ fn parse_key_origin(s: &str) -> Result<(&str, Option<bip32::KeySource>), Descrip
843986
}
844987
}
845988

846-
/// Parse an extended key concatenated to a derivation path.
847-
fn parse_xkey_deriv<K: InnerXKey>(
989+
fn parse_bip32_xpub(xkey_str: &str) -> Result<bip32::Xpub, DescriptorKeyParseError> {
990+
bip32::Xpub::from_str(xkey_str).map_err(DescriptorKeyParseError::Bip32Xpub)
991+
}
992+
993+
fn parse_bip32_xpriv(xkey_str: &str) -> Result<bip32::Xpriv, DescriptorKeyParseError> {
994+
bip32::Xpriv::from_str(xkey_str).map_err(DescriptorKeyParseError::Bip32Xpriv)
995+
}
996+
997+
fn parse_xkey_deriv<Key>(
998+
parse_xkey_fn: impl Fn(&str) -> Result<Key, DescriptorKeyParseError>,
848999
key_deriv: &str,
849-
) -> Result<(K, Vec<bip32::DerivationPath>, Wildcard), DescriptorKeyParseError> {
1000+
) -> Result<(Key, Vec<bip32::DerivationPath>, Wildcard), DescriptorKeyParseError> {
8501001
let mut key_deriv = key_deriv.split('/');
8511002
let xkey_str = key_deriv
8521003
.next()
853-
.ok_or(DescriptorKeyParseError("No key found after origin description"))?;
854-
let xkey =
855-
K::from_str(xkey_str).map_err(|_| DescriptorKeyParseError("Error while parsing xkey."))?;
1004+
.ok_or(DescriptorKeyParseError::MalformedKeyData(
1005+
MalformedKeyDataKind::NoKeyAfterOrigin,
1006+
))?;
1007+
1008+
let xkey = parse_xkey_fn(xkey_str)?;
8561009

8571010
let mut wildcard = Wildcard::None;
8581011
let mut multipath = false;
@@ -865,26 +1018,26 @@ fn parse_xkey_deriv<K: InnerXKey>(
8651018
wildcard = Wildcard::Hardened;
8661019
None
8671020
} else if wildcard != Wildcard::None {
868-
Some(Err(DescriptorKeyParseError(
869-
"'*' may only appear as last element in a derivation path.",
1021+
Some(Err(DescriptorKeyParseError::MalformedKeyData(
1022+
MalformedKeyDataKind::InvalidWildcardInDerivationPath,
8701023
)))
8711024
} else {
8721025
// BIP389 defines a new step in the derivation path. This step contains two or more
8731026
// derivation indexes in the form '<1;2;3';4h;5H;6>'.
8741027
if p.starts_with('<') && p.ends_with('>') {
8751028
// There may only be one occurence of this step.
8761029
if multipath {
877-
return Some(Err(DescriptorKeyParseError(
878-
"'<' may only appear once in a derivation path.",
1030+
return Some(Err(DescriptorKeyParseError::MalformedKeyData(
1031+
MalformedKeyDataKind::MultipleDerivationPathIndexSteps,
8791032
)));
8801033
}
8811034
multipath = true;
8821035

8831036
// The step must contain at least two derivation indexes.
8841037
// So it's at least '<' + a number + ';' + a number + '>'.
8851038
if p.len() < 5 || !p.contains(';') {
886-
return Some(Err(DescriptorKeyParseError(
887-
"Invalid multi index step in multipath descriptor.",
1039+
return Some(Err(DescriptorKeyParseError::MalformedKeyData(
1040+
MalformedKeyDataKind::InvalidMultiIndexStep,
8881041
)));
8891042
}
8901043

@@ -894,10 +1047,11 @@ fn parse_xkey_deriv<K: InnerXKey>(
8941047
indexes
8951048
.into_iter()
8961049
.map(|s| {
897-
bip32::ChildNumber::from_str(s).map_err(|_| {
898-
DescriptorKeyParseError(
899-
"Error while parsing index in key derivation path.",
900-
)
1050+
bip32::ChildNumber::from_str(s).map_err(|err| {
1051+
DescriptorKeyParseError::DerivationIndexError {
1052+
index: s.to_owned(),
1053+
err,
1054+
}
9011055
})
9021056
})
9031057
.collect::<Result<Vec<bip32::ChildNumber>, _>>(),
@@ -907,8 +1061,9 @@ fn parse_xkey_deriv<K: InnerXKey>(
9071061
Some(
9081062
bip32::ChildNumber::from_str(p)
9091063
.map(|i| vec![i])
910-
.map_err(|_| {
911-
DescriptorKeyParseError("Error while parsing key derivation path")
1064+
.map_err(|err| DescriptorKeyParseError::DerivationIndexError {
1065+
index: p.to_owned(),
1066+
err,
9121067
}),
9131068
)
9141069
}
@@ -1139,8 +1294,8 @@ impl FromStr for DefiniteDescriptorKey {
11391294

11401295
fn from_str(s: &str) -> Result<Self, Self::Err> {
11411296
let inner = DescriptorPublicKey::from_str(s)?;
1142-
DefiniteDescriptorKey::new(inner).ok_or(DescriptorKeyParseError(
1143-
"cannot parse key with a wilcard as a DerivedDescriptorKey",
1297+
DefiniteDescriptorKey::new(inner).ok_or(DescriptorKeyParseError::MalformedKeyData(
1298+
MalformedKeyDataKind::WildcardAsDerivedDescriptorKey,
11441299
))
11451300
}
11461301
}
@@ -1215,8 +1370,7 @@ mod test {
12151370
use serde_test::{assert_tokens, Token};
12161371

12171372
use super::{
1218-
DescriptorKeyParseError, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey,
1219-
MiniscriptKey, Wildcard,
1373+
DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, MiniscriptKey, Wildcard,
12201374
};
12211375
use crate::prelude::*;
12221376

@@ -1225,52 +1379,50 @@ mod test {
12251379
// And ones with misplaced wildcard
12261380
let desc = "[78412e3a/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*/44";
12271381
assert_eq!(
1228-
DescriptorPublicKey::from_str(desc),
1229-
Err(DescriptorKeyParseError(
1230-
"\'*\' may only appear as last element in a derivation path."
1231-
))
1382+
DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1383+
"\'*\' may only appear as last element in a derivation path"
12321384
);
12331385

12341386
// And ones with invalid fingerprints
12351387
let desc = "[NonHexor]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*";
12361388
assert_eq!(
1237-
DescriptorPublicKey::from_str(desc),
1238-
Err(DescriptorKeyParseError("Malformed master fingerprint, expected 8 hex chars"))
1389+
DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1390+
"error while parsing master fingerprint 'NonHexor': failed to parse hex digit"
12391391
);
12401392

12411393
// And ones with invalid xpubs..
12421394
let desc = "[78412e3a]xpub1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaLcgJvLJuZZvRcEL/1/*";
12431395
assert_eq!(
1244-
DescriptorPublicKey::from_str(desc),
1245-
Err(DescriptorKeyParseError("Error while parsing xkey."))
1396+
DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1397+
"error while parsing BIP32 Xpub: base58 encoding error"
12461398
);
12471399

12481400
// ..or invalid raw keys
12491401
let desc = "[78412e3a]0208a117f3897c3a13c9384b8695eed98dc31bc2500feb19a1af424cd47a5d83/1/*";
12501402
assert_eq!(
1251-
DescriptorPublicKey::from_str(desc),
1252-
Err(DescriptorKeyParseError("Public keys must be 64/66/130 characters in size"))
1403+
DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1404+
"public keys must be 64, 66 or 130 characters in size",
12531405
);
12541406

12551407
// ..or invalid separators
12561408
let desc = "[78412e3a]]03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8";
12571409
assert_eq!(
1258-
DescriptorPublicKey::from_str(desc),
1259-
Err(DescriptorKeyParseError("Multiple \']\' in Descriptor Public Key"))
1410+
DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1411+
"multiple \']\' in Descriptor Public Key"
12601412
);
12611413

12621414
// fuzzer errors
12631415
let desc = "[11111f11]033333333333333333333333333333323333333333333333333333333433333333]]333]]3]]101333333333333433333]]]10]333333mmmm";
12641416
assert_eq!(
1265-
DescriptorPublicKey::from_str(desc),
1266-
Err(DescriptorKeyParseError("Multiple \']\' in Descriptor Public Key"))
1417+
DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1418+
"multiple \']\' in Descriptor Public Key"
12671419
);
12681420

12691421
// fuzz failure, hybrid keys
12701422
let desc = "0777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777";
12711423
assert_eq!(
1272-
DescriptorPublicKey::from_str(desc),
1273-
Err(DescriptorKeyParseError("Only publickeys with prefixes 02/03/04 are allowed"))
1424+
DescriptorPublicKey::from_str(desc).unwrap_err().to_string(),
1425+
"only full public keys with prefixes '02', '03' or '04' are allowed"
12741426
);
12751427
}
12761428

@@ -1279,22 +1431,24 @@ mod test {
12791431
// Xpubs are invalid
12801432
let secret_key = "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL";
12811433
assert_eq!(
1282-
DescriptorSecretKey::from_str(secret_key),
1283-
Err(DescriptorKeyParseError("Error while parsing xkey."))
1434+
DescriptorSecretKey::from_str(secret_key)
1435+
.unwrap_err()
1436+
.to_string(),
1437+
"error while parsing BIP32 Xpriv: unknown version magic bytes: [4, 136, 178, 30]"
12841438
);
12851439

12861440
// And ones with invalid fingerprints
12871441
let desc = "[NonHexor]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/*";
12881442
assert_eq!(
1289-
DescriptorSecretKey::from_str(desc),
1290-
Err(DescriptorKeyParseError("Malformed master fingerprint, expected 8 hex chars"))
1443+
DescriptorSecretKey::from_str(desc).unwrap_err().to_string(),
1444+
"error while parsing master fingerprint 'NonHexor': failed to parse hex digit"
12911445
);
12921446

12931447
// ..or invalid raw keys
12941448
let desc = "[78412e3a]L32jTfVLei6BYTPUpwpJSkrHx8iL9GZzeErVS8y4Y/1/*";
12951449
assert_eq!(
1296-
DescriptorSecretKey::from_str(desc),
1297-
Err(DescriptorKeyParseError("Error while parsing a WIF private key"))
1450+
DescriptorSecretKey::from_str(desc).unwrap_err().to_string(),
1451+
"error while parsing WIF private key: invalid base58"
12981452
);
12991453
}
13001454

‎src/descriptor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ mod key;
5050
pub use self::key::{
5151
ConversionError, DefiniteDescriptorKey, DerivPaths, DescriptorKeyParseError,
5252
DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey, InnerXKey,
53-
SinglePriv, SinglePub, SinglePubKey, Wildcard,
53+
MalformedKeyDataKind, SinglePriv, SinglePub, SinglePubKey, Wildcard,
5454
};
5555

5656
/// Alias type for a map of public key to secret key

0 commit comments

Comments
 (0)
Please sign in to comment.