genesis_protocol/
error.rs

1//! 🚨 Genesis Protocol Error Types
2//!
3//! This module defines all error types used throughout the Genesis Protocol.
4//! Each component has its own error type that can be converted to the main
5//! GenesisError for unified error handling.
6
7use thiserror::Error;
8
9/// Main error type for Genesis Protocol
10#[derive(Error, Debug)]
11pub enum GenesisError {
12    #[error("DNA error: {0}")]
13    DNA(#[from] crate::dna::DNAError),
14    
15    #[error("TRON organism error: {0}")]
16    TRON(#[from] crate::tron::TRONError),
17    
18    #[error("Neural communication error: {0}")]
19    Neural(#[from] crate::neural::SynapseError),
20    
21    #[error("Evolution error: {0}")]
22    Evolution(#[from] crate::evolution::EvolutionError),
23    
24    #[error("Collective intelligence error: {0}")]
25    Collective(#[from] crate::collective::CollectiveError),
26    
27    #[error("Network error: {0}")]
28    Network(#[from] crate::network::NetworkError),
29    
30    #[error("Organism not found: {0}")]
31    OrganismNotFound(String),
32    
33    #[error("Network capacity exceeded: {current} organisms (max: {max})")]
34    NetworkCapacityExceeded { current: usize, max: usize },
35    
36    #[error("Protocol version mismatch: expected {expected}, got {actual}")]
37    ProtocolVersionMismatch { expected: String, actual: String },
38    
39    #[error("Invalid configuration: {0}")]
40    InvalidConfiguration(String),
41    
42    #[error("Insufficient resources: {resource}")]
43    InsufficientResources { resource: String },
44    
45    #[error("Operation timeout: {operation} took longer than {timeout_ms}ms")]
46    OperationTimeout { operation: String, timeout_ms: u64 },
47    
48    #[error("Security violation: {0}")]
49    SecurityViolation(String),
50    
51    #[error("IO error: {0}")]
52    IO(#[from] std::io::Error),
53    
54    #[error("Serialization error: {0}")]
55    Serialization(#[from] serde_json::Error),
56    
57    #[error("Internal error: {0}")]
58    Internal(String),
59}
60
61/// Result type for Genesis Protocol operations
62pub type GenesisResult<T> = Result<T, GenesisError>;
63
64/// Error recovery strategies
65#[derive(Debug, Clone, Copy)]
66pub enum ErrorRecovery {
67    /// Retry the operation
68    Retry,
69    /// Fallback to alternative method
70    Fallback,
71    /// Gracefully degrade functionality
72    Degrade,
73    /// Fail fast and propagate error
74    Fail,
75}
76
77/// Error context for better debugging
78#[derive(Debug, Clone)]
79pub struct ErrorContext {
80    pub operation: String,
81    pub organism_id: Option<String>,
82    pub timestamp: u64,
83    pub recovery_strategy: ErrorRecovery,
84    pub metadata: std::collections::HashMap<String, String>,
85}
86
87impl ErrorContext {
88    pub fn new(operation: &str) -> Self {
89        ErrorContext {
90            operation: operation.to_string(),
91            organism_id: None,
92            timestamp: std::time::SystemTime::now()
93                .duration_since(std::time::UNIX_EPOCH)
94                .unwrap()
95                .as_secs(),
96            recovery_strategy: ErrorRecovery::Fail,
97            metadata: std::collections::HashMap::new(),
98        }
99    }
100    
101    pub fn with_organism(mut self, organism_id: &str) -> Self {
102        self.organism_id = Some(organism_id.to_string());
103        self
104    }
105    
106    pub fn with_recovery(mut self, strategy: ErrorRecovery) -> Self {
107        self.recovery_strategy = strategy;
108        self
109    }
110    
111    pub fn with_metadata(mut self, key: &str, value: &str) -> Self {
112        self.metadata.insert(key.to_string(), value.to_string());
113        self
114    }
115}
116
117/// Enhanced error with context
118#[derive(Debug)]
119pub struct ContextualError {
120    pub error: GenesisError,
121    pub context: ErrorContext,
122    pub source_location: Option<String>,
123}
124
125impl ContextualError {
126    pub fn new(error: GenesisError, context: ErrorContext) -> Self {
127        ContextualError {
128            error,
129            context,
130            source_location: None,
131        }
132    }
133    
134    pub fn with_location(mut self, location: &str) -> Self {
135        self.source_location = Some(location.to_string());
136        self
137    }
138}
139
140impl std::fmt::Display for ContextualError {
141    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142        write!(f, "Error in {}: {}", self.context.operation, self.error)?;
143        if let Some(organism_id) = &self.context.organism_id {
144            write!(f, " (organism: {})", organism_id)?;
145        }
146        if let Some(location) = &self.source_location {
147            write!(f, " at {}", location)?;
148        }
149        Ok(())
150    }
151}
152
153impl std::error::Error for ContextualError {
154    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
155        Some(&self.error)
156    }
157}
158
159/// Macro for creating contextual errors
160#[macro_export]
161macro_rules! genesis_error {
162    ($error:expr, $operation:expr) => {
163        ContextualError::new(
164            $error.into(),
165            ErrorContext::new($operation)
166        ).with_location(&format!("{}:{}", file!(), line!()))
167    };
168    
169    ($error:expr, $operation:expr, $organism_id:expr) => {
170        ContextualError::new(
171            $error.into(),
172            ErrorContext::new($operation).with_organism($organism_id)
173        ).with_location(&format!("{}:{}", file!(), line!()))
174    };
175    
176    ($error:expr, $operation:expr, $organism_id:expr, $recovery:expr) => {
177        ContextualError::new(
178            $error.into(),
179            ErrorContext::new($operation)
180                .with_organism($organism_id)
181                .with_recovery($recovery)
182        ).with_location(&format!("{}:{}", file!(), line!()))
183    };
184}
185
186/// Error metrics for monitoring
187#[derive(Debug, Clone)]
188pub struct ErrorMetrics {
189    pub total_errors: u64,
190    pub errors_by_type: std::collections::HashMap<String, u64>,
191    pub errors_by_organism: std::collections::HashMap<String, u64>,
192    pub recovery_attempts: u64,
193    pub successful_recoveries: u64,
194    pub last_error_time: u64,
195}
196
197impl ErrorMetrics {
198    pub fn new() -> Self {
199        ErrorMetrics {
200            total_errors: 0,
201            errors_by_type: std::collections::HashMap::new(),
202            errors_by_organism: std::collections::HashMap::new(),
203            recovery_attempts: 0,
204            successful_recoveries: 0,
205            last_error_time: 0,
206        }
207    }
208    
209    pub fn record_error(&mut self, error: &GenesisError, organism_id: Option<&str>) {
210        self.total_errors += 1;
211        self.last_error_time = std::time::SystemTime::now()
212            .duration_since(std::time::UNIX_EPOCH)
213            .unwrap()
214            .as_secs();
215        
216        let error_type = match error {
217            GenesisError::DNA(_) => "DNA",
218            GenesisError::TRON(_) => "TRON",
219            GenesisError::Neural(_) => "Neural",
220            GenesisError::Evolution(_) => "Evolution",
221            GenesisError::Collective(_) => "Collective",
222            GenesisError::Network(_) => "Network",
223            GenesisError::OrganismNotFound(_) => "OrganismNotFound",
224            GenesisError::NetworkCapacityExceeded { .. } => "NetworkCapacityExceeded",
225            GenesisError::ProtocolVersionMismatch { .. } => "ProtocolVersionMismatch",
226            GenesisError::InvalidConfiguration(_) => "InvalidConfiguration",
227            GenesisError::InsufficientResources { .. } => "InsufficientResources",
228            GenesisError::OperationTimeout { .. } => "OperationTimeout",
229            GenesisError::SecurityViolation(_) => "SecurityViolation",
230            GenesisError::IO(_) => "IO",
231            GenesisError::Serialization(_) => "Serialization",
232            GenesisError::Internal(_) => "Internal",
233        };
234        
235        *self.errors_by_type.entry(error_type.to_string()).or_insert(0) += 1;
236        
237        if let Some(organism_id) = organism_id {
238            *self.errors_by_organism.entry(organism_id.to_string()).or_insert(0) += 1;
239        }
240    }
241    
242    pub fn record_recovery_attempt(&mut self, successful: bool) {
243        self.recovery_attempts += 1;
244        if successful {
245            self.successful_recoveries += 1;
246        }
247    }
248    
249    pub fn get_error_rate(&self) -> f64 {
250        if self.total_errors == 0 {
251            0.0
252        } else {
253            self.total_errors as f64 / std::time::SystemTime::now()
254                .duration_since(std::time::UNIX_EPOCH)
255                .unwrap()
256                .as_secs() as f64
257        }
258    }
259    
260    pub fn get_recovery_rate(&self) -> f64 {
261        if self.recovery_attempts == 0 {
262            0.0
263        } else {
264            self.successful_recoveries as f64 / self.recovery_attempts as f64
265        }
266    }
267}
268
269impl Default for ErrorMetrics {
270    fn default() -> Self {
271        Self::new()
272    }
273}
274
275/// Error handler trait for custom error handling
276pub trait ErrorHandler {
277    fn handle_error(&self, error: &GenesisError, context: &ErrorContext) -> ErrorRecovery;
278    fn should_retry(&self, error: &GenesisError, attempt: u32) -> bool;
279    fn get_retry_delay(&self, error: &GenesisError, attempt: u32) -> std::time::Duration;
280}
281
282/// Default error handler implementation
283pub struct DefaultErrorHandler {
284    max_retries: u32,
285    base_delay_ms: u64,
286}
287
288impl DefaultErrorHandler {
289    pub fn new() -> Self {
290        DefaultErrorHandler {
291            max_retries: 3,
292            base_delay_ms: 100,
293        }
294    }
295    
296    pub fn with_max_retries(mut self, max_retries: u32) -> Self {
297        self.max_retries = max_retries;
298        self
299    }
300    
301    pub fn with_base_delay(mut self, delay_ms: u64) -> Self {
302        self.base_delay_ms = delay_ms;
303        self
304    }
305}
306
307impl ErrorHandler for DefaultErrorHandler {
308    fn handle_error(&self, error: &GenesisError, _context: &ErrorContext) -> ErrorRecovery {
309        match error {
310            GenesisError::Neural(_) => ErrorRecovery::Retry,
311            GenesisError::Network(_) => ErrorRecovery::Retry,
312            GenesisError::OperationTimeout { .. } => ErrorRecovery::Retry,
313            GenesisError::InsufficientResources { .. } => ErrorRecovery::Degrade,
314            GenesisError::NetworkCapacityExceeded { .. } => ErrorRecovery::Degrade,
315            GenesisError::DNA(_) => ErrorRecovery::Fail,
316            GenesisError::TRON(_) => ErrorRecovery::Fallback,
317            GenesisError::Evolution(_) => ErrorRecovery::Fallback,
318            GenesisError::SecurityViolation(_) => ErrorRecovery::Fail,
319            _ => ErrorRecovery::Fail,
320        }
321    }
322    
323    fn should_retry(&self, error: &GenesisError, attempt: u32) -> bool {
324        if attempt >= self.max_retries {
325            return false;
326        }
327        
328        match error {
329            GenesisError::Neural(_) => true,
330            GenesisError::Network(_) => true,
331            GenesisError::OperationTimeout { .. } => true,
332            GenesisError::IO(_) => true,
333            _ => false,
334        }
335    }
336    
337    fn get_retry_delay(&self, _error: &GenesisError, attempt: u32) -> std::time::Duration {
338        // Exponential backoff
339        let delay_ms = self.base_delay_ms * (2_u64.pow(attempt));
340        std::time::Duration::from_millis(delay_ms)
341    }
342}
343
344impl Default for DefaultErrorHandler {
345    fn default() -> Self {
346        Self::new()
347    }
348}
349
350#[cfg(test)]
351mod tests {
352    use super::*;
353    use crate::dna::DNAError;
354
355    #[test]
356    fn test_genesis_error_conversion() {
357        let dna_error = DNAError::InvalidSecretKey;
358        let genesis_error: GenesisError = dna_error.into();
359        
360        match genesis_error {
361            GenesisError::DNA(DNAError::InvalidSecretKey) => {},
362            _ => panic!("Error conversion failed"),
363        }
364    }
365
366    #[test]
367    fn test_error_context() {
368        let context = ErrorContext::new("test_operation")
369            .with_organism("tron_123")
370            .with_recovery(ErrorRecovery::Retry)
371            .with_metadata("key", "value");
372        
373        assert_eq!(context.operation, "test_operation");
374        assert_eq!(context.organism_id, Some("tron_123".to_string()));
375        assert!(matches!(context.recovery_strategy, ErrorRecovery::Retry));
376        assert_eq!(context.metadata.get("key"), Some(&"value".to_string()));
377    }
378
379    #[test]
380    fn test_contextual_error() {
381        let error = GenesisError::OrganismNotFound("tron_123".to_string());
382        let context = ErrorContext::new("neural_connect");
383        let contextual = ContextualError::new(error, context)
384            .with_location("test.rs:42");
385        
386        let error_string = contextual.to_string();
387        assert!(error_string.contains("neural_connect"));
388        assert!(error_string.contains("test.rs:42"));
389    }
390
391    #[test]
392    fn test_error_metrics() {
393        let mut metrics = ErrorMetrics::new();
394        
395        let error = GenesisError::DNA(DNAError::InvalidSecretKey);
396        metrics.record_error(&error, Some("tron_123"));
397        
398        assert_eq!(metrics.total_errors, 1);
399        assert_eq!(metrics.errors_by_type.get("DNA"), Some(&1));
400        assert_eq!(metrics.errors_by_organism.get("tron_123"), Some(&1));
401        
402        metrics.record_recovery_attempt(true);
403        assert_eq!(metrics.recovery_attempts, 1);
404        assert_eq!(metrics.successful_recoveries, 1);
405        assert_eq!(metrics.get_recovery_rate(), 1.0);
406    }
407
408    #[test]
409    fn test_default_error_handler() {
410        let handler = DefaultErrorHandler::new();
411        
412        let neural_error = GenesisError::Neural(crate::neural::SynapseError::ConnectionRefused);
413        let context = ErrorContext::new("test");
414        
415        assert!(matches!(handler.handle_error(&neural_error, &context), ErrorRecovery::Retry));
416        assert!(handler.should_retry(&neural_error, 1));
417        assert!(!handler.should_retry(&neural_error, 5));
418        
419        let delay = handler.get_retry_delay(&neural_error, 1);
420        assert_eq!(delay, std::time::Duration::from_millis(200));
421    }
422}