Hide base58::Error internals
As is convention here in `rust-bitcoin`, hide the `base58::Error` internals by adding struct error types.
This commit is contained in:
parent
4f68e79da0
commit
af49841433
|
@ -6,16 +6,16 @@ use core::fmt;
|
||||||
|
|
||||||
use internals::write_err;
|
use internals::write_err;
|
||||||
|
|
||||||
/// An error that might occur during base58 decoding.
|
/// An error occurred during base58 decoding (with checksum).
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Invalid character while decoding.
|
/// Invalid character while decoding.
|
||||||
Decode(InvalidCharacterError),
|
Decode(InvalidCharacterError),
|
||||||
/// Checksum was not correct (expected, actual).
|
/// Checksum was not correct.
|
||||||
BadChecksum(u32, u32),
|
IncorrectChecksum(IncorrectChecksumError),
|
||||||
/// Checked data was less than 4 bytes.
|
/// Checked data was too short.
|
||||||
TooShort(usize),
|
TooShort(TooShortError),
|
||||||
}
|
}
|
||||||
|
|
||||||
internals::impl_from_infallible!(Error);
|
internals::impl_from_infallible!(Error);
|
||||||
|
@ -26,9 +26,8 @@ impl fmt::Display for Error {
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Decode(ref e) => write_err!(f, "decode"; e),
|
Decode(ref e) => write_err!(f, "decode"; e),
|
||||||
BadChecksum(exp, actual) =>
|
IncorrectChecksum(ref e) => write_err!(f, "incorrect checksum"; e),
|
||||||
write!(f, "base58ck checksum {:#x} does not match expected {:#x}", actual, exp),
|
TooShort(ref e) => write_err!(f, "too short"; e),
|
||||||
TooShort(_) => write!(f, "base58ck data not even long enough for a checksum"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,10 +37,10 @@ impl std::error::Error for Error {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
use Error::*;
|
use Error::*;
|
||||||
|
|
||||||
match self {
|
match *self {
|
||||||
Decode(ref e) => Some(e),
|
Decode(ref e) => Some(e),
|
||||||
BadChecksum(_, _)
|
IncorrectChecksum(ref e) => Some(e),
|
||||||
| TooShort(_) => None,
|
TooShort(ref e) => Some(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +50,64 @@ impl From<InvalidCharacterError> for Error {
|
||||||
fn from(e: InvalidCharacterError) -> Self { Self::Decode(e) }
|
fn from(e: InvalidCharacterError) -> Self { Self::Decode(e) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<IncorrectChecksumError> for Error {
|
||||||
|
#[inline]
|
||||||
|
fn from(e: IncorrectChecksumError) -> Self { Self::IncorrectChecksum(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TooShortError> for Error {
|
||||||
|
#[inline]
|
||||||
|
fn from(e: TooShortError) -> Self { Self::TooShort(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checksum was not correct.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct IncorrectChecksumError {
|
||||||
|
/// The incorrect checksum.
|
||||||
|
pub(super) incorrect: u32,
|
||||||
|
/// The expected checksum.
|
||||||
|
pub(super) expected: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IncorrectChecksumError {
|
||||||
|
/// Returns the incorrect checksum along with the expected checksum.
|
||||||
|
pub fn incorrect_checksum(&self) -> (u32, u32) { (self.incorrect, self.expected) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for IncorrectChecksumError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"base58 checksum {:#x} does not match expected {:#x}",
|
||||||
|
self.incorrect, self.expected
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for IncorrectChecksumError {}
|
||||||
|
|
||||||
|
/// The decode base58 data was too short (require at least 4 bytes for checksum).
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct TooShortError {
|
||||||
|
/// The length of the decoded data.
|
||||||
|
pub(super) length: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TooShortError {
|
||||||
|
/// Returns the invalid base58 string length (require at least 4 bytes for checksum).
|
||||||
|
pub fn invalid_base58_length(&self) -> usize { self.length }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TooShortError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "base58 decoded data was not long enough, must be at least 4 byte: {}", self.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for TooShortError {}
|
||||||
|
|
||||||
/// Found a invalid ASCII byte while decoding base58 string.
|
/// Found a invalid ASCII byte while decoding base58 string.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct InvalidCharacterError {
|
pub struct InvalidCharacterError {
|
||||||
|
|
|
@ -34,6 +34,8 @@ pub use std::{string::String, vec::Vec};
|
||||||
|
|
||||||
use hashes::{sha256d, Hash};
|
use hashes::{sha256d, Hash};
|
||||||
|
|
||||||
|
use crate::error::{IncorrectChecksumError, TooShortError};
|
||||||
|
|
||||||
#[rustfmt::skip] // Keep public re-exports separate.
|
#[rustfmt::skip] // Keep public re-exports separate.
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use self::error::{Error, InvalidCharacterError};
|
pub use self::error::{Error, InvalidCharacterError};
|
||||||
|
@ -93,7 +95,7 @@ pub fn decode(data: &str) -> Result<Vec<u8>, InvalidCharacterError> {
|
||||||
pub fn decode_check(data: &str) -> Result<Vec<u8>, Error> {
|
pub fn decode_check(data: &str) -> Result<Vec<u8>, Error> {
|
||||||
let mut ret: Vec<u8> = decode(data)?;
|
let mut ret: Vec<u8> = decode(data)?;
|
||||||
if ret.len() < 4 {
|
if ret.len() < 4 {
|
||||||
return Err(Error::TooShort(ret.len()));
|
return Err(TooShortError { length: ret.len() }.into());
|
||||||
}
|
}
|
||||||
let check_start = ret.len() - 4;
|
let check_start = ret.len() - 4;
|
||||||
|
|
||||||
|
@ -104,8 +106,8 @@ pub fn decode_check(data: &str) -> Result<Vec<u8>, Error> {
|
||||||
let expected = u32::from_le_bytes(hash_check);
|
let expected = u32::from_le_bytes(hash_check);
|
||||||
let actual = u32::from_le_bytes(data_check);
|
let actual = u32::from_le_bytes(data_check);
|
||||||
|
|
||||||
if expected != actual {
|
if actual != expected {
|
||||||
return Err(Error::BadChecksum(expected, actual));
|
return Err(IncorrectChecksumError { incorrect: actual, expected }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.truncate(check_start);
|
ret.truncate(check_start);
|
||||||
|
@ -282,6 +284,6 @@ mod tests {
|
||||||
// Check that empty slice passes roundtrip.
|
// Check that empty slice passes roundtrip.
|
||||||
assert_eq!(decode_check(&encode_check(&[])), Ok(vec![]));
|
assert_eq!(decode_check(&encode_check(&[])), Ok(vec![]));
|
||||||
// Check that `len > 4` is enforced.
|
// Check that `len > 4` is enforced.
|
||||||
assert_eq!(decode_check(&encode(&[1, 2, 3])), Err(Error::TooShort(3)));
|
assert_eq!(decode_check(&encode(&[1, 2, 3])), Err(TooShortError { length: 3 }.into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue