Move consensus error code to submodule

The `consensus` module has a bunch of error types, move them all to a
separate module. Add re-exports so the types are still available at the
same place they were. Make the `error` module private and re-export all
errors from the `consensus` module root.
This commit is contained in:
Tobin C. Harding 2024-10-18 09:55:00 +11:00
parent 8de5432de9
commit a6254212dc
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
3 changed files with 167 additions and 150 deletions

View File

@ -14,132 +14,29 @@
//! scripts come with an opcode decode, hashes are big-endian, numbers are //! scripts come with an opcode decode, hashes are big-endian, numbers are
//! typically big-endian decimals, etc.) //! typically big-endian decimals, etc.)
use core::{fmt, mem}; use core::mem;
use hashes::{sha256, sha256d, GeneralHash, Hash}; use hashes::{sha256, sha256d, GeneralHash, Hash};
use hex::error::{InvalidCharError, OddLengthStringError}; use hex::DisplayHex as _;
use internals::{compact_size, write_err, ToU64}; use internals::{compact_size, ToU64};
use io::{BufRead, Cursor, Read, Write}; use io::{BufRead, Cursor, Read, Write};
use super::IterReader;
use crate::bip152::{PrefilledTransaction, ShortId}; use crate::bip152::{PrefilledTransaction, ShortId};
use crate::bip158::{FilterHash, FilterHeader}; use crate::bip158::{FilterHash, FilterHeader};
use crate::block::{self, BlockHash}; use crate::block::{self, BlockHash};
use crate::consensus::{DecodeError, IterReader};
use crate::merkle_tree::TxMerkleNode; use crate::merkle_tree::TxMerkleNode;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::p2p::{ use crate::p2p::{
address::{AddrV2Message, Address}, address::{AddrV2Message, Address},
message_blockdata::Inventory, message_blockdata::Inventory,
}; };
use crate::prelude::{rc, sync, Box, Cow, DisplayHex, String, Vec}; use crate::prelude::{rc, sync, Box, Cow, String, Vec};
use crate::taproot::TapLeafHash; use crate::taproot::TapLeafHash;
use crate::transaction::{Transaction, TxIn, TxOut}; use crate::transaction::{Transaction, TxIn, TxOut};
/// Encoding error. #[rustfmt::skip] // Keep public re-exports separate.
#[derive(Debug)] pub use super::{Error, FromHexError};
#[non_exhaustive]
pub enum Error {
/// And I/O error.
Io(io::Error),
/// 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!(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),
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 Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use Error::*;
match self {
Io(e) => Some(e),
OversizedVectorAllocation { .. }
| InvalidChecksum { .. }
| NonMinimalVarInt
| ParseFailed(_)
| UnsupportedSegwitFlag(_) => None,
}
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self { Error::Io(error) }
}
/// Hex deserialization error.
#[derive(Debug)]
pub enum FromHexError {
/// Purported hex string had odd length.
OddLengthString(OddLengthStringError),
/// Decoding error.
Decode(DecodeError<InvalidCharError>),
}
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<OddLengthStringError> for FromHexError {
#[inline]
fn from(e: OddLengthStringError) -> Self { Self::OddLengthString(e) }
}
/// Encodes an object into a vector. /// Encodes an object into a vector.
pub fn serialize<T: Encodable + ?Sized>(data: &T) -> Vec<u8> { pub fn serialize<T: Encodable + ?Sized>(data: &T) -> Vec<u8> {
@ -859,6 +756,7 @@ impl Decodable for TapLeafHash {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use core::fmt;
use core::mem::discriminant; use core::mem::discriminant;
use super::*; use super::*;

View File

@ -0,0 +1,157 @@
// 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 when consensus decoding from an `[IterReader]`.
#[derive(Debug)]
pub enum DecodeError<E> {
/// Attempted to decode an object from an iterator that yielded too many bytes.
TooManyBytes,
/// Invalid consensus encoding.
Consensus(Error),
/// Other decoding error.
Other(E),
}
internals::impl_from_infallible!(DecodeError<E>);
impl<E: fmt::Debug> fmt::Display for DecodeError<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use DecodeError::*;
match *self {
TooManyBytes =>
write!(f, "attempted to decode object from an iterator that yielded too many bytes"),
Consensus(ref e) => write_err!(f, "invalid consensus encoding"; e),
Other(ref other) => write!(f, "other decoding error: {:?}", other),
}
}
}
#[cfg(feature = "std")]
impl<E: fmt::Debug> std::error::Error for DecodeError<E> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use DecodeError::*;
match *self {
TooManyBytes => None,
Consensus(ref e) => Some(e),
Other(_) => None, // TODO: Is this correct?
}
}
}
/// Encoding error.
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
/// And I/O error.
Io(io::Error),
/// 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!(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),
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 Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use Error::*;
match self {
Io(e) => Some(e),
OversizedVectorAllocation { .. }
| InvalidChecksum { .. }
| NonMinimalVarInt
| ParseFailed(_)
| UnsupportedSegwitFlag(_) => None,
}
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self { Error::Io(error) }
}
/// Hex deserialization error.
#[derive(Debug)]
pub enum FromHexError {
/// Purported hex string had odd length.
OddLengthString(OddLengthStringError),
/// Decoding error.
Decode(DecodeError<InvalidCharError>),
}
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<OddLengthStringError> for FromHexError {
#[inline]
fn from(e: OddLengthStringError) -> Self { Self::OddLengthString(e) }
}

View File

@ -6,12 +6,12 @@
//! conform to Bitcoin consensus. //! conform to Bitcoin consensus.
pub mod encode; pub mod encode;
mod error;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
pub mod serde; pub mod serde;
use core::fmt; use core::fmt;
use internals::write_err;
use io::{BufRead, Read}; use io::{BufRead, Read};
use crate::consensus; use crate::consensus;
@ -20,6 +20,7 @@ use crate::consensus;
#[doc(inline)] #[doc(inline)]
pub use self::{ pub use self::{
encode::{deserialize, deserialize_partial, serialize, Decodable, Encodable, ReadExt, WriteExt}, encode::{deserialize, deserialize_partial, serialize, Decodable, Encodable, ReadExt, WriteExt},
error::{Error, FromHexError, DecodeError},
}; };
struct IterReader<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> { struct IterReader<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> {
@ -102,42 +103,3 @@ impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> BufRead for IterReader<E,
} }
} }
} }
/// Error when consensus decoding from an `[IterReader]`.
#[derive(Debug)]
pub enum DecodeError<E> {
/// Attempted to decode an object from an iterator that yielded too many bytes.
TooManyBytes,
/// Invalid consensus encoding.
Consensus(consensus::encode::Error),
/// Other decoding error.
Other(E),
}
internals::impl_from_infallible!(DecodeError<E>);
impl<E: fmt::Debug> fmt::Display for DecodeError<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use DecodeError::*;
match *self {
TooManyBytes =>
write!(f, "attempted to decode object from an iterator that yielded too many bytes"),
Consensus(ref e) => write_err!(f, "invalid consensus encoding"; e),
Other(ref other) => write!(f, "other decoding error: {:?}", other),
}
}
}
#[cfg(feature = "std")]
impl<E: fmt::Debug> std::error::Error for DecodeError<E> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use DecodeError::*;
match *self {
TooManyBytes => None,
Consensus(ref e) => Some(e),
Other(_) => None, // TODO: Is this correct?
}
}
}