NAC_Blockchain/nac-acc-service/src/acc20c_judicial.rs

420 lines
16 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// acc20c_judicial.rs — ACC-20C 司法冻结与合规检查模块
//
// 本模块实现 CNNL 宪法条款 A53合规检查和 A55司法冻结要求的功能。
// 作为独立文件新增,不修改现有 main.rs 的任何逻辑。
//
// 新增路由:
// POST /acc20c/freeze — 司法冻结包装资产A55
// POST /acc20c/unfreeze — 解除司法冻结A55
// POST /acc20c/compliance/check — 合规性检查A53
//
// 依赖:复用 main.rs 中已定义的 SharedState、Acc20cWrappedAsset 等类型
use actix_web::{web, HttpResponse};
use chrono::Utc;
use serde::{Deserialize, Serialize};
use sha3::{Digest, Sha3_384};
use crate::{AccState, SharedState};
// ============================================================
// 请求/响应数据结构
// ============================================================
/// 司法冻结请求CNNL 宪法条款 A55
#[derive(Debug, Deserialize)]
pub struct FreezeReq {
/// 要冻结的 Wrapper Token ID
pub wrapper_token_id: String,
/// 冻结发起方地址(必须是司法授权地址)
pub authority_address: String,
/// 冻结原因(司法命令编号或描述)
pub reason: String,
/// 司法辖区代码
pub jurisdiction: String,
/// 宪法收据 ID由 CEE 颁发,证明此冻结已通过宪法审查)
pub constitutional_receipt_id: Option<String>,
}
/// 解冻请求CNNL 宪法条款 A55
#[derive(Debug, Deserialize)]
pub struct UnfreezeReq {
/// 要解冻的 Wrapper Token ID
pub wrapper_token_id: String,
/// 解冻发起方地址(必须是司法授权地址)
pub authority_address: String,
/// 解冻原因
pub reason: String,
/// 宪法收据 ID由 CEE 颁发)
pub constitutional_receipt_id: Option<String>,
}
/// 合规检查请求CNNL 宪法条款 A53
#[derive(Debug, Deserialize)]
pub struct ComplianceCheckReq {
/// 要检查的 Wrapper Token ID
pub wrapper_token_id: String,
/// 检查类型wrap / unwrap / transfer / valuation
pub check_type: String,
/// 操作发起方地址
pub initiator: String,
/// 目标地址(转移时使用)
pub target: Option<String>,
}
/// 合规检查结果
#[derive(Debug, Serialize)]
pub struct ComplianceCheckResult {
pub wrapper_token_id: String,
pub check_type: String,
pub passed: bool,
pub clauses_verified: Vec<String>,
pub failed_clause: Option<String>,
pub reason: String,
pub checked_at: i64,
pub constitutional_receipt_id: String,
}
/// 冻结/解冻操作结果
#[derive(Debug, Serialize)]
pub struct JudicialActionResult {
pub wrapper_token_id: String,
pub action: String,
pub success: bool,
pub previous_status: String,
pub new_status: String,
pub authority_address: String,
pub reason: String,
pub tx_hash: String,
pub jurisdiction: String,
pub constitutional_receipt_id: String,
pub timestamp: i64,
}
// ============================================================
// 内部辅助函数
// ============================================================
/// 生成 SHA3-384 哈希NAC 原生 48 字节哈希)
fn sha3_384_hex(input: &str) -> String {
let mut hasher = Sha3_384::new();
hasher.update(input.as_bytes());
hex::encode(hasher.finalize())
}
/// 验证地址格式NAC 原生 32 字节地址 = 64 个十六进制字符)
fn is_valid_nac_address(addr: &str) -> bool {
addr.len() == 64 && addr.chars().all(|c| c.is_ascii_hexdigit())
}
/// 生成宪法收据 ID模拟 CEE 颁发)
fn generate_cr_id(action: &str, token_id: &str, authority: &str) -> String {
let input = format!(
"CR:ACC20C:{}:{}:{}:{}",
action,
token_id,
authority,
Utc::now().timestamp_millis()
);
format!("CR-{}", &sha3_384_hex(&input)[..32])
}
// ============================================================
// 路由处理函数
// ============================================================
/// POST /acc20c/freeze — 司法冻结包装资产
/// 对应 CNNL 宪法条款 A55司法冻结操作必须通过 CEE 宪法执行引擎审查
pub async fn acc20c_freeze(
state: web::Data<SharedState>,
req: web::Json<FreezeReq>,
) -> HttpResponse {
// ── 1. 验证权限地址格式 ──────────────────────────────────
if !is_valid_nac_address(&req.authority_address) {
return HttpResponse::BadRequest().json(serde_json::json!({
"success": false,
"error": "无效的权限地址格式(需要 64 位十六进制 NAC 原生地址)",
"clause": "A55"
}));
}
// ── 2. 验证冻结原因不为空 ────────────────────────────────
if req.reason.trim().is_empty() {
return HttpResponse::BadRequest().json(serde_json::json!({
"success": false,
"error": "冻结原因不能为空(宪法条款 A55 要求)",
"clause": "A55"
}));
}
let mut s: std::sync::MutexGuard<AccState> = state.lock().unwrap();
// ── 3. 查找包装资产 ──────────────────────────────────────
let asset = match s.acc20c_wrapped_assets.get(&req.wrapper_token_id) {
Some(a) => a.clone(),
None => {
return HttpResponse::NotFound().json(serde_json::json!({
"success": false,
"error": "包装资产不存在",
"wrapper_token_id": req.wrapper_token_id
}));
}
};
// ── 4. 检查资产是否已被冻结 ──────────────────────────────
if asset.status == "frozen" {
return HttpResponse::Conflict().json(serde_json::json!({
"success": false,
"error": "资产已处于冻结状态",
"wrapper_token_id": req.wrapper_token_id,
"current_status": "frozen"
}));
}
// ── 5. 检查资产是否已被销毁 ──────────────────────────────
if asset.status == "burned" {
return HttpResponse::Conflict().json(serde_json::json!({
"success": false,
"error": "已销毁的资产不能被冻结",
"wrapper_token_id": req.wrapper_token_id
}));
}
// ── 6. 生成宪法收据 ID ───────────────────────────────────
let cr_id = req.constitutional_receipt_id.clone().unwrap_or_else(|| {
generate_cr_id("FREEZE", &req.wrapper_token_id, &req.authority_address)
});
// ── 7. 生成交易哈希 ──────────────────────────────────────
let tx_input = format!(
"ACC20C:FREEZE:{}:{}:{}:{}",
req.wrapper_token_id,
req.authority_address,
req.reason,
Utc::now().timestamp_millis()
);
let tx_hash = format!("0x{}", &sha3_384_hex(&tx_input)[..64]);
let previous_status = asset.status.clone();
// ── 8. 执行冻结 ──────────────────────────────────────────
if let Some(a) = s.acc20c_wrapped_assets.get_mut(&req.wrapper_token_id) {
a.status = "frozen".to_string();
a.constitutional_receipt_id = cr_id.clone();
}
let result = JudicialActionResult {
wrapper_token_id: req.wrapper_token_id.clone(),
action: "freeze".to_string(),
success: true,
previous_status,
new_status: "frozen".to_string(),
authority_address: req.authority_address.clone(),
reason: req.reason.clone(),
tx_hash,
jurisdiction: req.jurisdiction.clone(),
constitutional_receipt_id: cr_id,
timestamp: Utc::now().timestamp_millis(),
};
HttpResponse::Ok().json(serde_json::json!({
"success": true,
"result": result,
"clause": "A55",
"message": "资产已成功冻结,宪法条款 A55 已执行"
}))
}
/// POST /acc20c/unfreeze — 解除司法冻结
/// 对应 CNNL 宪法条款 A55解冻操作同样需要宪法授权
pub async fn acc20c_unfreeze(
state: web::Data<SharedState>,
req: web::Json<UnfreezeReq>,
) -> HttpResponse {
// ── 1. 验证权限地址格式 ──────────────────────────────────
if !is_valid_nac_address(&req.authority_address) {
return HttpResponse::BadRequest().json(serde_json::json!({
"success": false,
"error": "无效的权限地址格式(需要 64 位十六进制 NAC 原生地址)",
"clause": "A55"
}));
}
let mut s: std::sync::MutexGuard<AccState> = state.lock().unwrap();
// ── 2. 查找包装资产 ──────────────────────────────────────
let asset = match s.acc20c_wrapped_assets.get(&req.wrapper_token_id) {
Some(a) => a.clone(),
None => {
return HttpResponse::NotFound().json(serde_json::json!({
"success": false,
"error": "包装资产不存在",
"wrapper_token_id": req.wrapper_token_id
}));
}
};
// ── 3. 检查资产是否处于冻结状态 ──────────────────────────
if asset.status != "frozen" {
return HttpResponse::Conflict().json(serde_json::json!({
"success": false,
"error": "资产当前不处于冻结状态,无需解冻",
"wrapper_token_id": req.wrapper_token_id,
"current_status": asset.status
}));
}
// ── 4. 生成宪法收据 ID ───────────────────────────────────
let cr_id = req.constitutional_receipt_id.clone().unwrap_or_else(|| {
generate_cr_id("UNFREEZE", &req.wrapper_token_id, &req.authority_address)
});
// ── 5. 生成交易哈希 ──────────────────────────────────────
let tx_input = format!(
"ACC20C:UNFREEZE:{}:{}:{}:{}",
req.wrapper_token_id,
req.authority_address,
req.reason,
Utc::now().timestamp_millis()
);
let tx_hash = format!("0x{}", &sha3_384_hex(&tx_input)[..64]);
// ── 6. 执行解冻 ──────────────────────────────────────────
if let Some(a) = s.acc20c_wrapped_assets.get_mut(&req.wrapper_token_id) {
a.status = "active".to_string();
a.constitutional_receipt_id = cr_id.clone();
}
let result = JudicialActionResult {
wrapper_token_id: req.wrapper_token_id.clone(),
action: "unfreeze".to_string(),
success: true,
previous_status: "frozen".to_string(),
new_status: "active".to_string(),
authority_address: req.authority_address.clone(),
reason: req.reason.clone(),
tx_hash,
jurisdiction: asset.jurisdiction.clone(),
constitutional_receipt_id: cr_id,
timestamp: Utc::now().timestamp_millis(),
};
HttpResponse::Ok().json(serde_json::json!({
"success": true,
"result": result,
"clause": "A55",
"message": "资产已成功解冻,宪法条款 A55 已执行"
}))
}
/// POST /acc20c/compliance/check — 合规性检查
/// 对应 CNNL 宪法条款 A53所有 ACC-20C 操作前必须通过合规检查
pub async fn acc20c_compliance_check(
state: web::Data<SharedState>,
req: web::Json<ComplianceCheckReq>,
) -> HttpResponse {
let s: std::sync::MutexGuard<AccState> = state.lock().unwrap();
// ── 1. 查找包装资产 ──────────────────────────────────────
let asset = match s.acc20c_wrapped_assets.get(&req.wrapper_token_id) {
Some(a) => a.clone(),
None => {
return HttpResponse::NotFound().json(serde_json::json!({
"success": false,
"error": "包装资产不存在",
"wrapper_token_id": req.wrapper_token_id
}));
}
};
let now = Utc::now().timestamp_millis();
let mut clauses_verified: Vec<String> = Vec::new();
let mut passed = true;
let mut failed_clause: Option<String> = None;
let mut reason = "所有宪法条款验证通过".to_string();
// ── 2. 验证 A53资产状态检查 ────────────────────────────
if asset.status == "frozen" {
passed = false;
failed_clause = Some("A55".to_string());
reason = format!(
"资产处于司法冻结状态,{}操作被拒绝(宪法条款 A55",
req.check_type
);
} else if asset.status == "burned" {
passed = false;
failed_clause = Some("A53".to_string());
reason = "资产已销毁,无法执行任何操作(宪法条款 A53".to_string();
} else {
clauses_verified.push("A53".to_string());
}
// ── 3. 验证 A54解包冷却期检查仅 unwrap 操作)────────
if passed && req.check_type == "unwrap" {
if asset.unlock_timestamp > now {
let remaining_secs = (asset.unlock_timestamp - now) / 1000;
passed = false;
failed_clause = Some("A54".to_string());
reason = format!(
"解包冷却期未结束,还需等待 {} 秒(宪法条款 A54",
remaining_secs
);
} else {
clauses_verified.push("A54".to_string());
}
}
// ── 4. 验证 A56转移目标地址格式仅 transfer 操作)────
if passed && req.check_type == "transfer" {
match &req.target {
None => {
passed = false;
failed_clause = Some("A56".to_string());
reason = "转移操作必须提供目标地址(宪法条款 A56".to_string();
}
Some(target) => {
if !is_valid_nac_address(target) {
passed = false;
failed_clause = Some("A56".to_string());
reason = "目标地址格式无效(需要 64 位十六进制 NAC 原生地址,宪法条款 A56"
.to_string();
} else {
clauses_verified.push("A56".to_string());
}
}
}
}
// ── 5. 生成合规检查收据 ──────────────────────────────────
let cr_input = format!(
"CR:COMPLIANCE:{}:{}:{}:{}",
req.check_type, req.wrapper_token_id, req.initiator, now
);
let cr_id = format!("CR-COMP-{}", &sha3_384_hex(&cr_input)[..28]);
let result = ComplianceCheckResult {
wrapper_token_id: req.wrapper_token_id.clone(),
check_type: req.check_type.clone(),
passed,
clauses_verified,
failed_clause,
reason,
checked_at: now,
constitutional_receipt_id: cr_id,
};
let status_code = if passed { 200u16 } else { 403u16 };
if status_code == 200 {
HttpResponse::Ok().json(serde_json::json!({
"success": true,
"result": result
}))
} else {
HttpResponse::Forbidden().json(serde_json::json!({
"success": false,
"result": result
}))
}
}