/ src / error.rs
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  }