csv_adapter_aptos/
error.rs1use thiserror::Error;
7
8#[derive(Error, Debug)]
12pub enum AptosError {
13 #[error("RPC error: {0}")]
16 RpcError(String),
17
18 #[error("Resource already used: {0}")]
21 ResourceUsed(String),
22
23 #[error("State proof verification failed: {0}")]
26 StateProofFailed(String),
27
28 #[error("Event proof verification failed: {0}")]
31 EventProofFailed(String),
32
33 #[error("Checkpoint certification failed: {0}")]
36 CheckpointFailed(String),
37
38 #[error("Transaction failed: {0}")]
41 TransactionFailed(String),
42
43 #[error("Serialization error: {0}")]
46 SerializationError(String),
47
48 #[error("Transaction confirmation timeout after {timeout_ms}ms: {tx_hash}")]
51 ConfirmationTimeout { tx_hash: String, timeout_ms: u64 },
52
53 #[error("Chain reorg detected at version {version}: anchor may be invalid")]
56 ReorgDetected { version: u64 },
57
58 #[error("Network mismatch: expected chain_id {expected}, got {actual}")]
61 NetworkMismatch { expected: u64, actual: u64 },
62
63 #[error(transparent)]
65 CoreError(#[from] csv_adapter_core::AdapterError),
66}
67
68impl AptosError {
69 pub fn is_transient(&self) -> bool {
71 match self {
72 AptosError::RpcError(_)
73 | AptosError::ConfirmationTimeout { .. }
74 | AptosError::TransactionFailed(_) => true,
75 AptosError::ResourceUsed(_)
76 | AptosError::StateProofFailed(_)
77 | AptosError::EventProofFailed(_)
78 | AptosError::CheckpointFailed(_)
79 | AptosError::SerializationError(_)
80 | AptosError::ReorgDetected { .. }
81 | AptosError::NetworkMismatch { .. }
82 | AptosError::CoreError(_) => false,
83 }
84 }
85
86 pub fn timeout(tx_hash: &str, timeout_ms: u64) -> Self {
88 AptosError::ConfirmationTimeout {
89 tx_hash: tx_hash.to_string(),
90 timeout_ms,
91 }
92 }
93
94 pub fn reorg(version: u64) -> Self {
96 AptosError::ReorgDetected { version }
97 }
98}
99
100impl From<Box<dyn std::error::Error + Send + Sync>> for AptosError {
101 fn from(err: Box<dyn std::error::Error + Send + Sync>) -> Self {
102 AptosError::RpcError(err.to_string())
103 }
104}
105
106impl From<AptosError> for csv_adapter_core::AdapterError {
107 fn from(err: AptosError) -> Self {
108 match err {
109 AptosError::CoreError(e) => e,
110 AptosError::RpcError(msg) | AptosError::TransactionFailed(msg) => {
111 csv_adapter_core::AdapterError::NetworkError(msg)
112 }
113 AptosError::ResourceUsed(msg) => csv_adapter_core::AdapterError::InvalidSeal(msg),
114 AptosError::StateProofFailed(msg) | AptosError::EventProofFailed(msg) => {
115 csv_adapter_core::AdapterError::InclusionProofFailed(msg)
116 }
117 AptosError::CheckpointFailed(msg) => csv_adapter_core::AdapterError::NetworkError(msg),
118 AptosError::SerializationError(msg) => csv_adapter_core::AdapterError::InvalidSeal(msg),
119 AptosError::ConfirmationTimeout {
120 tx_hash,
121 timeout_ms,
122 } => csv_adapter_core::AdapterError::NetworkError(format!(
123 "Timeout waiting for tx {} after {}ms",
124 tx_hash, timeout_ms
125 )),
126 AptosError::ReorgDetected { version } => csv_adapter_core::AdapterError::ReorgInvalid(
127 format!("Reorg at version {}", version),
128 ),
129 aptos_err => csv_adapter_core::AdapterError::NetworkError(format!("{}", aptos_err)),
130 }
131 }
132}
133
134pub type AptosResult<T> = Result<T, AptosError>;
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_transient_errors() {
142 assert!(AptosError::RpcError("connection refused".to_string()).is_transient());
143 assert!(AptosError::ConfirmationTimeout {
144 tx_hash: "abc".to_string(),
145 timeout_ms: 30000
146 }
147 .is_transient());
148 assert!(AptosError::TransactionFailed("out of gas".to_string()).is_transient());
149 }
150
151 #[test]
152 fn test_non_transient_errors() {
153 assert!(!AptosError::ResourceUsed("seal consumed".to_string()).is_transient());
154 assert!(!AptosError::StateProofFailed("invalid merkle".to_string()).is_transient());
155 assert!(!AptosError::ReorgDetected { version: 100 }.is_transient());
156 }
157
158 #[test]
159 fn test_error_conversion() {
160 let aptos_err = AptosError::StateProofFailed("bad proof".to_string());
161 let core_err: csv_adapter_core::AdapterError = aptos_err.into();
162 assert!(matches!(
163 core_err,
164 csv_adapter_core::AdapterError::InclusionProofFailed(_)
165 ));
166 }
167}