From 2c2883f2f5c3d4bd47696c61a880b466a9c3b26e Mon Sep 17 00:00:00 2001 From: NAC Admin Date: Sat, 7 Mar 2026 12:17:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(constitution):=20Issue=20#70=20=E2=80=94?= =?UTF-8?q?=20=E5=AE=AA=E6=B3=95=E5=B1=82=E6=96=B0=E5=A2=9EA44-A52?= =?UTF-8?q?=E5=A4=9A=E8=BE=96=E5=8C=BA=E8=8A=82=E7=82=B9=E5=85=B1=E4=BA=AB?= =?UTF-8?q?=E6=9D=A1=E6=AC=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增宪法条款(A44-A52): - A44: 多辖区节点物理共享许可(容器化逻辑隔离) - A45: 跨辖区区块生产双CR强制(jurisdiction_merkle_root) - A46: 共享资源辖区协商分配(≥67%委员会投票) - A47: 节点身份辖区绑定强制(GIDS增强) - A48: WASM规则插件沙箱执行强制(≤10ms/64MB) - A49: CEE节点跨辖区共享验证(负载均衡) - A50: 辖区争议宪法法院裁决(链上判决) - A51: CSNP辖区感知路由强制 - A52: 共享存储敏感数据加密(AES-256-GCM) 新增文件: - nac-constitution/clauses/node_sharing_clauses.cnnl - nac-constitution-clauses/src/node_sharing.rs(12个测试全部通过) - nac-multi-jurisdiction/src/node_sharing_enhanced.rs(5个测试全部通过) - charter-std/src/constitution_interface.charter - ISSUE_070_CONSTITUTIONAL_RULES_DELIVERY.md 关联:Issue #59(多辖区节点共享方案)、Issue #66(宪法增补条款A01-A43) --- ISSUE_070_CONSTITUTIONAL_RULES_DELIVERY.md | 213 ++++ .../src/constitution_interface.charter | 435 +++++++ nac-constitution-clauses/src/lib.rs | 1 + nac-constitution-clauses/src/node_sharing.rs | 1026 +++++++++++++++++ .../clauses/node_sharing_clauses.cnnl | 216 ++++ nac-multi-jurisdiction/src/lib.rs | 1 + .../src/node_sharing_enhanced.rs | 798 +++++++++++++ 7 files changed, 2690 insertions(+) create mode 100644 ISSUE_070_CONSTITUTIONAL_RULES_DELIVERY.md create mode 100644 charter-std/src/constitution_interface.charter create mode 100644 nac-constitution-clauses/src/node_sharing.rs create mode 100644 nac-constitution/clauses/node_sharing_clauses.cnnl create mode 100644 nac-multi-jurisdiction/src/node_sharing_enhanced.rs diff --git a/ISSUE_070_CONSTITUTIONAL_RULES_DELIVERY.md b/ISSUE_070_CONSTITUTIONAL_RULES_DELIVERY.md new file mode 100644 index 0000000..fae6e5b --- /dev/null +++ b/ISSUE_070_CONSTITUTIONAL_RULES_DELIVERY.md @@ -0,0 +1,213 @@ +# Issue #70 — 宪法层规则增补:多辖区节点共享条款 + +**状态:** 已完成 +**版本:** 1.0 +**日期:** 2026-03-07 +**关联白皮书:** 《NAC公链多辖区节点共享方案与技术落地白皮书》v1.0 +**关联 Issue:** #59(多辖区节点共享方案)、#66(宪法增补条款A01-A43) + +--- + +## 一、工作概述 + +本次工单在现有宪法增补条款(A01-A43)基础上,新增 **9 条多辖区节点共享宪法条款(A44-A52)**,覆盖物理共享逻辑隔离、跨辖区区块生产、资源协商分配、节点身份绑定、WASM沙箱、CEE集群、争议裁决、CSNP路由、存储加密等核心规则。 + +--- + +## 二、新增宪法条款清单(A44-A52) + +| 条款编号 | 层级 | 条款名称 | 核心规则 | 违规处理 | +|----------|------|----------|----------|----------| +| A44 | Strategic | 多辖区节点物理共享许可 | 物理共享节点必须容器化逻辑隔离 | reject_block | +| A45 | Strategic | 跨辖区区块生产双CR强制 | 区块头必须含 jurisdiction_merkle_root | reject_block | +| A46 | Strategic | 共享资源辖区协商分配 | 资源分配需委员会≥67%投票 | revert_allocation | +| A47 | Tactical | 节点身份辖区绑定强制 | GIDS注册需辖区政府数字签名 | reject_node_registration | +| A48 | Tactical | WASM规则插件沙箱执行强制 | 插件执行≤10ms、≤64MB、哈希上链 | terminate_plugin_execution | +| A49 | Tactical | CEE节点跨辖区共享验证 | CEE必须支持多辖区并行验证 | fallback_to_single_jurisdiction_cee | +| A50 | Tactical | 辖区争议宪法法院裁决 | 争议必须提交宪法法院、判决上链 | freeze_disputed_resources | +| A51 | Tactical | CSNP辖区感知路由强制 | CSNP必须识别辖区并保留原始CR | reject_non_compliant_routing | +| A52 | Tactical | 共享存储敏感数据加密 | AES-256-GCM加密、≥3副本冗余 | quarantine_unencrypted_data | + +--- + +## 三、交付文件清单 + +### 3.1 CNNL 宪法条款文件 + +``` +nac-constitution/clauses/node_sharing_clauses.cnnl +``` + +- 9条条款的 CNNL 形式化表达 +- 每条包含:tier(层级)、clause_index(索引)、predicate(谓词)、obligation(义务)、violation_action(违规处理)、test(测试块) +- 完整测试块(9个测试用例) + +### 3.2 Rust 验证引擎 + +``` +nac-constitution-clauses/src/node_sharing.rs +``` + +- 每条条款独立的验证函数(`validate_a44_*` 至 `validate_a52_*`) +- 综合验证报告(`NodeSharingComplianceReport`) +- 违规摘要生成(`violation_summary()`) +- 完整单元测试(12个测试用例,覆盖合规和违规场景) + +### 3.3 多辖区运行时增强 + +``` +nac-multi-jurisdiction/src/node_sharing_enhanced.rs +``` + +- `SharedNodeRegistry`:节点共享注册表(隔离违规检测) +- `DynamicQuotaManager`:动态资源配额管理(A46) +- `CrossJurisdictionBlockCoordinator`:跨辖区区块生产协调器(A45) +- `GidsEnhancedRegistry`:GIDS增强注册表(A47) +- 完整单元测试(5个测试用例) + +### 3.4 Charter 合约接口 + +``` +charter-std/src/constitution_interface.charter +``` + +- `IConstitution` 接口:宪法内置合约完整接口定义 +- `RwaAssetCrossJurisdictionTransfer` 示例合约:演示A45/A46/A47/A50/A51集成 +- `NodeSharingRegistry` 示例合约:演示A44/A47/A48集成 + +--- + +## 四、架构设计说明 + +### 4.1 条款层级设计 + +``` +宪法层级结构(A44-A52 扩展后): + +永恒级(Eternal,索引1-100): + A01-A08 基础架构条款(NAC原生技术栈保护) + +战略级(Strategic,索引101-1000): + A09-A16 资产合规条款 + A17-A24 节点治理条款 + A25-A32 XTZH货币条款 + A33-A38 多辖区条款(基础) + A39-A43 AI合规条款 + ★ A44 多辖区节点物理共享许可(新增,索引101) + ★ A45 跨辖区区块生产双CR强制(新增,索引102) + ★ A46 共享资源辖区协商分配(新增,索引103) + +战术级(Tactical,索引1001+): + ★ A47 节点身份辖区绑定强制(新增,索引1001) + ★ A48 WASM规则插件沙箱执行强制(新增,索引1002) + ★ A49 CEE节点跨辖区共享验证(新增,索引1003) + ★ A50 辖区争议宪法法院裁决(新增,索引1004) + ★ A51 CSNP辖区感知路由强制(新增,索引1005) + ★ A52 共享存储敏感数据加密(新增,索引1006) +``` + +### 4.2 跨辖区区块生产流程(A45) + +``` +区块生产节点收到跨辖区交易 + ↓ +为每笔跨辖区交易选择最优CEE节点(A49负载均衡) + ↓ +CEE节点并行调用源辖区和目标辖区插件(A48 WASM沙箱) + ↓ +生成双CR(源辖区CR + 目标辖区CR) + ↓ +将所有双CR哈希构建默克尔树 → jurisdiction_merkle_root + ↓ +写入区块头 block.header.jurisdiction_merkle_root + ↓ +CBPP验证节点验证 jurisdiction_merkle_root 有效性 + ↓ +区块上链 +``` + +### 4.3 节点注册流程(A47) + +``` +节点申请加入网络 + ↓ +向辖区政府/监管机构申请辖区证明(jurisdiction_proof) + ↓ +提交 GIDS 注册(DID + 辖区 + 辖区证明 + 插件哈希列表) + ↓ +GIDS 验证: + - DID 格式(must start with "did:nac:") + - 辖区 != 0 + - 辖区证明签名有效且未过期 + - 至少一个已授权插件哈希 + ↓ +注册成功,节点可加入网络 + ↓ +节点加载插件时,GIDS 实时验证插件哈希(A47+A48) +``` + +### 4.4 资源分配流程(A46) + +``` +辖区提交资源分配提案 + ↓ +辖区协商委员会(JurisdictionCouncil)投票 + ↓ +投票比例 ≥ 67%? + ├─ 是 → 提案通过,DynamicQuotaManager 应用新配额 + └─ 否 → 提案拒绝,维持原配额 + ↓ +配额变更记录写入宪法附录(链上存证) + ↓ +各辖区节点按新配额运行 + ↓ +超出配额时触发 A46 违规处理(revert_allocation) +``` + +--- + +## 五、与现有模块的集成关系 + +| 现有模块 | 集成方式 | 涉及条款 | +|----------|----------|----------| +| `nac-constitution-clauses` | 新增 `node_sharing.rs` 验证器 | A44-A52 | +| `nac-multi-jurisdiction` | 新增 `node_sharing_enhanced.rs` 运行时 | A44-A47、A49 | +| `nac-cbpp` | 区块头新增 `jurisdiction_merkle_root` 字段 | A45 | +| `nac-csnp` | 新增辖区感知路由模块 | A51 | +| `nac-nvm` | 新增宪法内置合约(地址0x...0001) | A44-A52 | +| `charter-std` | 新增 `constitution_interface.charter` | A44-A52 | +| `nac-ai-compliance` | AI合规检查集成A39-A43 | A39-A43 | + +--- + +## 六、测试覆盖 + +| 文件 | 测试数量 | 覆盖场景 | +|------|----------|----------| +| `node_sharing.rs` | 12 | A44合规/违规、A45跨辖区、A46投票、A47身份、A48沙箱、A52存储 | +| `node_sharing_enhanced.rs` | 5 | 注册表、隔离检测、配额超额、GIDS验证、区块协调器 | +| `node_sharing_clauses.cnnl` | 9 | 每条条款独立测试块 | + +--- + +## 七、后台管理员信息 + +- **Gitea 管理员账号:** nacadmin +- **Gitea 管理员密码:** NACadmin2026! +- **服务器 SSH:** root@103.96.148.7:22000 +- **服务器密码:** XKUigTFMJXhH +- **宝塔面板:** http://103.96.148.7:12/btwest(cproot / vajngkvf) + +--- + +## 八、下一步工作建议 + +1. **Issue #71**:将 `jurisdiction_merkle_root` 字段集成到 CBPP 区块头结构(`nac-cbpp` 模块) +2. **Issue #72**:实现 NVM 宪法内置合约(地址 `0x0000000000000000000000000000000000000001`) +3. **Issue #73**:CSNP 辖区感知路由实现(`nac-csnp` 模块扩展) +4. **Issue #74**:WASM 插件运行时沙箱集成(`nac-nvm` 模块扩展) +5. **Issue #75**:宪法条款 A44-A52 主网部署和测试 + +--- + +*本文档由 NAC 核心协议工程组生成 | Issue #70 | 2026-03-07* diff --git a/charter-std/src/constitution_interface.charter b/charter-std/src/constitution_interface.charter new file mode 100644 index 0000000..6a3a244 --- /dev/null +++ b/charter-std/src/constitution_interface.charter @@ -0,0 +1,435 @@ +// charter-std/src/constitution_interface.charter +// NAC公链 Charter 智能合约宪法接口 +// Issue #70 | 版本: 1.0 | 2026-03-07 +// +// 本文件定义 Charter 合约访问宪法层的标准接口: +// - 宪法条款查询接口(A44-A52) +// - 节点共享合规验证绑定 +// - 跨辖区资源分配查询 +// - 辖区身份验证接口 + +// ============================================================ +// 标准库导入(Charter 原生) +// ============================================================ + +import std::types::{ Address, Hash, Bytes48, Uint16, Uint64, Bool, String } +import std::acc20::{ AssetId, AssetRecord } +import std::cr::{ ConstitutionalReceipt, DualConstitutionalReceipt } +import std::jurisdiction::{ JurisdictionId, JurisdictionProof } + +// ============================================================ +// 宪法条款查询接口 +// ============================================================ + +/// 宪法条款层级 +enum ClauseTier { + Eternal, // 永恒级(索引1-100) + Strategic, // 战略级(索引101-1000) + Tactical, // 战术级(索引1001+) +} + +/// 宪法条款记录 +struct ConstitutionalClause { + clause_index: Uint64, + title: String, + tier: ClauseTier, + is_active: Bool, + effective_from: Uint64, + clause_hash: Bytes48, +} + +/// 节点共享宪法条款(A44-A52) +struct NodeSharingClause { + clause_index: Uint64, + name: String, + tier: ClauseTier, + // 条款核心谓词(CNNL形式化表达) + predicate_hash: Bytes48, + // 违规处理动作 + violation_action: String, + is_active: Bool, +} + +// ============================================================ +// 宪法接口(内置合约,地址 0x0000...CONST) +// ============================================================ + +/// NAC宪法内置合约接口 +/// 合约地址:0x0000000000000000000000000000000000000001 +interface IConstitution { + + // --- 条款查询 --- + + /// 查询宪法条款是否激活 + /// @param clause_index 条款索引(如 A44 = 44) + /// @returns 条款是否处于激活状态 + fn is_clause_active(clause_index: Uint64) -> Bool + + /// 获取条款详情 + /// @param clause_index 条款索引 + /// @returns 条款记录(不存在时 panic) + fn get_clause(clause_index: Uint64) -> ConstitutionalClause + + /// 获取节点共享条款(A44-A52) + /// @param clause_index 条款索引(44-52) + /// @returns 节点共享条款记录 + fn get_node_sharing_clause(clause_index: Uint64) -> NodeSharingClause + + // --- 节点共享合规验证(A44)--- + + /// 验证节点是否满足物理共享逻辑隔离要求(A44) + /// @param node_did 节点DID + /// @param container_id 容器实例ID(不能为空) + /// @param network_namespace 网络命名空间(不能为空) + /// @returns 是否合规 + fn verify_node_sharing_isolation( + node_did: String, + container_id: String, + network_namespace: String, + ) -> Bool + + // --- 跨辖区双CR验证(A45)--- + + /// 验证跨辖区交易的双CR(A45) + /// @param source_cr 源辖区宪法收据 + /// @param target_cr 目标辖区宪法收据 + /// @returns 双CR是否有效 + fn verify_dual_cr( + source_cr: ConstitutionalReceipt, + target_cr: ConstitutionalReceipt, + ) -> Bool + + /// 获取当前区块的 jurisdiction_merkle_root(A45) + /// @returns 当前区块的辖区默克尔树根(无跨辖区交易时返回零哈希) + fn get_jurisdiction_merkle_root() -> Bytes48 + + // --- 资源配额查询(A46)--- + + /// 查询辖区当前资源配额(A46) + /// @param jurisdiction 辖区ID + /// @returns (cpu_share, memory_share, bandwidth_share, storage_share) 定点数1e4 + fn get_jurisdiction_quota(jurisdiction: JurisdictionId) -> (Uint64, Uint64, Uint64, Uint64) + + /// 检查辖区是否超出资源配额(A46) + /// @param jurisdiction 辖区ID + /// @returns 是否超出配额 + fn is_quota_exceeded(jurisdiction: JurisdictionId) -> Bool + + // --- 节点身份辖区绑定(A47)--- + + /// 验证节点DID的辖区绑定(A47) + /// @param node_did 节点DID + /// @param jurisdiction 声明的辖区ID + /// @returns 绑定是否有效 + fn verify_node_jurisdiction_binding( + node_did: String, + jurisdiction: JurisdictionId, + ) -> Bool + + /// 验证节点加载的插件哈希是否已授权(A47) + /// @param node_did 节点DID + /// @param plugin_hash 插件哈希(SHA3-384) + /// @returns 插件是否已授权 + fn verify_plugin_hash_authorized( + node_did: String, + plugin_hash: Bytes48, + ) -> Bool + + // --- WASM沙箱验证(A48)--- + + /// 验证插件是否在WASM沙箱中执行(A48) + /// @param plugin_hash 插件哈希 + /// @returns 是否在WASM沙箱中执行 + fn verify_wasm_sandbox_execution(plugin_hash: Bytes48) -> Bool + + /// 检查插件哈希是否已上链(A48) + /// @param plugin_hash 插件哈希 + /// @returns 是否已上链 + fn is_plugin_hash_on_chain(plugin_hash: Bytes48) -> Bool + + // --- CEE集群查询(A49)--- + + /// 获取支持指定辖区的CEE节点列表(A49) + /// @param jurisdiction 辖区ID + /// @returns CEE节点DID列表 + fn get_cee_nodes_for_jurisdiction(jurisdiction: JurisdictionId) -> Array + + /// 获取负载最低的CEE节点(A49,用于跨辖区交易路由) + /// @param source_jurisdiction 源辖区 + /// @param target_jurisdiction 目标辖区 + /// @returns 最优CEE节点DID(无可用节点时返回空字符串) + fn get_optimal_cee_node( + source_jurisdiction: JurisdictionId, + target_jurisdiction: JurisdictionId, + ) -> String + + // --- 争议状态查询(A50)--- + + /// 查询辖区间是否存在未解决争议(A50) + /// @param jurisdiction_a 辖区A + /// @param jurisdiction_b 辖区B + /// @returns 是否存在未解决争议 + fn has_pending_dispute( + jurisdiction_a: JurisdictionId, + jurisdiction_b: JurisdictionId, + ) -> Bool + + // --- CSNP路由验证(A51)--- + + /// 验证CSNP辖区感知路由是否启用(A51) + /// @returns 是否启用 + fn is_csnp_jurisdiction_routing_enabled() -> Bool + + // --- 存储加密验证(A52)--- + + /// 验证存储节点是否满足加密要求(A52) + /// @param storage_node_did 存储节点DID + /// @returns 是否满足A52要求 + fn verify_storage_encryption_compliance(storage_node_did: String) -> Bool +} + +// ============================================================ +// 示例合约:使用宪法接口的 RWA 资产跨辖区转移合约 +// ============================================================ + +/// RWA资产跨辖区转移合约(集成A44-A52宪法条款) +contract RwaAssetCrossJurisdictionTransfer { + + // 宪法内置合约地址 + const CONSTITUTION_ADDRESS: Address = 0x0000000000000000000000000000000000000001 + + // 状态变量 + state { + owner: Address, + asset_id: AssetId, + source_jurisdiction: JurisdictionId, + target_jurisdiction: JurisdictionId, + transfer_status: TransferStatus, + source_cr: ConstitutionalReceipt, + target_cr: ConstitutionalReceipt, + initiated_at: Uint64, + } + + enum TransferStatus { + Pending, + CrVerified, + Completed, + Failed, + } + + // 构造函数 + constructor( + asset_id: AssetId, + source_jurisdiction: JurisdictionId, + target_jurisdiction: JurisdictionId, + ) { + self.owner = msg.sender + self.asset_id = asset_id + self.source_jurisdiction = source_jurisdiction + self.target_jurisdiction = target_jurisdiction + self.transfer_status = TransferStatus::Pending + self.initiated_at = block.timestamp + } + + /// 提交双CR并验证(A45) + /// 调用者必须提供源辖区和目标辖区的宪法收据 + fn submit_dual_cr( + source_cr: ConstitutionalReceipt, + target_cr: ConstitutionalReceipt, + ) -> Bool { + // 仅资产所有者可提交 + require(msg.sender == self.owner, "仅资产所有者可提交双CR") + require(self.transfer_status == TransferStatus::Pending, "转移状态不正确") + + // 调用宪法内置合约验证双CR(A45) + let constitution = IConstitution(CONSTITUTION_ADDRESS) + let is_valid = constitution.verify_dual_cr(source_cr, target_cr) + + if !is_valid { + self.transfer_status = TransferStatus::Failed + emit DualCrVerificationFailed(self.asset_id, block.timestamp) + return false + } + + // 检查辖区间是否有未解决争议(A50) + let has_dispute = constitution.has_pending_dispute( + self.source_jurisdiction, + self.target_jurisdiction, + ) + require(!has_dispute, "A50: 辖区间存在未解决争议,转移被暂停") + + // 检查目标辖区资源配额(A46) + let quota_exceeded = constitution.is_quota_exceeded(self.target_jurisdiction) + require(!quota_exceeded, "A46: 目标辖区资源配额已超出,请稍后重试") + + self.source_cr = source_cr + self.target_cr = target_cr + self.transfer_status = TransferStatus::CrVerified + + emit DualCrVerified(self.asset_id, self.source_jurisdiction, self.target_jurisdiction) + return true + } + + /// 执行跨辖区转移(A45验证通过后) + fn execute_transfer(recipient: Address) -> Bool { + require(msg.sender == self.owner, "仅资产所有者可执行转移") + require(self.transfer_status == TransferStatus::CrVerified, "双CR未验证") + + let constitution = IConstitution(CONSTITUTION_ADDRESS) + + // 验证接收方节点的辖区绑定(A47) + // 注:实际实现中需要通过 NRPC4.0 查询接收方节点DID + + // 验证CSNP路由是否启用(A51) + let routing_enabled = constitution.is_csnp_jurisdiction_routing_enabled() + require(routing_enabled, "A51: CSNP辖区感知路由未启用,无法执行跨辖区转移") + + // 执行ACC-20资产转移(NAC原生标准) + // 注:使用 std::acc20 而非 ERC-20 + let transfer_result = acc20::transfer_cross_jurisdiction( + self.asset_id, + self.owner, + recipient, + self.source_cr, + self.target_cr, + ) + + if transfer_result { + self.transfer_status = TransferStatus::Completed + emit TransferCompleted( + self.asset_id, + self.owner, + recipient, + self.source_jurisdiction, + self.target_jurisdiction, + block.timestamp, + ) + } else { + self.transfer_status = TransferStatus::Failed + emit TransferFailed(self.asset_id, block.timestamp) + } + + return transfer_result + } + + // 事件定义 + event DualCrVerificationFailed(asset_id: AssetId, timestamp: Uint64) + event DualCrVerified( + asset_id: AssetId, + source_jurisdiction: JurisdictionId, + target_jurisdiction: JurisdictionId, + ) + event TransferCompleted( + asset_id: AssetId, + from: Address, + to: Address, + source_jurisdiction: JurisdictionId, + target_jurisdiction: JurisdictionId, + timestamp: Uint64, + ) + event TransferFailed(asset_id: AssetId, timestamp: Uint64) +} + +// ============================================================ +// 示例合约:节点共享注册合约(A44/A47) +// ============================================================ + +/// 节点共享注册合约 +/// 用于在链上记录节点的物理共享状态和辖区绑定 +contract NodeSharingRegistry { + + const CONSTITUTION_ADDRESS: Address = 0x0000000000000000000000000000000000000001 + + state { + admin: Address, + // 节点DID → 共享节点记录 + nodes: Map, + // 辖区 → 节点DID列表 + jurisdiction_nodes: Map>, + total_nodes: Uint64, + } + + struct SharedNodeOnChain { + node_did: String, + jurisdiction: JurisdictionId, + physical_host_id: String, + container_id: String, + network_namespace: String, + plugin_hashes: Array, + is_active: Bool, + registered_at: Uint64, + jurisdiction_proof_hash: Bytes48, + } + + constructor() { + self.admin = msg.sender + self.total_nodes = 0 + } + + /// 注册共享节点(A44 + A47 双重验证) + fn register_shared_node( + node_did: String, + jurisdiction: JurisdictionId, + physical_host_id: String, + container_id: String, + network_namespace: String, + plugin_hashes: Array, + jurisdiction_proof_hash: Bytes48, + ) -> Bool { + let constitution = IConstitution(CONSTITUTION_ADDRESS) + + // A44: 验证节点逻辑隔离 + let isolation_ok = constitution.verify_node_sharing_isolation( + node_did, + container_id, + network_namespace, + ) + require(isolation_ok, "A44: 节点未满足逻辑隔离要求") + + // A47: 验证节点辖区绑定 + let binding_ok = constitution.verify_node_jurisdiction_binding(node_did, jurisdiction) + require(binding_ok, "A47: 节点辖区绑定验证失败") + + // A47: 验证所有插件哈希已授权 + for hash in plugin_hashes { + let authorized = constitution.verify_plugin_hash_authorized(node_did, hash) + require(authorized, "A47: 存在未授权的辖区规则插件") + } + + // A48: 验证插件在WASM沙箱中执行 + for hash in plugin_hashes { + let wasm_ok = constitution.verify_wasm_sandbox_execution(hash) + require(wasm_ok, "A48: 插件必须在WASM沙箱中执行") + + let on_chain = constitution.is_plugin_hash_on_chain(hash) + require(on_chain, "A48: 插件哈希必须已上链验证") + } + + // 记录节点信息 + let record = SharedNodeOnChain { + node_did: node_did, + jurisdiction: jurisdiction, + physical_host_id: physical_host_id, + container_id: container_id, + network_namespace: network_namespace, + plugin_hashes: plugin_hashes, + is_active: true, + registered_at: block.timestamp, + jurisdiction_proof_hash: jurisdiction_proof_hash, + } + + self.nodes[node_did] = record + self.jurisdiction_nodes[jurisdiction].push(node_did) + self.total_nodes += 1 + + emit NodeRegistered(node_did, jurisdiction, block.timestamp) + return true + } + + /// 查询辖区节点数量 + fn get_jurisdiction_node_count(jurisdiction: JurisdictionId) -> Uint64 { + return self.jurisdiction_nodes[jurisdiction].length() as Uint64 + } + + event NodeRegistered(node_did: String, jurisdiction: JurisdictionId, timestamp: Uint64) +} diff --git a/nac-constitution-clauses/src/lib.rs b/nac-constitution-clauses/src/lib.rs index b0f480a..f3b9cd1 100644 --- a/nac-constitution-clauses/src/lib.rs +++ b/nac-constitution-clauses/src/lib.rs @@ -17,6 +17,7 @@ pub mod storage; pub mod manager; pub mod lifecycle; pub mod upgrade; +pub mod node_sharing; // 重新导出常用类型 pub use validator::{ClauseValidator, ValidationError}; diff --git a/nac-constitution-clauses/src/node_sharing.rs b/nac-constitution-clauses/src/node_sharing.rs new file mode 100644 index 0000000..e76a5e0 --- /dev/null +++ b/nac-constitution-clauses/src/node_sharing.rs @@ -0,0 +1,1026 @@ +// nac-constitution-clauses/src/node_sharing.rs +// Issue #70: 多辖区节点共享宪法条款实现 +// 版本: 1.0 | 2026-03-07 +// 基于《NAC公链多辖区节点共享方案与技术落地白皮书》v1.0 +// +// 本模块实现宪法条款 A44-A52 的 Rust 验证逻辑: +// - A44: 多辖区节点物理共享许可(战略级) +// - A45: 跨辖区区块生产双CR强制(战略级) +// - A46: 共享资源辖区协商分配(战略级) +// - A47: 节点身份辖区绑定强制(战术级) +// - A48: WASM规则插件沙箱执行强制(战术级) +// - A49: CEE节点跨辖区共享验证(战术级) +// - A50: 辖区争议宪法法院裁决(战术级) +// - A51: CSNP辖区感知路由强制(战术级) +// - A52: 共享存储敏感数据加密(战术级) + +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +// ============================================================ +// 条款 A44:多辖区节点物理共享许可 +// ============================================================ + +/// 节点共享状态(用于 A44 验证) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NodeSharingState { + /// 节点是否物理共享 + pub physical_shared: bool, + /// 节点是否逻辑隔离(容器化) + pub logical_isolated: bool, + /// 是否使用独立网络命名空间 + pub network_namespace_isolated: bool, + /// 是否使用独立存储卷 + pub storage_volume_isolated: bool, + /// 容器类型(Docker/Kubernetes/VM) + pub container_type: ContainerType, + /// 资源配额是否已设置 + pub resource_quota_set: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum ContainerType { + Docker, + Kubernetes, + VirtualMachine, + None, +} + +/// A44 验证结果 +#[derive(Debug, Clone)] +pub struct A44ValidationResult { + pub passed: bool, + pub violations: Vec, +} + +/// 验证 A44:物理共享节点必须逻辑隔离 +pub fn validate_a44_node_sharing(state: &NodeSharingState) -> A44ValidationResult { + let mut violations = Vec::new(); + + if state.physical_shared && !state.logical_isolated { + violations.push( + "A44违规:物理共享节点必须启用逻辑隔离(容器化/虚拟化)".to_string(), + ); + } + + if state.physical_shared && !state.network_namespace_isolated { + violations.push( + "A44违规:物理共享节点必须使用独立网络命名空间".to_string(), + ); + } + + if state.physical_shared && !state.storage_volume_isolated { + violations.push( + "A44违规:物理共享节点必须使用独立存储卷".to_string(), + ); + } + + if state.physical_shared && !state.resource_quota_set { + violations.push( + "A44违规:物理共享节点必须设置资源配额,防止资源抢占".to_string(), + ); + } + + if state.physical_shared && state.container_type == ContainerType::None { + violations.push( + "A44违规:物理共享节点必须使用容器化技术(Docker/K8s/VM)".to_string(), + ); + } + + A44ValidationResult { + passed: violations.is_empty(), + violations, + } +} + +// ============================================================ +// 条款 A45:跨辖区区块生产双CR强制 +// ============================================================ + +/// 区块头辖区信息(CBPP扩展字段) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BlockJurisdictionHeader { + /// jurisdiction_merkle_root:所有跨辖区交易CR哈希的默克尔树根 + /// SHA3-384,48字节 + pub jurisdiction_merkle_root: Option>, + /// 区块内跨辖区交易数量 + pub cross_jurisdiction_tx_count: u32, + /// 涉及的辖区列表 + pub involved_jurisdictions: Vec, +} + +/// 跨辖区交易双CR +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DualConstitutionalReceipt { + /// 源辖区CR哈希 + pub source_cr_hash: Vec, + /// 目标辖区CR哈希 + pub target_cr_hash: Vec, + /// 源辖区ID(ISO3166-1 + 子辖区扩展) + pub source_jurisdiction: u16, + /// 目标辖区ID + pub target_jurisdiction: u16, + /// CR签发时间戳(防重放) + pub issued_at: u64, + /// CEE节点签名 + pub cee_signature: Vec, + /// 是否有效 + pub is_valid: bool, +} + +/// A45 验证结果 +#[derive(Debug, Clone)] +pub struct A45ValidationResult { + pub passed: bool, + pub violations: Vec, +} + +/// 验证 A45:跨辖区区块必须包含 jurisdiction_merkle_root +pub fn validate_a45_cross_jurisdiction_consensus( + header: &BlockJurisdictionHeader, + cross_tx_receipts: &[DualConstitutionalReceipt], +) -> A45ValidationResult { + let mut violations = Vec::new(); + + // 如果有跨辖区交易,必须有 jurisdiction_merkle_root + if header.cross_jurisdiction_tx_count > 0 { + if header.jurisdiction_merkle_root.is_none() { + violations.push( + "A45违规:含跨辖区交易的区块必须包含 jurisdiction_merkle_root 字段".to_string(), + ); + } + + // 验证每笔跨辖区交易都有双CR + for (i, receipt) in cross_tx_receipts.iter().enumerate() { + if !receipt.is_valid { + violations.push(format!( + "A45违规:第{}笔跨辖区交易的双CR无效(辖区 {} → {})", + i + 1, + receipt.source_jurisdiction, + receipt.target_jurisdiction + )); + } + if receipt.cee_signature.is_empty() { + violations.push(format!( + "A45违规:第{}笔跨辖区交易缺少CEE节点签名", + i + 1 + )); + } + } + + // 验证双CR数量与跨辖区交易数量匹配 + if cross_tx_receipts.len() != header.cross_jurisdiction_tx_count as usize { + violations.push(format!( + "A45违规:跨辖区交易数量({})与双CR数量({})不匹配", + header.cross_jurisdiction_tx_count, + cross_tx_receipts.len() + )); + } + } + + A45ValidationResult { + passed: violations.is_empty(), + violations, + } +} + +// ============================================================ +// 条款 A46:共享资源辖区协商分配 +// ============================================================ + +/// 资源分配提案 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ResourceAllocationProposal { + /// 提案ID + pub proposal_id: u64, + /// 提案辖区 + pub proposer_jurisdiction: u16, + /// 资源分配方案(辖区ID → 配额百分比,定点数1e4) + pub allocation_map: HashMap, + /// 投票结果(辖区ID → 赞成/反对) + pub votes: HashMap, + /// 总辖区数 + pub total_jurisdictions: u32, + /// 是否已通过 + pub is_approved: bool, + /// 提案时间戳 + pub proposed_at: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ResourceQuotaProposal { + pub cpu_share: u64, // 定点数1e4(2500 = 25.00%) + pub memory_share: u64, + pub bandwidth_share: u64, + pub storage_share: u64, +} + +/// A46 验证结果 +#[derive(Debug, Clone)] +pub struct A46ValidationResult { + pub passed: bool, + pub vote_ratio: u64, + pub violations: Vec, +} + +/// 验证 A46:资源分配必须经过辖区协商委员会投票(≥67%) +pub fn validate_a46_resource_allocation( + proposal: &ResourceAllocationProposal, +) -> A46ValidationResult { + let mut violations = Vec::new(); + + // 计算赞成票比例 + let votes_for = proposal.votes.values().filter(|&&v| v).count() as u64; + let vote_ratio = if proposal.total_jurisdictions > 0 { + votes_for * 10000 / proposal.total_jurisdictions as u64 + } else { + 0 + }; + + // 必须达到67%法定人数 + if vote_ratio < 6700 { + violations.push(format!( + "A46违规:资源分配提案投票比例({:.2}%)未达到法定人数(67%)", + vote_ratio as f64 / 100.0 + )); + } + + // 验证各辖区配额总和不超过100% + let total_cpu: u64 = proposal.allocation_map.values().map(|q| q.cpu_share).sum(); + let total_memory: u64 = proposal.allocation_map.values().map(|q| q.memory_share).sum(); + let total_bandwidth: u64 = proposal.allocation_map.values().map(|q| q.bandwidth_share).sum(); + let total_storage: u64 = proposal.allocation_map.values().map(|q| q.storage_share).sum(); + + if total_cpu > 10000 { + violations.push(format!( + "A46违规:CPU配额总和({:.2}%)超过100%", + total_cpu as f64 / 100.0 + )); + } + if total_memory > 10000 { + violations.push(format!( + "A46违规:内存配额总和({:.2}%)超过100%", + total_memory as f64 / 100.0 + )); + } + if total_bandwidth > 10000 { + violations.push(format!( + "A46违规:带宽配额总和({:.2}%)超过100%", + total_bandwidth as f64 / 100.0 + )); + } + if total_storage > 10000 { + violations.push(format!( + "A46违规:存储配额总和({:.2}%)超过100%", + total_storage as f64 / 100.0 + )); + } + + A46ValidationResult { + passed: violations.is_empty(), + vote_ratio, + violations, + } +} + +// ============================================================ +// 条款 A47:节点身份辖区绑定强制 +// ============================================================ + +/// 节点身份(GIDS增强版) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NodeIdentity { + /// 节点DID(去中心化标识符) + pub did: String, + /// 司法辖区ID(ISO3166-1 + 子辖区扩展,16位) + pub jurisdiction: u16, + /// 节点公钥(Ed25519,32字节) + pub public_key: Vec, + /// 已加载的辖区插件哈希列表(SHA3-384,48字节) + pub plugin_hashes: Vec>, + /// 辖区政府/监管机构数字签名 + pub jurisdiction_proof: JurisdictionProof, + /// 网络端点 + pub endpoint: String, + /// 注册时间戳 + pub registered_at: u64, +} + +/// 辖区证明(由辖区政府授权CA签发) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct JurisdictionProof { + /// 签发机构DID + pub issuer_did: String, + /// 签名数据(Ed25519) + pub signature: Vec, + /// 证明有效期(Unix时间戳) + pub expires_at: u64, + /// 是否有效 + pub is_valid: bool, +} + +/// A47 验证结果 +#[derive(Debug, Clone)] +pub struct A47ValidationResult { + pub passed: bool, + pub violations: Vec, +} + +/// 验证 A47:节点身份辖区绑定 +pub fn validate_a47_node_identity( + identity: &NodeIdentity, + current_timestamp: u64, + gids_plugin_hashes: &[Vec], +) -> A47ValidationResult { + let mut violations = Vec::new(); + + // DID不能为空 + if identity.did.is_empty() { + violations.push("A47违规:节点DID不能为空".to_string()); + } + + // 辖区ID不能为0 + if identity.jurisdiction == 0 { + violations.push("A47违规:节点必须绑定有效的司法辖区(jurisdiction != 0)".to_string()); + } + + // 辖区证明必须有效 + if !identity.jurisdiction_proof.is_valid { + violations.push("A47违规:辖区政府数字签名无效".to_string()); + } + + // 辖区证明不能过期 + if identity.jurisdiction_proof.expires_at < current_timestamp { + violations.push("A47违规:辖区证明已过期,需要重新获取".to_string()); + } + + // 签名不能为空 + if identity.jurisdiction_proof.signature.is_empty() { + violations.push("A47违规:辖区证明签名不能为空".to_string()); + } + + // 插件哈希不能为空 + if identity.plugin_hashes.is_empty() { + violations.push("A47违规:节点必须至少加载一个辖区规则插件".to_string()); + } + + // 插件哈希必须与GIDS记录一致 + if !gids_plugin_hashes.is_empty() { + for hash in &identity.plugin_hashes { + if !gids_plugin_hashes.contains(hash) { + violations.push( + "A47违规:节点加载的插件哈希与GIDS记录不一致,可能存在未授权插件".to_string(), + ); + break; + } + } + } + + A47ValidationResult { + passed: violations.is_empty(), + violations, + } +} + +// ============================================================ +// 条款 A48:WASM规则插件沙箱执行强制 +// ============================================================ + +/// WASM插件执行环境配置 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WasmPluginConfig { + /// 执行环境类型 + pub execution_env: ExecutionEnvironment, + /// 最大执行时间(毫秒) + pub max_execution_ms: u64, + /// 最大内存使用(MB) + pub max_memory_mb: u64, + /// 插件哈希(SHA3-384,48字节) + pub plugin_hash: Vec, + /// 插件哈希是否已上链 + pub hash_on_chain: bool, + /// 是否禁止文件系统访问 + pub no_filesystem_access: bool, + /// 是否禁止网络访问 + pub no_network_access: bool, + /// 是否禁止环境变量访问 + pub no_env_access: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum ExecutionEnvironment { + WasmSandbox, + Native, + Jvm, + Other(String), +} + +/// A48 验证结果 +#[derive(Debug, Clone)] +pub struct A48ValidationResult { + pub passed: bool, + pub violations: Vec, +} + +/// 验证 A48:WASM沙箱限制 +pub fn validate_a48_wasm_sandbox(config: &WasmPluginConfig) -> A48ValidationResult { + let mut violations = Vec::new(); + + // 必须使用WASM沙箱 + if config.execution_env != ExecutionEnvironment::WasmSandbox { + violations.push( + "A48违规:辖区规则插件必须在WASM沙箱中执行,不允许原生执行".to_string(), + ); + } + + // 执行时间上限10ms + if config.max_execution_ms > 10 { + violations.push(format!( + "A48违规:WASM插件执行时间上限({}ms)超过10ms限制", + config.max_execution_ms + )); + } + + // 内存上限64MB + if config.max_memory_mb > 64 { + violations.push(format!( + "A48违规:WASM插件内存上限({}MB)超过64MB限制", + config.max_memory_mb + )); + } + + // 插件哈希必须上链 + if !config.hash_on_chain { + violations.push("A48违规:插件哈希必须存储在IPFS并上链验证".to_string()); + } + + // 必须禁止主机访问 + if !config.no_filesystem_access { + violations.push("A48违规:WASM沙箱必须禁止文件系统访问".to_string()); + } + if !config.no_network_access { + violations.push("A48违规:WASM沙箱必须禁止直接网络访问".to_string()); + } + if !config.no_env_access { + violations.push("A48违规:WASM沙箱必须禁止环境变量访问".to_string()); + } + + A48ValidationResult { + passed: violations.is_empty(), + violations, + } +} + +// ============================================================ +// 条款 A49:CEE节点跨辖区共享验证 +// ============================================================ + +/// CEE节点配置 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CeeNodeConfig { + /// CEE节点DID + pub did: String, + /// 是否支持多辖区验证 + pub supports_multi_jurisdiction: bool, + /// 是否支持并行插件执行 + pub parallel_plugin_execution: bool, + /// 是否已在GIDS注册 + pub registered_in_gids: bool, + /// 支持的辖区列表 + pub supported_jurisdictions: Vec, + /// 负载均衡权重(0-10000) + pub load_balance_weight: u64, +} + +/// A49 验证结果 +#[derive(Debug, Clone)] +pub struct A49ValidationResult { + pub passed: bool, + pub violations: Vec, +} + +/// 验证 A49:CEE节点跨辖区共享 +pub fn validate_a49_cee_shared_cluster(config: &CeeNodeConfig) -> A49ValidationResult { + let mut violations = Vec::new(); + + if !config.supports_multi_jurisdiction { + violations.push( + "A49违规:CEE节点必须支持多辖区验证逻辑".to_string(), + ); + } + + if !config.parallel_plugin_execution { + violations.push( + "A49违规:CEE节点必须支持并行调用辖区插件以提高验证效率".to_string(), + ); + } + + if !config.registered_in_gids { + violations.push( + "A49违规:CEE节点必须在GIDS中注册,以支持负载均衡".to_string(), + ); + } + + if config.supported_jurisdictions.is_empty() { + violations.push( + "A49违规:CEE节点必须至少支持一个辖区的验证".to_string(), + ); + } + + A49ValidationResult { + passed: violations.is_empty(), + violations, + } +} + +// ============================================================ +// 条款 A50:辖区争议宪法法院裁决 +// ============================================================ + +/// 辖区争议记录 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct JurisdictionDispute { + /// 争议ID + pub dispute_id: u64, + /// 争议类型 + pub dispute_type: DisputeType, + /// 申诉辖区 + pub claimant_jurisdiction: u16, + /// 被申诉辖区 + pub respondent_jurisdiction: u16, + /// 解决路径 + pub resolution_path: ResolutionPath, + /// 宪法法院判决是否已上链 + pub judgment_on_chain: bool, + /// 链上投票是否已确认 + pub chain_vote_confirmed: bool, + /// 争议状态 + pub status: DisputeStatus, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum DisputeType { + ResourceContention, + RuleConflict, + IdentityImpersonation, + ConsensusViolation, + DataPrivacyBreach, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum ResolutionPath { + ConstitutionalCourt, + DirectNegotiation, + AutomaticRule, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum DisputeStatus { + Pending, + UnderReview, + Resolved, + Appealed, +} + +/// A50 验证结果 +#[derive(Debug, Clone)] +pub struct A50ValidationResult { + pub passed: bool, + pub violations: Vec, +} + +/// 验证 A50:争议必须通过宪法法院裁决 +pub fn validate_a50_dispute_resolution(dispute: &JurisdictionDispute) -> A50ValidationResult { + let mut violations = Vec::new(); + + // 争议必须提交至宪法法院 + if dispute.resolution_path != ResolutionPath::ConstitutionalCourt { + violations.push( + "A50违规:跨辖区节点争议必须提交至宪法法院裁决,不允许私下解决".to_string(), + ); + } + + // 判决必须上链 + if dispute.status == DisputeStatus::Resolved && !dispute.judgment_on_chain { + violations.push( + "A50违规:宪法法院判决结果必须上链存证".to_string(), + ); + } + + // 判决必须经链上投票确认 + if dispute.judgment_on_chain && !dispute.chain_vote_confirmed { + violations.push( + "A50违规:宪法法院判决必须经链上投票确认后方可执行".to_string(), + ); + } + + A50ValidationResult { + passed: violations.is_empty(), + violations, + } +} + +// ============================================================ +// 条款 A51:CSNP辖区感知路由强制 +// ============================================================ + +/// CSNP路由配置 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CsnpRoutingConfig { + /// 是否启用辖区感知路由 + pub jurisdiction_aware_routing: bool, + /// 是否支持跨辖区中继 + pub cross_jurisdiction_relay: bool, + /// 是否保留原始CR(协议转换时) + pub preserves_original_cr: bool, + /// 是否支持多播优化 + pub multicast_optimization: bool, + /// 是否支持协议版本转换 + pub protocol_version_conversion: bool, +} + +/// A51 验证结果 +#[derive(Debug, Clone)] +pub struct A51ValidationResult { + pub passed: bool, + pub violations: Vec, +} + +/// 验证 A51:CSNP辖区感知路由 +pub fn validate_a51_csnp_routing(config: &CsnpRoutingConfig) -> A51ValidationResult { + let mut violations = Vec::new(); + + if !config.jurisdiction_aware_routing { + violations.push( + "A51违规:CSNP必须启用辖区感知路由,自动识别目标地址辖区".to_string(), + ); + } + + if !config.cross_jurisdiction_relay { + violations.push( + "A51违规:CSNP必须支持跨辖区中继节点转发".to_string(), + ); + } + + if !config.preserves_original_cr { + violations.push( + "A51违规:协议转换时必须保留原始CR作为合规证据".to_string(), + ); + } + + A51ValidationResult { + passed: violations.is_empty(), + violations, + } +} + +// ============================================================ +// 条款 A52:共享存储敏感数据加密 +// ============================================================ + +/// 共享存储配置 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SharedStorageConfig { + /// 敏感数据是否加密 + pub sensitive_data_encrypted: bool, + /// 是否仅授权节点可访问 + pub authorized_access_only: bool, + /// 数据冗余副本数 + pub redundancy_copies: u32, + /// 加密算法 + pub encryption_algorithm: EncryptionAlgorithm, + /// 是否使用分布式存储 + pub distributed_storage: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum EncryptionAlgorithm { + Aes256Gcm, + ChaCha20Poly1305, + None, +} + +/// A52 验证结果 +#[derive(Debug, Clone)] +pub struct A52ValidationResult { + pub passed: bool, + pub violations: Vec, +} + +/// 验证 A52:共享存储加密和冗余 +pub fn validate_a52_shared_storage(config: &SharedStorageConfig) -> A52ValidationResult { + let mut violations = Vec::new(); + + if !config.sensitive_data_encrypted { + violations.push( + "A52违规:共享存储中的敏感数据(法律文件哈希、KYC信息)必须加密存储".to_string(), + ); + } + + if config.encryption_algorithm == EncryptionAlgorithm::None && config.sensitive_data_encrypted { + violations.push( + "A52违规:加密算法不能为None,必须使用AES-256-GCM或ChaCha20-Poly1305".to_string(), + ); + } + + if !config.authorized_access_only { + violations.push( + "A52违规:加密数据必须仅允许授权节点访问,需配置访问控制列表".to_string(), + ); + } + + if config.redundancy_copies < 3 { + violations.push(format!( + "A52违规:数据冗余副本数({})不足,最低要求3副本", + config.redundancy_copies + )); + } + + A52ValidationResult { + passed: violations.is_empty(), + violations, + } +} + +// ============================================================ +// 综合验证器:A44-A52 批量验证 +// ============================================================ + +/// 多辖区节点共享综合验证报告 +#[derive(Debug, Clone)] +pub struct NodeSharingComplianceReport { + pub a44_result: Option, + pub a45_result: Option, + pub a46_result: Option, + pub a47_result: Option, + pub a48_result: Option, + pub a49_result: Option, + pub a50_result: Option, + pub a51_result: Option, + pub a52_result: Option, + pub overall_passed: bool, + pub total_violations: usize, +} + +impl NodeSharingComplianceReport { + /// 计算综合合规状态 + pub fn compute_overall(&mut self) { + let mut total = 0; + let mut all_passed = true; + + macro_rules! check_result { + ($field:expr) => { + if let Some(ref r) = $field { + if !r.passed { + all_passed = false; + total += r.violations.len(); + } + } + }; + } + + check_result!(self.a44_result); + check_result!(self.a45_result); + check_result!(self.a46_result); + check_result!(self.a47_result); + check_result!(self.a48_result); + check_result!(self.a49_result); + check_result!(self.a50_result); + check_result!(self.a51_result); + check_result!(self.a52_result); + + self.overall_passed = all_passed; + self.total_violations = total; + } + + /// 生成违规摘要 + pub fn violation_summary(&self) -> Vec { + let mut all_violations = Vec::new(); + + macro_rules! collect_violations { + ($field:expr, $clause:expr) => { + if let Some(ref r) = $field { + for v in &r.violations { + all_violations.push(format!("[{}] {}", $clause, v)); + } + } + }; + } + + collect_violations!(self.a44_result, "A44"); + collect_violations!(self.a45_result, "A45"); + collect_violations!(self.a46_result, "A46"); + collect_violations!(self.a47_result, "A47"); + collect_violations!(self.a48_result, "A48"); + collect_violations!(self.a49_result, "A49"); + collect_violations!(self.a50_result, "A50"); + collect_violations!(self.a51_result, "A51"); + collect_violations!(self.a52_result, "A52"); + + all_violations + } +} + +// ============================================================ +// 单元测试 +// ============================================================ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_a44_physical_shared_must_be_isolated() { + let state = NodeSharingState { + physical_shared: true, + logical_isolated: false, + network_namespace_isolated: false, + storage_volume_isolated: false, + container_type: ContainerType::None, + resource_quota_set: false, + }; + let result = validate_a44_node_sharing(&state); + assert!(!result.passed); + assert!(!result.violations.is_empty()); + } + + #[test] + fn test_a44_compliant_node() { + let state = NodeSharingState { + physical_shared: true, + logical_isolated: true, + network_namespace_isolated: true, + storage_volume_isolated: true, + container_type: ContainerType::Docker, + resource_quota_set: true, + }; + let result = validate_a44_node_sharing(&state); + assert!(result.passed); + assert!(result.violations.is_empty()); + } + + #[test] + fn test_a44_non_shared_node_always_passes() { + let state = NodeSharingState { + physical_shared: false, + logical_isolated: false, + network_namespace_isolated: false, + storage_volume_isolated: false, + container_type: ContainerType::None, + resource_quota_set: false, + }; + let result = validate_a44_node_sharing(&state); + assert!(result.passed); + } + + #[test] + fn test_a45_cross_jurisdiction_block_needs_merkle_root() { + let header = BlockJurisdictionHeader { + jurisdiction_merkle_root: None, + cross_jurisdiction_tx_count: 2, + involved_jurisdictions: vec![784, 156], + }; + let receipts = vec![]; + let result = validate_a45_cross_jurisdiction_consensus(&header, &receipts); + assert!(!result.passed); + } + + #[test] + fn test_a45_no_cross_jurisdiction_tx_passes() { + let header = BlockJurisdictionHeader { + jurisdiction_merkle_root: None, + cross_jurisdiction_tx_count: 0, + involved_jurisdictions: vec![], + }; + let result = validate_a45_cross_jurisdiction_consensus(&header, &[]); + assert!(result.passed); + } + + #[test] + fn test_a46_resource_allocation_needs_quorum() { + let mut votes = HashMap::new(); + votes.insert(784u16, true); + votes.insert(156u16, false); + votes.insert(356u16, false); + + let proposal = ResourceAllocationProposal { + proposal_id: 1, + proposer_jurisdiction: 784, + allocation_map: HashMap::new(), + votes, + total_jurisdictions: 3, + is_approved: false, + proposed_at: 1000000, + }; + let result = validate_a46_resource_allocation(&proposal); + assert!(!result.passed); // 1/3 = 33.33% < 67% + } + + #[test] + fn test_a47_node_identity_must_have_jurisdiction() { + let identity = NodeIdentity { + did: "did:nac:test123".to_string(), + jurisdiction: 0, // 违规:辖区为0 + public_key: vec![0u8; 32], + plugin_hashes: vec![vec![0u8; 48]], + jurisdiction_proof: JurisdictionProof { + issuer_did: "did:nac:gov-ae".to_string(), + signature: vec![1u8; 64], + expires_at: u64::MAX, + is_valid: true, + }, + endpoint: "https://node.example.com".to_string(), + registered_at: 1000000, + }; + let result = validate_a47_node_identity(&identity, 1000000, &[]); + assert!(!result.passed); + } + + #[test] + fn test_a48_wasm_sandbox_limits() { + let config = WasmPluginConfig { + execution_env: ExecutionEnvironment::WasmSandbox, + max_execution_ms: 15, // 违规:超过10ms + max_memory_mb: 64, + plugin_hash: vec![0u8; 48], + hash_on_chain: true, + no_filesystem_access: true, + no_network_access: true, + no_env_access: true, + }; + let result = validate_a48_wasm_sandbox(&config); + assert!(!result.passed); + } + + #[test] + fn test_a48_compliant_wasm_config() { + let config = WasmPluginConfig { + execution_env: ExecutionEnvironment::WasmSandbox, + max_execution_ms: 10, + max_memory_mb: 64, + plugin_hash: vec![0u8; 48], + hash_on_chain: true, + no_filesystem_access: true, + no_network_access: true, + no_env_access: true, + }; + let result = validate_a48_wasm_sandbox(&config); + assert!(result.passed); + } + + #[test] + fn test_a52_storage_redundancy() { + let config = SharedStorageConfig { + sensitive_data_encrypted: true, + authorized_access_only: true, + redundancy_copies: 2, // 违规:不足3副本 + encryption_algorithm: EncryptionAlgorithm::Aes256Gcm, + distributed_storage: true, + }; + let result = validate_a52_shared_storage(&config); + assert!(!result.passed); + } + + #[test] + fn test_a52_compliant_storage() { + let config = SharedStorageConfig { + sensitive_data_encrypted: true, + authorized_access_only: true, + redundancy_copies: 3, + encryption_algorithm: EncryptionAlgorithm::Aes256Gcm, + distributed_storage: true, + }; + let result = validate_a52_shared_storage(&config); + assert!(result.passed); + } + + #[test] + fn test_compliance_report_aggregation() { + let node_state = NodeSharingState { + physical_shared: true, + logical_isolated: true, + network_namespace_isolated: true, + storage_volume_isolated: true, + container_type: ContainerType::Kubernetes, + resource_quota_set: true, + }; + let a44 = validate_a44_node_sharing(&node_state); + + let mut report = NodeSharingComplianceReport { + a44_result: Some(a44), + a45_result: None, + a46_result: None, + a47_result: None, + a48_result: None, + a49_result: None, + a50_result: None, + a51_result: None, + a52_result: None, + overall_passed: false, + total_violations: 0, + }; + report.compute_overall(); + assert!(report.overall_passed); + assert_eq!(report.total_violations, 0); + } +} diff --git a/nac-constitution/clauses/node_sharing_clauses.cnnl b/nac-constitution/clauses/node_sharing_clauses.cnnl new file mode 100644 index 0000000..a3ee26c --- /dev/null +++ b/nac-constitution/clauses/node_sharing_clauses.cnnl @@ -0,0 +1,216 @@ +// NAC公链宪法增补条款 - 多辖区节点共享规则 +// Issue #70 | 版本: 1.0 | 共 9 条增补条款(A44-A52) +// 基于《NAC公链多辖区节点共享方案与技术落地白皮书》v1.0 +// 制定方:NAC 核心协议工程组 · 多司法辖区工作组 +// 发布日期:2026-03-07 +// 关联文档:amendments.cnnl(A01-A43)、nac-multi-jurisdiction 模块 + +program NacNodeSharingClauses + name: "NAC公链多辖区节点共享宪法条款" + version: "1.0.0" + description: "9条多辖区节点共享宪法条款(A44-A52),规范物理共享与逻辑隔离" + +// ============================================================ +// 第七章:多辖区节点共享条款(A44-A52) +// ============================================================ + +// --- 战略级条款(Strategic Tier)--- + +clause A44_NodeSharing + name: "多辖区节点物理共享许可" + tier: Strategic + clause_index: 101 + description: "允许不同辖区节点共享物理基础设施(数据中心、云平台、硬件集群), + 但必须通过容器化/虚拟化技术保持逻辑强隔离,确保各辖区规则互不干扰" + predicate: node.physical_shared implies node.logical_isolated == true + obligation: system.enforce_node_logical_isolation per_block + violation_action: reject_block + test: A44_test_node_sharing_isolation + references: ["多辖区节点共享白皮书 §3.2", "宪法层规范 §NODE_SHARING"] + +clause A45_CrossJurisdictionConsensus + name: "跨辖区区块生产双CR强制" + tier: Strategic + clause_index: 102 + description: "跨辖区区块生产时,区块头必须包含 jurisdiction_merkle_root 字段, + 该字段为区块内所有跨辖区交易的宪法收据(CR)哈希的默克尔树根; + 每笔跨辖区交易必须附带源辖区和目标辖区的双CR" + predicate: block.has_cross_jurisdiction_tx implies + block.header.jurisdiction_merkle_root != null + obligation: cbpp.include_jurisdiction_merkle_root per_block + violation_action: reject_block + test: A45_test_cross_jurisdiction_consensus + references: ["多辖区节点共享白皮书 §3.4", "CBPP协议扩展规范"] + +clause A46_ResourceAllocationByCouncil + name: "共享资源辖区协商分配" + tier: Strategic + clause_index: 103 + description: "共享物理资源(CPU、内存、带宽、存储)的分配方案必须由辖区协商委员会 + (JurisdictionCouncil)通过法定人数投票决定(≥67%), + 并将分配结果写入宪法附录,不得由单一辖区单方面决定" + predicate: resource.allocation_method == "council_vote" and + resource.council_quorum >= 6700 + obligation: governance.require_council_vote_for_resource_change per_epoch + violation_action: revert_allocation + test: A46_test_resource_allocation_council + references: ["多辖区节点共享白皮书 §5.2", "辖区协商机制规范"] + +// --- 战术级条款(Tactical Tier)--- + +clause A47_NodeIdentityJurisdictionBinding + name: "节点身份辖区绑定强制" + tier: Tactical + clause_index: 1001 + description: "每个节点在GIDS注册时,其DID必须绑定明确的司法辖区(jurisdiction字段), + 并提供该辖区政府或监管机构的数字签名(jurisdiction_proof)作为证明; + 节点加载的规则插件哈希(plugin_hashes)必须与GIDS记录一致" + predicate: node.did != "" and + node.jurisdiction != 0 and + node.jurisdiction_proof.valid == true and + node.plugin_hashes == gids.get_plugin_hashes(node.did) + obligation: gids.verify_node_jurisdiction_binding per_block + violation_action: reject_node_registration + test: A47_test_node_identity_binding + references: ["多辖区节点共享白皮书 §3.1", "GIDS增强规范"] + +clause A48_WasmPluginSandbox + name: "WASM规则插件沙箱执行强制" + tier: Tactical + clause_index: 1002 + description: "辖区规则插件必须以WASM模块形式在沙箱中执行, + 沙箱必须满足:无主机文件系统/网络访问、 + 执行时间上限10ms、内存上限64MB; + 插件哈希必须存储在IPFS并上链验证" + predicate: plugin.execution_env == "WASM_SANDBOX" and + plugin.max_execution_ms <= 10 and + plugin.max_memory_mb <= 64 and + plugin.hash_on_chain == true + obligation: system.enforce_wasm_sandbox_limits per_block + violation_action: terminate_plugin_execution + test: A48_test_wasm_sandbox + references: ["多辖区节点共享白皮书 §3.3", "WASM沙箱安全规范"] + +clause A49_CeeSharedCluster + name: "CEE节点跨辖区共享验证" + tier: Tactical + clause_index: 1003 + description: "宪法执行引擎(CEE)节点可配置为同时支持多个辖区的验证逻辑, + 通过并行调用所有相关辖区插件并汇总结果,签发多签名宪法收据(CR); + CEE节点必须通过GIDS中的负载均衡列表选择,防止单点故障" + predicate: cee.supports_multi_jurisdiction == true and + cee.parallel_plugin_execution == true and + cee.registered_in_gids == true + obligation: cee.enable_multi_jurisdiction_verification per_block + violation_action: fallback_to_single_jurisdiction_cee + test: A49_test_cee_shared_cluster + references: ["多辖区节点共享白皮书 §3.6", "CEE集群规范"] + +clause A50_JurisdictionDisputeResolution + name: "辖区争议宪法法院裁决" + tier: Tactical + clause_index: 1004 + description: "跨辖区节点争议(资源抢占、规则冲突、身份冒充等)必须提交至宪法法院裁决; + 宪法法院根据全球细则和辖区插件条款作出最终判决; + 判决结果通过链上投票确认后方可执行" + predicate: dispute.resolution_path == "constitutional_court" and + dispute.judgment_on_chain == true and + dispute.chain_vote_confirmed == true + obligation: governance.route_cross_jurisdiction_dispute_to_court per_epoch + violation_action: freeze_disputed_resources + test: A50_test_dispute_resolution + references: ["多辖区节点共享白皮书 §5.3", "宪法法院裁决规范"] + +clause A51_CsnpJurisdictionAwareRouting + name: "CSNP辖区感知路由强制" + tier: Tactical + clause_index: 1005 + description: "CSNP网络层必须支持辖区感知路由:节点发送交易前查询目标地址辖区信息, + 跨辖区交易选择目标辖区中继节点转发; + 协议转换时必须保留原始CR作为证据" + predicate: csnp.jurisdiction_aware_routing == true and + csnp.cross_jurisdiction_relay == true and + csnp.preserves_original_cr == true + obligation: csnp.enforce_jurisdiction_aware_routing per_block + violation_action: reject_non_compliant_routing + test: A51_test_csnp_routing + references: ["多辖区节点共享白皮书 §3.5", "CSNP扩展规范"] + +clause A52_SharedStorageDataPrivacy + name: "共享存储敏感数据加密" + tier: Tactical + clause_index: 1006 + description: "在物理共享存储环境中,敏感数据(法律文件哈希、KYC信息、辖区密钥) + 必须加密存储,仅授权节点可解密; + 区块链数据分片存储时必须通过冗余编码保证可用性(最低3副本)" + predicate: storage.sensitive_data_encrypted == true and + storage.authorized_access_only == true and + storage.redundancy_copies >= 3 + obligation: storage.enforce_encryption_and_redundancy per_epoch + violation_action: quarantine_unencrypted_data + test: A52_test_shared_storage_privacy + references: ["多辖区节点共享白皮书 §3.7", "§4 安全与隐私保护"] + +// ============================================================ +// 测试块 +// ============================================================ + +test A44_test_node_sharing_isolation { + // 物理共享节点必须有逻辑隔离标志 + assert node.physical_shared == true implies node.logical_isolated == true + assert node.container_isolated == true + assert node.network_namespace_isolated == true +} + +test A45_test_cross_jurisdiction_consensus { + // 跨辖区区块必须包含 jurisdiction_merkle_root + assert block.has_cross_jurisdiction_tx == true implies + block.header.jurisdiction_merkle_root != null + // 跨辖区交易必须有双CR + assert cross_tx.source_cr.valid == true + assert cross_tx.target_cr.valid == true +} + +test A46_test_resource_allocation_council { + // 资源分配必须经过委员会投票 + assert resource.allocation_proposal.council_approved == true + assert resource.allocation_proposal.vote_ratio >= 6700 +} + +test A47_test_node_identity_binding { + // 节点DID必须绑定辖区 + assert node.did != "" + assert node.jurisdiction != 0 + assert node.jurisdiction_proof.signature_valid == true + assert node.plugin_hashes.len() > 0 +} + +test A48_test_wasm_sandbox { + // WASM沙箱限制验证 + assert plugin.execution_env == "WASM_SANDBOX" + assert plugin.max_execution_ms <= 10 + assert plugin.max_memory_mb <= 64 +} + +test A49_test_cee_shared_cluster { + // CEE多辖区支持验证 + assert cee.supports_multi_jurisdiction == true + assert cee.gids_registered == true +} + +test A50_test_dispute_resolution { + // 争议解决路径验证 + assert dispute.resolution_path == "constitutional_court" +} + +test A51_test_csnp_routing { + // CSNP辖区感知路由验证 + assert csnp.jurisdiction_aware_routing == true + assert csnp.preserves_original_cr == true +} + +test A52_test_shared_storage_privacy { + // 共享存储加密验证 + assert storage.sensitive_data_encrypted == true + assert storage.redundancy_copies >= 3 +} diff --git a/nac-multi-jurisdiction/src/lib.rs b/nac-multi-jurisdiction/src/lib.rs index 883350e..4d15ac5 100644 --- a/nac-multi-jurisdiction/src/lib.rs +++ b/nac-multi-jurisdiction/src/lib.rs @@ -21,6 +21,7 @@ pub mod plugin; pub mod dual_receipt; pub mod discovery; pub mod governance; +pub mod node_sharing_enhanced; pub use jurisdiction::{Jurisdiction, JurisdictionId, JurisdictionConfig, JurisdictionRegistry}; pub use isolation::{IsolationLayer, IsolationPolicy, IsolationViolation}; diff --git a/nac-multi-jurisdiction/src/node_sharing_enhanced.rs b/nac-multi-jurisdiction/src/node_sharing_enhanced.rs new file mode 100644 index 0000000..f61707d --- /dev/null +++ b/nac-multi-jurisdiction/src/node_sharing_enhanced.rs @@ -0,0 +1,798 @@ +// nac-multi-jurisdiction/src/node_sharing_enhanced.rs +// Issue #70: 多辖区节点共享增强实现 +// 版本: 1.0 | 2026-03-07 +// 基于《NAC公链多辖区节点共享方案与技术落地白皮书》v1.0 +// +// 本模块实现多辖区节点共享的核心运行时逻辑: +// - 节点共享注册表(SharedNodeRegistry) +// - 资源配额动态调整(DynamicQuotaManager) +// - 跨辖区区块生产协调器(CrossJurisdictionBlockCoordinator) +// - WASM插件运行时(WasmPluginRuntime) +// - CEE共享集群管理器(CeeClusterManager) + +use std::collections::HashMap; +use serde::{Deserialize, Serialize}; + +// ============================================================ +// 节点共享注册表 +// ============================================================ + +/// 辖区ID(16位,ISO3166-1 + 子辖区扩展) +pub type JurisdictionId = u16; + +/// 节点共享注册表 +/// 管理所有物理共享节点的逻辑隔离状态 +pub struct SharedNodeRegistry { + /// 节点ID → 共享节点记录 + nodes: HashMap, + /// 辖区ID → 节点ID列表 + jurisdiction_nodes: HashMap>, +} + +/// 共享节点记录 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SharedNodeRecord { + /// 节点唯一标识 + pub node_id: String, + /// 节点DID + pub did: String, + /// 所属辖区 + pub jurisdiction: JurisdictionId, + /// 物理主机标识(相同主机的节点共享物理资源) + pub physical_host_id: String, + /// 容器实例ID + pub container_id: String, + /// 网络命名空间ID + pub network_namespace: String, + /// 存储卷ID + pub storage_volume_id: String, + /// 已加载的辖区插件哈希 + pub plugin_hashes: Vec>, + /// 节点状态 + pub status: NodeStatus, + /// 资源使用统计 + pub resource_usage: ResourceUsageStats, + /// 注册时间戳 + pub registered_at: u64, + /// 最后心跳时间 + pub last_heartbeat: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum NodeStatus { + Active, + Inactive, + Suspended, // 因违规暂停 + Quarantined, // 因安全问题隔离 +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct ResourceUsageStats { + pub cpu_usage_millicores: u64, + pub memory_usage_mb: u64, + pub bandwidth_usage_mbps: u64, + pub storage_usage_gb: u64, + pub last_updated: u64, +} + +impl SharedNodeRegistry { + pub fn new() -> Self { + SharedNodeRegistry { + nodes: HashMap::new(), + jurisdiction_nodes: HashMap::new(), + } + } + + /// 注册共享节点(A44/A47验证后调用) + pub fn register_node(&mut self, record: SharedNodeRecord) -> Result<(), RegistryError> { + // 验证节点未重复注册 + if self.nodes.contains_key(&record.node_id) { + return Err(RegistryError::NodeAlreadyRegistered(record.node_id.clone())); + } + + // 验证辖区有效 + if record.jurisdiction == 0 { + return Err(RegistryError::InvalidJurisdiction); + } + + // 验证容器隔离(A44) + if record.container_id.is_empty() { + return Err(RegistryError::MissingContainerIsolation); + } + if record.network_namespace.is_empty() { + return Err(RegistryError::MissingNetworkNamespace); + } + + // 更新辖区节点索引 + self.jurisdiction_nodes + .entry(record.jurisdiction) + .or_insert_with(Vec::new) + .push(record.node_id.clone()); + + self.nodes.insert(record.node_id.clone(), record); + Ok(()) + } + + /// 获取同一物理主机上的所有节点(用于资源争用检测) + pub fn get_nodes_on_host(&self, host_id: &str) -> Vec<&SharedNodeRecord> { + self.nodes + .values() + .filter(|n| n.physical_host_id == host_id) + .collect() + } + + /// 获取辖区的所有活跃节点 + pub fn get_active_nodes_for_jurisdiction( + &self, + jurisdiction: JurisdictionId, + ) -> Vec<&SharedNodeRecord> { + self.jurisdiction_nodes + .get(&jurisdiction) + .map(|ids| { + ids.iter() + .filter_map(|id| self.nodes.get(id)) + .filter(|n| n.status == NodeStatus::Active) + .collect() + }) + .unwrap_or_default() + } + + /// 检测同一物理主机上的辖区隔离违规 + pub fn detect_isolation_violations(&self, host_id: &str) -> Vec { + let host_nodes = self.get_nodes_on_host(host_id); + let mut violations = Vec::new(); + + // 检查是否有节点缺少网络命名空间隔离 + for node in &host_nodes { + if node.network_namespace.is_empty() { + violations.push(IsolationViolation { + node_id: node.node_id.clone(), + violation_type: ViolationType::MissingNetworkNamespace, + description: format!( + "节点 {} 在物理主机 {} 上缺少网络命名空间隔离", + node.node_id, host_id + ), + }); + } + } + + // 检查是否有多个辖区节点共享同一网络命名空间(违反A44) + let mut namespace_jurisdictions: HashMap> = HashMap::new(); + for node in &host_nodes { + namespace_jurisdictions + .entry(node.network_namespace.clone()) + .or_insert_with(Vec::new) + .push(node.jurisdiction); + } + for (namespace, jurisdictions) in &namespace_jurisdictions { + if jurisdictions.len() > 1 { + let unique_jurisdictions: std::collections::HashSet<_> = jurisdictions.iter().collect(); + if unique_jurisdictions.len() > 1 { + violations.push(IsolationViolation { + node_id: format!("namespace:{}", namespace), + violation_type: ViolationType::SharedNetworkNamespace, + description: format!( + "网络命名空间 {} 被多个辖区({:?})共享,违反A44逻辑隔离要求", + namespace, jurisdictions + ), + }); + } + } + } + + violations + } + + pub fn node_count(&self) -> usize { + self.nodes.len() + } +} + +#[derive(Debug, Clone)] +pub struct IsolationViolation { + pub node_id: String, + pub violation_type: ViolationType, + pub description: String, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum ViolationType { + MissingNetworkNamespace, + SharedNetworkNamespace, + MissingStorageIsolation, + ResourceQuotaExceeded, + UnauthorizedPluginLoaded, +} + +#[derive(Debug, Clone)] +pub enum RegistryError { + NodeAlreadyRegistered(String), + InvalidJurisdiction, + MissingContainerIsolation, + MissingNetworkNamespace, +} + +// ============================================================ +// 动态资源配额管理器 +// ============================================================ + +/// 动态资源配额管理器(A46) +pub struct DynamicQuotaManager { + /// 辖区ID → 当前配额 + quotas: HashMap, + /// 配额变更历史 + change_history: Vec, + /// 总物理资源 + total_resources: PhysicalResources, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DynamicQuota { + pub jurisdiction: JurisdictionId, + /// CPU配额(毫核) + pub cpu_millicores: u64, + /// 内存配额(MB) + pub memory_mb: u64, + /// 带宽配额(Mbps) + pub bandwidth_mbps: u64, + /// 存储配额(GB) + pub storage_gb: u64, + /// 配额生效时间 + pub effective_from: u64, + /// 配额来源提案ID + pub proposal_id: u64, +} + +#[derive(Debug, Clone)] +pub struct PhysicalResources { + pub total_cpu_millicores: u64, + pub total_memory_mb: u64, + pub total_bandwidth_mbps: u64, + pub total_storage_gb: u64, +} + +#[derive(Debug, Clone)] +pub struct QuotaChangeRecord { + pub jurisdiction: JurisdictionId, + pub old_quota: Option, + pub new_quota: DynamicQuota, + pub changed_at: u64, + pub proposal_id: u64, +} + +impl DynamicQuotaManager { + pub fn new(total_resources: PhysicalResources) -> Self { + DynamicQuotaManager { + quotas: HashMap::new(), + change_history: Vec::new(), + total_resources, + } + } + + /// 应用经委员会投票通过的资源分配提案(A46) + pub fn apply_allocation_proposal( + &mut self, + proposal_id: u64, + allocations: HashMap, + timestamp: u64, + ) -> Result<(), QuotaError> { + // 验证总配额不超过物理资源 + let total_cpu: u64 = allocations.values().map(|q| q.cpu_millicores).sum(); + let total_memory: u64 = allocations.values().map(|q| q.memory_mb).sum(); + let total_bandwidth: u64 = allocations.values().map(|q| q.bandwidth_mbps).sum(); + let total_storage: u64 = allocations.values().map(|q| q.storage_gb).sum(); + + if total_cpu > self.total_resources.total_cpu_millicores { + return Err(QuotaError::CpuOverAllocation { + requested: total_cpu, + available: self.total_resources.total_cpu_millicores, + }); + } + if total_memory > self.total_resources.total_memory_mb { + return Err(QuotaError::MemoryOverAllocation { + requested: total_memory, + available: self.total_resources.total_memory_mb, + }); + } + if total_bandwidth > self.total_resources.total_bandwidth_mbps { + return Err(QuotaError::BandwidthOverAllocation { + requested: total_bandwidth, + available: self.total_resources.total_bandwidth_mbps, + }); + } + if total_storage > self.total_resources.total_storage_gb { + return Err(QuotaError::StorageOverAllocation { + requested: total_storage, + available: self.total_resources.total_storage_gb, + }); + } + + // 应用配额变更 + for (jurisdiction, new_quota) in allocations { + let old_quota = self.quotas.remove(&jurisdiction); + self.change_history.push(QuotaChangeRecord { + jurisdiction, + old_quota: old_quota.clone(), + new_quota: new_quota.clone(), + changed_at: timestamp, + proposal_id, + }); + self.quotas.insert(jurisdiction, new_quota); + } + + Ok(()) + } + + /// 检查辖区是否超出配额 + pub fn check_quota_violation( + &self, + jurisdiction: JurisdictionId, + usage: &ResourceUsageStats, + ) -> Vec { + let mut violations = Vec::new(); + + if let Some(quota) = self.quotas.get(&jurisdiction) { + if usage.cpu_usage_millicores > quota.cpu_millicores { + violations.push(format!( + "辖区 {} CPU使用({}m)超出配额({}m)", + jurisdiction, usage.cpu_usage_millicores, quota.cpu_millicores + )); + } + if usage.memory_usage_mb > quota.memory_mb { + violations.push(format!( + "辖区 {} 内存使用({}MB)超出配额({}MB)", + jurisdiction, usage.memory_usage_mb, quota.memory_mb + )); + } + if usage.bandwidth_usage_mbps > quota.bandwidth_mbps { + violations.push(format!( + "辖区 {} 带宽使用({}Mbps)超出配额({}Mbps)", + jurisdiction, usage.bandwidth_usage_mbps, quota.bandwidth_mbps + )); + } + if usage.storage_usage_gb > quota.storage_gb { + violations.push(format!( + "辖区 {} 存储使用({}GB)超出配额({}GB)", + jurisdiction, usage.storage_usage_gb, quota.storage_gb + )); + } + } + + violations + } +} + +#[derive(Debug, Clone)] +pub enum QuotaError { + CpuOverAllocation { requested: u64, available: u64 }, + MemoryOverAllocation { requested: u64, available: u64 }, + BandwidthOverAllocation { requested: u64, available: u64 }, + StorageOverAllocation { requested: u64, available: u64 }, +} + +// ============================================================ +// 跨辖区区块生产协调器(A45) +// ============================================================ + +/// 跨辖区区块生产协调器 +pub struct CrossJurisdictionBlockCoordinator { + /// 待处理的跨辖区交易 + pending_cross_txs: Vec, + /// CEE集群(辖区ID → CEE节点列表) + cee_cluster: HashMap>, +} + +#[derive(Debug, Clone)] +pub struct PendingCrossJurisdictionTx { + pub tx_hash: Vec, + pub source_jurisdiction: JurisdictionId, + pub target_jurisdiction: JurisdictionId, + pub source_cr: Option, + pub target_cr: Option, + pub submitted_at: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ConstitutionalReceiptRef { + /// CR哈希(SHA3-384,48字节) + pub cr_hash: Vec, + /// 签发辖区 + pub issuing_jurisdiction: JurisdictionId, + /// 签发CEE节点DID + pub issuing_cee_did: String, + /// 签发时间戳 + pub issued_at: u64, + /// CEE签名 + pub cee_signature: Vec, +} + +#[derive(Debug, Clone)] +pub struct CeeNodeInfo { + pub did: String, + pub endpoint: String, + pub supported_jurisdictions: Vec, + pub current_load: u64, + pub is_available: bool, +} + +impl CrossJurisdictionBlockCoordinator { + pub fn new() -> Self { + CrossJurisdictionBlockCoordinator { + pending_cross_txs: Vec::new(), + cee_cluster: HashMap::new(), + } + } + + /// 注册CEE节点到集群 + pub fn register_cee_node(&mut self, node: CeeNodeInfo) { + for jurisdiction in &node.supported_jurisdictions { + self.cee_cluster + .entry(*jurisdiction) + .or_insert_with(Vec::new) + .push(node.clone()); + } + } + + /// 为跨辖区交易选择最优CEE节点(负载均衡) + pub fn select_cee_for_cross_tx( + &self, + source: JurisdictionId, + target: JurisdictionId, + ) -> Option<&CeeNodeInfo> { + // 优先选择同时支持源辖区和目标辖区的CEE节点(A49) + let all_cee: Vec<&CeeNodeInfo> = self + .cee_cluster + .values() + .flatten() + .filter(|n| { + n.is_available + && n.supported_jurisdictions.contains(&source) + && n.supported_jurisdictions.contains(&target) + }) + .collect(); + + // 按负载排序,选择负载最低的节点 + all_cee.into_iter().min_by_key(|n| n.current_load) + } + + /// 构建区块的 jurisdiction_merkle_root(A45) + /// 将所有跨辖区交易的双CR哈希构建成默克尔树 + pub fn build_jurisdiction_merkle_root( + &self, + cross_tx_receipts: &[(&ConstitutionalReceiptRef, &ConstitutionalReceiptRef)], + ) -> Option> { + if cross_tx_receipts.is_empty() { + return None; + } + + // 将所有CR哈希连接后计算SHA3-384 + // 实际实现中应使用标准默克尔树算法 + use sha3::{Digest, Sha3_384}; + let mut hasher = Sha3_384::new(); + for (source_cr, target_cr) in cross_tx_receipts { + hasher.update(&source_cr.cr_hash); + hasher.update(&target_cr.cr_hash); + } + let result = hasher.finalize(); + let mut root = vec![0u8; 48]; + root.copy_from_slice(&result); + Some(root) + } + + /// 验证区块的跨辖区合规性(A45) + pub fn verify_block_cross_jurisdiction_compliance( + &self, + cross_tx_count: u32, + jurisdiction_merkle_root: Option>, + receipts: &[(&ConstitutionalReceiptRef, &ConstitutionalReceiptRef)], + ) -> CrossJurisdictionComplianceResult { + let mut violations = Vec::new(); + + if cross_tx_count > 0 { + // 必须有 jurisdiction_merkle_root + if jurisdiction_merkle_root.is_none() { + violations.push( + "A45: 含跨辖区交易的区块缺少 jurisdiction_merkle_root".to_string(), + ); + } + + // 每笔跨辖区交易必须有双CR + if receipts.len() != cross_tx_count as usize { + violations.push(format!( + "A45: 跨辖区交易数量({})与双CR数量({})不匹配", + cross_tx_count, + receipts.len() + )); + } + + // 验证每个CR的签名不为空 + for (i, (source_cr, target_cr)) in receipts.iter().enumerate() { + if source_cr.cee_signature.is_empty() { + violations.push(format!("A45: 第{}笔交易源辖区CR缺少CEE签名", i + 1)); + } + if target_cr.cee_signature.is_empty() { + violations.push(format!("A45: 第{}笔交易目标辖区CR缺少CEE签名", i + 1)); + } + } + } + + CrossJurisdictionComplianceResult { + passed: violations.is_empty(), + violations, + } + } +} + +#[derive(Debug, Clone)] +pub struct CrossJurisdictionComplianceResult { + pub passed: bool, + pub violations: Vec, +} + +// ============================================================ +// GIDS增强:节点身份辖区绑定(A47) +// ============================================================ + +/// GIDS增强注册表(支持辖区绑定) +pub struct GidsEnhancedRegistry { + /// DID → 节点身份记录 + identities: HashMap, + /// 辖区ID → DID列表 + jurisdiction_index: HashMap>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GidsNodeIdentity { + pub did: String, + pub jurisdiction: JurisdictionId, + pub public_key: [u8; 32], + /// 辖区政府授权的数字签名(Ed25519) + pub jurisdiction_proof_signature: Vec, + /// 辖区证明签发机构DID + pub proof_issuer_did: String, + /// 辖区证明过期时间 + pub proof_expires_at: u64, + /// 已授权的插件哈希列表 + pub authorized_plugin_hashes: Vec>, + /// 节点角色 + pub node_role: NodeRole, + /// 注册时间 + pub registered_at: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum NodeRole { + Validator, // 验证节点 + CeeNode, // 宪法执行引擎节点 + RelayNode, // 中继节点(CSNP) + StorageNode, // 存储节点 + FullNode, // 全节点 +} + +impl GidsEnhancedRegistry { + pub fn new() -> Self { + GidsEnhancedRegistry { + identities: HashMap::new(), + jurisdiction_index: HashMap::new(), + } + } + + /// 注册节点身份(A47验证后调用) + pub fn register_identity( + &mut self, + identity: GidsNodeIdentity, + current_timestamp: u64, + ) -> Result<(), GidsError> { + // 验证DID格式 + if identity.did.is_empty() || !identity.did.starts_with("did:nac:") { + return Err(GidsError::InvalidDid(identity.did.clone())); + } + + // 验证辖区 + if identity.jurisdiction == 0 { + return Err(GidsError::InvalidJurisdiction); + } + + // 验证辖区证明未过期 + if identity.proof_expires_at < current_timestamp { + return Err(GidsError::JurisdictionProofExpired); + } + + // 验证签名不为空 + if identity.jurisdiction_proof_signature.is_empty() { + return Err(GidsError::MissingJurisdictionProof); + } + + // 验证至少有一个授权插件 + if identity.authorized_plugin_hashes.is_empty() { + return Err(GidsError::NoAuthorizedPlugins); + } + + // 更新辖区索引 + self.jurisdiction_index + .entry(identity.jurisdiction) + .or_insert_with(Vec::new) + .push(identity.did.clone()); + + self.identities.insert(identity.did.clone(), identity); + Ok(()) + } + + /// 验证节点加载的插件哈希是否已授权(A47) + pub fn verify_plugin_hashes( + &self, + did: &str, + loaded_hashes: &[Vec], + ) -> Result<(), GidsError> { + let identity = self.identities.get(did) + .ok_or_else(|| GidsError::NodeNotFound(did.to_string()))?; + + for hash in loaded_hashes { + if !identity.authorized_plugin_hashes.contains(hash) { + return Err(GidsError::UnauthorizedPlugin(hash.clone())); + } + } + Ok(()) + } + + /// 获取辖区的所有节点DID列表 + pub fn get_jurisdiction_nodes(&self, jurisdiction: JurisdictionId) -> Vec<&str> { + self.jurisdiction_index + .get(&jurisdiction) + .map(|dids| dids.iter().map(|s| s.as_str()).collect()) + .unwrap_or_default() + } +} + +#[derive(Debug, Clone)] +pub enum GidsError { + InvalidDid(String), + InvalidJurisdiction, + JurisdictionProofExpired, + MissingJurisdictionProof, + NoAuthorizedPlugins, + NodeNotFound(String), + UnauthorizedPlugin(Vec), +} + +// ============================================================ +// 单元测试 +// ============================================================ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_shared_node_registry_register() { + let mut registry = SharedNodeRegistry::new(); + let record = SharedNodeRecord { + node_id: "node-001".to_string(), + did: "did:nac:node001".to_string(), + jurisdiction: 784, // UAE + physical_host_id: "host-01".to_string(), + container_id: "container-abc123".to_string(), + network_namespace: "netns-node001".to_string(), + storage_volume_id: "vol-node001".to_string(), + plugin_hashes: vec![vec![0u8; 48]], + status: NodeStatus::Active, + resource_usage: ResourceUsageStats::default(), + registered_at: 1000000, + last_heartbeat: 1000000, + }; + assert!(registry.register_node(record).is_ok()); + assert_eq!(registry.node_count(), 1); + } + + #[test] + fn test_isolation_violation_detection() { + let mut registry = SharedNodeRegistry::new(); + + // 两个不同辖区的节点共享同一网络命名空间(违规) + let node1 = SharedNodeRecord { + node_id: "node-001".to_string(), + did: "did:nac:node001".to_string(), + jurisdiction: 784, // UAE + physical_host_id: "host-01".to_string(), + container_id: "container-001".to_string(), + network_namespace: "shared-netns".to_string(), // 共享命名空间 + storage_volume_id: "vol-001".to_string(), + plugin_hashes: vec![vec![0u8; 48]], + status: NodeStatus::Active, + resource_usage: ResourceUsageStats::default(), + registered_at: 1000000, + last_heartbeat: 1000000, + }; + let node2 = SharedNodeRecord { + node_id: "node-002".to_string(), + did: "did:nac:node002".to_string(), + jurisdiction: 156, // China + physical_host_id: "host-01".to_string(), + container_id: "container-002".to_string(), + network_namespace: "shared-netns".to_string(), // 同一命名空间 + storage_volume_id: "vol-002".to_string(), + plugin_hashes: vec![vec![1u8; 48]], + status: NodeStatus::Active, + resource_usage: ResourceUsageStats::default(), + registered_at: 1000000, + last_heartbeat: 1000000, + }; + + registry.register_node(node1).unwrap(); + registry.register_node(node2).unwrap(); + + let violations = registry.detect_isolation_violations("host-01"); + assert!(!violations.is_empty()); + assert!(violations.iter().any(|v| v.violation_type == ViolationType::SharedNetworkNamespace)); + } + + #[test] + fn test_dynamic_quota_manager_over_allocation() { + let total = PhysicalResources { + total_cpu_millicores: 16000, + total_memory_mb: 32768, + total_bandwidth_mbps: 1000, + total_storage_gb: 2000, + }; + let mut manager = DynamicQuotaManager::new(total); + + let mut allocations = HashMap::new(); + allocations.insert(784u16, DynamicQuota { + jurisdiction: 784, + cpu_millicores: 10000, + memory_mb: 20000, + bandwidth_mbps: 600, + storage_gb: 1200, + effective_from: 1000000, + proposal_id: 1, + }); + allocations.insert(156u16, DynamicQuota { + jurisdiction: 156, + cpu_millicores: 8000, // 总计18000 > 16000,超额 + memory_mb: 15000, + bandwidth_mbps: 500, + storage_gb: 900, + effective_from: 1000000, + proposal_id: 1, + }); + + let result = manager.apply_allocation_proposal(1, allocations, 1000000); + assert!(matches!(result, Err(QuotaError::CpuOverAllocation { .. }))); + } + + #[test] + fn test_gids_enhanced_registry() { + let mut registry = GidsEnhancedRegistry::new(); + let identity = GidsNodeIdentity { + did: "did:nac:validator001".to_string(), + jurisdiction: 784, + public_key: [0u8; 32], + jurisdiction_proof_signature: vec![1u8; 64], + proof_issuer_did: "did:nac:uae-adgm-gov".to_string(), + proof_expires_at: u64::MAX, + authorized_plugin_hashes: vec![vec![0u8; 48]], + node_role: NodeRole::Validator, + registered_at: 1000000, + }; + assert!(registry.register_identity(identity, 1000000).is_ok()); + + // 验证已授权插件 + assert!(registry.verify_plugin_hashes("did:nac:validator001", &[vec![0u8; 48]]).is_ok()); + + // 验证未授权插件 + assert!(registry.verify_plugin_hashes("did:nac:validator001", &[vec![1u8; 48]]).is_err()); + } + + #[test] + fn test_cross_jurisdiction_block_coordinator() { + let coordinator = CrossJurisdictionBlockCoordinator::new(); + + // 无跨辖区交易的区块应通过验证 + let result = coordinator.verify_block_cross_jurisdiction_compliance(0, None, &[]); + assert!(result.passed); + + // 有跨辖区交易但缺少 jurisdiction_merkle_root 应失败 + let result = coordinator.verify_block_cross_jurisdiction_compliance(1, None, &[]); + assert!(!result.passed); + } +}