// SPDX-License-Identifier: CC0-1.0 //! Consensus encoding errors. use core::fmt; use hex::error::{InvalidCharError, OddLengthStringError}; use hex::DisplayHex as _; use internals::write_err; #[cfg(doc)] use super::IterReader; /// Error deserializing from a slice. #[derive(Debug, PartialEq, Eq)] #[non_exhaustive] pub enum DeserializeError { /// Error parsing encoded object. Parse(ParseError), /// Data unconsumed error. Unconsumed, } internals::impl_from_infallible!(DeserializeError); impl fmt::Display for DeserializeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use DeserializeError::*; match *self { Parse(ref e) => write_err!(f, "error parsing encoded object"; e), Unconsumed => write!(f, "data not consumed entirely when deserializing"), } } } #[cfg(feature = "std")] impl std::error::Error for DeserializeError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { use DeserializeError::*; match *self { Parse(ref e) => Some(e), Unconsumed => None, } } } impl From for DeserializeError { fn from(e: ParseError) -> Self { Self::Parse(e) } } /// Error when consensus decoding from an `[IterReader]`. /// /// This is the same as a `DeserializeError` with an additional variant to return any error yealded /// by the inner bytes iterator. #[derive(Debug)] pub enum DecodeError { /// Invalid consensus encoding. Parse(ParseError), /// Data unconsumed error. Unconsumed, /// Other decoding error. Other(E), // Yielded by the inner iterator. } internals::impl_from_infallible!(DecodeError); impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use DecodeError::*; match *self { Parse(ref e) => write_err!(f, "error parsing encoded object"; e), Unconsumed => write!(f, "data not consumed entirely when deserializing"), Other(ref other) => write!(f, "other decoding error: {:?}", other), } } } #[cfg(feature = "std")] impl std::error::Error for DecodeError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { use DecodeError::*; match *self { Parse(ref e) => Some(e), Unconsumed => None, Other(ref e) => Some(e), } } } /// Encoding error. #[derive(Debug)] #[non_exhaustive] pub enum Error { /// And I/O error. Io(io::Error), /// Error parsing encoded object. Parse(ParseError), } internals::impl_from_infallible!(Error); impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use Error::*; match *self { Io(ref e) => write_err!(f, "IO error"; e), Parse(ref e) => write_err!(f, "error parsing encoded object"; e), } } } #[cfg(feature = "std")] impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { use Error::*; match *self { Io(ref e) => Some(e), Parse(ref e) => Some(e), } } } impl From for Error { fn from(e: io::Error) -> Self { use io::ErrorKind; match e.kind() { ErrorKind::UnexpectedEof => Error::Parse(ParseError::MissingData), _ => Error::Io(e), } } } impl From for Error { fn from(e: ParseError) -> Self { Error::Parse(e) } } /// Encoding is invalid. #[derive(Debug, PartialEq, Eq)] #[non_exhaustive] pub enum ParseError { /// Missing data (early end of file or slice too short). MissingData, // TODO: Can we add more context? /// Tried to allocate an oversized vector. OversizedVectorAllocation { /// The capacity requested. requested: usize, /// The maximum capacity. max: usize, }, /// Checksum was invalid. InvalidChecksum { /// The expected checksum. expected: [u8; 4], /// The invalid checksum. actual: [u8; 4], }, /// VarInt was encoded in a non-minimal way. NonMinimalVarInt, /// Parsing error. ParseFailed(&'static str), /// Unsupported Segwit flag. UnsupportedSegwitFlag(u8), } internals::impl_from_infallible!(ParseError); impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use ParseError::*; match *self { MissingData => write!(f, "missing data (early end of file or slice too short)"), OversizedVectorAllocation { requested: ref r, max: ref m } => write!(f, "allocation of oversized vector: requested {}, maximum {}", r, m), InvalidChecksum { expected: ref e, actual: ref a } => write!(f, "invalid checksum: expected {:x}, actual {:x}", e.as_hex(), a.as_hex()), NonMinimalVarInt => write!(f, "non-minimal varint"), ParseFailed(ref s) => write!(f, "parse failed: {}", s), UnsupportedSegwitFlag(ref swflag) => write!(f, "unsupported segwit version: {}", swflag), } } } #[cfg(feature = "std")] impl std::error::Error for ParseError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { use ParseError::*; match self { MissingData | OversizedVectorAllocation { .. } | InvalidChecksum { .. } | NonMinimalVarInt | ParseFailed(_) | UnsupportedSegwitFlag(_) => None, } } } /// Hex deserialization error. #[derive(Debug)] pub enum FromHexError { /// Purported hex string had odd length. OddLengthString(OddLengthStringError), /// Decoding error. Decode(DecodeError), } impl fmt::Display for FromHexError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use FromHexError::*; match *self { OddLengthString(ref e) => write_err!(f, "odd length, failed to create bytes from hex"; e), Decode(ref e) => write_err!(f, "decoding error"; e), } } } #[cfg(feature = "std")] impl std::error::Error for FromHexError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { use FromHexError::*; match *self { OddLengthString(ref e) => Some(e), Decode(ref e) => Some(e), } } } impl From for FromHexError { #[inline] fn from(e: OddLengthStringError) -> Self { Self::OddLengthString(e) } } /// Constructs a new `Error::ParseFailed` error. // This whole variant should go away because of the inner string. pub(crate) fn parse_failed_error(msg: &'static str) -> Error { Error::Parse(ParseError::ParseFailed(msg)) }