Skip to main content

zescrow_core/
error.rs

1//! Error types for `zescrow_core`.
2//!
3//! Provides the following error types:
4//! - [`EscrowError`]: Top-level error for escrow operations
5//! - [`ConditionError`]: Cryptographic condition verification failures
6//! - [`IdentityError`]: Identity parsing and validation errors
7//! - [`AssetError`]: Asset validation and serialization errors
8//! - [`CommitmentError`]: Public-commitment journal encoding/decoding errors
9
10use thiserror::Error;
11
12/// Errors arising from on-chain `Escrow` operations and parameter validation.
13#[derive(Debug, Error)]
14#[non_exhaustive]
15pub enum EscrowError {
16    /// A cryptographic condition failed to verify.
17    #[error("condition error: {0}")]
18    Condition(#[from] ConditionError),
19
20    /// Attempted to transition an `Escrow` in an invalid state.
21    #[error("invalid state transition")]
22    InvalidState,
23
24    /// An identity could not be parsed or validated.
25    #[error("identity error: {0}")]
26    Identity(#[from] IdentityError),
27
28    /// An asset failed parsing, validation, or formatting.
29    #[error("asset error: {0}")]
30    Asset(#[from] AssetError),
31
32    /// Attempted a chain-specific operation on the wrong network
33    /// (e.g., getting Solana PDA on Ethereum).
34    #[error("invalid chain operation: {0}")]
35    InvalidChainOp(String),
36
37    /// An I/O error occurred (e.g., reading or writing JSON files).
38    #[error("I/O error: {0}")]
39    Io(#[from] std::io::Error),
40
41    /// JSON parsing or serialization error.
42    #[cfg(feature = "json")]
43    #[error("JSON error: {0}")]
44    Json(#[from] serde_json::Error),
45
46    /// The specified blockchain network is not supported.
47    #[error("unsupported chain specified")]
48    UnsupportedChain,
49}
50
51/// Errors related to cryptographic condition verification.
52#[derive(Debug, Error)]
53#[non_exhaustive]
54pub enum ConditionError {
55    /// Hashlock error
56    #[error("preimage (hashlock) failed: {0}")]
57    Hashlock(#[from] crate::condition::hashlock::Error),
58
59    /// Ed25519 error
60    #[error("ed25519 signature failed: {0}")]
61    Ed25519(#[from] crate::condition::ed25519::Error),
62
63    /// Secp256k1 error
64    #[error("secp256k1 signature failed: {0}")]
65    Secp256k1(#[from] crate::condition::secp256k1::Error),
66
67    /// Threshold error
68    #[error("threshold check failed: {0}")]
69    Threshold(#[from] crate::condition::threshold::Error),
70}
71
72/// Errors related to identity parsing and validation.
73#[derive(Debug, Error)]
74#[non_exhaustive]
75pub enum IdentityError {
76    /// The provided identity string was empty.
77    #[error("empty identity string")]
78    EmptyIdentity,
79
80    /// The provided identity string exceeds the maximum allowed.
81    #[error("input length {len} exceeds maximum of {max} characters")]
82    InputTooLong {
83        /// Input length
84        len: usize,
85        /// Max allowed
86        max: usize,
87    },
88
89    /// Error decoding a hex-encoded identity.
90    #[error("hex decoding error: {0}")]
91    Hex(#[from] hex::FromHexError),
92
93    /// Error decoding a Base58-encoded identity.
94    #[error("Base58 decoding error: {0}")]
95    Base58(#[from] bs58::decode::Error),
96
97    /// Error decoding a Base64-encoded identity.
98    #[error("Base64 decoding error: {0}")]
99    Base64(#[from] base64::DecodeError),
100
101    /// The input string did not match any supported identity format (hex, Base58, Base64).
102    #[error("unsupported identity format")]
103    UnsupportedFormat,
104}
105
106/// Errors related to asset parsing, validation, or formatting.
107#[derive(Debug, Error)]
108#[non_exhaustive]
109pub enum AssetError {
110    /// Failed to serialize an asset to bytes or JSON.
111    #[error("could not serialize asset: {0}")]
112    Serialization(String),
113
114    /// Failed to parse an asset from bytes or JSON.
115    #[error("could not parse asset: {0}")]
116    Parsing(String),
117
118    /// A token or native amount was zero, which is not allowed.
119    #[error("amount must be non-zero")]
120    ZeroAmount,
121
122    /// The contract address or mint for a fungible token was not provided.
123    #[error("missing ID for asset, program, or contract")]
124    MissingId,
125}
126
127impl EscrowError {
128    /// A helper to bypass the unavailability of the `ToString` trait
129    /// in the RISC Zero guest.
130    pub fn to_str(&self) -> String {
131        self.to_string()
132    }
133}
134
135/// Errors encoding or decoding the public-commitment journal.
136#[derive(Debug, Error)]
137#[non_exhaustive]
138pub enum CommitmentError {
139    /// The amount did not fit in the fixed 256-bit journal field.
140    #[error("amount exceeds 256 bits and cannot be committed")]
141    AmountTooLarge,
142
143    /// A length-prefixed field exceeded the journal's 16-bit size limit.
144    #[error("field length {0} exceeds the journal's 16-bit size limit")]
145    FieldTooLong(usize),
146
147    /// The journal ended before a field could be fully read.
148    #[error("journal truncated at offset {0}")]
149    Truncated(usize),
150
151    /// The journal carried unexpected bytes past its declared fields.
152    #[error("journal has trailing bytes after offset {0}")]
153    TrailingBytes(usize),
154
155    /// The journal's leading version byte is not a layout this build understands.
156    #[error("unknown journal version {0}")]
157    UnknownVersion(u8),
158
159    /// An enum discriminant in the journal did not map to a known variant.
160    #[error("unknown {field} tag {value}")]
161    UnknownTag {
162        /// Name of the field whose tag was unrecognized.
163        field: &'static str,
164        /// The unrecognized tag value.
165        value: u8,
166    },
167}
168
169impl CommitmentError {
170    /// Constructs a [`CommitmentError::UnknownTag`] for `field` and `value`.
171    pub(crate) fn unknown_tag(field: &'static str, value: u8) -> Self {
172        Self::UnknownTag { field, value }
173    }
174}