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:
nacadmin 2026-02-28 12:28:46 +08:00
parent 70373e5da9
commit 9b1bae2d49
29 changed files with 6608 additions and 0 deletions

View File

@ -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")]

View File

@ -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

10
charter-std/mod.ch Normal file
View File

@ -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; // 主权合规

View File

@ -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
}

86
charter-std/xtzh/rate.ch Normal file
View File

@ -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;
}

View File

@ -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 系统处理)
}
}

190
charter-std/xtzh/reserve.ch Normal file
View File

@ -0,0 +1,190 @@
// Charter Standard Library - XTZH 黄金储备模块
// Issue #61/#62: 黄金永续合约储备系统
// 版本: 1.0
/// 交易所信息
public struct ExchangeInfo {
name: string,
weight: uint64, // 权重,定点数 1e410000 = 100%
max_exposure: uint64, // 最大敞口,定点数 1e4
is_active: bool
}
/// 储备状态快照
public struct ReserveSnapshot {
timestamp: uint64,
total_notional: uint64, // 合约名义总价值XTZH 单位)
xtzh_supply: uint64, // XTZH 流通量
coverage_ratio: uint64, // 覆盖率,定点数 1e412500 = 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 缓冲
}
}
}

View File

@ -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 原生内置 |

View File

@ -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
}

2820
nac-daemon/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

34
nac-daemon/Cargo.toml Normal file
View File

@ -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"

253
nac-daemon/src/cli.rs Normal file
View File

@ -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(())
}

78
nac-daemon/src/config.rs Normal file
View File

@ -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(())
}
}

View File

@ -0,0 +1,2 @@
// nac-daemon/src/contract.rs
// 模块占位 - 后续实现

273
nac-daemon/src/main.rs Normal file
View File

@ -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(())
}

View File

@ -0,0 +1,2 @@
// nac-daemon/src/network.rs
// 模块占位 - 后续实现

View File

@ -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(),
}
}
}

2
nac-daemon/src/wallet.rs Normal file
View File

@ -0,0 +1,2 @@
// nac-daemon/src/wallet.rs
// 模块占位 - 后续实现

734
nac-multi-jurisdiction/Cargo.lock generated Normal file
View File

@ -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"

View File

@ -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"

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -0,0 +1,105 @@
// nac-multi-jurisdiction/src/governance.rs
// Issue #59: 共享资源治理
use crate::jurisdiction::JurisdictionId;
/// 辖区协商委员会
pub struct JurisdictionCouncil {
members: Vec<JurisdictionId>,
/// 决议通过门限(定点数 1e46700 = 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(())
}
}

View File

@ -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()
}
}

View File

@ -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-38448字节
pub plugin_hash: Vec<u8>,
/// 最大资源共享比例,定点数 1e43000 = 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()
}
}

View File

@ -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());
}
}

View File

@ -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()
}
}

View File

@ -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 共享比例,定点数 1e42500 = 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,
}