// NAC_Lens 4.0 辖区路由层集成模块(Issue #77) // 将 jurisdiction_router.rs 集成到 NAC_Lens 消息分发管道 // CBPP原则:约法即是治法 | 宪法即是规则 | 参与即是共识 | 节点产生区块交易决定区块大小 // NAC_Lens 是 NAC 原生协议(原 NRPC 已统一更名为 NAC_Lens) // 跨辖区交易:源辖区节点和目标辖区节点各自独立出具CR(参与即是共识,非多签) use serde::{Deserialize, Serialize}; use std::collections::HashMap; /// NAC_Lens 消息类型 #[derive(Debug, Clone, Serialize, Deserialize)] pub enum NacLensMessageType { /// 单辖区交易 IntraJurisdiction { jurisdiction: String, }, /// 跨辖区交易(源辖区 -> 目标辖区) CrossJurisdiction { source_jurisdiction: String, target_jurisdiction: String, }, /// 辖区规则更新广播(CA签名授权,约法即是治法) JurisdictionRuleUpdate { jurisdiction: String, new_version: String, ca_signature: Vec, }, /// 宪法收据(CR)广播(参与即是共识) ConstitutionalReceiptBroadcast { jurisdiction: String, tx_hash: String, cr_hash: String, }, /// 辖区节点注册(GIDS辖区证明) NodeRegistration { jurisdiction: String, node_id: String, gids_proof: Vec, }, } /// NAC_Lens 消息信封 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct NacLensEnvelope { /// 协议版本(NAC_Lens 4.0) pub protocol_version: String, /// 消息ID pub message_id: String, /// 消息类型 pub message_type: NacLensMessageType, /// 消息体(序列化的交易或规则数据) pub payload: Vec, /// 发送节点ID pub sender_node_id: String, /// 时间戳(UTC Unix 毫秒) pub timestamp: u64, } impl NacLensEnvelope { pub fn new( message_id: &str, message_type: NacLensMessageType, payload: Vec, sender_node_id: &str, ) -> Self { Self { protocol_version: "NAC_Lens/4.0".to_string(), message_id: message_id.to_string(), message_type, payload, sender_node_id: sender_node_id.to_string(), timestamp: 0, // 实际使用时由运行时填充 } } } /// 辖区路由表条目 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct JurisdictionRouteEntry { /// 辖区代码 pub jurisdiction_code: String, /// 辖区节点列表(节点ID -> 节点地址) pub nodes: HashMap, /// 当前活跃规则版本 pub active_rule_version: String, /// 路由优先级(0=最高) pub priority: u8, /// 是否接受跨辖区消息 pub accepts_cross_jurisdiction: bool, } /// NAC_Lens 辖区路由器 /// 负责将消息路由到正确的辖区节点,支持跨辖区消息转发 pub struct NacLensJurisdictionRouter { /// 路由表(jurisdiction_code -> RouteEntry) routing_table: HashMap, /// 本节点所属辖区 local_jurisdiction: String, /// 本节点ID local_node_id: String, } impl NacLensJurisdictionRouter { pub fn new(local_jurisdiction: &str, local_node_id: &str) -> Self { Self { routing_table: HashMap::new(), local_jurisdiction: local_jurisdiction.to_string(), local_node_id: local_node_id.to_string(), } } /// 注册辖区路由 pub fn register_jurisdiction(&mut self, entry: JurisdictionRouteEntry) { self.routing_table.insert(entry.jurisdiction_code.clone(), entry); } /// 路由消息到目标辖区节点 /// 约法即是治法:路由决策基于宪法规则,不基于节点偏好 pub fn route(&self, envelope: &NacLensEnvelope) -> RoutingDecision { match &envelope.message_type { NacLensMessageType::IntraJurisdiction { jurisdiction } => { self.route_intra_jurisdiction(jurisdiction, envelope) } NacLensMessageType::CrossJurisdiction { source_jurisdiction, target_jurisdiction, } => self.route_cross_jurisdiction(source_jurisdiction, target_jurisdiction, envelope), NacLensMessageType::JurisdictionRuleUpdate { jurisdiction, ca_signature, .. } => { // 规则更新:广播到所有辖区节点(CA签名验证通过后立即生效) if ca_signature.is_empty() { return RoutingDecision::Rejected { reason: "Rule update rejected: missing CA signature. \ Per CBPP '约法即是治法', rule updates require CA authorization." .to_string(), }; } self.route_rule_update_broadcast(jurisdiction) } NacLensMessageType::ConstitutionalReceiptBroadcast { jurisdiction, tx_hash, cr_hash, } => { // CR广播:广播到所有节点(参与即是共识) RoutingDecision::Broadcast { target_jurisdictions: self.routing_table.keys().cloned().collect(), message_summary: format!( "CR broadcast: jurisdiction={}, tx={}, cr={}", jurisdiction, tx_hash, cr_hash ), } } NacLensMessageType::NodeRegistration { jurisdiction, node_id, gids_proof, } => { if gids_proof.is_empty() { return RoutingDecision::Rejected { reason: format!( "Node {} registration rejected: missing GIDS proof for jurisdiction {}", node_id, jurisdiction ), }; } RoutingDecision::Forward { target_jurisdiction: jurisdiction.clone(), target_nodes: self .routing_table .get(jurisdiction) .map(|e| e.nodes.keys().cloned().collect()) .unwrap_or_default(), } } } } /// 单辖区内部路由 fn route_intra_jurisdiction( &self, jurisdiction: &str, _envelope: &NacLensEnvelope, ) -> RoutingDecision { if let Some(entry) = self.routing_table.get(jurisdiction) { RoutingDecision::Forward { target_jurisdiction: jurisdiction.to_string(), target_nodes: entry.nodes.keys().cloned().collect(), } } else { RoutingDecision::Rejected { reason: format!( "Jurisdiction {} not found in routing table. \ Node must register jurisdiction before routing.", jurisdiction ), } } } /// 跨辖区路由 /// 参与即是共识:源辖区和目标辖区各自独立处理,各自出具CR fn route_cross_jurisdiction( &self, source: &str, target: &str, _envelope: &NacLensEnvelope, ) -> RoutingDecision { let source_entry = self.routing_table.get(source); let target_entry = self.routing_table.get(target); match (source_entry, target_entry) { (Some(_src), Some(tgt)) => { if !tgt.accepts_cross_jurisdiction { return RoutingDecision::Rejected { reason: format!( "Jurisdiction {} does not accept cross-jurisdiction messages", target ), }; } // 跨辖区:同时转发到源辖区和目标辖区 // 各辖区节点独立出具CR(参与即是共识,非多签) RoutingDecision::CrossJurisdictionForward { source_jurisdiction: source.to_string(), target_jurisdiction: target.to_string(), source_nodes: self .routing_table .get(source) .map(|e| e.nodes.keys().cloned().collect()) .unwrap_or_default(), target_nodes: tgt.nodes.keys().cloned().collect(), } } (None, _) => RoutingDecision::Rejected { reason: format!("Source jurisdiction {} not registered", source), }, (_, None) => RoutingDecision::Rejected { reason: format!("Target jurisdiction {} not registered", target), }, } } /// 规则更新广播路由 fn route_rule_update_broadcast(&self, jurisdiction: &str) -> RoutingDecision { RoutingDecision::Broadcast { target_jurisdictions: vec![jurisdiction.to_string()], message_summary: format!( "Rule update broadcast to all {} nodes (CA-authorized, effective immediately)", jurisdiction ), } } /// 获取辖区路由表统计 pub fn routing_stats(&self) -> RoutingStats { let total_nodes: usize = self.routing_table.values().map(|e| e.nodes.len()).sum(); RoutingStats { registered_jurisdictions: self.routing_table.len(), total_nodes, local_jurisdiction: self.local_jurisdiction.clone(), local_node_id: self.local_node_id.clone(), } } /// 更新辖区规则版本(CA签名授权后调用) pub fn update_jurisdiction_version(&mut self, jurisdiction: &str, new_version: &str) -> bool { if let Some(entry) = self.routing_table.get_mut(jurisdiction) { entry.active_rule_version = new_version.to_string(); true } else { false } } } /// 路由决策 #[derive(Debug, Clone)] pub enum RoutingDecision { /// 转发到指定辖区节点 Forward { target_jurisdiction: String, target_nodes: Vec, }, /// 跨辖区转发(源辖区和目标辖区各自独立处理) CrossJurisdictionForward { source_jurisdiction: String, target_jurisdiction: String, source_nodes: Vec, target_nodes: Vec, }, /// 广播到多个辖区 Broadcast { target_jurisdictions: Vec, message_summary: String, }, /// 拒绝路由 Rejected { reason: String, }, } /// 路由统计信息 #[derive(Debug, Clone)] pub struct RoutingStats { pub registered_jurisdictions: usize, pub total_nodes: usize, pub local_jurisdiction: String, pub local_node_id: String, } #[cfg(test)] mod tests { use super::*; fn make_router() -> NacLensJurisdictionRouter { let mut router = NacLensJurisdictionRouter::new("CN", "node_cn_001"); // 注册 CN 辖区 let mut cn_nodes = HashMap::new(); cn_nodes.insert("node_cn_001".to_string(), "192.168.1.1:8080".to_string()); cn_nodes.insert("node_cn_002".to_string(), "192.168.1.2:8080".to_string()); router.register_jurisdiction(JurisdictionRouteEntry { jurisdiction_code: "CN".to_string(), nodes: cn_nodes, active_rule_version: "1.0.0".to_string(), priority: 0, accepts_cross_jurisdiction: true, }); // 注册 HK 辖区 let mut hk_nodes = HashMap::new(); hk_nodes.insert("node_hk_001".to_string(), "10.0.1.1:8080".to_string()); router.register_jurisdiction(JurisdictionRouteEntry { jurisdiction_code: "HK".to_string(), nodes: hk_nodes, active_rule_version: "1.0.0".to_string(), priority: 0, accepts_cross_jurisdiction: true, }); router } #[test] fn test_intra_jurisdiction_routing() { let router = make_router(); let envelope = NacLensEnvelope::new( "msg_001", NacLensMessageType::IntraJurisdiction { jurisdiction: "CN".to_string(), }, vec![], "node_cn_001", ); let decision = router.route(&envelope); assert!(matches!(decision, RoutingDecision::Forward { .. })); if let RoutingDecision::Forward { target_jurisdiction, target_nodes } = decision { assert_eq!(target_jurisdiction, "CN"); assert_eq!(target_nodes.len(), 2); } } #[test] fn test_cross_jurisdiction_routing() { let router = make_router(); let envelope = NacLensEnvelope::new( "msg_002", NacLensMessageType::CrossJurisdiction { source_jurisdiction: "CN".to_string(), target_jurisdiction: "HK".to_string(), }, vec![], "node_cn_001", ); let decision = router.route(&envelope); // 跨辖区:各辖区独立处理,参与即是共识 assert!(matches!(decision, RoutingDecision::CrossJurisdictionForward { .. })); } #[test] fn test_rule_update_requires_ca_signature() { let router = make_router(); let envelope = NacLensEnvelope::new( "msg_003", NacLensMessageType::JurisdictionRuleUpdate { jurisdiction: "CN".to_string(), new_version: "2.0.0".to_string(), ca_signature: vec![], // 无签名 }, vec![], "node_cn_001", ); let decision = router.route(&envelope); assert!(matches!(decision, RoutingDecision::Rejected { .. })); } #[test] fn test_rule_update_with_ca_signature() { let router = make_router(); let envelope = NacLensEnvelope::new( "msg_004", NacLensMessageType::JurisdictionRuleUpdate { jurisdiction: "CN".to_string(), new_version: "2.0.0".to_string(), ca_signature: vec![1u8; 64], // 有效CA签名 }, vec![], "node_cn_001", ); let decision = router.route(&envelope); assert!(matches!(decision, RoutingDecision::Broadcast { .. })); } #[test] fn test_unknown_jurisdiction_rejected() { let router = make_router(); let envelope = NacLensEnvelope::new( "msg_005", NacLensMessageType::IntraJurisdiction { jurisdiction: "UNKNOWN".to_string(), }, vec![], "node_cn_001", ); let decision = router.route(&envelope); assert!(matches!(decision, RoutingDecision::Rejected { .. })); } #[test] fn test_routing_stats() { let router = make_router(); let stats = router.routing_stats(); assert_eq!(stats.registered_jurisdictions, 2); assert_eq!(stats.total_nodes, 3); assert_eq!(stats.local_jurisdiction, "CN"); } #[test] fn test_node_registration_without_gids_rejected() { let router = make_router(); let envelope = NacLensEnvelope::new( "msg_006", NacLensMessageType::NodeRegistration { jurisdiction: "CN".to_string(), node_id: "node_new".to_string(), gids_proof: vec![], // 无GIDS证明 }, vec![], "node_new", ); let decision = router.route(&envelope); assert!(matches!(decision, RoutingDecision::Rejected { .. })); } #[test] fn test_update_jurisdiction_version() { let mut router = make_router(); let updated = router.update_jurisdiction_version("CN", "2.0.0"); assert!(updated); let stats = router.routing_stats(); assert_eq!(stats.registered_jurisdictions, 2); } }