error.rs
1 use thiserror::Error; 2 3 #[derive(Error, Debug)] 4 pub enum NodeError { 5 #[error("Configuration error: {0}")] 6 Config(#[from] ConfigError), 7 8 #[error("Storage error: {0}")] 9 Storage(#[from] StorageError), 10 11 #[error("Network error: {0}")] 12 Network(#[from] NetworkError), 13 14 #[error("RPC error: {0}")] 15 Rpc(#[from] RpcError), 16 17 #[error("API error: {0}")] 18 Api(#[from] ApiError), 19 20 #[error("Metrics error: {0}")] 21 Metrics(#[from] MetricsError), 22 23 #[error("Event publishing error: {0}")] 24 Events(#[from] EventError), 25 26 #[error("IO error: {0}")] 27 Io(#[from] std::io::Error), 28 29 #[error("Serialization error: {0}")] 30 Serialization(#[from] toml::de::Error), 31 32 #[error("Serialization error: {0}")] 33 SerializationSer(#[from] toml::ser::Error), 34 35 #[error("Actor mailbox error: {0}")] 36 Mailbox(#[from] actix::MailboxError), 37 38 #[error("Generic error: {0}")] 39 Generic(#[from] anyhow::Error), 40 } 41 42 #[derive(Error, Debug)] 43 pub enum ConfigError { 44 #[error("Invalid network: {0}")] 45 InvalidNetwork(String), 46 47 #[error("Missing required field: {0}")] 48 MissingField(String), 49 50 #[error("Invalid value for {field}: {value}")] 51 InvalidValue { field: String, value: String }, 52 } 53 54 #[derive(Error, Debug)] 55 pub enum StorageError { 56 #[error("RocksDB error: {0}")] 57 RocksDb(#[from] rocksdb::Error), 58 59 #[error("Database not found: {path}")] 60 DatabaseNotFound { path: String }, 61 62 #[error("Corruption detected in {component}")] 63 Corruption { component: String }, 64 65 #[error("Serialization error: {0}")] 66 Serialization(String), 67 } 68 69 #[derive(Error, Debug)] 70 pub enum NetworkError { 71 #[error("Connection failed to {peer}: {reason}")] 72 ConnectionFailed { peer: String, reason: String }, 73 74 #[error("Protocol error: {0}")] 75 Protocol(String), 76 77 #[error("Peer disconnected: {peer}")] 78 PeerDisconnected { peer: String }, 79 80 #[error("ZMQ error: {0}")] 81 Zmq(String), 82 } 83 84 #[derive(Error, Debug)] 85 pub enum RpcError { 86 #[error("Invalid method: {0}")] 87 InvalidMethod(String), 88 89 #[error("Invalid parameters: {0}")] 90 InvalidParams(String), 91 92 #[error("Internal error: {0}")] 93 Internal(String), 94 95 #[error("Authentication failed")] 96 AuthenticationFailed, 97 } 98 99 #[derive(Error, Debug)] 100 pub enum ApiError { 101 #[error("Invalid request: {0}")] 102 InvalidRequest(String), 103 104 #[error("Not found: {0}")] 105 NotFound(String), 106 107 #[error("Internal server error: {0}")] 108 Internal(String), 109 } 110 111 #[derive(Error, Debug)] 112 pub enum MetricsError { 113 #[error("Failed to initialize metrics: {0}")] 114 Initialization(String), 115 116 #[error("Failed to export metrics: {0}")] 117 Export(String), 118 119 #[error("Invalid metric name: {0}")] 120 InvalidName(String), 121 } 122 123 #[derive(Error, Debug)] 124 pub enum EventError { 125 #[error("Failed to publish event: {0}")] 126 PublishFailed(String), 127 128 #[error("Publisher not available: {0}")] 129 PublisherUnavailable(String), 130 131 #[error("Kubernetes API error: {0}")] 132 KubernetesApi(String), 133 134 #[error("Event serialization error: {0}")] 135 Serialization(String), 136 } 137 138 // Result type aliases for convenience 139 pub type NodeResult<T> = Result<T, NodeError>; 140 pub type ConfigResult<T> = Result<T, ConfigError>; 141 pub type StorageResult<T> = Result<T, StorageError>; 142 pub type NetworkResult<T> = Result<T, NetworkError>; 143 pub type RpcResult<T> = Result<T, RpcError>; 144 pub type ApiResult<T> = Result<T, ApiError>; 145 pub type MetricsResult<T> = Result<T, MetricsError>; 146 pub type EventResult<T> = Result<T, EventError>; 147 148 #[cfg(test)] 149 mod tests { 150 use super::*; 151 152 #[test] 153 fn test_config_error_display() { 154 let error = ConfigError::InvalidNetwork("invalid".to_string()); 155 assert_eq!(error.to_string(), "Invalid network: invalid"); 156 157 let error = ConfigError::MissingField("port".to_string()); 158 assert_eq!(error.to_string(), "Missing required field: port"); 159 160 let error = ConfigError::InvalidValue { 161 field: "timeout".to_string(), 162 value: "negative".to_string(), 163 }; 164 assert_eq!(error.to_string(), "Invalid value for timeout: negative"); 165 } 166 167 #[test] 168 fn test_storage_error_display() { 169 let error = StorageError::DatabaseNotFound { 170 path: "/tmp/db".to_string(), 171 }; 172 assert_eq!(error.to_string(), "Database not found: /tmp/db"); 173 174 let error = StorageError::Corruption { 175 component: "blocks".to_string(), 176 }; 177 assert_eq!(error.to_string(), "Corruption detected in blocks"); 178 179 let error = StorageError::Serialization("invalid data".to_string()); 180 assert_eq!(error.to_string(), "Serialization error: invalid data"); 181 } 182 183 #[test] 184 fn test_network_error_display() { 185 let error = NetworkError::ConnectionFailed { 186 peer: "127.0.0.1:8333".to_string(), 187 reason: "timeout".to_string(), 188 }; 189 assert_eq!(error.to_string(), "Connection failed to 127.0.0.1:8333: timeout"); 190 191 let error = NetworkError::Protocol("invalid message".to_string()); 192 assert_eq!(error.to_string(), "Protocol error: invalid message"); 193 194 let error = NetworkError::PeerDisconnected { 195 peer: "peer1".to_string(), 196 }; 197 assert_eq!(error.to_string(), "Peer disconnected: peer1"); 198 } 199 200 #[test] 201 fn test_rpc_error_display() { 202 let error = RpcError::InvalidMethod("unknown".to_string()); 203 assert_eq!(error.to_string(), "Invalid method: unknown"); 204 205 let error = RpcError::InvalidParams("missing txid".to_string()); 206 assert_eq!(error.to_string(), "Invalid parameters: missing txid"); 207 208 let error = RpcError::AuthenticationFailed; 209 assert_eq!(error.to_string(), "Authentication failed"); 210 } 211 212 #[test] 213 fn test_api_error_display() { 214 let error = ApiError::InvalidRequest("malformed JSON".to_string()); 215 assert_eq!(error.to_string(), "Invalid request: malformed JSON"); 216 217 let error = ApiError::NotFound("block not found".to_string()); 218 assert_eq!(error.to_string(), "Not found: block not found"); 219 220 let error = ApiError::Internal("database error".to_string()); 221 assert_eq!(error.to_string(), "Internal server error: database error"); 222 } 223 224 #[test] 225 fn test_metrics_error_display() { 226 let error = MetricsError::Initialization("failed to start".to_string()); 227 assert_eq!(error.to_string(), "Failed to initialize metrics: failed to start"); 228 229 let error = MetricsError::Export("connection refused".to_string()); 230 assert_eq!(error.to_string(), "Failed to export metrics: connection refused"); 231 232 let error = MetricsError::InvalidName("invalid-name".to_string()); 233 assert_eq!(error.to_string(), "Invalid metric name: invalid-name"); 234 } 235 236 #[test] 237 fn test_event_error_display() { 238 let error = EventError::PublishFailed("network error".to_string()); 239 assert_eq!(error.to_string(), "Failed to publish event: network error"); 240 241 let error = EventError::PublisherUnavailable("zmq".to_string()); 242 assert_eq!(error.to_string(), "Publisher not available: zmq"); 243 244 let error = EventError::Serialization("invalid JSON".to_string()); 245 assert_eq!(error.to_string(), "Event serialization error: invalid JSON"); 246 } 247 248 #[test] 249 fn test_node_error_from_conversions() { 250 let config_error = ConfigError::InvalidNetwork("test".to_string()); 251 let node_error: NodeError = config_error.into(); 252 assert!(matches!(node_error, NodeError::Config(_))); 253 254 let storage_error = StorageError::Serialization("test".to_string()); 255 let node_error: NodeError = storage_error.into(); 256 assert!(matches!(node_error, NodeError::Storage(_))); 257 } 258 }