Skip to main content

blockchain_zc_parser/
error.rs

1//! Parse error types.
2
3#[cfg(feature = "std")]
4extern crate std;
5
6/// All errors that can occur during parsing.
7#[derive(Debug, Clone, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum ParseError {
10    /// Input ended before the structure was complete.
11    UnexpectedEof {
12        /// How many bytes were needed.
13        needed: usize,
14        /// How many were available.
15        available: usize,
16    },
17    /// A variable-length integer had an invalid encoding.
18    InvalidVarInt,
19    /// A length/value was valid as a u64 but does not fit into the platform usize.
20    IntegerTooLarge {
21        /// The original integer value that could not fit into `usize`.
22        value: u64,
23    },
24    /// A script or data field exceeded the allowed maximum size.
25    OversizedData {
26        /// Actual size that was encountered.
27        size: usize,
28        /// Maximum size allowed by the parser.
29        max: usize,
30    },
31    /// The block / transaction version is not supported by this parser.
32    UnsupportedVersion(i32),
33    /// The magic bytes at the start of a raw block did not match.
34    MagicMismatch {
35        /// The magic bytes this parser was configured to expect.
36        expected: [u8; 4],
37        /// The magic bytes that were actually found in the input.
38        got: [u8; 4],
39    },
40    /// Segwit marker / flag bytes are invalid.
41    InvalidSegwitFlag(
42        /// The invalid flag byte.
43        u8,
44    ),
45    /// Transaction input count was invalid (e.g., zero in legacy format).
46    InvalidInputCount,
47    /// Extra bytes remained after parsing a structure in strict mode.
48    TrailingBytes {
49        /// Number of bytes left unread.
50        remaining: usize,
51    },
52    /// Not all transactions declared in the block were parsed.
53    IncompleteTransactions {
54        /// Number of transactions declared in the block header.
55        expected: usize,
56        /// Number of transactions that were actually parsed.
57        parsed: usize,
58    },
59    /// Coinbase transaction had a non-empty `txid` reference (must be all-zero).
60    InvalidCoinbase,
61    /// A block contained an unexpected number of coinbase transactions.
62    InvalidCoinbaseCount {
63        /// Number of coinbase transactions observed while parsing.
64        count: usize,
65    },
66    /// An underlying I/O error occurred (only available with the `std` feature).
67    #[cfg(feature = "std")]
68    Io {
69        /// Human-readable I/O error message.
70        message: std::string::String,
71    },
72}
73
74impl core::fmt::Display for ParseError {
75    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76        match self {
77            ParseError::UnexpectedEof { needed, available } => write!(
78                f,
79                "unexpected end of input: needed {needed} bytes but only {available} available"
80            ),
81            ParseError::InvalidVarInt => write!(f, "invalid variable-length integer encoding"),
82            ParseError::IntegerTooLarge { value } => {
83                write!(f, "integer too large to fit into usize: {value}")
84            }
85            ParseError::OversizedData { size, max } => {
86                write!(f, "data size {size} exceeds maximum allowed {max}")
87            }
88            ParseError::UnsupportedVersion(v) => {
89                write!(f, "unsupported version: {v}")
90            }
91            ParseError::MagicMismatch { expected, got } => {
92                write!(f, "magic mismatch: expected {expected:02x?} got {got:02x?}")
93            }
94            ParseError::InvalidSegwitFlag(b) => {
95                write!(f, "invalid segwit flag byte: {b:#x}")
96            }
97            ParseError::InvalidInputCount => {
98                write!(f, "invalid transaction input count")
99            }
100            ParseError::TrailingBytes { remaining } => {
101                write!(f, "trailing bytes after parse: {remaining}")
102            }
103            ParseError::IncompleteTransactions { expected, parsed } => {
104                write!(
105                    f,
106                    "incomplete transaction parsing: expected {expected}, parsed {parsed}"
107                )
108            }
109            ParseError::InvalidCoinbase => {
110                write!(f, "coinbase txid reference must be all-zero bytes")
111            }
112            ParseError::InvalidCoinbaseCount { count } => {
113                write!(f, "invalid coinbase tx count in block: {count}")
114            }
115            #[cfg(feature = "std")]
116            ParseError::Io { message } => {
117                write!(f, "io error: {message}")
118            }
119        }
120    }
121}
122
123#[cfg(feature = "std")]
124impl std::error::Error for ParseError {}
125
126/// Convenience alias.
127pub type ParseResult<T> = Result<T, ParseError>;
128
129#[cfg(feature = "std")]
130impl From<std::io::Error> for ParseError {
131    fn from(e: std::io::Error) -> Self {
132        ParseError::Io {
133            message: e.to_string(),
134        }
135    }
136}