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]
|
||||
default = ["std"]
|
||||
std = ["hashes/std"]
|
||||
std = ["hashes/std", "internals/std"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
|
||||
use core::fmt;
|
||||
|
||||
use internals::write_err;
|
||||
|
||||
/// An error that might occur during base58 decoding.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
/// Invalid character encountered.
|
||||
BadByte(u8),
|
||||
/// Invalid character while decoding.
|
||||
Decode(InvalidCharacterError),
|
||||
/// Checksum was not correct (expected, actual).
|
||||
BadChecksum(u32, u32),
|
||||
/// The length (in bytes) of the object was not correct.
|
||||
|
@ -32,7 +34,7 @@ impl fmt::Display for Error {
|
|||
use Error::*;
|
||||
|
||||
match *self {
|
||||
BadByte(b) => write!(f, "invalid base58 character {:#x}", b),
|
||||
Decode(ref e) => write_err!(f, "decode"; e),
|
||||
BadChecksum(exp, actual) =>
|
||||
write!(f, "base58ck checksum {:#x} does not match expected {:#x}", actual, exp),
|
||||
InvalidLength(ell) => write!(f, "length {} invalid for this base58 type", ell),
|
||||
|
@ -51,8 +53,8 @@ impl std::error::Error for Error {
|
|||
use Error::*;
|
||||
|
||||
match self {
|
||||
BadByte(_)
|
||||
| BadChecksum(_, _)
|
||||
Decode(ref e) => Some(e),
|
||||
BadChecksum(_, _)
|
||||
| InvalidLength(_)
|
||||
| InvalidExtendedKeyVersion(_)
|
||||
| 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.
|
||||
#[doc(inline)]
|
||||
pub use self::error::Error;
|
||||
pub use self::error::{Error, InvalidCharacterError};
|
||||
|
||||
#[rustfmt::skip]
|
||||
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.
|
||||
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)
|
||||
let mut scratch = vec![0u8; 1 + data.len() * 11 / 15];
|
||||
// Build in base 256
|
||||
for d58 in data.bytes() {
|
||||
// Compute "X = X * 58 + next_digit" in base 256
|
||||
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] {
|
||||
Some(d58) => d58 as u32,
|
||||
None => {
|
||||
return Err(Error::BadByte(d58));
|
||||
return Err(InvalidCharacterError { invalid: d58 });
|
||||
}
|
||||
};
|
||||
for d256 in scratch.iter_mut().rev() {
|
||||
|
@ -266,7 +266,10 @@ mod tests {
|
|||
Some(hex!("00f8917303bfa8ef24f292e8fa1419b20460ba064d"))
|
||||
);
|
||||
// Non Base58 char.
|
||||
assert_eq!(decode("¢").unwrap_err(), Error::BadByte(194));
|
||||
assert_eq!(
|
||||
decode("¢").unwrap_err(),
|
||||
InvalidCharacterError { invalid: 194 }
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -2500,7 +2500,7 @@ mod tests {
|
|||
|
||||
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!(
|
||||
Amount::from_str("xBTC"),
|
||||
Err(Unknown(UnknownDenominationError("xBTC".into())).into()),
|
||||
|
|
Loading…
Reference in New Issue