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}