kinetic_core/error/
governance.rs1use super::Severity;
21use thiserror::Error;
22
23#[derive(Error, Debug, PartialEq, Eq)]
25pub enum GovernanceError {
26 #[error("ROOT_PUBLIC_KEY_HEX is not configured. This is a fatal error.")]
28 MissingRootKey,
29
30 #[error("Key length mismatch")]
32 KeyLengthMismatch,
33 #[error("Governance action too old, replay rejected")]
35 StaleProposal,
36 #[error("Timelock has not expired yet")]
38 TimelockNotExpired,
39
40 #[error("Target hash is not a pending timelock or was vetoed")]
42 NotPendingOrVetoed,
43
44 #[error("Governance is disabled in permissionless mode")]
46 GovernanceDisabled,
47
48 #[error("Insufficient valid signatures")]
50 InsufficientSignatures,
51 #[error("Premium name grants must be exactly 1 character long")]
53 InvalidPremiumNameLength,
54 #[error("Infrastructure name grants must target a valid Category 2 infrastructure name")]
56 InvalidInfrastructureName,
57}
58
59impl GovernanceError {
60 pub fn code(&self) -> &'static str {
62 match self {
63 Self::MissingRootKey => "KIN-GOV-001",
64 Self::GovernanceDisabled => "KIN-GOV-002",
65 Self::KeyLengthMismatch => "KIN-GOV-003",
66 Self::StaleProposal => "KIN-GOV-004",
67 Self::TimelockNotExpired => "KIN-GOV-005",
68
69 Self::NotPendingOrVetoed => "KIN-GOV-007",
70
71 Self::InsufficientSignatures => "KIN-GOV-016",
72 Self::InvalidPremiumNameLength => "KIN-GOV-019",
73 Self::InvalidInfrastructureName => "KIN-GOV-020",
74 }
75 }
76
77 pub fn error_type_uri(&self) -> String {
79 format!("{}/errors/{}", crate::constants::DOCS_URL, self.code())
80 }
81
82 pub fn severity(&self) -> Severity {
84 match self {
85 Self::MissingRootKey => Severity::Critical,
86 Self::StaleProposal | Self::TimelockNotExpired | Self::NotPendingOrVetoed => {
87 Severity::Info
88 }
89 Self::KeyLengthMismatch => Severity::Error,
90 Self::InsufficientSignatures
91 | Self::GovernanceDisabled
92 | Self::InvalidPremiumNameLength
93 | Self::InvalidInfrastructureName => Severity::Warning,
94 }
95 }
96
97 pub fn is_retryable(&self) -> bool {
99 matches!(
100 self,
101 Self::TimelockNotExpired | Self::InsufficientSignatures
102 )
103 }
104
105 pub fn user_message(&self) -> String {
107 match self {
108 Self::MissingRootKey => "The ROOT_PUBLIC_KEY_HEX environment variable is not set. This is a fatal configuration error.".to_string(),
109
110 Self::KeyLengthMismatch => "The provided cryptographic key length is invalid.".to_string(),
111 Self::StaleProposal => "The proposed governance action is too old and has been rejected to prevent replay attacks.".to_string(),
112 Self::TimelockNotExpired => "The governance action is still in its mandatory waiting period and cannot be executed yet.".to_string(),
113
114 Self::NotPendingOrVetoed => {
115 "The requested governance hash is not in a modifiable pending state.".to_string()
116 }
117 Self::GovernanceDisabled => {
118 "The network is operating in permissionless mode where governance actions are universally rejected.".to_string()
119 }
120 Self::InsufficientSignatures => {
121 "The message lacks the required cryptographic signatures to meet the council quorum threshold.".to_string()
122 }
123 Self::InvalidPremiumNameLength => "Premium names governed by this action must be exactly 1 character long.".to_string(),
124 Self::InvalidInfrastructureName => "Infrastructure names governed by this action must be valid Category 2 names.".to_string(),
125 }
126 }
127}