// NAC CEE Client - 宪法执行引擎客户端 // 用于请求和验证宪法收据(Constitutional Receipt) use serde::{Deserialize, Serialize}; use std::time::Duration; use crate::constitutional_receipt::ConstitutionalReceipt; /// CEE错误类型 #[derive(Debug, thiserror::Error)] pub enum CeeError { #[error("网络错误: {0}")] Network(String), #[error("JSON解析错误: {0}")] JsonParse(String), #[error("CEE错误: {0}")] Cee(String), #[error("验证失败: {0}")] Validation(String), #[error("超时")] Timeout, #[error("无效响应")] InvalidResponse, } /// CR请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CrRequest { /// 交易数据(十六进制) pub transaction_data: String, /// 发送者地址 pub from: String, /// 接收者地址 pub to: String, /// 金额 pub value: String, /// 资产ID pub asset_id: String, /// 资产GNACS编码 pub gnacs_code: Option, /// KYC凭证哈希 pub kyc_credential_hash: Option, /// 额外元数据 pub metadata: std::collections::HashMap, } /// CR响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CrResponse { /// 宪法收据 pub receipt: ConstitutionalReceipt, /// CEE节点ID pub cee_node_id: String, /// 响应时间戳 pub timestamp: u64, } /// 宪法哈希响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ConstitutionalHashResponse { /// 当前宪法哈希 pub hash: String, /// 宪法版本 pub version: u64, /// 生效时间 pub effective_time: u64, } /// 健康检查响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HealthResponse { /// 状态 pub status: String, /// CEE节点ID pub node_id: String, /// 版本 pub version: String, /// 当前负载 pub load: f64, } /// NAC CEE客户端 pub struct NacCeeClient { url: String, client: reqwest::Client, } impl NacCeeClient { /// 创建新的CEE客户端 pub fn new(url: impl Into) -> Self { let client = reqwest::Client::builder() .timeout(Duration::from_secs(30)) .build() .expect("Failed to create HTTP client"); Self { url: url.into(), client, } } /// 请求宪法收据 pub async fn request_cr(&self, request: &CrRequest) -> Result { let url = format!("{}/api/v1/cr/request", self.url); let response = self.client .post(&url) .json(request) .send() .await .map_err(|e| CeeError::Network(e.to_string()))?; if !response.status().is_success() { let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); return Err(CeeError::Cee(error_text)); } let cr_response: CrResponse = response .json() .await .map_err(|e| CeeError::JsonParse(e.to_string()))?; Ok(cr_response.receipt) } /// 验证宪法收据 pub async fn verify_cr(&self, cr: &ConstitutionalReceipt) -> Result { let url = format!("{}/api/v1/cr/verify", self.url); let response = self.client .post(&url) .json(cr) .send() .await .map_err(|e| CeeError::Network(e.to_string()))?; if !response.status().is_success() { return Ok(false); } #[derive(Deserialize)] struct VerifyResponse { valid: bool, } let verify_response: VerifyResponse = response .json() .await .map_err(|e| CeeError::JsonParse(e.to_string()))?; Ok(verify_response.valid) } /// 获取当前宪法哈希 pub async fn get_constitutional_hash(&self) -> Result { let url = format!("{}/api/v1/constitution/hash", self.url); let response = self.client .get(&url) .send() .await .map_err(|e| CeeError::Network(e.to_string()))?; if !response.status().is_success() { let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); return Err(CeeError::Cee(error_text)); } let hash_response: ConstitutionalHashResponse = response .json() .await .map_err(|e| CeeError::JsonParse(e.to_string()))?; Ok(hash_response) } /// 健康检查 pub async fn health_check(&self) -> Result { let url = format!("{}/api/v1/health", self.url); let response = self.client .get(&url) .send() .await .map_err(|e| CeeError::Network(e.to_string()))?; if !response.status().is_success() { return Err(CeeError::Cee("Health check failed".to_string())); } let health_response: HealthResponse = response .json() .await .map_err(|e| CeeError::JsonParse(e.to_string()))?; Ok(health_response) } /// 本地验证宪法收据 pub fn validate_cr_locally(&self, cr: &ConstitutionalReceipt) -> Result<(), CeeError> { // 1. 检查有效期 let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_secs(); if now < cr.timestamp { return Err(CeeError::Validation("CR时间戳在未来".to_string())); } if now > cr.timestamp + cr.validity_window { return Err(CeeError::Validation("CR已过期".to_string())); } // 2. 检查签名数量 if cr.signatures.is_empty() { return Err(CeeError::Validation("CR缺少签名".to_string())); } // 3. 检查receipt_id不为空 if cr.receipt_id == [0u8; 32] { return Err(CeeError::Validation("CR ID无效".to_string())); } Ok(()) } } /// 多CEE节点管理器 pub struct CeeNodeManager { nodes: Vec, current_index: std::sync::atomic::AtomicUsize, } impl CeeNodeManager { /// 创建新的CEE节点管理器 pub fn new(urls: Vec) -> Self { let nodes = urls.into_iter() .map(|url| NacCeeClient::new(url)) .collect(); Self { nodes, current_index: std::sync::atomic::AtomicUsize::new(0), } } /// 获取下一个节点 fn next_node(&self) -> &NacCeeClient { let index = self.current_index.fetch_add(1, std::sync::atomic::Ordering::SeqCst); &self.nodes[index % self.nodes.len()] } /// 请求CR(带重试和负载均衡) pub async fn request_cr(&self, request: &CrRequest) -> Result { let mut last_error = None; // 尝试所有节点 for _ in 0..self.nodes.len() { let node = self.next_node(); match node.request_cr(request).await { Ok(cr) => return Ok(cr), Err(e) => { eprintln!("CEE节点请求失败: {}", e); last_error = Some(e); } } } Err(last_error.unwrap_or(CeeError::Cee("所有CEE节点都不可用".to_string()))) } /// 验证CR pub async fn verify_cr(&self, cr: &ConstitutionalReceipt) -> Result { // 先本地验证 self.nodes[0].validate_cr_locally(cr)?; // 再远程验证 let node = self.next_node(); node.verify_cr(cr).await } /// 获取宪法哈希 pub async fn get_constitutional_hash(&self) -> Result { let node = self.next_node(); node.get_constitutional_hash().await } /// 健康检查所有节点 pub async fn health_check_all(&self) -> Vec> { let mut results = Vec::new(); for node in &self.nodes { results.push(node.health_check().await); } results } } #[cfg(test)] mod tests { use super::*; #[test] fn test_cee_client_creation() { let client = NacCeeClient::new("https://cee.newassetchain.com"); assert_eq!(client.url, "https://cee.newassetchain.com"); } #[test] fn test_node_manager_creation() { let manager = CeeNodeManager::new(vec![ "https://cee1.newassetchain.com".to_string(), "https://cee2.newassetchain.com".to_string(), ]); assert_eq!(manager.nodes.len(), 2); } #[test] fn test_node_manager_round_robin() { let manager = CeeNodeManager::new(vec![ "https://cee1.newassetchain.com".to_string(), "https://cee2.newassetchain.com".to_string(), ]); let node1 = manager.next_node(); let node2 = manager.next_node(); let node3 = manager.next_node(); assert_eq!(node1.url, "https://cee1.newassetchain.com"); assert_eq!(node2.url, "https://cee2.newassetchain.com"); assert_eq!(node3.url, "https://cee1.newassetchain.com"); } #[test] fn test_validate_cr_locally() { let client = NacCeeClient::new("https://cee.newassetchain.com"); let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_secs(); let cr = ConstitutionalReceipt { transaction_hash: [1u8; 32], constitutional_hash: [2u8; 32], clause_mask: 0xFF, execution_result_hash: [3u8; 32], timestamp: now, validity_window: 3600, signatures: vec![vec![4u8; 64]], receipt_id: [5u8; 32], }; assert!(client.validate_cr_locally(&cr).is_ok()); } #[test] fn test_validate_cr_expired() { let client = NacCeeClient::new("https://cee.newassetchain.com"); let cr = ConstitutionalReceipt { transaction_hash: [1u8; 32], constitutional_hash: [2u8; 32], clause_mask: 0xFF, execution_result_hash: [3u8; 32], timestamp: 1000000, // 很久以前 validity_window: 3600, signatures: vec![vec![4u8; 64]], receipt_id: [5u8; 32], }; assert!(client.validate_cr_locally(&cr).is_err()); } }