1use std::fmt;
14use std::io;
15use std::time::Duration;
16
17use thiserror::Error;
18
19pub type Result<T> = std::result::Result<T, Error>;
21
22#[derive(Debug, Error)]
24pub enum Error {
25 #[error("Cryptographic error: {0}")]
27 Crypto(#[from] CryptoError),
28
29 #[error("Consensus error: {0}")]
31 Consensus(#[from] ConsensusError),
32
33 #[error("Agent error: {0}")]
35 Agent(#[from] AgentError),
36
37 #[error("Validation error: {0}")]
39 Validation(#[from] ValidationError),
40
41 #[error("System error: {0}")]
43 System(#[from] SystemError),
44
45 #[error("Network error: {0}")]
47 Network(#[from] NetworkError),
48
49 #[error("I/O error: {0}")]
51 Io(#[from] io::Error),
52
53 #[error("Serialization error: {0}")]
55 Serialization(#[from] SerializationError),
56
57 #[error("Operation timed out after {duration:?}: {operation}")]
59 Timeout {
60 operation: String,
62 duration: Duration,
64 },
65
66 #[error("{message}")]
68 Other {
69 message: String,
71 #[source]
73 source: Option<Box<dyn std::error::Error + Send + Sync>>,
74 },
75
76 #[error("Key not found: {0}")]
78 KeyNotFound(String),
79
80 #[error("Configuration error: {0}")]
82 Configuration(String),
83
84 #[error("Task join error: {0}")]
86 TaskJoin(String),
87
88 #[error("Agent pool exhausted")]
90 PoolExhausted,
91
92 #[error("Config error: {0}")]
94 Config(String),
95
96 #[error("DID error: {0}")]
98 Did(String),
99
100 #[error("Invalid state: {message}")]
102 InvalidState {
103 message: String,
105 },
106
107 #[error("Authority not found: {authority}")]
109 AuthorityNotFound {
110 authority: String,
112 },
113
114 #[error("Invalid vote from {authority}: {reason}")]
116 InvalidVote {
117 authority: String,
119 reason: String,
121 },
122
123 #[error("Duplicate vote from {authority}")]
125 DuplicateVote {
126 authority: String,
128 },
129
130 #[error("Byzantine fault: {message}")]
132 ByzantineFault {
133 message: String,
135 },
136
137 #[error("View change required: {0}")]
139 ViewChangeRequired(String),
140
141 #[error("Consensus already reached")]
143 AlreadyReached,
144}
145
146#[derive(Debug, Error)]
148pub enum CryptoError {
149 #[error("Signature verification failed: {reason}")]
151 SignatureVerificationFailed {
152 reason: String,
154 public_key: Option<String>,
156 },
157
158 #[error("Invalid signature format: {details}")]
160 InvalidSignature {
161 details: String,
163 },
164
165 #[error("Invalid public key: {details}")]
167 InvalidPublicKey {
168 details: String,
170 },
171
172 #[error("Invalid private key: {details}")]
174 InvalidPrivateKey {
175 details: String,
177 },
178
179 #[error("Key generation failed: {reason}")]
181 KeyGenerationFailed {
182 reason: String,
184 },
185
186 #[error("Key derivation failed: {reason}")]
188 KeyDerivationFailed {
189 reason: String,
191 },
192
193 #[error("PKCS#8 error: {details}")]
195 Pkcs8Error {
196 details: String,
198 },
199
200 #[error("Hash computation failed: {algorithm}")]
202 HashError {
203 algorithm: String,
205 },
206
207 #[error("Random number generation failed: {reason}")]
209 RandomGenerationFailed {
210 reason: String,
212 },
213
214 #[error("Batch verification failed: {passed}/{total} signatures valid")]
216 BatchVerificationFailed {
217 passed: usize,
219 total: usize,
221 },
222
223 #[error("HSM operation failed: {operation}")]
225 HsmError {
226 operation: String,
228 },
229}
230
231#[derive(Debug, Error)]
233pub enum ConsensusError {
234 #[error("Consensus not reached: {votes_for}/{total_votes} votes (required {required})")]
236 ConsensusNotReached {
237 votes_for: usize,
239 total_votes: usize,
241 required: usize,
243 },
244
245 #[error("Quorum not achieved: {available}/{required} agents available")]
247 QuorumNotAchieved {
248 available: usize,
250 required: usize,
252 },
253
254 #[error("BFT voting round {round} failed: {reason}")]
256 VotingRoundFailed {
257 round: u64,
259 reason: String,
261 },
262
263 #[error("Byzantine agent detected: {agent_id} - {behavior}")]
265 ByzantineAgentDetected {
266 agent_id: String,
268 behavior: String,
270 },
271
272 #[error("Invalid vote from agent {agent_id}: {reason}")]
274 InvalidVote {
275 agent_id: String,
277 reason: String,
279 },
280
281 #[error("Consensus timeout after {duration:?} with {votes_cast}/{total_agents} votes")]
283 ConsensusTimeout {
284 duration: Duration,
286 votes_cast: usize,
288 total_agents: usize,
290 },
291
292 #[error("Pool size {size} too small for BFT (minimum {minimum} required)")]
294 InsufficientPoolSize {
295 size: usize,
297 minimum: usize,
299 },
300
301 #[error("Conflicting consensus results: {count} different outcomes")]
303 ConflictingResults {
304 count: usize,
306 },
307
308 #[error("Invalid consensus state: {0}")]
310 InvalidState(String),
311
312 #[error("Authority not found: {0}")]
314 AuthorityNotFound(String),
315
316 #[error("Duplicate vote from authority: {0}")]
318 DuplicateVote(String),
319
320 #[error("Byzantine fault detected: {0}")]
322 ByzantineFault(String),
323
324 #[error("View change required: {0}")]
326 ViewChangeRequired(String),
327
328 #[error("Consensus already reached")]
330 AlreadyReached,
331}
332
333#[derive(Debug, Error)]
335pub enum AgentError {
336 #[error("Failed to spawn agent {agent_type}: {reason}")]
338 SpawnFailed {
339 agent_type: String,
341 reason: String,
343 },
344
345 #[error("Agent not found: {agent_id}")]
347 AgentNotFound {
348 agent_id: String,
350 },
351
352 #[error("Agent {agent_id} communication timeout after {duration:?}")]
354 CommunicationTimeout {
355 agent_id: String,
357 duration: Duration,
359 },
360
361 #[error("Agent {agent_id} crashed: {reason}")]
363 AgentCrashed {
364 agent_id: String,
366 reason: String,
368 },
369
370 #[error("Failed to recover agent {agent_id}: {reason}")]
372 RecoveryFailed {
373 agent_id: String,
375 reason: String,
377 },
378
379 #[error("Agent pool exhausted: {active}/{maximum} agents, cannot spawn more")]
381 PoolExhausted {
382 active: usize,
384 maximum: usize,
386 },
387
388 #[error("Invalid state transition for agent {agent_id}: {from} -> {to}")]
390 InvalidStateTransition {
391 agent_id: String,
393 from: String,
395 to: String,
397 },
398
399 #[error("Agent {agent_id} task execution failed: {task}")]
401 TaskExecutionFailed {
402 agent_id: String,
404 task: String,
406 details: Option<String>,
408 },
409
410 #[error("Communication error between {from_agent} and {to_agent}: {reason}")]
412 InterAgentCommunicationFailed {
413 from_agent: String,
415 to_agent: String,
417 reason: String,
419 },
420
421 #[error("Agent pool error: {reason}")]
423 AgentPoolError {
424 reason: String,
426 },
427
428 #[error("Health check failed: {reason}")]
430 HealthCheckFailed {
431 reason: String,
433 },
434}
435
436#[derive(Debug, Error)]
438pub enum ValidationError {
439 #[error("Trust chain validation failed: {reason}")]
441 TrustChainInvalid {
442 reason: String,
444 depth: Option<usize>,
446 },
447
448 #[error("Certificate not found: {cert_id}")]
450 CertificateNotFound {
451 cert_id: String,
453 },
454
455 #[error("Certificate expired: {cert_id} (expired at {expired_at})")]
457 CertificateExpired {
458 cert_id: String,
460 expired_at: String,
462 },
463
464 #[error("Certificate revoked: {cert_id} (reason: {reason})")]
466 CertificateRevoked {
467 cert_id: String,
469 reason: String,
471 },
472
473 #[error("Untrusted certificate issuer: {issuer}")]
475 UntrustedIssuer {
476 issuer: String,
478 },
479
480 #[error("Certificate chain too long: {length} (maximum {maximum})")]
482 ChainTooLong {
483 length: usize,
485 maximum: usize,
487 },
488
489 #[error("Invalid certificate format: {details}")]
491 InvalidCertificateFormat {
492 details: String,
494 },
495
496 #[error("Verifiable Credential validation failed: {reason}")]
498 CredentialValidationFailed {
499 reason: String,
501 },
502
503 #[error("DID resolution failed: {did}")]
505 DidResolutionFailed {
506 did: String,
508 },
509
510 #[error("Mandate validation failed: {reason}")]
512 MandateValidationFailed {
513 reason: String,
515 },
516
517 #[error("Invalid proof: {details}")]
519 InvalidProof {
520 details: String,
522 },
523}
524
525#[derive(Debug, Error)]
527pub enum SystemError {
528 #[error("System initialization failed: {reason}")]
530 InitializationFailed {
531 reason: String,
533 },
534
535 #[error("Invalid configuration: {parameter} = {value}")]
537 InvalidConfiguration {
538 parameter: String,
540 value: String,
542 expected: Option<String>,
544 },
545
546 #[error("Resource allocation failed: {resource}")]
548 ResourceAllocationFailed {
549 resource: String,
551 details: Option<String>,
553 },
554
555 #[error("System not initialized: {component}")]
557 NotInitialized {
558 component: String,
560 },
561
562 #[error("System already initialized: {component}")]
564 AlreadyInitialized {
565 component: String,
567 },
568
569 #[error("Shutdown failed: {reason}")]
571 ShutdownFailed {
572 reason: String,
574 },
575
576 #[error("Database error: {operation}")]
578 DatabaseError {
579 operation: String,
581 details: Option<String>,
583 },
584
585 #[error("Metrics error: {reason}")]
587 MetricsError {
588 reason: String,
590 },
591
592 #[error("Thread pool error: {reason}")]
594 ThreadPoolError {
595 reason: String,
597 },
598}
599
600#[derive(Debug, Error)]
602pub enum NetworkError {
603 #[error("Connection failed to {endpoint}: {reason}")]
605 ConnectionFailed {
606 endpoint: String,
608 reason: String,
610 },
611
612 #[error("Connection timeout to {endpoint} after {duration:?}")]
614 ConnectionTimeout {
615 endpoint: String,
617 duration: Duration,
619 },
620
621 #[error("Network partition detected: {details}")]
623 NetworkPartition {
624 details: String,
626 },
627
628 #[error("Failed to send message to {recipient}: {reason}")]
630 SendFailed {
631 recipient: String,
633 reason: String,
635 },
636
637 #[error("Failed to receive message from {sender}: {reason}")]
639 ReceiveFailed {
640 sender: String,
642 reason: String,
644 },
645
646 #[error("Protocol error: {protocol} - {details}")]
648 ProtocolError {
649 protocol: String,
651 details: String,
653 },
654
655 #[error("Peer disconnected: {peer_id}")]
657 PeerDisconnected {
658 peer_id: String,
660 },
661
662 #[error("Invalid network address: {address}")]
664 InvalidAddress {
665 address: String,
667 },
668}
669
670#[derive(Debug, Error)]
672pub enum SerializationError {
673 #[error("JSON serialization error: {0}")]
675 Json(#[from] serde_json::Error),
676
677 #[error("Base64 error: {details}")]
679 Base64 {
680 details: String,
682 },
683
684 #[error("Invalid data format: expected {expected}, got {actual}")]
686 InvalidFormat {
687 expected: String,
689 actual: String,
691 },
692
693 #[error("Data corruption detected: {details}")]
695 DataCorruption {
696 details: String,
698 },
699}
700
701impl From<ed25519_dalek::SignatureError> for Error {
704 fn from(err: ed25519_dalek::SignatureError) -> Self {
705 Error::Crypto(CryptoError::SignatureVerificationFailed {
706 reason: err.to_string(),
707 public_key: None,
708 })
709 }
710}
711
712impl From<pkcs8::Error> for Error {
713 fn from(err: pkcs8::Error) -> Self {
714 Error::Crypto(CryptoError::Pkcs8Error {
715 details: err.to_string(),
716 })
717 }
718}
719
720impl From<base64::DecodeError> for Error {
721 fn from(err: base64::DecodeError) -> Self {
722 Error::Serialization(SerializationError::Base64 {
723 details: err.to_string(),
724 })
725 }
726}
727
728impl From<uuid::Error> for Error {
729 fn from(err: uuid::Error) -> Self {
730 Error::Serialization(SerializationError::InvalidFormat {
731 expected: "valid UUID".to_string(),
732 actual: err.to_string(),
733 })
734 }
735}
736
737impl Error {
740 pub fn timeout(operation: impl Into<String>, duration: Duration) -> Self {
742 Self::Timeout {
743 operation: operation.into(),
744 duration,
745 }
746 }
747
748 pub fn other(message: impl Into<String>) -> Self {
750 Self::Other {
751 message: message.into(),
752 source: None,
753 }
754 }
755
756 pub fn with_source(
758 message: impl Into<String>,
759 source: impl std::error::Error + Send + Sync + 'static,
760 ) -> Self {
761 Self::Other {
762 message: message.into(),
763 source: Some(Box::new(source)),
764 }
765 }
766
767 pub fn agent_pool(message: impl Into<String>) -> Self {
769 Self::Agent(AgentError::AgentPoolError {
770 reason: message.into(),
771 })
772 }
773
774 pub fn config(message: impl Into<String>) -> Self {
776 Self::Configuration(message.into())
777 }
778
779 pub fn verification(message: impl Into<String>) -> Self {
781 Self::Crypto(CryptoError::SignatureVerificationFailed {
782 reason: message.into(),
783 public_key: None,
784 })
785 }
786
787 pub fn health_check(message: impl Into<String>) -> Self {
789 Self::Agent(AgentError::HealthCheckFailed {
790 reason: message.into(),
791 })
792 }
793}
794
795impl CryptoError {
796 pub fn signature_failed(reason: impl Into<String>) -> Self {
798 Self::SignatureVerificationFailed {
799 reason: reason.into(),
800 public_key: None,
801 }
802 }
803
804 pub fn signature_failed_with_key(reason: impl Into<String>, public_key: impl Into<String>) -> Self {
806 Self::SignatureVerificationFailed {
807 reason: reason.into(),
808 public_key: Some(public_key.into()),
809 }
810 }
811}
812
813impl ConsensusError {
814 pub fn not_reached(votes_for: usize, total_votes: usize, required: usize) -> Self {
816 Self::ConsensusNotReached {
817 votes_for,
818 total_votes,
819 required,
820 }
821 }
822
823 pub fn no_quorum(available: usize, required: usize) -> Self {
825 Self::QuorumNotAchieved { available, required }
826 }
827}
828
829impl AgentError {
830 pub fn spawn_failed(agent_type: impl Into<String>, reason: impl Into<String>) -> Self {
832 Self::SpawnFailed {
833 agent_type: agent_type.into(),
834 reason: reason.into(),
835 }
836 }
837
838 pub fn not_found(agent_id: impl Into<String>) -> Self {
840 Self::AgentNotFound {
841 agent_id: agent_id.into(),
842 }
843 }
844}
845
846impl ValidationError {
847 pub fn trust_chain_invalid(reason: impl Into<String>) -> Self {
849 Self::TrustChainInvalid {
850 reason: reason.into(),
851 depth: None,
852 }
853 }
854
855 pub fn certificate_expired(cert_id: impl Into<String>, expired_at: impl Into<String>) -> Self {
857 Self::CertificateExpired {
858 cert_id: cert_id.into(),
859 expired_at: expired_at.into(),
860 }
861 }
862}
863
864impl SystemError {
865 pub fn init_failed(reason: impl Into<String>) -> Self {
867 Self::InitializationFailed {
868 reason: reason.into(),
869 }
870 }
871
872 pub fn invalid_config(parameter: impl Into<String>, value: impl Into<String>) -> Self {
874 Self::InvalidConfiguration {
875 parameter: parameter.into(),
876 value: value.into(),
877 expected: None,
878 }
879 }
880}
881
882#[cfg(test)]
883mod tests {
884 use super::*;
885
886 #[test]
887 fn test_error_display() {
888 let err = Error::Crypto(CryptoError::SignatureVerificationFailed {
889 reason: "invalid signature".to_string(),
890 public_key: Some("abc123".to_string()),
891 });
892 assert!(err.to_string().contains("Cryptographic error"));
893 assert!(err.to_string().contains("Signature verification failed"));
894 }
895
896 #[test]
897 fn test_consensus_error_display() {
898 let err = ConsensusError::not_reached(3, 5, 4);
899 assert!(err.to_string().contains("3/5"));
900 assert!(err.to_string().contains("required 4"));
901 }
902
903 #[test]
904 fn test_error_helper_methods() {
905 let err = Error::timeout("verification", Duration::from_secs(5));
906 assert!(matches!(err, Error::Timeout { .. }));
907
908 let err = Error::other("something went wrong");
909 assert!(matches!(err, Error::Other { .. }));
910 }
911
912 #[test]
913 fn test_crypto_error_helper() {
914 let err = CryptoError::signature_failed("bad sig");
915 assert!(matches!(err, CryptoError::SignatureVerificationFailed { .. }));
916 }
917
918 #[test]
919 fn test_agent_error_helper() {
920 let err = AgentError::spawn_failed("verifier", "out of memory");
921 assert!(matches!(err, AgentError::SpawnFailed { .. }));
922 }
923
924 #[test]
925 fn test_error_source_chain() {
926 let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
927 let err: Error = io_err.into();
928 assert!(matches!(err, Error::Io(_)));
929 }
930
931 #[test]
932 fn test_serialization_error_from_json() {
933 let json_str = "{invalid json}";
934 let json_err = serde_json::from_str::<serde_json::Value>(json_str).unwrap_err();
935 let ser_err: SerializationError = json_err.into();
936 let err: Error = ser_err.into();
937 assert!(matches!(err, Error::Serialization(SerializationError::Json(_))));
938 }
939}