base58: Add InvalidCharacterError for decoding
The `base58::decode` function can only return a single error type, add a `InvalidCharacterError` struct (leaf error) to use as the return type.
This commit is contained in:
parent
ec8609393b
commit
669d5e8fc6
|
@ -14,7 +14,7 @@ exclude = ["tests", "contrib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["hashes/std"]
|
std = ["hashes/std", "internals/std"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
|
|
@ -4,12 +4,14 @@
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
use internals::write_err;
|
||||||
|
|
||||||
/// An error that might occur during base58 decoding.
|
/// An error that might occur during base58 decoding.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Invalid character encountered.
|
/// Invalid character while decoding.
|
||||||
BadByte(u8),
|
Decode(InvalidCharacterError),
|
||||||
/// Checksum was not correct (expected, actual).
|
/// Checksum was not correct (expected, actual).
|
||||||
BadChecksum(u32, u32),
|
BadChecksum(u32, u32),
|
||||||
/// The length (in bytes) of the object was not correct.
|
/// The length (in bytes) of the object was not correct.
|
||||||
|
@ -32,7 +34,7 @@ impl fmt::Display for Error {
|
||||||
use Error::*;
|
use Error::*;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
BadByte(b) => write!(f, "invalid base58 character {:#x}", b),
|
Decode(ref e) => write_err!(f, "decode"; e),
|
||||||
BadChecksum(exp, actual) =>
|
BadChecksum(exp, actual) =>
|
||||||
write!(f, "base58ck checksum {:#x} does not match expected {:#x}", actual, exp),
|
write!(f, "base58ck checksum {:#x} does not match expected {:#x}", actual, exp),
|
||||||
InvalidLength(ell) => write!(f, "length {} invalid for this base58 type", ell),
|
InvalidLength(ell) => write!(f, "length {} invalid for this base58 type", ell),
|
||||||
|
@ -51,8 +53,8 @@ impl std::error::Error for Error {
|
||||||
use Error::*;
|
use Error::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
BadByte(_)
|
Decode(ref e) => Some(e),
|
||||||
| BadChecksum(_, _)
|
BadChecksum(_, _)
|
||||||
| InvalidLength(_)
|
| InvalidLength(_)
|
||||||
| InvalidExtendedKeyVersion(_)
|
| InvalidExtendedKeyVersion(_)
|
||||||
| InvalidAddressVersion(_)
|
| InvalidAddressVersion(_)
|
||||||
|
@ -60,3 +62,28 @@ impl std::error::Error for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<InvalidCharacterError> for Error {
|
||||||
|
#[inline]
|
||||||
|
fn from(e: InvalidCharacterError) -> Self { Self::Decode(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Found a invalid ASCII byte while decoding base58 string.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct InvalidCharacterError {
|
||||||
|
pub(super) invalid: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InvalidCharacterError {
|
||||||
|
/// Returns the ASCII byte that is not a valid base58 character.
|
||||||
|
pub fn invalid_base58_character(&self) -> u8 { self.invalid }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for InvalidCharacterError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "invalid base58 character {:#x}", self.invalid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for InvalidCharacterError {}
|
||||||
|
|
|
@ -36,7 +36,7 @@ use hashes::{sha256d, Hash};
|
||||||
|
|
||||||
#[rustfmt::skip] // Keep public re-exports separate.
|
#[rustfmt::skip] // Keep public re-exports separate.
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use self::error::Error;
|
pub use self::error::{Error, InvalidCharacterError};
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
static BASE58_DIGITS: [Option<u8>; 128] = [
|
static BASE58_DIGITS: [Option<u8>; 128] = [
|
||||||
|
@ -59,19 +59,19 @@ static BASE58_DIGITS: [Option<u8>; 128] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Decodes a base58-encoded string into a byte vector.
|
/// Decodes a base58-encoded string into a byte vector.
|
||||||
pub fn decode(data: &str) -> Result<Vec<u8>, Error> {
|
pub fn decode(data: &str) -> Result<Vec<u8>, InvalidCharacterError> {
|
||||||
// 11/15 is just over log_256(58)
|
// 11/15 is just over log_256(58)
|
||||||
let mut scratch = vec![0u8; 1 + data.len() * 11 / 15];
|
let mut scratch = vec![0u8; 1 + data.len() * 11 / 15];
|
||||||
// Build in base 256
|
// Build in base 256
|
||||||
for d58 in data.bytes() {
|
for d58 in data.bytes() {
|
||||||
// Compute "X = X * 58 + next_digit" in base 256
|
// Compute "X = X * 58 + next_digit" in base 256
|
||||||
if d58 as usize >= BASE58_DIGITS.len() {
|
if d58 as usize >= BASE58_DIGITS.len() {
|
||||||
return Err(Error::BadByte(d58));
|
return Err(InvalidCharacterError { invalid: d58 });
|
||||||
}
|
}
|
||||||
let mut carry = match BASE58_DIGITS[d58 as usize] {
|
let mut carry = match BASE58_DIGITS[d58 as usize] {
|
||||||
Some(d58) => d58 as u32,
|
Some(d58) => d58 as u32,
|
||||||
None => {
|
None => {
|
||||||
return Err(Error::BadByte(d58));
|
return Err(InvalidCharacterError { invalid: d58 });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for d256 in scratch.iter_mut().rev() {
|
for d256 in scratch.iter_mut().rev() {
|
||||||
|
@ -266,7 +266,10 @@ mod tests {
|
||||||
Some(hex!("00f8917303bfa8ef24f292e8fa1419b20460ba064d"))
|
Some(hex!("00f8917303bfa8ef24f292e8fa1419b20460ba064d"))
|
||||||
);
|
);
|
||||||
// Non Base58 char.
|
// Non Base58 char.
|
||||||
assert_eq!(decode("¢").unwrap_err(), Error::BadByte(194));
|
assert_eq!(
|
||||||
|
decode("¢").unwrap_err(),
|
||||||
|
InvalidCharacterError { invalid: 194 }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -2500,7 +2500,7 @@ mod tests {
|
||||||
|
|
||||||
use super::ParseAmountError as E;
|
use super::ParseAmountError as E;
|
||||||
|
|
||||||
assert_eq!(Amount::from_str("x BTC"), Err(E::from(InvalidCharacterError { invalid_char: 'x', position: 0 }).into()));
|
assert_eq!(Amount::from_str("x BTC"), Err(InvalidCharacterError { invalid_char: 'x', position: 0 }.into()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Amount::from_str("xBTC"),
|
Amount::from_str("xBTC"),
|
||||||
Err(Unknown(UnknownDenominationError("xBTC".into())).into()),
|
Err(Unknown(UnknownDenominationError("xBTC".into())).into()),
|
||||||
|
|
Loading…
Reference in New Issue