225 lines
7.4 KiB
Rust
225 lines
7.4 KiB
Rust
//! 宪法收据(Constitutional Receipt, CR)
|
||
//!
|
||
//! CBPP 共识的核心凭证。每笔交易在上链前必须由宪法执行引擎(CEE)
|
||
//! 签发 CR,节点只需验证 CR 的有效性(签名、宪法哈希、时间窗口),
|
||
//! 无需投票或协商——这是 CBPP 与 PoW/PoS/BFT 的根本区别。
|
||
//!
|
||
//! # CBPP 共识原则
|
||
//! - 参与即共识:节点遵守规则的行为本身就是共识,无需额外投票
|
||
//! - 规则服从 vs 协商共识:CBPP 是规则验证而非节点协商
|
||
//! - 宪法收据(CR):交易合法性的唯一证明,由 CEE 签发
|
||
|
||
use chrono::{DateTime, Utc};
|
||
use serde::{Deserialize, Serialize};
|
||
use sha3::{Digest, Sha3_384};
|
||
|
||
/// 宪法收据(Constitutional Receipt)
|
||
///
|
||
/// 每笔交易的合法性证明,包含交易哈希、宪法哈希、执行结果哈希、CEE 签名。
|
||
/// 节点通过验证 CR 来确认交易合法,无需投票。
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct ConstitutionalReceipt {
|
||
/// 收据 ID(唯一标识)
|
||
pub receipt_id: String,
|
||
/// 交易哈希(SHA3-384,48 字节)
|
||
pub tx_hash: String,
|
||
/// 宪法哈希(当前生效的宪法版本哈希)
|
||
pub constitution_hash: String,
|
||
/// 执行结果哈希(CEE 执行后的状态哈希)
|
||
pub execution_result_hash: String,
|
||
/// CEE 签名(宪法执行引擎的签名)
|
||
pub cee_signature: String,
|
||
/// 签发时间
|
||
pub issued_at: DateTime<Utc>,
|
||
/// 有效期截止时间(时间窗口)
|
||
pub expires_at: DateTime<Utc>,
|
||
/// 收据权重(用于分叉选择的收据权重累计)
|
||
pub weight: u64,
|
||
/// 合规等级(1-5,影响权重)
|
||
pub compliance_level: u8,
|
||
/// 资产类型(GNACS 编码)
|
||
pub asset_gnacs_code: Option<String>,
|
||
}
|
||
|
||
impl ConstitutionalReceipt {
|
||
/// 创建新的宪法收据
|
||
pub fn new(
|
||
tx_hash: String,
|
||
constitution_hash: String,
|
||
execution_result_hash: String,
|
||
cee_signature: String,
|
||
compliance_level: u8,
|
||
asset_gnacs_code: Option<String>,
|
||
) -> Self {
|
||
let issued_at = Utc::now();
|
||
// 收据有效期:10 分钟时间窗口
|
||
let expires_at = issued_at + chrono::Duration::minutes(10);
|
||
let weight = Self::calculate_weight(compliance_level);
|
||
let receipt_id = Self::generate_id(&tx_hash, &constitution_hash, &issued_at);
|
||
|
||
ConstitutionalReceipt {
|
||
receipt_id,
|
||
tx_hash,
|
||
constitution_hash,
|
||
execution_result_hash,
|
||
cee_signature,
|
||
issued_at,
|
||
expires_at,
|
||
weight,
|
||
compliance_level,
|
||
asset_gnacs_code,
|
||
}
|
||
}
|
||
|
||
/// 计算收据权重
|
||
///
|
||
/// 权重基于合规等级,用于分叉选择时的收据权重累计。
|
||
/// 高合规等级的交易权重更高,鼓励合规行为。
|
||
pub fn calculate_weight(compliance_level: u8) -> u64 {
|
||
match compliance_level {
|
||
1 => 100, // 基础合规
|
||
2 => 200, // 标准合规
|
||
3 => 400, // 增强合规
|
||
4 => 700, // 高级合规
|
||
5 => 1000, // 最高合规(机构级)
|
||
_ => 50, // 未知等级,最低权重
|
||
}
|
||
}
|
||
|
||
/// 生成收据 ID
|
||
fn generate_id(tx_hash: &str, constitution_hash: &str, issued_at: &DateTime<Utc>) -> String {
|
||
let data = format!("{}{}{}CR", tx_hash, constitution_hash, issued_at.timestamp_nanos_opt().unwrap_or(0));
|
||
let hash = Sha3_384::digest(data.as_bytes());
|
||
format!("CR-{}", hex::encode(&hash[..16]))
|
||
}
|
||
|
||
/// 验证 CR 是否在有效时间窗口内
|
||
pub fn is_valid_time_window(&self) -> bool {
|
||
let now = Utc::now();
|
||
now >= self.issued_at && now <= self.expires_at
|
||
}
|
||
|
||
/// 验证 CR 签名(简化版,实际应使用 BLS 签名验证)
|
||
pub fn verify_signature(&self) -> bool {
|
||
// 实际实现中需要使用 CEE 公钥验证 BLS 签名
|
||
// 此处为结构占位,真实验证由 CeeSignatureVerifier 完成
|
||
!self.cee_signature.is_empty()
|
||
}
|
||
|
||
/// 验证宪法哈希是否匹配当前生效宪法
|
||
pub fn verify_constitution_hash(&self, current_constitution_hash: &str) -> bool {
|
||
self.constitution_hash == current_constitution_hash
|
||
}
|
||
|
||
/// 完整验证 CR(签名 + 时间窗口 + 宪法哈希)
|
||
pub fn verify(&self, current_constitution_hash: &str) -> CrVerificationResult {
|
||
if !self.verify_signature() {
|
||
return CrVerificationResult::InvalidSignature;
|
||
}
|
||
if !self.is_valid_time_window() {
|
||
return CrVerificationResult::Expired;
|
||
}
|
||
if !self.verify_constitution_hash(current_constitution_hash) {
|
||
return CrVerificationResult::ConstitutionMismatch;
|
||
}
|
||
CrVerificationResult::Valid
|
||
}
|
||
}
|
||
|
||
/// CR 验证结果
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
pub enum CrVerificationResult {
|
||
/// 验证通过
|
||
Valid,
|
||
/// 签名无效(CEE 签名不匹配)
|
||
InvalidSignature,
|
||
/// 已过期(超出时间窗口)
|
||
Expired,
|
||
/// 宪法哈希不匹配(宪法已更新)
|
||
ConstitutionMismatch,
|
||
}
|
||
|
||
/// CR 集合(一个区块内的所有宪法收据)
|
||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||
pub struct ReceiptSet {
|
||
/// 收据列表
|
||
receipts: Vec<ConstitutionalReceipt>,
|
||
/// 总权重(用于分叉选择)
|
||
total_weight: u64,
|
||
}
|
||
|
||
impl ReceiptSet {
|
||
pub fn new() -> Self {
|
||
Self::default()
|
||
}
|
||
|
||
/// 添加已验证的 CR
|
||
pub fn add_receipt(&mut self, receipt: ConstitutionalReceipt) {
|
||
self.total_weight += receipt.weight;
|
||
self.receipts.push(receipt);
|
||
}
|
||
|
||
/// 获取总权重(分叉选择时使用)
|
||
pub fn total_weight(&self) -> u64 {
|
||
self.total_weight
|
||
}
|
||
|
||
/// 获取收据数量
|
||
pub fn len(&self) -> usize {
|
||
self.receipts.len()
|
||
}
|
||
|
||
/// 是否为空
|
||
pub fn is_empty(&self) -> bool {
|
||
self.receipts.is_empty()
|
||
}
|
||
|
||
/// 获取所有收据
|
||
pub fn receipts(&self) -> &[ConstitutionalReceipt] {
|
||
&self.receipts
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_cr_creation() {
|
||
let cr = ConstitutionalReceipt::new(
|
||
"tx_hash_001".to_string(),
|
||
"constitution_hash_v1".to_string(),
|
||
"exec_result_hash".to_string(),
|
||
"cee_signature_001".to_string(),
|
||
3,
|
||
Some("RE01".to_string()),
|
||
);
|
||
assert!(cr.receipt_id.starts_with("CR-"));
|
||
assert_eq!(cr.weight, 400); // 合规等级 3 → 权重 400
|
||
}
|
||
|
||
#[test]
|
||
fn test_cr_weight_calculation() {
|
||
assert_eq!(ConstitutionalReceipt::calculate_weight(1), 100);
|
||
assert_eq!(ConstitutionalReceipt::calculate_weight(3), 400);
|
||
assert_eq!(ConstitutionalReceipt::calculate_weight(5), 1000);
|
||
}
|
||
|
||
#[test]
|
||
fn test_receipt_set_weight() {
|
||
let mut set = ReceiptSet::new();
|
||
let cr1 = ConstitutionalReceipt::new(
|
||
"tx1".to_string(), "ch1".to_string(), "er1".to_string(),
|
||
"sig1".to_string(), 3, None,
|
||
);
|
||
let cr2 = ConstitutionalReceipt::new(
|
||
"tx2".to_string(), "ch1".to_string(), "er2".to_string(),
|
||
"sig2".to_string(), 5, None,
|
||
);
|
||
set.add_receipt(cr1);
|
||
set.add_receipt(cr2);
|
||
assert_eq!(set.total_weight(), 1400); // 400 + 1000
|
||
assert_eq!(set.len(), 2);
|
||
}
|
||
}
|