use sha2::{Digest, Sha256};
use std::collections::HashMap;
use super::types::{
GovernanceEffect, GovernanceState, Hash256, PublicKeyBytes, SignedGovernanceMessage,
};
use crate::constants::ROOT_PUBLIC_KEY_HEX;
use crate::error::GovernanceError;
pub fn validate_keys_initialized() -> Result<(), GovernanceError> {
if crate::config::is_dev_mode() {
return Ok(());
}
if ROOT_PUBLIC_KEY_HEX.contains("REPLACE_ME") {
return Err(GovernanceError::MissingRootKey);
}
let dummy_state = GovernanceState::new(0);
let _ = dummy_state.get_root_key()?;
Ok(())
}
impl GovernanceState {
pub fn new(genesis_timestamp_sec: u64) -> Self {
Self {
genesis_timestamp_sec,
active_root_key: None,
is_halted: false,
total_paused_kyns: 0,
pause_history: Vec::new(),
executed_hashes: HashMap::new(),
}
}
pub fn hash_action(msg: &SignedGovernanceMessage) -> Hash256 {
let mut hasher = Sha256::new();
hasher.update(msg.to_canonical_bytes());
let result = hasher.finalize();
let mut array = [0u8; 32];
array.copy_from_slice(&result);
array
}
pub fn prune(&mut self, current_time_sec: u64) {
self.executed_hashes.retain(|_, exec_time| {
current_time_sec <= *exec_time + crate::constants::MAX_AGE_SECONDS
});
}
pub fn get_root_key(&self) -> Result<PublicKeyBytes, GovernanceError> {
if let Some(key) = &self.active_root_key {
return Ok(key.clone());
}
let bytes =
hex::decode(ROOT_PUBLIC_KEY_HEX).map_err(|_| GovernanceError::MissingRootKey)?;
if bytes.len() != 1952 {
return Err(GovernanceError::KeyLengthMismatch);
}
Ok(bytes)
}
pub fn verify_action(
&mut self,
msg: &SignedGovernanceMessage,
current_time_sec: u64,
) -> Result<Option<GovernanceEffect>, GovernanceError> {
crate::governance::engine::get_active_engine().verify_action(self, msg, current_time_sec)
}
pub fn execute_action(
&mut self,
msg: &SignedGovernanceMessage,
current_time_sec: u64,
) -> Option<GovernanceEffect> {
crate::governance::engine::get_active_engine().execute_action(self, msg, current_time_sec)
}
}
pub fn process_governance_message(
state: &mut GovernanceState,
msg: &SignedGovernanceMessage,
) -> Result<Option<GovernanceEffect>, crate::error::GovernanceError> {
let current_time_sec = web_time::SystemTime::now()
.duration_since(web_time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
state.prune(current_time_sec);
let action_hash = GovernanceState::hash_action(msg);
if state.executed_hashes.contains_key(&action_hash) {
return Err(crate::error::GovernanceError::StaleProposal);
}
state.verify_action(msg, current_time_sec)
}