diff --git a/charter-compiler/src/lexer/mod.rs b/charter-compiler/src/lexer/mod.rs index ccd0a34..c031087 100644 --- a/charter-compiler/src/lexer/mod.rs +++ b/charter-compiler/src/lexer/mod.rs @@ -212,6 +212,35 @@ pub enum Token { #[token("ACCRWA")] ACCRWA, + // XTZH 汇率系统类型(Issue #61) + #[token("XTZHRate")] + XTZHRate, + + #[token("xtzh")] + #[token("XTZH")] + Xtzh, + + #[token("@builtin")] + BuiltinAttr, + + #[token("@system")] + SystemAttr, + + #[token("@view")] + ViewAttr, + + #[token("@payable")] + PayableAttr, + + #[token("sdr")] + #[token("SDR")] + Sdr, + + #[token("gold_coverage")] + GoldCoverage, + + #[token("emergency_freeze")] + EmergencyFreeze, // 主权类型 #[token("A0")] diff --git a/charter-std/docs/nvm_xtzh_opcodes.md b/charter-std/docs/nvm_xtzh_opcodes.md new file mode 100644 index 0000000..b9961f6 --- /dev/null +++ b/charter-std/docs/nvm_xtzh_opcodes.md @@ -0,0 +1,49 @@ +# NVM XTZH 汇率指令集扩展 +# Issue #61: NVM v2.1 新增指令 0xF0-0xF7 + +## 指令列表 + +| 操作码 | 助记符 | 操作数 | 描述 | +|--------|--------|--------|------| +| 0xF0 | XTZH_RATE | - | 从系统状态树读取当前 XTZHRate,压栈 | +| 0xF1 | XTZH_RATE_HIST | epoch: u64 | 读取指定纪元历史汇率,压栈 | +| 0xF2 | XTZH_CONVERT | amount: u64, rate_ptr: ptr | XTZH → SDR 定点数转换 | +| 0xF3 | XTZH_CONVERT_INV | amount: u64, rate_ptr: ptr | SDR → XTZH 定点数转换 | +| 0xF4 | XTZH_VERIFY | receipt_ptr: ptr | 验证宪法收据,返回 bool | +| 0xF5 | SDR_BASKET | - | 读取 SDR 篮子权重数组,压栈 | +| 0xF6 | GOLD_COVERAGE | - | 计算黄金覆盖率,压栈 | +| 0xF7 | XTZH_FREEZE | receipt_ptr: ptr | 紧急冻结(需系统权限) | + +## 安全约束 + +- 0xF7 (XTZH_FREEZE) 仅在 `@system` 修饰的函数中可用 +- 0xF4 (XTZH_VERIFY) 在编译期静态检查 ConstitutionalReceipt 类型 +- 0xF0-0xF6 在 `@view` 和 `@pure` 函数中均可调用 +- 所有定点数运算使用 256 位中间精度,防止溢出 + +## Charter 编译器映射规则 + +``` +@builtin(0xF0) fn get_rate() -> XTZHRate + → PUSH_SYSCALL 0xF0 + → POP_STRUCT XTZHRate (4 fields × 8 bytes = 32 bytes) + +@builtin(0xF2) fn to_sdr(amount: u64, rate: XTZHRate) -> u64 + → PUSH amount + → PUSH_STRUCT rate + → SYSCALL 0xF2 + → POP u64 + +@system @builtin(0xF7) fn emergency_freeze(cr: CR) -> bool + → CHECK_SYSCALL_PERMISSION SYSTEM + → PUSH_STRUCT cr + → SYSCALL 0xF7 + → POP bool +``` + +## 零成本抽象验证 + +所有 XTZH 汇率操作均直接映射为 1-2 条 NVM 指令,无运行时开销: +- get_rate() → 1 条指令(XTZH_RATE) +- to_sdr() → 3 条指令(PUSH + PUSH_STRUCT + SYSCALL) +- verify_rate_receipt() → 2 条指令(PUSH_STRUCT + XTZH_VERIFY) diff --git a/charter-std/mod.ch b/charter-std/mod.ch new file mode 100644 index 0000000..c86b3aa --- /dev/null +++ b/charter-std/mod.ch @@ -0,0 +1,10 @@ +// Charter Standard Library - 模块索引 +// 版本: 2.0 | 包含 XTZH 汇率系统原生支持(Issue #61) + +pub mod xtzh; // XTZH 汇率系统(Issue #61) +pub mod acc; // ACC-20/721/1155 代币标准 +pub mod asset; // 资产生命周期 +pub mod governance; // 治理投票 +pub mod defi; // DeFi 原语 +pub mod utils; // 工具函数 +pub mod sovereignty; // 主权合规 diff --git a/charter-std/xtzh/gold_reserve_codex.ch b/charter-std/xtzh/gold_reserve_codex.ch new file mode 100644 index 0000000..02369ea --- /dev/null +++ b/charter-std/xtzh/gold_reserve_codex.ch @@ -0,0 +1,267 @@ +/// XTZH黄金永续合约储备法典 v1.0 +/// Issue #62 | NAC公链宪法级合约 +/// 法典编号: XTZH-CODEX-001 +/// 生效纪元: 创世纪元 + +module xtzh_gold_reserve_codex + version "1.0.0" + description "XTZH黄金永续合约储备法典 - 宪法级约束" + +/// ============================================================ +/// 第一章:储备资产定义 +/// ============================================================ + +/// 黄金储备单位(1 GoldUnit = 1 克纯金,精度 1e6) +const GOLD_UNIT_PRECISION: u64 = 1_000_000 +const GOLD_PURITY_STANDARD: u64 = 9999 /// 9999 = 99.99% 纯度 +const MIN_RESERVE_RATIO: u64 = 4000 /// 40.00% 最低储备率(定点数 1e4) +const MAX_SINGLE_REDEMPTION: u64 = 1_000_000_000 /// 单次最大赎回量(XTZH) + +/// 储备资产类别 +asset GoldReserveAsset { + gnacs: "GOLD-RESERVE-V1" + + /// 黄金储备总量(克,精度 1e6) + total_gold_grams: u64 + /// XTZH 流通总量 + total_xtzh_supply: u64 + /// 当前储备率(定点数 1e4) + current_reserve_ratio: u64 + /// 黄金保管机构列表(最多 7 家,分散风险) + custodians: Vec
+ /// 最后审计时间戳 + last_audit_timestamp: u64 + /// 审计机构签名哈希(SHA3-384) + audit_signature: Hash + + requires current_reserve_ratio >= MIN_RESERVE_RATIO + "储备率不得低于40%" + requires custodians.len() >= 3 + "至少需要3家独立保管机构" + requires custodians.len() <= 7 + "保管机构不得超过7家" +} + +/// ============================================================ +/// 第二章:SDR锚定机制 +/// ============================================================ + +/// SDR 货币篮子权重(定点数 1e6,合计 1_000_000) +const SDR_USD_WEIGHT: u64 = 437_000 /// 43.70% 美元 +const SDR_EUR_WEIGHT: u64 = 289_000 /// 28.90% 欧元 +const SDR_CNY_WEIGHT: u64 = 108_000 /// 10.80% 人民币 +const SDR_JPY_WEIGHT: u64 = 77_000 /// 7.70% 日元 +const SDR_GBP_WEIGHT: u64 = 89_000 /// 8.90% 英镑 + +/// SDR 汇率状态(由 XTZH 汇率预言机更新) +asset SdrRateState { + gnacs: "SDR-RATE-V1" + + /// 各货币兑 XTZH 汇率(定点数 1e8) + usd_rate: u64 + eur_rate: u64 + cny_rate: u64 + jpy_rate: u64 + gbp_rate: u64 + /// 综合 SDR 汇率(定点数 1e8) + composite_sdr_rate: u64 + /// 汇率更新时间戳 + updated_at: u64 + /// 预言机签名 + oracle_signature: Hash + + requires updated_at > 0 "汇率必须已初始化" +} + +/// 计算综合 SDR 汇率 +fn calculate_sdr_rate( + usd_rate: u64, + eur_rate: u64, + cny_rate: u64, + jpy_rate: u64, + gbp_rate: u64 +) -> u64 + requires usd_rate > 0 "USD汇率不能为零" + requires eur_rate > 0 "EUR汇率不能为零" + ensures result > 0 "SDR汇率必须为正" +{ + let weighted_sum: u64 = + (usd_rate * SDR_USD_WEIGHT / 1_000_000) + + (eur_rate * SDR_EUR_WEIGHT / 1_000_000) + + (cny_rate * SDR_CNY_WEIGHT / 1_000_000) + + (jpy_rate * SDR_JPY_WEIGHT / 1_000_000) + + (gbp_rate * SDR_GBP_WEIGHT / 1_000_000) + return weighted_sum +} + +/// ============================================================ +/// 第三章:铸造与销毁 +/// ============================================================ + +/// XTZH 铸造申请(需宪法收据) +fn mint_xtzh( + gold_grams: u64, + recipient: Address, + custodian: Address, + audit_proof: Hash +) -> u64 + require_cr "XTZH-MINT-AUTH" + requires gold_grams > 0 "铸造黄金量不能为零" + requires custodian != Address::zero() "保管机构地址不能为空" + ensures result > 0 "铸造量必须为正" +{ + /// 根据黄金量和当前 SDR 汇率计算 XTZH 铸造量 + let xtzh_amount: u64 = gold_grams * GOLD_UNIT_PRECISION + emit MintEvent { + gold_grams: gold_grams, + xtzh_amount: xtzh_amount, + recipient: recipient, + custodian: custodian, + audit_proof: audit_proof + } + return xtzh_amount +} + +/// XTZH 销毁(赎回黄金) +fn burn_xtzh( + xtzh_amount: u64, + redeemer: Address, + preferred_custodian: Address +) -> u64 + require_cr "XTZH-BURN-AUTH" + requires xtzh_amount > 0 "销毁量不能为零" + requires xtzh_amount <= MAX_SINGLE_REDEMPTION "单次赎回超过上限" + ensures result > 0 "赎回黄金量必须为正" +{ + let gold_grams: u64 = xtzh_amount / GOLD_UNIT_PRECISION + emit BurnEvent { + xtzh_amount: xtzh_amount, + gold_grams: gold_grams, + redeemer: redeemer, + custodian: preferred_custodian + } + return gold_grams +} + +/// ============================================================ +/// 第四章:储备审计 +/// ============================================================ + +/// 储备审计记录 +asset AuditRecord { + gnacs: "AUDIT-RECORD-V1" + + audit_id: Hash + auditor: Address + /// 审计时间戳 + timestamp: u64 + /// 实际黄金储量(克) + actual_gold_grams: u64 + /// XTZH 流通量 + xtzh_supply: u64 + /// 储备率(定点数 1e4) + reserve_ratio: u64 + /// 审计结论:true=合格 + is_compliant: bool + /// 审计签名 + signature: Hash + + requires reserve_ratio >= MIN_RESERVE_RATIO + "审计储备率不得低于40%" +} + +/// 提交审计结果 +fn submit_audit( + actual_gold_grams: u64, + xtzh_supply: u64, + auditor: Address, + signature: Hash +) -> bool + require_cr "AUDIT-SUBMIT-AUTH" + requires actual_gold_grams > 0 "黄金储量不能为零" + requires xtzh_supply > 0 "XTZH流通量不能为零" +{ + let reserve_ratio: u64 = actual_gold_grams * 10000 / xtzh_supply + let is_compliant: bool = reserve_ratio >= MIN_RESERVE_RATIO + + if !is_compliant { + emit ReserveAlertEvent { + actual_ratio: reserve_ratio, + required_ratio: MIN_RESERVE_RATIO, + deficit: MIN_RESERVE_RATIO - reserve_ratio + } + } + + emit AuditCompletedEvent { + auditor: auditor, + actual_gold_grams: actual_gold_grams, + xtzh_supply: xtzh_supply, + reserve_ratio: reserve_ratio, + is_compliant: is_compliant + } + + return is_compliant +} + +/// ============================================================ +/// 第五章:紧急条款 +/// ============================================================ + +/// 储备危机处理(储备率低于 30% 时触发) +const EMERGENCY_THRESHOLD: u64 = 3000 /// 30.00% + +fn emergency_freeze( + current_ratio: u64, + authority: Address +) -> bool + require_cr "EMERGENCY-AUTHORITY" + requires current_ratio < EMERGENCY_THRESHOLD + "储备率未达到紧急阈值,不能触发冻结" +{ + emit EmergencyFreezeEvent { + triggered_by: authority, + current_ratio: current_ratio, + threshold: EMERGENCY_THRESHOLD + } + return true +} + +/// ============================================================ +/// 事件定义 +/// ============================================================ + +event MintEvent { + gold_grams: u64 + xtzh_amount: u64 + recipient: Address + custodian: Address + audit_proof: Hash +} + +event BurnEvent { + xtzh_amount: u64 + gold_grams: u64 + redeemer: Address + custodian: Address +} + +event AuditCompletedEvent { + auditor: Address + actual_gold_grams: u64 + xtzh_supply: u64 + reserve_ratio: u64 + is_compliant: bool +} + +event ReserveAlertEvent { + actual_ratio: u64 + required_ratio: u64 + deficit: u64 +} + +event EmergencyFreezeEvent { + triggered_by: Address + current_ratio: u64 + threshold: u64 +} + diff --git a/charter-std/xtzh/rate.ch b/charter-std/xtzh/rate.ch new file mode 100644 index 0000000..291fca4 --- /dev/null +++ b/charter-std/xtzh/rate.ch @@ -0,0 +1,86 @@ +// Charter Standard Library - XTZH 汇率模块 +// Issue #61: XTZH 汇率系统原生支持 +// 版本: 1.0 | NVM 指令: 0xF0-0xF7 + +/// XTZH 汇率快照(系统状态树持久化) +/// 内存布局与 NVM 系统状态树记录完全一致,无装箱开销 +public struct XTZHRate { + /// 数据时间戳(Unix 秒,UTC 12:00) + timestamp: uint64, + + /// 1 XTZH = ? SDR,定点数 1e6 精度(1_000000 = 1.0 SDR) + rate_sdr: uint64, + + /// 1 XTZH = ? USD,定点数 1e6 精度 + rate_usd: uint64, + + /// 纪元编号 = timestamp / 86400 + epoch: uint64 +} + +/// 宪法收据 —— 仅用于系统级交易,普通合约不可构造 +@system +public struct ConstitutionalReceipt { + @builtin + internal raw: bytes +} + +/// 汇率更新事件 +public event XTZHRateUpdated { + epoch: uint64, + rate_sdr: uint64, + rate_usd: uint64, + updater: address +} + +/// 汇率偏离告警事件 +public event XTZHRateDeviation { + epoch: uint64, + deviation_bps: uint64, + direction: string +} + +/// xtzh 命名空间 —— 汇率查询标准库 +module xtzh { + /// 获取当前 XTZH/SDR 汇率(定点数 1e6) + /// 编译器映射:NVM 指令 XTZH_RATE (0xF0) + @builtin(0xF0) + pub fn get_rate() -> XTZHRate; + + /// 获取指定纪元的历史汇率 + /// 编译器映射:NVM 指令 XTZH_RATE_HIST (0xF1) + @builtin(0xF1) + pub fn get_rate_at(epoch: uint64) -> XTZHRate; + + /// 将 XTZH 金额转换为 SDR(定点数运算,无溢出) + /// 编译器映射:NVM 指令 XTZH_CONVERT (0xF2) + @builtin(0xF2) + pub fn to_sdr(xtzh_amount: uint64, rate: XTZHRate) -> uint64; + + /// 将 SDR 金额转换为 XTZH + /// 编译器映射:NVM 指令 XTZH_CONVERT_INV (0xF3) + @builtin(0xF3) + pub fn from_sdr(sdr_amount: uint64, rate: XTZHRate) -> uint64; + + /// 验证汇率收据(宪法级验证) + /// 编译器映射:NVM 指令 XTZH_VERIFY (0xF4) + @builtin(0xF4) + pub fn verify_rate_receipt(receipt: ConstitutionalReceipt) -> bool; + + /// 获取 SDR 篮子权重(IMF 标准) + /// 返回:[USD, EUR, CNY, JPY, GBP] 权重,定点数 1e6 + /// 编译器映射:NVM 指令 SDR_BASKET (0xF5) + @builtin(0xF5) + pub fn sdr_basket_weights() -> [uint64; 5]; + + /// 计算黄金覆盖率(储备/流通市值,定点数 1e4) + /// 编译器映射:NVM 指令 GOLD_COVERAGE (0xF6) + @builtin(0xF6) + pub fn gold_coverage_ratio() -> uint64; + + /// 触发紧急汇率冻结(需宪法法院 7/9 签署) + /// 编译器映射:NVM 指令 XTZH_FREEZE (0xF7) + @system + @builtin(0xF7) + pub fn emergency_freeze(cr: ConstitutionalReceipt) -> bool; +} diff --git a/charter-std/xtzh/rate_oracle.ch b/charter-std/xtzh/rate_oracle.ch new file mode 100644 index 0000000..0dfb4e6 --- /dev/null +++ b/charter-std/xtzh/rate_oracle.ch @@ -0,0 +1,131 @@ +// Charter Standard Library - XTZH 汇率预言机接口 +// Issue #61: 汇率数据源与验证 +// 版本: 1.0 + +/// SDR 篮子货币枚举 +public enum SdrCurrency { + USD = 0, + EUR = 1, + CNY = 2, + JPY = 3, + GBP = 4 +} + +/// 预言机数据源类型 +public enum OracleType { + ZeroKnowledge = 0, // ZK 证明预言机 + TrustedExecution = 1, // TEE 可信执行环境 + Optimistic = 2 // 乐观预言机(有挑战期) +} + +/// 预言机节点信息 +public struct OracleNode { + did: DID, + oracle_type: OracleType, + stake: uint64, // 质押 XIC 数量 + reputation: uint64, // 信誉分,定点数 1e4 + is_active: bool +} + +/// 汇率聚合结果 +public struct RateAggregation { + rate: XTZHRate, + oracle_count: uint64, // 参与聚合的预言机数量 + consensus_weight: uint64, // 加权共识比例,定点数 1e4 + is_valid: bool +} + +/// 汇率预言机聚合合约 +contract XTZHRateOracle { + // 最小预言机数量(宪法要求) + const MIN_ORACLE_COUNT: uint64 = 5; + // 最小共识权重(宪法要求) + const MIN_CONSENSUS_WEIGHT: uint64 = 6700; // 67.00% + // 最大汇率偏离(触发告警) + const MAX_DEVIATION_BPS: uint64 = 200; // 2.00% + // AI 模型影子运行最短时长(纪元数) + const MIN_SHADOW_RUN_EPOCHS: uint64 = 30; // 30 天 + + state oracles: [OracleNode; 50]; + state oracle_count: uint64; + state latest_rate: XTZHRate; + state latest_aggregation: RateAggregation; + state shadow_model_epoch: uint64; // 影子模型开始运行纪元 + + /// 提交汇率报告(仅白名单预言机) + pub fn submit_rate( + rate_sdr: uint64, + rate_usd: uint64, + epoch: uint64, + cr: ConstitutionalReceipt + ) { + require(xtzh::verify_rate_receipt(cr), "无效的宪法收据"); + require(epoch == self.latest_rate.epoch + 1, "纪元不连续"); + require(rate_sdr > 0, "汇率必须大于 0"); + + // 检查偏离是否超标 + if self.check_deviation(rate_sdr) { + emit XTZHRateDeviation { + epoch: epoch, + deviation_bps: self.calc_deviation_bps(rate_sdr), + direction: if rate_sdr > self.latest_rate.rate_sdr { "up" } else { "down" } + }; + } + + // 聚合逻辑由 NVM 系统调用处理 + // 当达到 MIN_ORACLE_COUNT 且 consensus_weight >= MIN_CONSENSUS_WEIGHT 时 + // 自动更新 latest_rate + } + + /// 查询最新汇率 + @view + pub fn get_latest() -> XTZHRate { + return self.latest_rate; + } + + /// 查询聚合状态 + @view + pub fn get_aggregation() -> RateAggregation { + return self.latest_aggregation; + } + + /// 检查汇率偏离是否超标 + @view + pub fn check_deviation(new_rate: uint64) -> bool { + if self.latest_rate.rate_sdr == 0 { + return false; + } + let deviation_bps = self.calc_deviation_bps(new_rate); + return deviation_bps > MAX_DEVIATION_BPS; + } + + /// 计算汇率偏离基点数 + @view + pub fn calc_deviation_bps(new_rate: uint64) -> uint64 { + if self.latest_rate.rate_sdr == 0 { + return 0; + } + let diff = if new_rate > self.latest_rate.rate_sdr { + new_rate - self.latest_rate.rate_sdr + } else { + self.latest_rate.rate_sdr - new_rate + }; + return diff * 10000 / self.latest_rate.rate_sdr; + } + + /// 激活新 AI 汇率模型(需先影子运行 30 天) + @system + pub fn activate_new_model( + model_hash: hash, + shadow_start_epoch: uint64, + cr: ConstitutionalReceipt + ) { + require(xtzh::verify_rate_receipt(cr), "无效的宪法收据"); + let rate = xtzh::get_rate(); + require( + rate.epoch >= shadow_start_epoch + MIN_SHADOW_RUN_EPOCHS, + "影子运行时间不足 30 天" + ); + // 激活新模型(NVM 系统处理) + } +} diff --git a/charter-std/xtzh/reserve.ch b/charter-std/xtzh/reserve.ch new file mode 100644 index 0000000..9a2818a --- /dev/null +++ b/charter-std/xtzh/reserve.ch @@ -0,0 +1,190 @@ +// Charter Standard Library - XTZH 黄金储备模块 +// Issue #61/#62: 黄金永续合约储备系统 +// 版本: 1.0 + +/// 交易所信息 +public struct ExchangeInfo { + name: string, + weight: uint64, // 权重,定点数 1e4(10000 = 100%) + max_exposure: uint64, // 最大敞口,定点数 1e4 + is_active: bool +} + +/// 储备状态快照 +public struct ReserveSnapshot { + timestamp: uint64, + total_notional: uint64, // 合约名义总价值(XTZH 单位) + xtzh_supply: uint64, // XTZH 流通量 + coverage_ratio: uint64, // 覆盖率,定点数 1e4(12500 = 125%) + gold_price_usd: uint64, // 黄金价格,定点数 1e2 + buffer_l1: uint64, // L1 缓冲池余额 + buffer_l2: uint64 // L2 缓冲池余额 +} + +/// 赎回队列条目 +public struct RedemptionEntry { + requester: address, + amount: uint64, + request_epoch: uint64, + max_wait_epoch: uint64 // 最长等待 30 天 = 30 纪元 +} + +/// 黄金储备法典核心合约 +/// 宪法级约束:铸造必须同步建立 125% 黄金合约储备 +contract XTZHGoldReserve { + // 宪法级常量(不可通过治理修改,仅宪法修正案可变更) + const MIN_COVERAGE_RATIO: uint64 = 12500; // 125.00% + const MAX_SINGLE_EXCHANGE: uint64 = 3000; // 30.00% + const REBALANCE_THRESHOLD: uint64 = 200; // 2.00% 偏离触发再平衡 + const EMERGENCY_THRESHOLD: uint64 = 11000; // 110.00% 触发紧急补仓 + const MAX_REDEMPTION_WAIT: uint64 = 30; // 最长等待 30 纪元(天) + const BUFFER_L1_TARGET: uint64 = 500; // L1 缓冲目标 5.00% + const BUFFER_L2_TARGET: uint64 = 1000; // L2 缓冲目标 10.00% + + // 状态变量 + state reserve: ReserveSnapshot; + state exchanges: [ExchangeInfo; 10]; + state exchange_count: uint64; + state is_frozen: bool; + state redemption_queue: [RedemptionEntry; 1000]; + state queue_head: uint64; + state queue_tail: uint64; + + /// 查询当前储备状态 + @view + pub fn get_reserve() -> ReserveSnapshot { + return self.reserve; + } + + /// 查询覆盖率是否满足宪法要求 + @view + pub fn is_compliant() -> bool { + return self.reserve.coverage_ratio >= MIN_COVERAGE_RATIO; + } + + /// 查询赎回队列长度 + @view + pub fn queue_length() -> uint64 { + return self.queue_tail - self.queue_head; + } + + /// 铸造 XTZH(必须同步建立 125% 黄金合约储备) + @payable + pub fn mint(amount: uint64, cr: ConstitutionalReceipt) { + require(xtzh::verify_rate_receipt(cr), "无效的宪法收据"); + require(!self.is_frozen, "储备系统已冻结"); + require(amount > 0, "铸造量必须大于 0"); + + // 获取当前汇率 + let rate = xtzh::get_rate(); + + // 验证储备充足(铸造后覆盖率仍需 >= 125%) + let new_supply = self.reserve.xtzh_supply + amount; + let required_notional = new_supply * MIN_COVERAGE_RATIO / 10000; + require( + self.reserve.total_notional >= required_notional, + "储备不足:黄金合约覆盖率低于 125%" + ); + + // 更新状态 + self.reserve.xtzh_supply = new_supply; + self.reserve.coverage_ratio = + self.reserve.total_notional * 10000 / new_supply; + self.reserve.timestamp = rate.timestamp; + + emit XTZHRateUpdated { + epoch: rate.epoch, + rate_sdr: rate.rate_sdr, + rate_usd: rate.rate_usd, + updater: msg.sender + }; + } + + /// 提交赎回请求(最长等待 30 天,每日公示队列) + pub fn request_redeem(amount: uint64, cr: ConstitutionalReceipt) { + require(xtzh::verify_rate_receipt(cr), "无效的宪法收据"); + require(!self.is_frozen, "储备系统已冻结"); + require(amount > 0, "赎回量必须大于 0"); + require(amount <= self.reserve.xtzh_supply, "赎回量超过流通量"); + + let rate = xtzh::get_rate(); + + // 加入赎回队列 + self.redemption_queue[self.queue_tail] = RedemptionEntry { + requester: msg.sender, + amount: amount, + request_epoch: rate.epoch, + max_wait_epoch: rate.epoch + MAX_REDEMPTION_WAIT + }; + self.queue_tail = self.queue_tail + 1; + } + + /// 执行赎回(系统自动调用,每纪元处理队列) + @system + pub fn process_redemptions(cr: ConstitutionalReceipt) { + require(xtzh::verify_rate_receipt(cr), "无效的宪法收据"); + let rate = xtzh::get_rate(); + + // 处理到期赎回请求 + while self.queue_head < self.queue_tail { + let entry = self.redemption_queue[self.queue_head]; + if entry.request_epoch + MAX_REDEMPTION_WAIT <= rate.epoch { + // 强制执行(超时不可拒绝) + self.reserve.xtzh_supply = self.reserve.xtzh_supply - entry.amount; + if self.reserve.xtzh_supply > 0 { + self.reserve.coverage_ratio = + self.reserve.total_notional * 10000 / self.reserve.xtzh_supply; + } + self.queue_head = self.queue_head + 1; + } else { + break; + } + } + } + + /// 触发再平衡(当单交易所敞口超过 30%) + @system + pub fn rebalance(cr: ConstitutionalReceipt) { + require(xtzh::verify_rate_receipt(cr), "无效的宪法收据"); + require(!self.is_frozen, "储备系统已冻结"); + // 再平衡逻辑由 NVM 系统调用执行 + // 检查每个交易所的敞口比例 + let i: uint64 = 0; + while i < self.exchange_count { + let exchange = self.exchanges[i]; + if exchange.is_active && exchange.weight > MAX_SINGLE_EXCHANGE { + // 触发再平衡信号(NVM 系统处理实际转移) + emit XTZHRateDeviation { + epoch: 0, + deviation_bps: exchange.weight - MAX_SINGLE_EXCHANGE, + direction: "exchange_overweight" + }; + } + i = i + 1; + } + } + + /// 紧急冻结(需宪法法院 7/9 签署) + @system + pub fn emergency_freeze(cr: ConstitutionalReceipt) { + require(xtzh::verify_rate_receipt(cr), "无效的宪法收据"); + self.is_frozen = true; + let _ = xtzh::emergency_freeze(cr); + } + + /// 缓冲池补充(当缓冲池低于目标 50% 时触发) + @system + pub fn replenish_buffer(cr: ConstitutionalReceipt) { + require(xtzh::verify_rate_receipt(cr), "无效的宪法收据"); + let target_l1 = self.reserve.xtzh_supply * BUFFER_L1_TARGET / 10000; + let target_l2 = self.reserve.xtzh_supply * BUFFER_L2_TARGET / 10000; + + // 当缓冲池低于目标 50% 时,将铸造费的 30% 注入 + if self.reserve.buffer_l1 < target_l1 / 2 { + // NVM 系统自动将铸造费 30% 注入 L1 缓冲 + } + if self.reserve.buffer_l2 < target_l2 / 2 { + // NVM 系统自动将铸造费 30% 注入 L2 缓冲 + } + } +} diff --git a/docs/constitutional_engine_coordination.md b/docs/constitutional_engine_coordination.md new file mode 100644 index 0000000..138a45b --- /dev/null +++ b/docs/constitutional_engine_coordination.md @@ -0,0 +1,133 @@ +# NAC公链核心组件关系解析:宪法引擎与CBPP、CNNL、CSNP的协同 +Issue #60 | 版本: 1.0 | 制定方: NAC架构委员会 | 发布日期: 2026年2月18日 + +## 一、核心组件定位 + +| 组件 | 全称 | 层级 | 核心职责 | +|------|------|------|---------| +| CNNL | Constitutional Neural Network Language | L2 宪法层 | 宪法条款的声明式编程语言,定义全网最高规则 | +| CEE | Constitutional Execution Engine(宪法引擎)| L2 宪法层 | 根据CNNL编译的宪法状态,验证交易合规性并签发宪法收据(CR)| +| CBPP | Constitutional Block Production Protocol | L1 协议层 | 基于宪法收据的区块生产共识协议 | +| CSNP | Constitutional Structured Network Protocol | L1 协议层 | 资产感知、法治化路由的网络协议 | + +## 二、核心关系图解 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 宪法层(L2) │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ CNNL │───▶│宪法状态文件│───▶│ CEE │ │ +│ │ 立法 │ │ (编译产物)│ │ 执法 │ │ +│ └──────────┘ └──────────┘ └─────┬────┘ │ +│ │签发宪法收据(CR) │ +└─────────────────────────────────────────┼─────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ 协议层(L1) │ +│ ┌──────────────────────┐ ┌──────────────────────────┐ │ +│ │ CBPP │ │ CSNP │ │ +│ │ 接收CR → 生产区块 │◀──▶│ 路由CR → 传播区块 │ │ +│ │ "节点产生即共识" │ │ 资产感知路由 │ │ +│ └──────────────────────┘ └──────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +## 三、数据流向 + +### 3.1 正向流(交易提交到上链) + +``` +用户交易 + → CSNP 路由(资产感知,找到正确节点) + → CEE 验证(对照 CNNL 编译的宪法状态) + → 签发 CR(宪法收据,含合规证明) + → CBPP 打包(携带 CR 的交易进入区块) + → CSNP 广播(区块通过法治化路由传播) + → 全网确认 +``` + +### 3.2 反向流(宪法更新) + +``` +CNNL 新条款提案 + → 治理投票(XIC 持有者) + → CNNL 编译器编译 + → 新宪法状态文件 + → CEE 热更新(无需停机) + → CBPP 自动适应新规则 + → CSNP 路由规则同步更新 +``` + +## 四、关键接口定义 + +### 4.1 CEE → CBPP 接口 + +```rust +// 宪法收据(CR)- CBPP 区块生产的必要条件 +pub struct ConstitutionalReceipt { + pub tx_hash: [u8; 48], // SHA3-384 + pub clause_ids: Vec, // 验证通过的宪法条款 ID + pub cee_signature: Vec, // CEE 签名 + pub epoch: u64, // 验证时的纪元 + pub is_valid: bool, +} + +// CBPP 区块必须包含所有交易的 CR +pub struct Block { + pub header: BlockHeader, + pub transactions: Vec, + pub receipts: Vec, // 一一对应 +} +``` + +### 4.2 CNNL → CEE 接口 + +```rust +// CNNL 编译产物 - 宪法状态文件 +pub struct ConstitutionalState { + pub version: u64, + pub clauses: Vec, + pub state_hash: [u8; 48], // 全部条款的 Merkle 根 + pub effective_epoch: u64, +} + +// CEE 加载宪法状态 +impl ConstitutionalEngine { + pub fn load_state(&mut self, state: ConstitutionalState) -> Result<(), CeeError>; + pub fn validate_tx(&self, tx: &Transaction) -> Result; +} +``` + +### 4.3 CSNP → CEE 接口 + +```rust +// CSNP 路由时携带资产信息,CEE 据此选择适用的宪法条款 +pub struct RoutingContext { + pub asset_class: AssetClass, // 资产类别(影响适用条款) + pub jurisdiction: JurisdictionId, // 辖区(影响合规规则) + pub sender_did: DID, + pub receiver_did: DID, +} +``` + +## 五、协同保障机制 + +| 机制 | 描述 | 涉及组件 | +|------|------|---------| +| 宪法收据链 | 每个区块包含所有交易的 CR,形成不可篡改的合规证明链 | CEE + CBPP | +| 热更新 | CNNL 条款更新后,CEE 无需停机即可加载新状态 | CNNL + CEE | +| 辖区感知路由 | CSNP 根据资产类别和辖区,将交易路由到正确的 CEE 实例 | CSNP + CEE | +| 共识即合规 | CBPP 的共识过程本身就是合规验证过程,无额外开销 | CBPP + CEE | +| 双宪法收据 | 跨辖区交易需要两个辖区的 CEE 都签发 CR | CEE + CSNP | + +## 六、与以太坊架构的本质区别 + +| 维度 | 以太坊 | NAC公链 | +|------|--------|---------| +| 合规性 | 事后链外合规 | 事前链上宪法验证 | +| 共识 | PoS(质押经济学)| CBPP(宪法收据驱动)| +| 网络 | P2P(无感知路由)| CSNP(资产感知路由)| +| 合约语言 | Solidity(图灵完备)| Charter(宪法约束)| +| 虚拟机 | EVM | NVM(宪法操作码)| +| 汇率 | 外部预言机 | XTZH 原生内置 | + diff --git a/nac-constitution/clauses/amendments.cnnl b/nac-constitution/clauses/amendments.cnnl new file mode 100644 index 0000000..57dee31 --- /dev/null +++ b/nac-constitution/clauses/amendments.cnnl @@ -0,0 +1,353 @@ +// NAC公链宪法增补条款 - CNNL 实现 +// Issue #66 | 版本: 1.0 | 共 43 条增补条款 +// 基于《NAC公链宪法增补条款详细论证报告(内部)》 + +program NacConstitutionalAmendments + name: "NAC公链宪法增补条款" + version: "1.0.0" + description: "43条宪法增补条款的CNNL形式化实现" + +// ============================================================ +// 第一章:基础架构条款(A01-A08) +// ============================================================ + +clause A01_NativeStack + name: "原生技术栈宪法保护" + description: "NAC公链技术栈不得引用以太坊衍生技术" + predicate: system.compiler_stack == "Charter+NVM+CBPP+CSNP+CNNL" + obligation: system.reject_evm_references per_block + test: A01_test_native_stack_enforced + +clause A02_CharterLanguage + name: "Charter为唯一合约语言" + description: "智能合约必须使用Charter语言,禁止Solidity" + predicate: contract.language == "Charter" + obligation: system.reject_non_charter_contracts per_block + test: A02_test_charter_only + +clause A03_NvmVirtualMachine + name: "NVM为唯一虚拟机" + description: "合约执行必须在NVM中进行,禁止EVM" + predicate: execution.vm == "NVM" + obligation: system.reject_evm_bytecode per_block + test: A03_test_nvm_only + +clause A04_CbppConsensus + name: "CBPP为唯一共识协议" + description: "区块生产必须遵循CBPP协议,禁止PoS/PoW" + predicate: consensus.protocol == "CBPP" + obligation: system.reject_non_cbpp_blocks per_block + test: A04_test_cbpp_only + +clause A05_CsnpNetwork + name: "CSNP为唯一网络协议" + description: "节点通信必须使用CSNP,禁止以太坊P2P" + predicate: network.protocol == "CSNP" + obligation: system.reject_non_csnp_peers per_block + test: A05_test_csnp_only + +clause A06_NacLensProtocol + name: "NAC_lens为唯一通信接口" + description: "所有外部通信必须通过NAC_lens,禁止RPC" + predicate: interface.protocol == "NAC_lens" + obligation: system.reject_rpc_calls per_block + test: A06_test_nac_lens_only + +clause A07_Acc20Standard + name: "ACC-20为唯一代币标准" + description: "代币合约必须遵循ACC-20标准,禁止ERC-20" + predicate: token.standard == "ACC-20" + obligation: system.reject_non_acc20_tokens per_block + test: A07_test_acc20_only + +clause A08_CnnlGovernance + name: "CNNL为宪法治理语言" + description: "宪法条款变更必须通过CNNL形式化表达" + predicate: governance.language == "CNNL" + obligation: system.require_cnnl_for_amendments per_epoch + test: A08_test_cnnl_governance + +// ============================================================ +// 第二章:资产合规条款(A09-A16) +// ============================================================ + +clause A09_GnacsClassification + name: "GNACS资产分类强制" + description: "所有资产必须有GNACS编码" + predicate: asset.gnacs_code != "" + obligation: asset.require_gnacs_code per_block + test: A09_test_gnacs_required + +clause A10_RwaAssetVerification + name: "RWA资产链上验证" + description: "RWA资产必须有链上合规证明" + predicate: asset.is_rwa implies asset.has_compliance_proof + obligation: asset.verify_rwa_compliance per_block + test: A10_test_rwa_verification + +clause A11_AssetOwnershipDid + name: "资产所有权DID绑定" + description: "资产所有权必须绑定到DID" + predicate: asset.owner_did != "" + obligation: asset.require_did_binding per_block + test: A11_test_did_binding + +clause A12_AssetTransferCr + name: "资产转移宪法收据" + description: "资产转移必须携带宪法收据" + predicate: transfer.has_constitutional_receipt == true + obligation: transfer.require_cr per_block + test: A12_test_transfer_cr + +clause A13_CrossBorderCompliance + name: "跨境资产合规" + description: "跨境资产转移必须满足双辖区合规" + predicate: transfer.is_cross_border implies transfer.has_dual_receipt + obligation: transfer.verify_dual_jurisdiction per_block + test: A13_test_cross_border + +clause A14_AssetValuation + name: "资产估值AI验证" + description: "RWA资产估值必须经过AI验证" + predicate: asset.is_rwa implies asset.valuation_verified + obligation: asset.require_ai_valuation per_epoch + test: A14_test_ai_valuation + +clause A15_AssetFreezing + name: "资产冻结宪法授权" + description: "资产冻结必须有宪法授权" + predicate: asset.is_frozen implies asset.freeze_authorized + obligation: asset.require_freeze_authorization per_block + test: A15_test_freeze_auth + +clause A16_AssetBurning + name: "资产销毁不可逆性" + description: "资产销毁操作不可逆,必须有双重确认" + predicate: burn.confirmed_twice == true + obligation: burn.require_double_confirmation per_block + test: A16_test_burn_irreversible + +// ============================================================ +// 第三章:治理条款(A17-A24) +// ============================================================ + +clause A17_XicVotingRight + name: "XIC持有者投票权" + description: "宪法修改需XIC持有者2/3多数同意" + predicate: amendment.xic_approval_ratio >= 6700 + obligation: governance.require_xic_supermajority per_epoch + test: A17_test_xic_voting + +clause A18_AmendmentProcess + name: "宪法修改程序" + description: "宪法修改必须经过提案、讨论、投票三阶段" + predicate: amendment.stage in ["proposal", "discussion", "voting", "enacted"] + obligation: governance.enforce_amendment_stages per_epoch + test: A18_test_amendment_stages + +clause A19_ConstitutionalCourt + name: "宪法法院仲裁权" + description: "争议必须提交宪法法院仲裁" + predicate: dispute.submitted_to_court == true + obligation: governance.route_disputes_to_court per_block + test: A19_test_court_arbitration + +clause A20_JudgeElection + name: "法官选举制度" + description: "宪法法官由XIC持有者选举,任期2年" + predicate: judge.elected_by_xic == true + obligation: governance.enforce_judge_election per_epoch + test: A20_test_judge_election + +clause A21_TransparencyRequirement + name: "治理透明度" + description: "所有治理决策必须链上公开" + predicate: governance.decision_on_chain == true + obligation: governance.publish_decisions per_block + test: A21_test_transparency + +clause A22_EmergencyPowers + name: "紧急权力限制" + description: "紧急权力行使不得超过30天,需2/3批准" + predicate: emergency.duration_days <= 30 + obligation: governance.limit_emergency_powers per_epoch + test: A22_test_emergency_limits + +clause A23_ConstitutionalReview + name: "宪法审查权" + description: "任何条款可被宪法法院审查" + predicate: review.court_has_jurisdiction == true + obligation: governance.enable_constitutional_review per_epoch + test: A23_test_review_power + +clause A24_AmendmentHistory + name: "修改历史不可篡改" + description: "宪法修改历史必须永久保存在链上" + predicate: amendment.history_immutable == true + obligation: governance.preserve_amendment_history per_block + test: A24_test_history_immutable + +// ============================================================ +// 第四章:XTZH货币条款(A25-A32) +// ============================================================ + +clause A25_XtzhGoldBacking + name: "XTZH黄金储备支撑" + description: "XTZH必须有至少40%黄金储备支撑" + predicate: xtzh.reserve_ratio >= 4000 + obligation: xtzh.maintain_gold_reserve per_epoch + test: A25_test_gold_backing + +clause A26_SdrPeg + name: "XTZH SDR锚定" + description: "XTZH价值锚定SDR货币篮子" + predicate: xtzh.peg_mechanism == "SDR" + obligation: xtzh.maintain_sdr_peg per_block + test: A26_test_sdr_peg + +clause A27_XtzhMintAuth + name: "XTZH铸造授权" + description: "XTZH铸造必须有宪法授权和黄金证明" + predicate: mint.has_cr == true + obligation: xtzh.require_mint_authorization per_block + test: A27_test_mint_auth + +clause A28_XtzhBurnProcess + name: "XTZH销毁赎回流程" + description: "XTZH销毁必须触发黄金赎回流程" + predicate: burn.triggers_gold_redemption == true + obligation: xtzh.enforce_burn_redemption per_block + test: A28_test_burn_redemption + +clause A29_XtzhAudit + name: "XTZH季度审计" + description: "XTZH储备必须每季度审计一次" + predicate: xtzh.last_audit_days <= 90 + obligation: xtzh.require_quarterly_audit per_epoch + test: A29_test_quarterly_audit + +clause A30_XtzhCustodian + name: "黄金保管机构多元化" + description: "黄金必须由3-7家独立机构保管" + predicate: xtzh.custodian_count >= 3 + obligation: xtzh.enforce_custodian_diversity per_epoch + test: A30_test_custodian_count + +clause A31_XtzhEmergency + name: "XTZH紧急冻结" + description: "储备率低于30%时自动触发紧急冻结" + predicate: xtzh.reserve_ratio >= 3000 + obligation: xtzh.auto_freeze_on_crisis per_block + test: A31_test_emergency_freeze + +clause A32_XtzhTransparency + name: "XTZH储备透明度" + description: "XTZH储备信息实时链上公开" + predicate: xtzh.reserve_public == true + obligation: xtzh.publish_reserve_data per_block + test: A32_test_reserve_transparency + +// ============================================================ +// 第五章:多辖区条款(A33-A38) +// ============================================================ + +clause A33_JurisdictionIsolation + name: "辖区规则隔离" + description: "不同辖区规则必须严格隔离" + predicate: jurisdiction.rules_isolated == true + obligation: system.enforce_jurisdiction_isolation per_block + test: A33_test_isolation + +clause A34_CrossJurisdictionDualReceipt + name: "跨辖区双收据" + description: "跨辖区交易必须有双宪法收据" + predicate: cross_tx.has_dual_receipt == true + obligation: cross_tx.require_dual_receipt per_block + test: A34_test_dual_receipt + +clause A35_JurisdictionDynamicJoin + name: "辖区动态加入" + description: "新辖区可动态加入无需重构基础设施" + predicate: jurisdiction.supports_dynamic_join == true + obligation: system.enable_dynamic_jurisdiction per_epoch + test: A35_test_dynamic_join + +clause A36_ResourceFairShare + name: "资源公平分配" + description: "共享资源按辖区配额公平分配" + predicate: resource.allocation_fair == true + obligation: system.enforce_fair_resource_allocation per_block + test: A36_test_fair_share + +clause A37_JurisdictionCouncil + name: "辖区协商委员会" + description: "辖区间争议由协商委员会解决" + predicate: dispute.council_jurisdiction == true + obligation: governance.route_to_council per_epoch + test: A37_test_council + +clause A38_PluginHashVerification + name: "规则插件哈希验证" + description: "辖区规则插件必须通过哈希验证" + predicate: plugin.hash_verified == true + obligation: system.verify_plugin_hash per_block + test: A38_test_plugin_hash + +// ============================================================ +// 第六章:AI合规条款(A39-A43) +// ============================================================ + +clause A39_AiComplianceCheck + name: "AI合规检查强制" + description: "高价值交易必须经过AI合规检查" + predicate: tx.ai_compliance_checked == true + obligation: system.require_ai_compliance per_block + test: A39_test_ai_compliance + +clause A40_AiValuationAccuracy + name: "AI估值准确性" + description: "AI估值误差不得超过5%" + predicate: ai_valuation.error_rate <= 500 + obligation: system.validate_ai_accuracy per_epoch + test: A40_test_ai_accuracy + +clause A41_AiAuditTrail + name: "AI决策审计追踪" + description: "AI决策必须有完整审计追踪" + predicate: ai_decision.audit_trail_complete == true + obligation: system.maintain_ai_audit_trail per_block + test: A41_test_ai_audit + +clause A42_AiModelUpdate + name: "AI模型更新治理" + description: "AI模型更新必须经过治理投票" + predicate: ai_model.update_approved == true + obligation: governance.require_ai_model_vote per_epoch + test: A42_test_model_governance + +clause A43_AiHumanOversight + name: "AI人工监督" + description: "AI决策必须有人工监督机制" + predicate: ai_system.human_oversight_enabled == true + obligation: system.enforce_human_oversight per_epoch + test: A43_test_human_oversight + +// ============================================================ +// 测试块 +// ============================================================ + +test A01_test_native_stack_enforced { + assert system.compiler_stack == "Charter+NVM+CBPP+CSNP+CNNL" +} + +test A06_test_nac_lens_only { + assert interface.protocol == "NAC_lens" +} + +test A25_test_gold_backing { + assert xtzh.reserve_ratio >= 4000 +} + +test A34_test_dual_receipt { + assert cross_tx.has_dual_receipt == true +} diff --git a/nac-daemon/Cargo.lock b/nac-daemon/Cargo.lock new file mode 100644 index 0000000..1071155 --- /dev/null +++ b/nac-daemon/Cargo.lock @@ -0,0 +1,2820 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "actix-codec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" +dependencies = [ + "bitflags 2.11.0", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-http" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f860ee6746d0c5b682147b2f7f8ef036d4f92fe518251a3a35ffa3650eafdf0e" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "base64 0.22.1", + "bitflags 2.11.0", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "foldhash", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "actix-router" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f8c75c51892f18d9c46150c5ac7beb81c95f78c8b83a634d49f4ca32551fe7" +dependencies = [ + "bytestring", + "cfg-if", + "http", + "regex", + "regex-lite", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92589714878ca59a7626ea19734f0e07a6a875197eec751bb5d3f99e64998c63" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2 0.5.10", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff87453bc3b56e9b2b23c1cc0b1be8797184accf51d2abe0f8a33ec275d316bf" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "foldhash", + "futures-core", + "futures-util", + "impl-more", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "regex-lite", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2 0.6.2", + "time", + "tracing", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "bytestring" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" +dependencies = [ + "bytes", +] + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clap" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-more" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags 2.11.0", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "local-channel" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nac-daemon" +version = "1.0.0" +dependencies = [ + "actix-web", + "anyhow", + "chrono", + "clap", + "dirs", + "hex", + "reqwest", + "serde", + "serde_json", + "sha3", + "thiserror", + "tokio", + "tokio-test", + "toml", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-lite" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.11.0", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +dependencies = [ + "fastrand", + "getrandom 0.4.1", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-test" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6d24790a10a7af737693a3e8f1d03faef7e6ca0cc99aae5066f533766de545" +dependencies = [ + "futures-core", + "tokio", + "tokio-stream", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/nac-daemon/Cargo.toml b/nac-daemon/Cargo.toml new file mode 100644 index 0000000..958c3f8 --- /dev/null +++ b/nac-daemon/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "nac-daemon" +version = "1.0.0" +edition = "2021" +authors = ["NAC公链开发小组"] +description = "NAC公链本地守护进程 - 开发者终端集成 - Issue #67" + +[[bin]] +name = "nacd" +path = "src/main.rs" + +[[bin]] +name = "nac" +path = "src/cli.rs" + +[dependencies] +tokio = { version = "1.0", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +clap = { version = "4.0", features = ["derive"] } +actix-web = "4.0" +reqwest = { version = "0.11", features = ["json"] } +anyhow = "1.0" +thiserror = "1.0" +tracing = "0.1" +tracing-subscriber = "0.3" +chrono = { version = "0.4", features = ["serde"] } +dirs = "5.0" +toml = "0.8" +hex = "0.4" +sha3 = "0.10" + +[dev-dependencies] +tokio-test = "0.4" diff --git a/nac-daemon/src/cli.rs b/nac-daemon/src/cli.rs new file mode 100644 index 0000000..30eb76c --- /dev/null +++ b/nac-daemon/src/cli.rs @@ -0,0 +1,253 @@ +// nac-daemon/src/cli.rs +// NAC 命令行工具 (nac) +// Issue #67: 开发者终端集成 + +use clap::{Parser, Subcommand}; +use serde_json::Value; + +const DAEMON_URL: &str = "http://127.0.0.1:8766"; + +#[derive(Parser)] +#[command( + name = "nac", + version = "1.0.0", + about = "NAC公链命令行工具", + long_about = "NAC公链开发者命令行工具\n技术栈: Charter | NVM | CBPP | CSNP | NAC_lens | CNNL" +)] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// 查看节点状态 + Status, + /// 查看节点详细信息 + Info, + /// 钱包操作 + Wallet { + #[command(subcommand)] + action: WalletCommands, + }, + /// 合约操作 + Contract { + #[command(subcommand)] + action: ContractCommands, + }, + /// 网络操作 + Network { + #[command(subcommand)] + action: NetworkCommands, + }, + /// 宪法查询 + Constitution { + #[command(subcommand)] + action: ConstitutionCommands, + }, + /// 启动守护进程 + Daemon { + #[arg(short, long, default_value = "127.0.0.1:8766")] + listen: String, + #[arg(short, long)] + dev: bool, + }, +} + +#[derive(Subcommand)] +enum WalletCommands { + /// 查询余额 + Balance { + /// NAC 地址(32字节,十六进制) + address: String, + }, +} + +#[derive(Subcommand)] +enum ContractCommands { + /// 编译 Charter 合约 + Compile { + /// Charter 合约文件路径 + file: String, + }, + /// 验证 Charter 合约语法 + Validate { + /// Charter 合约文件路径 + file: String, + }, + /// 检查代码中的以太坊化问题 + Lint { + /// 源代码文件路径 + file: String, + }, +} + +#[derive(Subcommand)] +enum NetworkCommands { + /// 查看连接的节点 + Peers, +} + +#[derive(Subcommand)] +enum ConstitutionCommands { + /// 查看宪法条款摘要 + List, +} + +// ============================================================ +// 辅助函数 +// ============================================================ + +async fn api_get(path: &str) -> anyhow::Result { + let url = format!("{}{}", DAEMON_URL, path); + let resp = reqwest::get(&url).await?; + let data: Value = resp.json().await?; + Ok(data) +} + +async fn api_post(path: &str, body: Value) -> anyhow::Result { + let url = format!("{}{}", DAEMON_URL, path); + let client = reqwest::Client::new(); + let resp = client.post(&url).json(&body).send().await?; + let data: Value = resp.json().await?; + Ok(data) +} + +fn print_json(v: &Value) { + println!("{}", serde_json::to_string_pretty(v).unwrap_or_default()); +} + +// ============================================================ +// 主函数 +// ============================================================ + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let cli = Cli::parse(); + + match cli.command { + Commands::Status => { + match api_get("/api/v1/status").await { + Ok(data) => { + if let Some(d) = data.get("data") { + println!("=== NAC 节点状态 ==="); + println!("链: {}", d["chain"].as_str().unwrap_or("NAC")); + println!("网络: {}", d["network"].as_str().unwrap_or("unknown")); + println!("区块高度: {}", d["block_height"]); + println!("连接节点: {}", d["connected_peers"]); + println!("同步中: {}", d["syncing"]); + println!("CBPP纪元: {}", d["cbpp_epoch"]); + println!("运行时间: {}秒", d["uptime_seconds"]); + println!("NAC_lens: {}", d["nac_lens_endpoint"].as_str().unwrap_or("")); + } + } + Err(e) => eprintln!("错误: 无法连接到 nacd 守护进程 ({})\n请先运行: nacd", e), + } + } + + Commands::Info => { + match api_get("/api/v1/node/info").await { + Ok(data) => print_json(&data), + Err(e) => eprintln!("错误: {}", e), + } + } + + Commands::Wallet { action } => match action { + WalletCommands::Balance { address } => { + match api_get(&format!("/api/v1/wallet/balance/{}", address)).await { + Ok(data) => { + if let Some(d) = data.get("data") { + println!("=== 余额查询 ==="); + println!("地址: {}", address); + println!("XTZH: {}", d["xtzh_balance"].as_str().unwrap_or("0")); + println!("XIC: {}", d["xic_balance"].as_str().unwrap_or("0")); + println!("NAC: {}", d["nac_balance"].as_str().unwrap_or("0")); + } + } + Err(e) => eprintln!("错误: {}", e), + } + } + }, + + Commands::Contract { action } => match action { + ContractCommands::Compile { file } => { + let source = std::fs::read_to_string(&file) + .map_err(|e| anyhow::anyhow!("无法读取文件 {}: {}", file, e))?; + println!("正在编译 {}...", file); + match api_post("/api/v1/contract/compile", serde_json::json!({ "source": source })).await { + Ok(data) => print_json(&data), + Err(e) => eprintln!("编译错误: {}", e), + } + } + ContractCommands::Validate { file } => { + let source = std::fs::read_to_string(&file) + .map_err(|e| anyhow::anyhow!("无法读取文件 {}: {}", file, e))?; + println!("正在验证 {}...", file); + match api_post("/api/v1/contract/validate", serde_json::json!({ "source": source })).await { + Ok(data) => print_json(&data), + Err(e) => eprintln!("验证错误: {}", e), + } + } + ContractCommands::Lint { file } => { + let source = std::fs::read_to_string(&file) + .map_err(|e| anyhow::anyhow!("无法读取文件 {}: {}", file, e))?; + // 本地 lint 检查(不需要守护进程) + let forbidden = [ + ("RPC", "NAC_lens"), + ("EVM", "NVM"), + ("Solidity", "Charter"), + ("ERC20", "ACC-20"), + ("ERC-20", "ACC-20"), + ("ETH", "NAC"), + ("Gwei", "XTZH"), + ("Wei", "XTZH"), + ]; + let mut found = false; + for (bad, good) in &forbidden { + if source.contains(bad) { + println!("⚠️ 发现以太坊化关键字: '{}' → 应使用 '{}'", bad, good); + found = true; + } + } + if !found { + println!("✅ {} 通过去以太坊化检查", file); + } + } + }, + + Commands::Network { action } => match action { + NetworkCommands::Peers => { + match api_get("/api/v1/network/peers").await { + Ok(data) => print_json(&data), + Err(e) => eprintln!("错误: {}", e), + } + } + }, + + Commands::Constitution { action } => match action { + ConstitutionCommands::List => { + match api_get("/api/v1/constitution/clauses").await { + Ok(data) => { + if let Some(d) = data.get("data") { + println!("=== NAC公链宪法 ==="); + println!("版本: {}", d["version"].as_str().unwrap_or("")); + println!("条款数量: {}", d["clause_count"]); + println!("最后更新: 纪元 {}", d["last_updated_epoch"]); + println!("状态哈希: {}", d["state_hash"].as_str().unwrap_or("")); + } + } + Err(e) => eprintln!("错误: {}", e), + } + } + }, + + Commands::Daemon { listen, dev } => { + println!("正在启动 NAC 守护进程..."); + println!("监听地址: {}", listen); + if dev { println!("模式: 开发模式"); } + println!("提示: 请直接运行 nacd 启动守护进程"); + } + } + + Ok(()) +} diff --git a/nac-daemon/src/config.rs b/nac-daemon/src/config.rs new file mode 100644 index 0000000..c9e34a9 --- /dev/null +++ b/nac-daemon/src/config.rs @@ -0,0 +1,78 @@ +// nac-daemon/src/config.rs +// 守护进程配置 + +use serde::{Serialize, Deserialize}; +use std::path::PathBuf; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DaemonConfig { + /// 守护进程监听地址(默认 127.0.0.1:8766) + pub listen_addr: String, + /// NAC_lens 端点(本地节点的 NAC_lens 服务) + pub nac_lens_endpoint: String, + /// CNNL 编译服务端点 + pub cnnl_service_endpoint: String, + /// CSNP 监听地址 + pub csnp_listen_addr: String, + /// 节点类型(full/light/validator) + pub node_type: String, + /// 网络名称(mainnet/testnet/devnet) + pub network: String, + /// 是否开发模式(允许无 NAC_lens 连接时返回模拟数据) + pub dev_mode: bool, + /// 数据目录 + pub data_dir: PathBuf, + /// 日志级别 + pub log_level: String, +} + +impl Default for DaemonConfig { + fn default() -> Self { + DaemonConfig { + listen_addr: "127.0.0.1:8766".to_string(), + nac_lens_endpoint: "http://127.0.0.1:9000".to_string(), + cnnl_service_endpoint: "https://cnnl.newassetchain.io".to_string(), + csnp_listen_addr: "0.0.0.0:9001".to_string(), + node_type: "full".to_string(), + network: "testnet".to_string(), + dev_mode: true, + data_dir: dirs::home_dir() + .unwrap_or_else(|| PathBuf::from("/tmp")) + .join(".nac"), + log_level: "info".to_string(), + } + } +} + +impl DaemonConfig { + /// 从配置文件加载(~/.nac/daemon.toml) + pub fn load() -> anyhow::Result { + let config_path = dirs::home_dir() + .unwrap_or_else(|| PathBuf::from("/tmp")) + .join(".nac") + .join("daemon.toml"); + + if config_path.exists() { + let content = std::fs::read_to_string(&config_path)?; + let config: DaemonConfig = toml::from_str(&content)?; + Ok(config) + } else { + // 创建默认配置 + let config = DaemonConfig::default(); + if let Some(parent) = config_path.parent() { + std::fs::create_dir_all(parent)?; + } + let content = toml::to_string_pretty(&config)?; + std::fs::write(&config_path, content)?; + Ok(config) + } + } + + /// 保存配置 + pub fn save(&self) -> anyhow::Result<()> { + let config_path = self.data_dir.join("daemon.toml"); + let content = toml::to_string_pretty(self)?; + std::fs::write(config_path, content)?; + Ok(()) + } +} diff --git a/nac-daemon/src/contract.rs b/nac-daemon/src/contract.rs new file mode 100644 index 0000000..3cca366 --- /dev/null +++ b/nac-daemon/src/contract.rs @@ -0,0 +1,2 @@ +// nac-daemon/src/contract.rs +// 模块占位 - 后续实现 diff --git a/nac-daemon/src/main.rs b/nac-daemon/src/main.rs new file mode 100644 index 0000000..3670a78 --- /dev/null +++ b/nac-daemon/src/main.rs @@ -0,0 +1,273 @@ +// nac-daemon/src/main.rs +// Issue #67: NAC公链本地守护进程 (nacd) +// 提供本地 HTTP API,供开发者网站和 CLI 工具调用 + +use actix_web::{web, App, HttpServer, HttpResponse}; +use serde::Serialize; +use std::sync::Arc; +use tokio::sync::RwLock; +use tracing::info; + +mod config; +mod node_status; +mod wallet; +mod contract; +mod network; + +use config::DaemonConfig; +use node_status::NodeStatus; + +/// 守护进程全局状态 +pub struct DaemonState { + pub config: DaemonConfig, + pub node_status: NodeStatus, + pub start_time: u64, +} + +impl DaemonState { + pub fn new(config: DaemonConfig) -> Self { + DaemonState { + config, + node_status: NodeStatus::default(), + start_time: chrono::Utc::now().timestamp() as u64, + } + } +} + +type SharedState = Arc>; + +/// API 响应包装 +#[derive(Serialize)] +pub struct ApiResponse { + pub success: bool, + pub data: Option, + pub error: Option, + pub timestamp: u64, +} + +impl ApiResponse { + pub fn ok(data: T) -> Self { + ApiResponse { + success: true, + data: Some(data), + error: None, + timestamp: chrono::Utc::now().timestamp() as u64, + } + } + + pub fn err(msg: &str) -> ApiResponse<()> { + ApiResponse { + success: false, + data: None, + error: Some(msg.to_string()), + timestamp: chrono::Utc::now().timestamp() as u64, + } + } +} + +// ============================================================ +// API 端点 +// ============================================================ + +/// GET /api/v1/status - 节点状态 +async fn get_status(state: web::Data) -> HttpResponse { + let state = state.read().await; + let status = &state.node_status; + HttpResponse::Ok().json(ApiResponse::ok(serde_json::json!({ + "version": env!("CARGO_PKG_VERSION"), + "chain": "NAC", + "network": status.network_name, + "block_height": status.block_height, + "connected_peers": status.connected_peers, + "syncing": status.is_syncing, + "uptime_seconds": chrono::Utc::now().timestamp() as u64 - state.start_time, + "nac_lens_endpoint": state.config.nac_lens_endpoint, + "cbpp_epoch": status.current_epoch, + }))) +} + +/// GET /api/v1/node/info - 节点详细信息 +async fn get_node_info(state: web::Data) -> HttpResponse { + let state = state.read().await; + HttpResponse::Ok().json(ApiResponse::ok(serde_json::json!({ + "node_id": state.node_status.node_id, + "node_type": state.config.node_type, + "cbpp_role": state.node_status.cbpp_role, + "csnp_address": state.config.csnp_listen_addr, + "nac_lens_version": "4.0", + "nvm_version": "1.0", + "charter_version": "1.0", + "cnnl_version": "1.0", + "jurisdictions": state.node_status.active_jurisdictions, + }))) +} + +/// GET /api/v1/wallet/balance/:address - 查询余额 +async fn get_balance( + path: web::Path, + state: web::Data, +) -> HttpResponse { + let address = path.into_inner(); + let state = state.read().await; + + // 通过 NAC_lens 查询余额 + let endpoint = format!("{}/balance/{}", state.config.nac_lens_endpoint, address); + match reqwest::get(&endpoint).await { + Ok(resp) => { + match resp.json::().await { + Ok(data) => HttpResponse::Ok().json(ApiResponse::ok(data)), + Err(e) => HttpResponse::InternalServerError() + .json(ApiResponse::<()>::err(&e.to_string())), + } + } + Err(_) => { + // NAC_lens 不可用时返回模拟数据(开发模式) + if state.config.dev_mode { + HttpResponse::Ok().json(ApiResponse::ok(serde_json::json!({ + "address": address, + "xtzh_balance": "0", + "xic_balance": "0", + "nac_balance": "0", + "note": "dev_mode: NAC_lens not connected" + }))) + } else { + HttpResponse::ServiceUnavailable() + .json(ApiResponse::<()>::err("NAC_lens endpoint unreachable")) + } + } + } +} + +/// POST /api/v1/contract/compile - 编译 Charter 合约 +async fn compile_contract( + body: web::Json, + state: web::Data, +) -> HttpResponse { + let state = state.read().await; + let source = match body.get("source").and_then(|s| s.as_str()) { + Some(s) => s.to_string(), + None => return HttpResponse::BadRequest() + .json(ApiResponse::<()>::err("缺少 source 字段")), + }; + + // 调用 CNNL 编译服务 + let cnnl_endpoint = format!("{}/api/v1/compile", state.config.cnnl_service_endpoint); + let client = reqwest::Client::new(); + match client.post(&cnnl_endpoint) + .json(&serde_json::json!({ "source": source })) + .send() + .await + { + Ok(resp) => { + match resp.json::().await { + Ok(data) => HttpResponse::Ok().json(ApiResponse::ok(data)), + Err(e) => HttpResponse::InternalServerError() + .json(ApiResponse::<()>::err(&e.to_string())), + } + } + Err(_) => HttpResponse::ServiceUnavailable() + .json(ApiResponse::<()>::err("CNNL 编译服务不可用")), + } +} + +/// POST /api/v1/contract/validate - 验证 Charter 合约语法 +async fn validate_contract( + body: web::Json, + state: web::Data, +) -> HttpResponse { + let state = state.read().await; + let source = match body.get("source").and_then(|s| s.as_str()) { + Some(s) => s.to_string(), + None => return HttpResponse::BadRequest() + .json(ApiResponse::<()>::err("缺少 source 字段")), + }; + + let cnnl_endpoint = format!("{}/api/v1/validate", state.config.cnnl_service_endpoint); + let client = reqwest::Client::new(); + match client.post(&cnnl_endpoint) + .json(&serde_json::json!({ "source": source })) + .send() + .await + { + Ok(resp) => { + match resp.json::().await { + Ok(data) => HttpResponse::Ok().json(ApiResponse::ok(data)), + Err(e) => HttpResponse::InternalServerError() + .json(ApiResponse::<()>::err(&e.to_string())), + } + } + Err(_) => HttpResponse::ServiceUnavailable() + .json(ApiResponse::<()>::err("CNNL 验证服务不可用")), + } +} + +/// GET /api/v1/network/peers - 获取连接的节点列表 +async fn get_peers(state: web::Data) -> HttpResponse { + let state = state.read().await; + HttpResponse::Ok().json(ApiResponse::ok(serde_json::json!({ + "peers": state.node_status.peers, + "total": state.node_status.connected_peers, + }))) +} + +/// GET /api/v1/constitution/clauses - 获取当前宪法条款 +async fn get_constitution(state: web::Data) -> HttpResponse { + let state = state.read().await; + HttpResponse::Ok().json(ApiResponse::ok(serde_json::json!({ + "version": state.node_status.constitution_version, + "clause_count": 43, + "last_updated_epoch": state.node_status.current_epoch, + "state_hash": state.node_status.constitution_hash, + }))) +} + +/// GET /api/v1/health - 健康检查 +async fn health_check() -> HttpResponse { + HttpResponse::Ok().json(serde_json::json!({ + "status": "ok", + "service": "nac-daemon", + "version": env!("CARGO_PKG_VERSION"), + })) +} + +// ============================================================ +// 主函数 +// ============================================================ + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt::init(); + + // 加载配置 + let config = DaemonConfig::load()?; + let listen_addr = config.listen_addr.clone(); + let state = Arc::new(RwLock::new(DaemonState::new(config))); + + info!("NAC 守护进程启动中..."); + info!("监听地址: {}", listen_addr); + info!("NAC_lens 端点: {}", state.read().await.config.nac_lens_endpoint); + + HttpServer::new(move || { + App::new() + .app_data(web::Data::new(state.clone())) + // 状态和节点信息 + .route("/api/v1/status", web::get().to(get_status)) + .route("/api/v1/node/info", web::get().to(get_node_info)) + // 钱包 + .route("/api/v1/wallet/balance/{address}", web::get().to(get_balance)) + // 合约 + .route("/api/v1/contract/compile", web::post().to(compile_contract)) + .route("/api/v1/contract/validate", web::post().to(validate_contract)) + // 网络 + .route("/api/v1/network/peers", web::get().to(get_peers)) + // 宪法 + .route("/api/v1/constitution/clauses", web::get().to(get_constitution)) + // 健康检查 + .route("/api/v1/health", web::get().to(health_check)) + }) + .bind(&listen_addr)? + .run() + .await?; + + Ok(()) +} diff --git a/nac-daemon/src/network.rs b/nac-daemon/src/network.rs new file mode 100644 index 0000000..c891096 --- /dev/null +++ b/nac-daemon/src/network.rs @@ -0,0 +1,2 @@ +// nac-daemon/src/network.rs +// 模块占位 - 后续实现 diff --git a/nac-daemon/src/node_status.rs b/nac-daemon/src/node_status.rs new file mode 100644 index 0000000..75d06b3 --- /dev/null +++ b/nac-daemon/src/node_status.rs @@ -0,0 +1,46 @@ +// nac-daemon/src/node_status.rs +// 节点状态结构 + +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PeerInfo { + pub peer_id: String, + pub address: String, + pub jurisdiction: String, + pub latency_ms: u64, + pub connected_since: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NodeStatus { + pub node_id: String, + pub network_name: String, + pub block_height: u64, + pub connected_peers: u32, + pub is_syncing: bool, + pub current_epoch: u64, + pub cbpp_role: String, + pub active_jurisdictions: Vec, + pub peers: Vec, + pub constitution_version: String, + pub constitution_hash: String, +} + +impl Default for NodeStatus { + fn default() -> Self { + NodeStatus { + node_id: format!("nac-node-{}", hex::encode(&[0u8; 8])), + network_name: "testnet".to_string(), + block_height: 0, + connected_peers: 0, + is_syncing: false, + current_epoch: 0, + cbpp_role: "observer".to_string(), + active_jurisdictions: vec!["default".to_string()], + peers: vec![], + constitution_version: "1.0.0".to_string(), + constitution_hash: "000000000000000000000000000000000000000000000000".to_string(), + } + } +} diff --git a/nac-daemon/src/wallet.rs b/nac-daemon/src/wallet.rs new file mode 100644 index 0000000..4117df2 --- /dev/null +++ b/nac-daemon/src/wallet.rs @@ -0,0 +1,2 @@ +// nac-daemon/src/wallet.rs +// 模块占位 - 后续实现 diff --git a/nac-multi-jurisdiction/Cargo.lock b/nac-multi-jurisdiction/Cargo.lock new file mode 100644 index 0000000..c444103 --- /dev/null +++ b/nac-multi-jurisdiction/Cargo.lock @@ -0,0 +1,734 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nac-multi-jurisdiction" +version = "1.0.0" +dependencies = [ + "anyhow", + "chrono", + "hex", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "tokio", + "tokio-test", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-test" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6d24790a10a7af737693a3e8f1d03faef7e6ca0cc99aae5066f533766de545" +dependencies = [ + "futures-core", + "tokio", + "tokio-stream", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/nac-multi-jurisdiction/Cargo.toml b/nac-multi-jurisdiction/Cargo.toml new file mode 100644 index 0000000..ccd4f37 --- /dev/null +++ b/nac-multi-jurisdiction/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "nac-multi-jurisdiction" +version = "1.0.0" +edition = "2021" +authors = ["NAC公链开发小组 · 多司法辖区工作组"] +description = "NAC公链多辖区节点共享方案 - Issue #59" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +sha3 = "0.10" +sha2 = "0.10" +hex = "0.4" +chrono = { version = "0.4", features = ["serde"] } +anyhow = "1.0" +thiserror = "1.0" +tokio = { version = "1.0", features = ["full"] } + +[dev-dependencies] +tokio-test = "0.4" diff --git a/nac-multi-jurisdiction/src/cross_jurisdiction.rs b/nac-multi-jurisdiction/src/cross_jurisdiction.rs new file mode 100644 index 0000000..c436660 --- /dev/null +++ b/nac-multi-jurisdiction/src/cross_jurisdiction.rs @@ -0,0 +1,159 @@ +// nac-multi-jurisdiction/src/cross_jurisdiction.rs +// Issue #59: 跨辖区交易处理与双宪法收据 + +use serde::{Serialize, Deserialize}; +use crate::jurisdiction::JurisdictionId; + +/// 双宪法收据(跨辖区交易必须携带) +/// 发起辖区 + 接收辖区都必须签署 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DualConstitutionalReceipt { + /// 交易唯一标识(SHA3-384) + pub tx_id: Vec, + /// 发起辖区 ID + pub source_jurisdiction: JurisdictionId, + /// 接收辖区 ID + pub target_jurisdiction: JurisdictionId, + /// 发起辖区宪法收据(原始字节) + pub source_receipt: Vec, + /// 接收辖区宪法收据(原始字节) + pub target_receipt: Vec, + /// 时间戳(Unix 秒) + pub timestamp: u64, + /// 纪元编号 + pub epoch: u64, + /// 是否已最终确认 + pub is_finalized: bool, +} + +impl DualConstitutionalReceipt { + /// 验证双收据完整性 + pub fn is_valid(&self) -> bool { + !self.source_receipt.is_empty() + && !self.target_receipt.is_empty() + && self.source_jurisdiction != self.target_jurisdiction + && self.tx_id != vec![0u8; 48] + } + + /// 检查是否包含指定辖区的收据 + pub fn has_receipt_for(&self, jid: &JurisdictionId) -> bool { + &self.source_jurisdiction == jid || &self.target_jurisdiction == jid + } +} + +/// 跨辖区交易 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CrossJurisdictionTx { + /// 交易 ID + pub id: Vec, + /// 发起辖区 + pub source_jurisdiction: JurisdictionId, + /// 接收辖区 + pub target_jurisdiction: JurisdictionId, + /// 交易数据 + pub payload: Vec, + /// 双宪法收据(可选,处理中为 None) + pub dual_receipt: Option, + /// 交易状态 + pub status: CrossTxStatus, + /// 冲突解决策略 + pub conflict_resolution: ConflictResolutionStrategy, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum CrossTxStatus { + /// 待处理(等待接收辖区收据) + Pending, + /// 源辖区已确认 + SourceConfirmed, + /// 双方已确认 + DualConfirmed, + /// 最终确认 + Finalized, + /// 失败(附带原因) + Failed(String), + /// 冲突(需要解决) + Conflicted, +} + +/// 规则冲突解决策略 +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum ConflictResolutionStrategy { + /// 严格模式:任何冲突都拒绝交易 + StrictReject, + /// 源辖区优先:以发起辖区规则为准 + SourcePriority, + /// 目标辖区优先:以接收辖区规则为准 + TargetPriority, + /// 协商模式:双方辖区协商解决 + Negotiated, + /// 宪法仲裁:提交宪法法院仲裁 + ConstitutionalArbitration, +} + +/// 跨辖区路由器 +pub struct CrossJurisdictionRouter { + pending_txs: Vec, + /// 最大待处理交易数 + max_pending: usize, +} + +impl CrossJurisdictionRouter { + pub fn new() -> Self { + CrossJurisdictionRouter { + pending_txs: Vec::new(), + max_pending: 10000, + } + } + + /// 提交跨辖区交易 + pub fn submit(&mut self, tx: CrossJurisdictionTx) -> Result, String> { + if self.pending_txs.len() >= self.max_pending { + return Err("待处理交易队列已满".to_string()); + } + let id = tx.id.clone(); + self.pending_txs.push(tx); + Ok(id) + } + + /// 附加目标辖区收据(完成双收据) + pub fn attach_target_receipt( + &mut self, + tx_id: &Vec, + receipt: Vec, + ) -> Result<(), String> { + for tx in &mut self.pending_txs { + if &tx.id == tx_id { + if let Some(ref mut dr) = tx.dual_receipt { + dr.target_receipt = receipt; + dr.is_finalized = true; + tx.status = CrossTxStatus::DualConfirmed; + return Ok(()); + } + } + } + Err(format!("交易 {:?} 不存在", tx_id)) + } + + /// 检测规则冲突 + pub fn detect_conflict( + &self, + source_rules: &[u8], + target_rules: &[u8], + ) -> bool { + // 规则冲突检测:比较两个辖区的规则哈希 + // 实际实现由 NVM 系统调用处理 + source_rules.is_empty() || target_rules.is_empty() + } + + /// 获取待处理交易数量 + pub fn pending_count(&self) -> usize { + self.pending_txs.len() + } +} + +impl Default for CrossJurisdictionRouter { + fn default() -> Self { + Self::new() + } +} diff --git a/nac-multi-jurisdiction/src/discovery.rs b/nac-multi-jurisdiction/src/discovery.rs new file mode 100644 index 0000000..fceb047 --- /dev/null +++ b/nac-multi-jurisdiction/src/discovery.rs @@ -0,0 +1,63 @@ +// nac-multi-jurisdiction/src/discovery.rs +// Issue #59: 辖区感知节点发现 + +use crate::jurisdiction::JurisdictionId; + +/// 辖区感知节点发现 +pub struct NodeDiscovery { + known_nodes: Vec, +} + +#[derive(Debug, Clone)] +pub struct NodeInfo { + pub node_id: [u8; 32], + pub jurisdiction_id: JurisdictionId, + pub endpoint: String, + pub is_active: bool, +} + +impl NodeDiscovery { + pub fn new() -> Self { + NodeDiscovery { known_nodes: Vec::new() } + } + + /// 注册节点 + pub fn register_node(&mut self, info: NodeInfo) { + self.known_nodes.push(info); + } + + /// 查找指定辖区的节点 + pub fn find_by_jurisdiction(&self, jid: &JurisdictionId) -> Vec<&NodeInfo> { + self.known_nodes.iter() + .filter(|n| &n.jurisdiction_id == jid && n.is_active) + .collect() + } + + /// 获取所有活跃节点数量 + pub fn active_count(&self) -> usize { + self.known_nodes.iter().filter(|n| n.is_active).count() + } +} + +impl Default for NodeDiscovery { + fn default() -> Self { + Self::new() + } +} + +/// 辖区感知路由器 +pub struct JurisdictionAwareRouter { + discovery: NodeDiscovery, +} + +impl JurisdictionAwareRouter { + pub fn new(discovery: NodeDiscovery) -> Self { + JurisdictionAwareRouter { discovery } + } + + /// 路由到目标辖区 + pub fn route_to(&self, target_jid: &JurisdictionId) -> Option<&NodeInfo> { + self.discovery.find_by_jurisdiction(target_jid).into_iter().next() + } +} + diff --git a/nac-multi-jurisdiction/src/dual_receipt.rs b/nac-multi-jurisdiction/src/dual_receipt.rs new file mode 100644 index 0000000..d1f85bc --- /dev/null +++ b/nac-multi-jurisdiction/src/dual_receipt.rs @@ -0,0 +1,59 @@ +// nac-multi-jurisdiction/src/dual_receipt.rs +// Issue #59: 双宪法收据验证 + +/// 双收据验证器 +pub struct DualReceiptVerifier { + /// 是否要求双签名 + require_dual: bool, +} + +impl DualReceiptVerifier { + pub fn new() -> Self { + DualReceiptVerifier { require_dual: true } + } + + pub fn requires_dual_signature(&self) -> bool { + self.require_dual + } + + /// 验证双收据完整性 + pub fn verify(&self, source_receipt: &[u8], target_receipt: &[u8]) -> bool { + !source_receipt.is_empty() && !target_receipt.is_empty() + } +} + +impl Default for DualReceiptVerifier { + fn default() -> Self { + Self::new() + } +} + +/// 收据链(跨辖区交易的收据历史) +pub struct ReceiptChain { + receipts: Vec>, +} + +impl ReceiptChain { + pub fn new() -> Self { + ReceiptChain { receipts: Vec::new() } + } + + pub fn append(&mut self, receipt: Vec) { + self.receipts.push(receipt); + } + + pub fn len(&self) -> usize { + self.receipts.len() + } + + pub fn is_empty(&self) -> bool { + self.receipts.is_empty() + } +} + +impl Default for ReceiptChain { + fn default() -> Self { + Self::new() + } +} + diff --git a/nac-multi-jurisdiction/src/governance.rs b/nac-multi-jurisdiction/src/governance.rs new file mode 100644 index 0000000..901edb2 --- /dev/null +++ b/nac-multi-jurisdiction/src/governance.rs @@ -0,0 +1,105 @@ +// nac-multi-jurisdiction/src/governance.rs +// Issue #59: 共享资源治理 + +use crate::jurisdiction::JurisdictionId; + +/// 辖区协商委员会 +pub struct JurisdictionCouncil { + members: Vec, + /// 决议通过门限(定点数 1e4,6700 = 67%) + quorum_threshold: u64, +} + +impl JurisdictionCouncil { + pub fn new() -> Self { + JurisdictionCouncil { + members: Vec::new(), + quorum_threshold: 6700, + } + } + + pub fn add_member(&mut self, jid: JurisdictionId) { + if !self.members.contains(&jid) { + self.members.push(jid); + } + } + + /// 检查是否达到法定人数 + pub fn has_quorum(&self, voting_count: usize) -> bool { + if self.members.is_empty() { + return false; + } + let ratio = voting_count as u64 * 10000 / self.members.len() as u64; + ratio >= self.quorum_threshold + } + + pub fn member_count(&self) -> usize { + self.members.len() + } +} + +impl Default for JurisdictionCouncil { + fn default() -> Self { + Self::new() + } +} + +/// 共享资源治理 +pub struct SharedResourceGovernance { + council: JurisdictionCouncil, + pending_proposals: Vec, +} + +#[derive(Debug, Clone)] +pub struct ResourceProposal { + pub id: u64, + pub proposer: JurisdictionId, + pub description: String, + pub votes_for: u64, + pub votes_against: u64, + pub is_passed: bool, +} + +impl SharedResourceGovernance { + pub fn new(council: JurisdictionCouncil) -> Self { + SharedResourceGovernance { + council, + pending_proposals: Vec::new(), + } + } + + /// 提交资源分配提案 + pub fn submit_proposal( + &mut self, + proposer: JurisdictionId, + description: String, + ) -> u64 { + let id = self.pending_proposals.len() as u64; + self.pending_proposals.push(ResourceProposal { + id, + proposer, + description, + votes_for: 0, + votes_against: 0, + is_passed: false, + }); + id + } + + /// 投票 + pub fn vote(&mut self, proposal_id: u64, in_favor: bool) -> Result<(), String> { + let proposal = self.pending_proposals.get_mut(proposal_id as usize) + .ok_or("提案不存在")?; + if in_favor { + proposal.votes_for += 1; + } else { + proposal.votes_against += 1; + } + // 检查是否达到法定人数 + let total_votes = proposal.votes_for + proposal.votes_against; + if self.council.has_quorum(total_votes as usize) { + proposal.is_passed = proposal.votes_for * 10000 / total_votes >= 6700; + } + Ok(()) + } +} diff --git a/nac-multi-jurisdiction/src/isolation.rs b/nac-multi-jurisdiction/src/isolation.rs new file mode 100644 index 0000000..0453b06 --- /dev/null +++ b/nac-multi-jurisdiction/src/isolation.rs @@ -0,0 +1,167 @@ +// nac-multi-jurisdiction/src/isolation.rs +// Issue #59: 逻辑隔离层 - 确保不同辖区规则互不干扰 + +use serde::{Serialize, Deserialize}; +use crate::jurisdiction::JurisdictionId; + +/// 隔离策略级别 +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum IsolationLevel { + /// 严格隔离:完全独立的执行环境(默认) + Strict, + /// 受控共享:允许只读数据共享 + ControlledSharing, + /// 联合模式:辖区间协商后的有限互操作 + Federated, +} + +/// 隔离策略 +#[derive(Debug, Clone)] +pub struct IsolationPolicy { + pub level: IsolationLevel, + /// 是否强制规则隔离 + pub enforce_rule_isolation: bool, + /// 是否强制数据隔离 + pub enforce_data_isolation: bool, + /// 是否强制网络隔离 + pub enforce_network_isolation: bool, + /// 是否强制存储隔离 + pub enforce_storage_isolation: bool, + /// 允许的跨辖区数据类型(白名单) + pub allowed_cross_data_types: Vec, +} + +impl IsolationPolicy { + /// 创建严格隔离策略(推荐默认) + pub fn strict() -> Self { + IsolationPolicy { + level: IsolationLevel::Strict, + enforce_rule_isolation: true, + enforce_data_isolation: true, + enforce_network_isolation: false, // 网络层允许路由 + enforce_storage_isolation: true, + allowed_cross_data_types: vec![ + "ConstitutionalReceipt".to_string(), + "BlockHeader".to_string(), + ], + } + } + + /// 创建受控共享策略 + pub fn controlled_sharing() -> Self { + IsolationPolicy { + level: IsolationLevel::ControlledSharing, + enforce_rule_isolation: true, + enforce_data_isolation: false, + enforce_network_isolation: false, + enforce_storage_isolation: false, + allowed_cross_data_types: vec![ + "ConstitutionalReceipt".to_string(), + "BlockHeader".to_string(), + "PublicAssetMetadata".to_string(), + ], + } + } + + pub fn enforces_rule_isolation(&self) -> bool { + self.enforce_rule_isolation + } + + pub fn enforces_data_isolation(&self) -> bool { + self.enforce_data_isolation + } + + /// 检查数据类型是否允许跨辖区传输 + pub fn is_allowed_cross_type(&self, data_type: &str) -> bool { + self.allowed_cross_data_types.iter().any(|t| t == data_type) + } +} + +/// 隔离违规事件 +#[derive(Debug, Clone)] +pub struct IsolationViolation { + pub source_jurisdiction: JurisdictionId, + pub target_jurisdiction: JurisdictionId, + pub violation_type: ViolationType, + pub data_type: String, + pub timestamp: u64, + pub severity: ViolationSeverity, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum ViolationType { + UnauthorizedDataAccess, + RuleConflict, + NetworkBypass, + StorageLeak, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum ViolationSeverity { + Low, + Medium, + High, + Critical, +} + +/// 隔离层执行器 +pub struct IsolationLayer { + policies: std::collections::HashMap, + violations: Vec, +} + +impl IsolationLayer { + pub fn new() -> Self { + IsolationLayer { + policies: std::collections::HashMap::new(), + violations: Vec::new(), + } + } + + /// 为辖区设置隔离策略 + pub fn set_policy(&mut self, jid: JurisdictionId, policy: IsolationPolicy) { + self.policies.insert(jid, policy); + } + + /// 检查跨辖区操作是否合规 + pub fn check_cross_operation( + &mut self, + from: &JurisdictionId, + to: &JurisdictionId, + data_type: &str, + ) -> Result<(), IsolationViolation> { + let policy = self.policies.get(from) + .cloned() + .unwrap_or_else(IsolationPolicy::strict); + + if policy.enforce_data_isolation && !policy.is_allowed_cross_type(data_type) { + let violation = IsolationViolation { + source_jurisdiction: from.clone(), + target_jurisdiction: to.clone(), + violation_type: ViolationType::UnauthorizedDataAccess, + data_type: data_type.to_string(), + timestamp: 0, + severity: ViolationSeverity::High, + }; + self.violations.push(violation.clone()); + return Err(violation); + } + Ok(()) + } + + /// 获取违规记录 + pub fn get_violations(&self) -> &[IsolationViolation] { + &self.violations + } + + /// 清除已处理的违规记录 + pub fn clear_violations(&mut self) { + self.violations.clear(); + } +} + +impl Default for IsolationLayer { + fn default() -> Self { + Self::new() + } +} diff --git a/nac-multi-jurisdiction/src/jurisdiction.rs b/nac-multi-jurisdiction/src/jurisdiction.rs new file mode 100644 index 0000000..77d0cae --- /dev/null +++ b/nac-multi-jurisdiction/src/jurisdiction.rs @@ -0,0 +1,153 @@ +// nac-multi-jurisdiction/src/jurisdiction.rs +// Issue #59: 辖区注册与配置管理 + +use std::collections::HashMap; +use serde::{Serialize, Deserialize}; + +/// 辖区唯一标识符(格式:国家代码-监管机构) +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct JurisdictionId(String); + +impl JurisdictionId { + pub fn from_str(s: &str) -> Self { + JurisdictionId(s.to_string()) + } + + pub fn as_str(&self) -> &str { + &self.0 + } + + /// 验证格式:必须符合 XX-XXXX 格式 + pub fn is_valid(&self) -> bool { + let parts: Vec<&str> = self.0.split('-').collect(); + parts.len() == 2 && parts[0].len() == 2 && parts[1].len() >= 2 + } +} + +/// 辖区配置(宪法级,变更需辖区协商) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct JurisdictionConfig { + /// 辖区唯一标识 + pub id: JurisdictionId, + /// 辖区名称 + pub name: String, + /// 地区代码(ISO 3166-2) + pub region_code: String, + /// 规则插件哈希(SHA3-384,48字节) + pub plugin_hash: Vec, + /// 最大资源共享比例,定点数 1e4(3000 = 30.00%) + pub max_resource_share: u64, + /// 是否激活 + pub is_active: bool, +} + +impl JurisdictionConfig { + /// 验证配置合法性 + pub fn is_valid(&self) -> bool { + self.id.is_valid() + && !self.name.is_empty() + && self.max_resource_share <= 10000 + && self.plugin_hash != vec![0u8; 48] + } +} + +/// 辖区信息(运行时状态) +#[derive(Debug, Clone)] +pub struct Jurisdiction { + pub config: JurisdictionConfig, + /// 当前节点数量 + pub node_count: u64, + /// 当前资源使用率,定点数 1e4 + pub resource_usage: u64, + /// 最后活跃时间戳 + pub last_active: u64, + /// 是否处于维护模式 + pub in_maintenance: bool, +} + +impl Jurisdiction { + pub fn new(config: JurisdictionConfig) -> Self { + Jurisdiction { + config, + node_count: 0, + resource_usage: 0, + last_active: 0, + in_maintenance: false, + } + } + + /// 检查资源使用是否超限 + pub fn is_resource_overloaded(&self) -> bool { + self.resource_usage > self.config.max_resource_share + } +} + +/// 辖区注册表(全局单例) +pub struct JurisdictionRegistry { + jurisdictions: HashMap, + /// 最大注册辖区数(宪法限制) + max_jurisdictions: usize, +} + +impl JurisdictionRegistry { + pub fn new() -> Self { + JurisdictionRegistry { + jurisdictions: HashMap::new(), + max_jurisdictions: 100, + } + } + + /// 注册新辖区(需宪法收据) + pub fn register(&mut self, config: JurisdictionConfig) -> Result<(), String> { + if !config.is_valid() { + return Err("辖区配置无效".to_string()); + } + if self.jurisdictions.len() >= self.max_jurisdictions { + return Err("辖区数量已达上限".to_string()); + } + let id = config.id.clone(); + self.jurisdictions.insert(id, Jurisdiction::new(config)); + Ok(()) + } + + /// 查询辖区 + pub fn get(&self, id: &JurisdictionId) -> Option<&Jurisdiction> { + self.jurisdictions.get(id) + } + + /// 获取所有活跃辖区 + pub fn active_jurisdictions(&self) -> Vec<&Jurisdiction> { + self.jurisdictions + .values() + .filter(|j| j.config.is_active && !j.in_maintenance) + .collect() + } + + /// 动态加入新辖区(无需重构基础设施) + pub fn dynamic_join(&mut self, config: JurisdictionConfig) -> Result { + let id = config.id.clone(); + self.register(config)?; + Ok(id) + } + + /// 辖区退出(进入维护模式,等待迁移完成) + pub fn graceful_exit(&mut self, id: &JurisdictionId) -> Result<(), String> { + if let Some(j) = self.jurisdictions.get_mut(id) { + j.in_maintenance = true; + Ok(()) + } else { + Err(format!("辖区 {} 不存在", id.as_str())) + } + } + + /// 辖区数量 + pub fn count(&self) -> usize { + self.jurisdictions.len() + } +} + +impl Default for JurisdictionRegistry { + fn default() -> Self { + Self::new() + } +} diff --git a/nac-multi-jurisdiction/src/lib.rs b/nac-multi-jurisdiction/src/lib.rs new file mode 100644 index 0000000..883350e --- /dev/null +++ b/nac-multi-jurisdiction/src/lib.rs @@ -0,0 +1,80 @@ +// nac-multi-jurisdiction/src/lib.rs +// Issue #59: NAC 公链多辖区节点共享方案 +// 版本: 1.0 | 制定方: NAC 核心协议工程组 · 多司法辖区工作组 + +//! # 多辖区节点共享模块 +//! +//! 实现不同司法辖区节点在物理层共享基础设施, +//! 在逻辑层保持各自合规性、自治性和独立性。 +//! +//! ## 核心设计 +//! - 逻辑强隔离:节点执行的规则完全由其所属辖区插件决定 +//! - 物理资源共享:支持节点共用计算、存储、带宽资源 +//! - 跨辖区互操作:通过双宪法收据(CR)保障合规性 +//! - 宪法级保障:所有共享方案受宪法条款约束 + +pub mod jurisdiction; +pub mod isolation; +pub mod cross_jurisdiction; +pub mod resource_sharing; +pub mod plugin; +pub mod dual_receipt; +pub mod discovery; +pub mod governance; + +pub use jurisdiction::{Jurisdiction, JurisdictionId, JurisdictionConfig, JurisdictionRegistry}; +pub use isolation::{IsolationLayer, IsolationPolicy, IsolationViolation}; +pub use cross_jurisdiction::{CrossJurisdictionTx, DualConstitutionalReceipt, CrossJurisdictionRouter}; +pub use resource_sharing::{ResourcePool, ResourceAllocation, ResourceQuota, ResourceMonitor}; +pub use plugin::{JurisdictionPlugin, PluginLoader, PluginRegistry, RuleConflictResolver}; +pub use dual_receipt::{DualReceiptVerifier, ReceiptChain}; +pub use discovery::{NodeDiscovery, JurisdictionAwareRouter}; +pub use governance::{JurisdictionCouncil, SharedResourceGovernance}; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_jurisdiction_registry() { + let mut registry = JurisdictionRegistry::new(); + let jid = JurisdictionId::from_str("UAE-ADGM"); + let config = JurisdictionConfig { + id: jid.clone(), + name: "阿联酋 ADGM 辖区".to_string(), + region_code: "AE-AZ".to_string(), + plugin_hash: vec![0u8; 48], + max_resource_share: 3000, // 30.00% + is_active: true, + }; + registry.register(config); + assert!(registry.get(&jid).is_some()); + } + + #[test] + fn test_isolation_policy() { + let policy = IsolationPolicy::strict(); + assert!(policy.enforces_rule_isolation()); + assert!(policy.enforces_data_isolation()); + } + + #[test] + fn test_resource_quota() { + let quota = ResourceQuota { + jurisdiction_id: JurisdictionId::from_str("SG-MAS"), + cpu_share: 2500, // 25.00% + memory_share: 2000, // 20.00% + bandwidth_share: 3000, // 30.00% + storage_share: 1500, // 15.00% + }; + assert!(quota.is_valid()); + assert!(quota.total_share() <= 10000); + } + + #[test] + fn test_dual_receipt_chain() { + let verifier = DualReceiptVerifier::new(); + // 双宪法收据验证:发起辖区 + 接收辖区都必须签署 + assert!(verifier.requires_dual_signature()); + } +} diff --git a/nac-multi-jurisdiction/src/plugin.rs b/nac-multi-jurisdiction/src/plugin.rs new file mode 100644 index 0000000..b67ee60 --- /dev/null +++ b/nac-multi-jurisdiction/src/plugin.rs @@ -0,0 +1,135 @@ +// nac-multi-jurisdiction/src/plugin.rs +// Issue #59: 可插拔辖区规则插件 + +use std::collections::HashMap; +use crate::jurisdiction::JurisdictionId; + +/// 辖区规则插件接口 +pub trait JurisdictionPlugin: Send + Sync { + /// 插件名称 + fn name(&self) -> &str; + /// 插件版本 + fn version(&self) -> &str; + /// 插件哈希(SHA3-384) + fn hash(&self) -> [u8; 48]; + /// 验证交易是否符合本辖区规则 + fn validate_tx(&self, tx_data: &[u8]) -> Result<(), String>; + /// 验证区块是否符合本辖区规则 + fn validate_block(&self, block_data: &[u8]) -> Result<(), String>; + /// 获取辖区特定的合规要求 + fn compliance_requirements(&self) -> Vec; +} + +/// 插件加载器 +pub struct PluginLoader { + plugins: HashMap>, +} + +impl PluginLoader { + pub fn new() -> Self { + PluginLoader { + plugins: HashMap::new(), + } + } + + /// 加载插件(通过哈希验证) + pub fn load( + &mut self, + jid: JurisdictionId, + plugin: Box, + expected_hash: &[u8; 48], + ) -> Result<(), String> { + if &plugin.hash() != expected_hash { + return Err("插件哈希验证失败:可能被篡改".to_string()); + } + self.plugins.insert(jid, plugin); + Ok(()) + } + + /// 获取辖区插件 + pub fn get(&self, jid: &JurisdictionId) -> Option<&dyn JurisdictionPlugin> { + self.plugins.get(jid).map(|p| p.as_ref()) + } + + /// 卸载插件 + pub fn unload(&mut self, jid: &JurisdictionId) { + self.plugins.remove(jid); + } +} + +impl Default for PluginLoader { + fn default() -> Self { + Self::new() + } +} + +/// 插件注册表 +pub struct PluginRegistry { + loader: PluginLoader, +} + +impl PluginRegistry { + pub fn new() -> Self { + PluginRegistry { + loader: PluginLoader::new(), + } + } +} + +impl Default for PluginRegistry { + fn default() -> Self { + Self::new() + } +} + +/// 规则冲突解决器 +pub struct RuleConflictResolver { + /// 冲突解决历史 + resolution_history: Vec, +} + +#[derive(Debug, Clone)] +pub struct ConflictRecord { + pub source: JurisdictionId, + pub target: JurisdictionId, + pub conflict_type: String, + pub resolution: String, + pub timestamp: u64, +} + +impl RuleConflictResolver { + pub fn new() -> Self { + RuleConflictResolver { + resolution_history: Vec::new(), + } + } + + /// 解决规则冲突(返回解决方案) + pub fn resolve( + &mut self, + source: &JurisdictionId, + target: &JurisdictionId, + conflict_type: &str, + ) -> String { + // 默认策略:提交宪法仲裁 + let resolution = format!( + "冲突已提交宪法仲裁:{} vs {} - {}", + source.as_str(), target.as_str(), conflict_type + ); + self.resolution_history.push(ConflictRecord { + source: source.clone(), + target: target.clone(), + conflict_type: conflict_type.to_string(), + resolution: resolution.clone(), + timestamp: 0, + }); + resolution + } +} + +impl Default for RuleConflictResolver { + fn default() -> Self { + Self::new() + } +} + diff --git a/nac-multi-jurisdiction/src/resource_sharing.rs b/nac-multi-jurisdiction/src/resource_sharing.rs new file mode 100644 index 0000000..09a943d --- /dev/null +++ b/nac-multi-jurisdiction/src/resource_sharing.rs @@ -0,0 +1,175 @@ +// nac-multi-jurisdiction/src/resource_sharing.rs +// Issue #59: 物理资源共享与公平分配 + +use std::collections::HashMap; +use serde::{Serialize, Deserialize}; +use crate::jurisdiction::JurisdictionId; + +/// 资源配额(每辖区) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ResourceQuota { + pub jurisdiction_id: JurisdictionId, + /// CPU 共享比例,定点数 1e4(2500 = 25.00%) + pub cpu_share: u64, + /// 内存共享比例,定点数 1e4 + pub memory_share: u64, + /// 带宽共享比例,定点数 1e4 + pub bandwidth_share: u64, + /// 存储共享比例,定点数 1e4 + pub storage_share: u64, +} + +impl ResourceQuota { + /// 验证配额合法性(各项不超过 100%) + pub fn is_valid(&self) -> bool { + self.cpu_share <= 10000 + && self.memory_share <= 10000 + && self.bandwidth_share <= 10000 + && self.storage_share <= 10000 + } + + /// 计算总资源占用(平均值) + pub fn total_share(&self) -> u64 { + (self.cpu_share + self.memory_share + self.bandwidth_share + self.storage_share) / 4 + } +} + +/// 资源分配记录 +#[derive(Debug, Clone)] +pub struct ResourceAllocation { + pub jurisdiction_id: JurisdictionId, + pub allocated_cpu: u64, // 毫核 + pub allocated_memory: u64, // MB + pub allocated_bandwidth: u64, // Mbps + pub allocated_storage: u64, // GB + pub timestamp: u64, +} + +/// 资源池(物理共享层) +pub struct ResourcePool { + /// 总 CPU(毫核) + total_cpu: u64, + /// 总内存(MB) + total_memory: u64, + /// 总带宽(Mbps) + total_bandwidth: u64, + /// 总存储(GB) + total_storage: u64, + /// 各辖区配额 + quotas: HashMap, + /// 当前分配 + allocations: HashMap, +} + +impl ResourcePool { + pub fn new(cpu: u64, memory: u64, bandwidth: u64, storage: u64) -> Self { + ResourcePool { + total_cpu: cpu, + total_memory: memory, + total_bandwidth: bandwidth, + total_storage: storage, + quotas: HashMap::new(), + allocations: HashMap::new(), + } + } + + /// 设置辖区资源配额 + pub fn set_quota(&mut self, quota: ResourceQuota) -> Result<(), String> { + if !quota.is_valid() { + return Err("资源配额无效".to_string()); + } + // 检查总配额不超过 100% + let total_cpu: u64 = self.quotas.values().map(|q| q.cpu_share).sum::() + + quota.cpu_share; + if total_cpu > 10000 { + return Err("CPU 总配额超过 100%".to_string()); + } + self.quotas.insert(quota.jurisdiction_id.clone(), quota); + Ok(()) + } + + /// 为辖区分配资源 + pub fn allocate(&mut self, jid: &JurisdictionId, timestamp: u64) -> Result { + let quota = self.quotas.get(jid) + .ok_or_else(|| format!("辖区 {} 没有配额", jid.as_str()))?; + + let allocation = ResourceAllocation { + jurisdiction_id: jid.clone(), + allocated_cpu: self.total_cpu * quota.cpu_share / 10000, + allocated_memory: self.total_memory * quota.memory_share / 10000, + allocated_bandwidth: self.total_bandwidth * quota.bandwidth_share / 10000, + allocated_storage: self.total_storage * quota.storage_share / 10000, + timestamp, + }; + + self.allocations.insert(jid.clone(), allocation.clone()); + Ok(allocation) + } + + /// 获取辖区当前分配 + pub fn get_allocation(&self, jid: &JurisdictionId) -> Option<&ResourceAllocation> { + self.allocations.get(jid) + } + + /// 检查是否存在资源抢占 + pub fn check_contention(&self) -> Vec { + // 返回资源使用超过配额的辖区 + self.allocations.iter() + .filter(|(jid, alloc)| { + if let Some(quota) = self.quotas.get(*jid) { + let used_cpu = alloc.allocated_cpu * 10000 / self.total_cpu; + used_cpu > quota.cpu_share + 500 // 超出 5% 视为抢占 + } else { + false + } + }) + .map(|(jid, _)| jid.clone()) + .collect() + } +} + +/// 资源监控器 +pub struct ResourceMonitor { + pool: ResourcePool, + alert_threshold: u64, // 超过配额多少时告警,定点数 1e4 +} + +impl ResourceMonitor { + pub fn new(pool: ResourcePool) -> Self { + ResourceMonitor { + pool, + alert_threshold: 1000, // 超出 10% 告警 + } + } + + /// 检查所有辖区资源使用情况 + pub fn check_all(&self) -> Vec { + let contention = self.pool.check_contention(); + contention.into_iter().map(|jid| ResourceAlert { + jurisdiction_id: jid, + alert_type: AlertType::ResourceContention, + severity: AlertSeverity::Warning, + }).collect() + } +} + +#[derive(Debug, Clone)] +pub struct ResourceAlert { + pub jurisdiction_id: JurisdictionId, + pub alert_type: AlertType, + pub severity: AlertSeverity, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum AlertType { + ResourceContention, + QuotaExceeded, + PoolExhausted, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum AlertSeverity { + Info, + Warning, + Critical, +}