1use crate::{ChainId, MessageId, StateKey};
2use thiserror::Error;
3
4#[derive(Clone, Debug, Error)]
14pub enum XenithError {
15 #[error("transport error on chain {chain}: {message}")]
20 Transport { chain: ChainId, message: String },
21
22 #[error("state diverged for key {key} across chains: {chains:?}")]
23 Divergence { key: StateKey, chains: Vec<ChainId> },
24
25 #[error("message {id} timed out after {elapsed_secs}s")]
26 Timeout { id: MessageId, elapsed_secs: u64 },
27
28 #[error("insufficient fee: required {required}, provided {provided}")]
29 InsufficientFee { required: String, provided: String },
30
31 #[error("chain {0} is not supported by this transport")]
32 UnsupportedChain(ChainId),
33
34 #[error("state store error: {0}")]
35 StoreError(String),
36
37 #[error("serialization error: {0}")]
38 Serialization(String),
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44
45 #[test]
46 fn transport_message() {
47 let e = XenithError::Transport {
48 chain: ChainId(1),
49 message: "connection refused".into(),
50 };
51 assert_eq!(
52 e.to_string(),
53 "transport error on chain 1: connection refused"
54 );
55 }
56
57 #[test]
58 fn divergence_message() {
59 let e = XenithError::Divergence {
60 key: StateKey::new("proto", "pool", "0xabc"),
61 chains: vec![ChainId(1), ChainId(42161)],
62 };
63 assert_eq!(
64 e.to_string(),
65 "state diverged for key proto.pool.0xabc across chains: [ChainId(1), ChainId(42161)]"
66 );
67 }
68
69 #[test]
70 fn timeout_message() {
71 let e = XenithError::Timeout {
72 id: MessageId(7),
73 elapsed_secs: 30,
74 };
75 assert_eq!(e.to_string(), "message 7 timed out after 30s");
76 }
77
78 #[test]
79 fn insufficient_fee_message() {
80 let e = XenithError::InsufficientFee {
81 required: "500000".into(),
82 provided: "100000".into(),
83 };
84 assert_eq!(
85 e.to_string(),
86 "insufficient fee: required 500000, provided 100000"
87 );
88 }
89
90 #[test]
91 fn unsupported_chain_message() {
92 let e = XenithError::UnsupportedChain(ChainId(9999));
93 assert_eq!(
94 e.to_string(),
95 "chain 9999 is not supported by this transport"
96 );
97 }
98
99 #[test]
100 fn store_error_message() {
101 let e = XenithError::StoreError("disk full".into());
102 assert_eq!(e.to_string(), "state store error: disk full");
103 }
104
105 #[test]
106 fn serialization_message() {
107 let e = XenithError::Serialization("unexpected EOF".into());
108 assert_eq!(e.to_string(), "serialization error: unexpected EOF");
109 }
110
111 #[test]
112 fn implements_std_error() {
113 fn takes_error(_: &dyn std::error::Error) {}
114 takes_error(&XenithError::StoreError("x".into()));
115 }
116}