Skip to main content

sidestr_header/
error.rs

1//! The one error type, for decoding and proof-of-work checks.
2
3use crate::HeaderFamily;
4use core::fmt;
5
6/// Why a header could not be decoded or does not satisfy a rule.
7///
8/// Each variant names the upstream rule it stands in for, so a rejection can
9/// be traced to the reference: the codec's length check
10/// (`codec/codec.js` `decode`, "trailing bytes after BlockHeader"), the
11/// header-family selection on version bit 31 (`siding/lib/parents.mjs`,
12/// SPEC 3.2), Bitcoin Core's `arith_uint256::SetCompact` overflow and negative
13/// cases, and siding's `pow` rule (SPEC 4 step 1).
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[non_exhaustive]
16pub enum Error {
17    /// The byte slice is not the family's wire size (80 or 164).
18    WrongLength {
19        /// The family the bytes were decoded as.
20        family: HeaderFamily,
21        /// That family's wire size.
22        expected: usize,
23        /// The length actually supplied.
24        actual: usize,
25    },
26    /// A stock header's version has bit 31 set. Beside a stock parent the
27    /// producer keeps it clear (`siding/lib/block.mjs` `buildBlock`,
28    /// `test/stock-header-test.mjs` "version keeps bit 31 clear"); on a
29    /// BLAKE2b-family chain the same bit would select the v2 layout, so a
30    /// stock header carrying it is not a header of either family.
31    VersionBit31Set,
32    /// A v2 header's version has bit 31 clear: the bytes are not a v2 header
33    /// (`isHeaderV2` in `codec/pow/knots-header-v2.js`).
34    VersionBit31Clear,
35    /// A v2 header's `flags` has a reserved bit (6 or 7) set
36    /// (`knots:rule-header-flags-reserved`, error code `bad-flags-highbits`).
37    ReservedFlags(u8),
38    /// A hex string was not 64 hex characters.
39    InvalidHex,
40    /// Compact `bits` with the sign bit set and a non-zero mantissa
41    /// (Core's `fNegative`).
42    CompactNegative(u32),
43    /// Compact `bits` whose mantissa would not fit in 256 bits
44    /// (Core's `fOverflow`).
45    CompactOverflow(u32),
46    /// The header's `bits` is not the compact encoding of the chain's
47    /// `powLimit`. Siding sets every block's bits to that value
48    /// (`siding/lib/chain.mjs`: `compactFromTarget(powLimit)`) and the
49    /// kernel's difficulty rule holds it there (`powNoRetargeting`).
50    BitsNotPowLimit {
51        /// The header's `bits`.
52        bits: u32,
53        /// `powLimit` in compact form.
54        expected: u32,
55    },
56    /// The block hash, read as a 256-bit number, exceeds the target `bits`
57    /// encodes (`btc:rule-header-pow`; SPEC 4 step 1).
58    TargetNotMet,
59}
60
61impl fmt::Display for Error {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        match self {
64            Error::WrongLength {
65                family,
66                expected,
67                actual,
68            } => write!(f, "a {family} header is {expected} bytes, got {actual}"),
69            Error::VersionBit31Set => f.write_str("stock header version has bit 31 set"),
70            Error::VersionBit31Clear => f.write_str("v2 header version has bit 31 clear"),
71            Error::ReservedFlags(flags) => {
72                write!(
73                    f,
74                    "v2 header flags {flags:#04x} set a reserved bit (6 or 7)"
75                )
76            }
77            Error::InvalidHex => f.write_str("expected 64 hex characters"),
78            Error::CompactNegative(bits) => write!(f, "compact target {bits:#010x} is negative"),
79            Error::CompactOverflow(bits) => {
80                write!(f, "compact target {bits:#010x} overflows 256 bits")
81            }
82            Error::BitsNotPowLimit { bits, expected } => write!(
83                f,
84                "header bits {bits:#010x} are not the chain's powLimit {expected:#010x}"
85            ),
86            Error::TargetNotMet => f.write_str("block hash does not meet the target"),
87        }
88    }
89}
90
91#[cfg(feature = "std")]
92impl std::error::Error for Error {}