xmtp_common/
error_code.rs1pub trait ErrorCode: std::error::Error {
30 fn error_code(&self) -> &'static str;
34}
35
36impl<E: ErrorCode> ErrorCode for Box<E> {
37 fn error_code(&self) -> &'static str {
38 (**self).error_code()
39 }
40}
41
42impl<E: ErrorCode> ErrorCode for &E {
43 fn error_code(&self) -> &'static str {
44 (*self).error_code()
45 }
46}
47
48#[allow(dead_code)]
51mod cryptography_error_codes {
52 #[derive(xmtp_common::ErrorCode)]
53 #[error_code(remote = "xmtp_cryptography::signature::SignatureError")]
54 enum SignatureError {
55 BadAddressFormat(()),
56 BadSignatureFormat(()),
57 BadSignature { addr: String },
58 Signer(()),
59 Unknown,
60 }
61
62 #[derive(xmtp_common::ErrorCode)]
63 #[error_code(remote = "xmtp_cryptography::signature::IdentifierValidationError")]
64 enum IdentifierValidationError {
65 InvalidAddresses(Vec<String>),
66 HexDecode(()),
67 Generic(String),
68 }
69
70 #[derive(xmtp_common::ErrorCode)]
71 #[error_code(remote = "xmtp_cryptography::ethereum::EthereumCryptoError")]
72 enum EthereumCryptoError {
73 InvalidLength,
74 InvalidKey,
75 SignFailure,
76 DecompressFailure,
77 }
78}
79
80impl ErrorCode for hex::FromHexError {
82 fn error_code(&self) -> &'static str {
83 "hex::FromHexError"
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::ErrorCode;
90 use thiserror::Error;
91 use xmtp_macro::ErrorCode;
92
93 #[derive(Debug, Error, ErrorCode)]
95 #[error("inner error")]
96 struct InnerError;
97
98 #[derive(Debug, Error, ErrorCode)]
99 enum StorageError {
100 #[error("connection failed")]
102 Connection,
103 #[error("not found")]
105 NotFound,
106 }
107
108 #[derive(Debug, Error, ErrorCode)]
109 enum GroupError {
110 #[error("group not found")]
112 NotFound,
113 #[error("invalid membership")]
115 InvalidMembership,
116 #[error("storage: {0}")]
117 #[error_code(inherit)]
118 Storage(#[from] StorageError),
119 #[error("inner: {0}")]
120 #[error_code(inherit)]
121 Inner(#[from] InnerError),
122 }
123
124 #[test]
125 fn test_struct_error_code() {
126 let err = InnerError;
127 assert_eq!(err.error_code(), "InnerError");
128 }
129
130 #[test]
131 fn test_enum_error_code() {
132 let err = StorageError::Connection;
133 assert_eq!(err.error_code(), "StorageError::Connection");
134
135 let err = StorageError::NotFound;
136 assert_eq!(err.error_code(), "StorageError::NotFound");
137 }
138
139 #[test]
140 fn test_inherited_error_code() {
141 let err = GroupError::NotFound;
142 assert_eq!(err.error_code(), "GroupError::NotFound");
143
144 let err = GroupError::InvalidMembership;
145 assert_eq!(err.error_code(), "GroupError::InvalidMembership");
146
147 let err = GroupError::Storage(StorageError::Connection);
149 assert_eq!(err.error_code(), "StorageError::Connection");
150
151 let err = GroupError::Inner(InnerError);
153 assert_eq!(err.error_code(), "InnerError");
154 }
155
156 #[test]
157 fn test_boxed_error_code() {
158 let err = Box::new(StorageError::Connection);
159 assert_eq!(err.error_code(), "StorageError::Connection");
160 }
161
162 #[test]
163 fn test_ref_error_code() {
164 let err = StorageError::Connection;
165 let err_ref = &err;
166 assert_eq!(err_ref.error_code(), "StorageError::Connection");
167 }
168
169 #[derive(Debug, Error, ErrorCode)]
171 enum RenamedError {
172 #[error("new name for the variant")]
174 #[error_code("RenamedError::OldVariantName")]
175 NewVariantName,
176 #[error("another variant")]
178 AnotherVariant,
179 }
180
181 #[test]
182 fn test_custom_error_code() {
183 let err = RenamedError::NewVariantName;
185 assert_eq!(err.error_code(), "RenamedError::OldVariantName");
186
187 let err = RenamedError::AnotherVariant;
189 assert_eq!(err.error_code(), "RenamedError::AnotherVariant");
190 }
191
192 #[test]
195 fn test_signature_error_codes() {
196 use xmtp_cryptography::signature::SignatureError;
197
198 let err = SignatureError::BadAddressFormat(hex::FromHexError::OddLength);
200 assert_eq!(err.error_code(), "SignatureError::BadAddressFormat");
201
202 let err = SignatureError::BadSignature {
204 addr: "0x123".to_string(),
205 };
206 assert_eq!(err.error_code(), "SignatureError::BadSignature");
207
208 let err = SignatureError::Unknown;
209 assert_eq!(err.error_code(), "SignatureError::Unknown");
210 }
211
212 #[test]
213 fn test_identifier_validation_error_codes() {
214 use xmtp_cryptography::signature::IdentifierValidationError;
215
216 let err = IdentifierValidationError::InvalidAddresses(vec!["bad".to_string()]);
217 assert_eq!(
218 err.error_code(),
219 "IdentifierValidationError::InvalidAddresses"
220 );
221
222 let err = IdentifierValidationError::HexDecode(hex::FromHexError::OddLength);
223 assert_eq!(err.error_code(), "IdentifierValidationError::HexDecode");
224
225 let err = IdentifierValidationError::Generic("generic error".to_string());
226 assert_eq!(err.error_code(), "IdentifierValidationError::Generic");
227 }
228
229 #[test]
230 fn test_ethereum_crypto_error_codes() {
231 use xmtp_cryptography::ethereum::EthereumCryptoError;
232
233 let err = EthereumCryptoError::InvalidLength;
234 assert_eq!(err.error_code(), "EthereumCryptoError::InvalidLength");
235
236 let err = EthereumCryptoError::InvalidKey;
237 assert_eq!(err.error_code(), "EthereumCryptoError::InvalidKey");
238
239 let err = EthereumCryptoError::SignFailure;
240 assert_eq!(err.error_code(), "EthereumCryptoError::SignFailure");
241
242 let err = EthereumCryptoError::DecompressFailure;
243 assert_eq!(err.error_code(), "EthereumCryptoError::DecompressFailure");
244 }
245
246 #[test]
247 fn test_hex_from_hex_error_code() {
248 let err = hex::FromHexError::OddLength;
249 assert_eq!(err.error_code(), "hex::FromHexError");
250
251 let err = hex::FromHexError::InvalidHexCharacter { c: 'Z', index: 0 };
252 assert_eq!(err.error_code(), "hex::FromHexError");
253
254 let err = hex::FromHexError::InvalidStringLength;
255 assert_eq!(err.error_code(), "hex::FromHexError");
256 }
257}