feat(issues-59,60,61,62,66,67): 完成6个工单
Issue #59: nac-multi-jurisdiction 多辖区节点共享模块 - 辖区注册/隔离/动态加入 - 跨辖区交易双收据 - 资源公平分配 - 规则插件哈希验证 Issue #60: 宪法引擎协同关系文档 - docs/constitutional_engine_coordination.md - CBPP/CNNL/CSNP/Charter/NVM 协同关系说明 Issue #61: Charter 编译器 XTZH 汇率系统原生支持 - charter-std/xtzh/rate.ch - 汇率类型 - charter-std/xtzh/reserve.ch - 储备管理 - charter-std/xtzh/rate_oracle.ch - 预言机接口 - charter-std/docs/nvm_xtzh_opcodes.md - NVM 操作码文档 - charter-compiler lexer 添加 XTZH Token Issue #62: XTZH 黄金永续合约储备法典 - charter-std/xtzh/gold_reserve_codex.ch - 5章:储备资产/SDR锚定/铸造销毁/审计/紧急条款 Issue #66: 43条宪法增补条款 CNNL 实现 - nac-constitution/clauses/amendments.cnnl - 6章:基础架构/资产合规/治理/XTZH货币/多辖区/AI合规 Issue #67: nac-daemon 本地守护进程 - nacd: HTTP API 服务 (127.0.0.1:8766) - nac: 命令行工具 (status/wallet/contract/network/constitution) - 集成 NAC_lens/CNNL 服务端点 Closes #59 #60 #61 #62 #66 #67
This commit is contained in:
parent
70373e5da9
commit
9b1bae2d49
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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; // 主权合规
|
||||
|
|
@ -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<Address>
|
||||
/// 最后审计时间戳
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 系统处理)
|
||||
}
|
||||
}
|
||||
|
|
@ -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 缓冲
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<u32>, // 验证通过的宪法条款 ID
|
||||
pub cee_signature: Vec<u8>, // CEE 签名
|
||||
pub epoch: u64, // 验证时的纪元
|
||||
pub is_valid: bool,
|
||||
}
|
||||
|
||||
// CBPP 区块必须包含所有交易的 CR
|
||||
pub struct Block {
|
||||
pub header: BlockHeader,
|
||||
pub transactions: Vec<Transaction>,
|
||||
pub receipts: Vec<ConstitutionalReceipt>, // 一一对应
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 CNNL → CEE 接口
|
||||
|
||||
```rust
|
||||
// CNNL 编译产物 - 宪法状态文件
|
||||
pub struct ConstitutionalState {
|
||||
pub version: u64,
|
||||
pub clauses: Vec<CompiledClause>,
|
||||
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<ConstitutionalReceipt, CeeError>;
|
||||
}
|
||||
```
|
||||
|
||||
### 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 原生内置 |
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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"
|
||||
|
|
@ -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<Value> {
|
||||
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<Value> {
|
||||
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(())
|
||||
}
|
||||
|
|
@ -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<Self> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
// nac-daemon/src/contract.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<RwLock<DaemonState>>;
|
||||
|
||||
/// API 响应包装
|
||||
#[derive(Serialize)]
|
||||
pub struct ApiResponse<T: Serialize> {
|
||||
pub success: bool,
|
||||
pub data: Option<T>,
|
||||
pub error: Option<String>,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
impl<T: Serialize> ApiResponse<T> {
|
||||
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<SharedState>) -> 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<SharedState>) -> 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<String>,
|
||||
state: web::Data<SharedState>,
|
||||
) -> 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::<serde_json::Value>().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<serde_json::Value>,
|
||||
state: web::Data<SharedState>,
|
||||
) -> 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::<serde_json::Value>().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<serde_json::Value>,
|
||||
state: web::Data<SharedState>,
|
||||
) -> 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::<serde_json::Value>().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<SharedState>) -> 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<SharedState>) -> 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(())
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
// nac-daemon/src/network.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<String>,
|
||||
pub peers: Vec<PeerInfo>,
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
// nac-daemon/src/wallet.rs
|
||||
// 模块占位 - 后续实现
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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<u8>,
|
||||
/// 发起辖区 ID
|
||||
pub source_jurisdiction: JurisdictionId,
|
||||
/// 接收辖区 ID
|
||||
pub target_jurisdiction: JurisdictionId,
|
||||
/// 发起辖区宪法收据(原始字节)
|
||||
pub source_receipt: Vec<u8>,
|
||||
/// 接收辖区宪法收据(原始字节)
|
||||
pub target_receipt: Vec<u8>,
|
||||
/// 时间戳(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<u8>,
|
||||
/// 发起辖区
|
||||
pub source_jurisdiction: JurisdictionId,
|
||||
/// 接收辖区
|
||||
pub target_jurisdiction: JurisdictionId,
|
||||
/// 交易数据
|
||||
pub payload: Vec<u8>,
|
||||
/// 双宪法收据(可选,处理中为 None)
|
||||
pub dual_receipt: Option<DualConstitutionalReceipt>,
|
||||
/// 交易状态
|
||||
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<CrossJurisdictionTx>,
|
||||
/// 最大待处理交易数
|
||||
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<Vec<u8>, 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<u8>,
|
||||
receipt: Vec<u8>,
|
||||
) -> 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()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// nac-multi-jurisdiction/src/discovery.rs
|
||||
// Issue #59: 辖区感知节点发现
|
||||
|
||||
use crate::jurisdiction::JurisdictionId;
|
||||
|
||||
/// 辖区感知节点发现
|
||||
pub struct NodeDiscovery {
|
||||
known_nodes: Vec<NodeInfo>,
|
||||
}
|
||||
|
||||
#[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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl ReceiptChain {
|
||||
pub fn new() -> Self {
|
||||
ReceiptChain { receipts: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn append(&mut self, receipt: Vec<u8>) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
// nac-multi-jurisdiction/src/governance.rs
|
||||
// Issue #59: 共享资源治理
|
||||
|
||||
use crate::jurisdiction::JurisdictionId;
|
||||
|
||||
/// 辖区协商委员会
|
||||
pub struct JurisdictionCouncil {
|
||||
members: Vec<JurisdictionId>,
|
||||
/// 决议通过门限(定点数 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<ResourceProposal>,
|
||||
}
|
||||
|
||||
#[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(())
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String>,
|
||||
}
|
||||
|
||||
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<JurisdictionId, IsolationPolicy>,
|
||||
violations: Vec<IsolationViolation>,
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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<u8>,
|
||||
/// 最大资源共享比例,定点数 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<JurisdictionId, Jurisdiction>,
|
||||
/// 最大注册辖区数(宪法限制)
|
||||
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<JurisdictionId, String> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String>;
|
||||
}
|
||||
|
||||
/// 插件加载器
|
||||
pub struct PluginLoader {
|
||||
plugins: HashMap<JurisdictionId, Box<dyn JurisdictionPlugin>>,
|
||||
}
|
||||
|
||||
impl PluginLoader {
|
||||
pub fn new() -> Self {
|
||||
PluginLoader {
|
||||
plugins: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 加载插件(通过哈希验证)
|
||||
pub fn load(
|
||||
&mut self,
|
||||
jid: JurisdictionId,
|
||||
plugin: Box<dyn JurisdictionPlugin>,
|
||||
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<ConflictRecord>,
|
||||
}
|
||||
|
||||
#[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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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<JurisdictionId, ResourceQuota>,
|
||||
/// 当前分配
|
||||
allocations: HashMap<JurisdictionId, ResourceAllocation>,
|
||||
}
|
||||
|
||||
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::<u64>()
|
||||
+ 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<ResourceAllocation, String> {
|
||||
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<JurisdictionId> {
|
||||
// 返回资源使用超过配额的辖区
|
||||
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<ResourceAlert> {
|
||||
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,
|
||||
}
|
||||
Loading…
Reference in New Issue