Skip to main content

dig_urn_resolver/
error.rs

1//! The resolver's error taxonomy.
2//!
3//! Two failure classes are deliberately kept apart (see the module docs on
4//! [`crate::resolver`]):
5//!
6//! * **Hard, fail-closed errors** — [`ResolveError`] — a malformed URN, a
7//!   not-found resource, or a verify/decrypt failure. A verify failure means the
8//!   served bytes did not chain to the trusted on-chain root (tampered / decoy):
9//!   the resolver NEVER returns those bytes, it fails closed.
10//! * **The network-unreachable state** — NOT an error. When every transport tier
11//!   is unreachable the resolver returns a branded HTML document via
12//!   [`crate::ResolvedData`] with `unreachable == true`, so a consuming webview can
13//!   render a friendly "connect a node" page instead of a crash.
14
15use thiserror::Error;
16
17/// A hard, fail-closed resolution failure. Distinct from the network-unreachable
18/// state, which is a successful [`crate::ResolvedData`] carrying a branded page.
19#[derive(Debug, Error)]
20pub enum ResolveError {
21    /// The input was not a syntactically valid DIG URN.
22    #[error("invalid DIG URN: {0}")]
23    Parse(String),
24
25    /// A transport-level failure talking to a specific endpoint (DNS, TLS,
26    /// connection, timeout, malformed HTTP). Not the same as "every tier down"
27    /// (that is the unreachable state), nor a not-found (that is [`Self::NotFound`]).
28    #[error("transport error: {0}")]
29    Transport(String),
30
31    /// The RPC endpoint returned a JSON-RPC / protocol error, or a malformed
32    /// response the resolver cannot interpret.
33    #[error("rpc error: {0}")]
34    Rpc(String),
35
36    /// The resource does not exist in the store at the resolved root. A hard,
37    /// fail-closed verdict — never masked behind a friendly page.
38    #[error("resource not found")]
39    NotFound,
40
41    /// A rootless URN was resolved over the untrusted rpc tier, where the trust root
42    /// cannot be established without trusting the gateway. Pin a root in the URN
43    /// (`urn:dig:chia:<store>:<root>/<path>`), or resolve via a loopback node. A
44    /// hard, fail-closed error — the resolver will not verify against a
45    /// gateway-asserted root.
46    #[error("a root-pinned URN is required to resolve over the public gateway (rootless URNs are not chain-verified there)")]
47    RootRequired,
48
49    /// The served ciphertext failed integrity verification against the
50    /// chain-anchored root (tampered bytes, a non-chaining proof, or a decoy from
51    /// a wrong store). FAIL-CLOSED: the bytes are discarded, never returned.
52    #[error("inclusion verification failed: {0}")]
53    VerifyFailed(String),
54
55    /// The verified ciphertext did not decrypt under the URN's key (AES-256-GCM-SIV
56    /// tag failure — wrong key/salt or corruption). FAIL-CLOSED.
57    #[error("decryption failed (wrong key/salt or corrupt ciphertext)")]
58    DecryptFailed,
59}
60
61/// Result alias for resolver operations.
62pub type Result<T> = core::result::Result<T, ResolveError>;