NAC_Blockchain/nac-jurisdiction-rules/CN/jurisdiction_plugin.rs

236 lines
7.9 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.

// NAC 中国大陆辖区宪法规则验证插件CN_PLUGIN
// CBPP原则约法即是治法宪法即是规则参与即是共识节点产生区块交易决定区块大小
// 此插件由CEE加载对每笔交易独立出具宪法收据CR
// 参与即是共识CN辖区节点加载此插件参与出块即代表对中国大陆辖区宪法规则的背书
use serde::{Deserialize, Serialize};
/// 中国大陆辖区交易上下文
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CNTxContext {
pub from: [u8; 32],
pub to: [u8; 32],
pub amount: u128,
pub asset_type: String,
pub kyc_level: KycLevel,
pub aml_cleared: bool,
pub regulatory_approved: bool,
pub is_cross_border: bool,
pub sanctions_cleared: bool,
}
/// KYC等级
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum KycLevel {
None,
Basic,
Enhanced,
Institutional,
}
/// 宪法收据CR— 参与即是共识节点出具CR即代表对规则的背书
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConstitutionalReceipt {
pub jurisdiction: String,
pub tx_hash: Vec<u8>,
pub rules_passed: Vec<String>,
pub timestamp: u64,
pub plugin_version: String,
}
/// 宪法规则违反错误
#[derive(Debug, Clone)]
pub struct ConstitutionalViolation {
pub rule_id: String,
pub reason: String,
}
/// 中国大陆辖区宪法规则验证器
pub struct CNConstitutionalValidator;
impl CNConstitutionalValidator {
pub fn new() -> Self {
Self
}
/// 验证交易是否符合中国大陆辖区宪法规则
/// CBPP参与即是共识节点调用此函数即代表对规则的背书
pub fn validate(&self, ctx: &CNTxContext) -> Result<ConstitutionalReceipt, ConstitutionalViolation> {
let mut rules_passed = Vec::new();
// 继承GLOBAL规则验证
self.validate_global_aml(ctx, &mut rules_passed)?;
self.validate_global_kyc(ctx, &mut rules_passed)?;
self.validate_global_sanctions(ctx, &mut rules_passed)?;
// 中国大陆辖区特定规则验证
self.validate_cn_cn_crypto_001(ctx, &mut rules_passed)?;
self.validate_cn_cn_sec_001(ctx, &mut rules_passed)?;
self.validate_cn_cn_forex_001(ctx, &mut rules_passed)?;
self.validate_cn_cn_rwa_001(ctx, &mut rules_passed)?;
Ok(ConstitutionalReceipt {
jurisdiction: "CN".to_string(),
tx_hash: vec![],
rules_passed,
timestamp: 0,
plugin_version: "v1.0".to_string(),
})
}
fn validate_global_aml(&self, ctx: &CNTxContext, passed: &mut Vec<String>)
-> Result<(), ConstitutionalViolation> {
if !ctx.aml_cleared {
return Err(ConstitutionalViolation {
rule_id: "GLOBAL_AML_001".to_string(),
reason: "AML检查未通过".to_string(),
});
}
passed.push("GLOBAL_AML_001".to_string());
Ok(())
}
fn validate_global_kyc(&self, ctx: &CNTxContext, passed: &mut Vec<String>)
-> Result<(), ConstitutionalViolation> {
if ctx.kyc_level == KycLevel::None {
return Err(ConstitutionalViolation {
rule_id: "GLOBAL_KYC_001".to_string(),
reason: "未完成KYC验证".to_string(),
});
}
passed.push("GLOBAL_KYC_001".to_string());
Ok(())
}
fn validate_global_sanctions(&self, ctx: &CNTxContext, passed: &mut Vec<String>)
-> Result<(), ConstitutionalViolation> {
if !ctx.sanctions_cleared {
return Err(ConstitutionalViolation {
rule_id: "GLOBAL_SANCTIONS".to_string(),
reason: "制裁名单检查未通过".to_string(),
});
}
passed.push("GLOBAL_SANCTIONS".to_string());
Ok(())
}
fn validate_cn_cn_crypto_001(&self, ctx: &CNTxContext, passed: &mut Vec<String>)
-> Result<(), ConstitutionalViolation> {
if ctx.asset_type == "CRYPTOCURRENCY" {
return Err(ConstitutionalViolation {
rule_id: "CN_CRYPTO_001".to_string(),
reason: "中国大陆禁止虚拟货币交易".to_string(),
});
}
passed.push("CN_CRYPTO_001".to_string());
Ok(())
}
fn validate_cn_cn_sec_001(&self, ctx: &CNTxContext, passed: &mut Vec<String>)
-> Result<(), ConstitutionalViolation> {
if !ctx.regulatory_approved {
return Err(ConstitutionalViolation {
rule_id: "CN_SEC_001".to_string(),
reason: "证券型代币须经CSRC核准".to_string(),
});
}
passed.push("CN_SEC_001".to_string());
Ok(())
}
fn validate_cn_cn_forex_001(&self, ctx: &CNTxContext, passed: &mut Vec<String>)
-> Result<(), ConstitutionalViolation> {
if ctx.is_cross_border && !ctx.regulatory_approved {
return Err(ConstitutionalViolation {
rule_id: "CN_FOREX_001".to_string(),
reason: "跨境资金流动须SAFE批准".to_string(),
});
}
passed.push("CN_FOREX_001".to_string());
Ok(())
}
fn validate_cn_cn_rwa_001(&self, ctx: &CNTxContext, passed: &mut Vec<String>)
-> Result<(), ConstitutionalViolation> {
if ctx.kyc_level == KycLevel::Basic {
return Err(ConstitutionalViolation {
rule_id: "CN_RWA_001".to_string(),
reason: "RWA通证化仅限合格投资者须Enhanced或Institutional级别KYC".to_string(),
});
}
passed.push("CN_RWA_001".to_string());
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_valid_ctx() -> CNTxContext {
CNTxContext {
from: [1u8; 32],
to: [2u8; 32],
amount: 1000,
asset_type: "REAL_ESTATE".to_string(),
kyc_level: KycLevel::Enhanced,
aml_cleared: true,
regulatory_approved: true,
is_cross_border: false,
sanctions_cleared: true,
}
}
#[test]
fn test_valid_transaction() {
let validator = CNConstitutionalValidator::new();
let ctx = make_valid_ctx();
let result = validator.validate(&ctx);
assert!(result.is_ok(), "合规交易应通过验证");
let cr = result.unwrap();
assert_eq!(cr.jurisdiction, "CN");
assert!(!cr.rules_passed.is_empty());
}
#[test]
fn test_aml_violation() {
let validator = CNConstitutionalValidator::new();
let mut ctx = make_valid_ctx();
ctx.aml_cleared = false;
let result = validator.validate(&ctx);
assert!(result.is_err());
assert_eq!(result.unwrap_err().rule_id, "GLOBAL_AML_001");
}
#[test]
fn test_kyc_violation() {
let validator = CNConstitutionalValidator::new();
let mut ctx = make_valid_ctx();
ctx.kyc_level = KycLevel::None;
let result = validator.validate(&ctx);
assert!(result.is_err());
assert_eq!(result.unwrap_err().rule_id, "GLOBAL_KYC_001");
}
#[test]
fn test_sanctions_violation() {
let validator = CNConstitutionalValidator::new();
let mut ctx = make_valid_ctx();
ctx.sanctions_cleared = false;
let result = validator.validate(&ctx);
assert!(result.is_err());
assert_eq!(result.unwrap_err().rule_id, "GLOBAL_SANCTIONS");
}
#[test]
fn test_regulatory_approval_required() {
let validator = CNConstitutionalValidator::new();
let mut ctx = make_valid_ctx();
ctx.regulatory_approved = false;
let result = validator.validate(&ctx);
// 大多数辖区要求监管批准,此处验证是否有对应规则拦截
// 具体规则ID因辖区而异
let _ = result; // 不同辖区可能有不同的第一个失败规则
}
}