NAC_Blockchain/nac-constitution-state/src/history.rs

404 lines
11 KiB
Rust

//! 宪法历史追踪模块
use crate::{ConstitutionVersion, Result, Error};
use nac_udm::primitives::Address;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use std::fs;
/// 历史记录类型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum HistoryRecordType {
/// 版本创建
VersionCreated,
/// 升级提议
UpgradeProposed,
/// 升级执行
UpgradeExecuted,
/// 升级取消
UpgradeCancelled,
/// 版本回滚
VersionRolledBack,
}
/// 历史记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryRecord {
/// 记录类型
pub record_type: HistoryRecordType,
/// 版本号
pub version: u64,
/// 操作者地址
pub operator: Address,
/// 时间戳
pub timestamp: u64,
/// 区块高度
pub block_height: u64,
/// 描述
pub description: String,
}
/// 审计日志
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditLog {
/// 日志ID
pub id: u64,
/// 历史记录
pub record: HistoryRecord,
/// 额外数据
pub extra_data: String,
}
/// 历史查询过滤器
#[derive(Debug, Clone)]
pub struct HistoryFilter {
/// 记录类型过滤
pub record_type: Option<HistoryRecordType>,
/// 版本号过滤
pub version: Option<u64>,
/// 操作者过滤
pub operator: Option<Address>,
/// 时间范围过滤(开始)
pub time_from: Option<u64>,
/// 时间范围过滤(结束)
pub time_to: Option<u64>,
/// 区块高度范围过滤(开始)
pub block_from: Option<u64>,
/// 区块高度范围过滤(结束)
pub block_to: Option<u64>,
}
impl Default for HistoryFilter {
fn default() -> Self {
Self {
record_type: None,
version: None,
operator: None,
time_from: None,
time_to: None,
block_from: None,
block_to: None,
}
}
}
/// 历史追踪器
pub struct HistoryTracker {
/// 历史记录列表
records: Vec<HistoryRecord>,
/// 审计日志列表
audit_logs: Vec<AuditLog>,
/// 存储路径
storage_path: PathBuf,
/// 下一个日志ID
next_log_id: u64,
}
impl HistoryTracker {
/// 创建新的历史追踪器
pub fn new() -> Self {
let temp_path = std::env::temp_dir().join("nac_history_test.json");
Self {
records: Vec::new(),
audit_logs: Vec::new(),
storage_path: temp_path,
next_log_id: 1,
}
}
/// 从存储加载历史追踪器
pub fn load(storage_path: &Path) -> Result<Self> {
let history_path = storage_path.join("history.json");
if !history_path.exists() {
return Ok(Self {
records: Vec::new(),
audit_logs: Vec::new(),
storage_path: history_path,
next_log_id: 1,
});
}
let json = fs::read_to_string(&history_path)
.map_err(|e| Error::StorageError(format!("读取历史文件失败: {}", e)))?;
let (records, audit_logs, next_log_id) = serde_json::from_str(&json)
.map_err(|e| Error::StorageError(format!("反序列化历史失败: {}", e)))?;
Ok(Self {
records,
audit_logs,
storage_path: history_path,
next_log_id,
})
}
/// 保存历史记录
fn save(&self) -> Result<()> {
if let Some(parent) = self.storage_path.parent() {
fs::create_dir_all(parent)
.map_err(|e| Error::StorageError(format!("创建目录失败: {}", e)))?;
}
let data = (&self.records, &self.audit_logs, self.next_log_id);
let json = serde_json::to_string_pretty(&data)
.map_err(|e| Error::StorageError(format!("序列化历史失败: {}", e)))?;
fs::write(&self.storage_path, json)
.map_err(|e| Error::StorageError(format!("写入历史文件失败: {}", e)))?;
Ok(())
}
/// 记录版本创建
pub fn record_version(&mut self, version: &ConstitutionVersion) -> Result<()> {
let record = HistoryRecord {
record_type: HistoryRecordType::VersionCreated,
version: version.version,
operator: version.created_by,
timestamp: version.created_at,
block_height: version.effective_from,
description: format!("创建版本: {}", version.description),
};
self.add_record(record, String::new())?;
Ok(())
}
/// 记录升级提议
pub fn record_proposal(&mut self, version: &ConstitutionVersion, proposer: &Address) -> Result<()> {
let record = HistoryRecord {
record_type: HistoryRecordType::UpgradeProposed,
version: version.version,
operator: *proposer,
timestamp: version.created_at,
block_height: version.effective_from,
description: format!("提议升级到版本{}: {}", version.version, version.description),
};
self.add_record(record, String::new())?;
Ok(())
}
/// 记录升级执行
pub fn record_upgrade(&mut self, version: &ConstitutionVersion, block_height: u64) -> Result<()> {
let record = HistoryRecord {
record_type: HistoryRecordType::UpgradeExecuted,
version: version.version,
operator: version.created_by,
timestamp: version.created_at,
block_height,
description: format!("执行升级到版本{}", version.version),
};
self.add_record(record, String::new())?;
Ok(())
}
/// 记录升级取消
pub fn record_cancellation(&mut self, version: &ConstitutionVersion, canceller: &Address) -> Result<()> {
let record = HistoryRecord {
record_type: HistoryRecordType::UpgradeCancelled,
version: version.version,
operator: *canceller,
timestamp: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs(),
block_height: 0,
description: format!("取消升级到版本{}", version.version),
};
self.add_record(record, String::new())?;
Ok(())
}
/// 记录版本回滚
pub fn record_rollback(&mut self, version: &ConstitutionVersion, operator: &Address) -> Result<()> {
let record = HistoryRecord {
record_type: HistoryRecordType::VersionRolledBack,
version: version.version,
operator: *operator,
timestamp: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs(),
block_height: 0,
description: format!("回滚到版本{}", version.version),
};
self.add_record(record, String::new())?;
Ok(())
}
/// 添加记录
fn add_record(&mut self, record: HistoryRecord, extra_data: String) -> Result<()> {
let audit_log = AuditLog {
id: self.next_log_id,
record: record.clone(),
extra_data,
};
self.records.push(record);
self.audit_logs.push(audit_log);
self.next_log_id += 1;
self.save()?;
Ok(())
}
/// 查询历史记录
pub fn query(&self, filter: HistoryFilter) -> Result<Vec<HistoryRecord>> {
let mut results = Vec::new();
for record in &self.records {
// 应用过滤器
if let Some(ref record_type) = filter.record_type {
if &record.record_type != record_type {
continue;
}
}
if let Some(version) = filter.version {
if record.version != version {
continue;
}
}
if let Some(operator) = filter.operator {
if record.operator != operator {
continue;
}
}
if let Some(time_from) = filter.time_from {
if record.timestamp < time_from {
continue;
}
}
if let Some(time_to) = filter.time_to {
if record.timestamp > time_to {
continue;
}
}
if let Some(block_from) = filter.block_from {
if record.block_height < block_from {
continue;
}
}
if let Some(block_to) = filter.block_to {
if record.block_height > block_to {
continue;
}
}
results.push(record.clone());
}
Ok(results)
}
/// 获取审计日志
pub fn get_audit_log(&self, from: u64, to: u64) -> Result<Vec<AuditLog>> {
let logs = self.audit_logs
.iter()
.filter(|log| log.id >= from && log.id <= to)
.cloned()
.collect();
Ok(logs)
}
/// 获取所有记录
pub fn get_all_records(&self) -> &[HistoryRecord] {
&self.records
}
/// 获取记录数量
pub fn record_count(&self) -> usize {
self.records.len()
}
}
impl Default for HistoryTracker {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use nac_udm::primitives::Hash;
fn create_test_version(version: u64) -> ConstitutionVersion {
ConstitutionVersion::new(
version,
Hash::zero(),
version * 1000,
10,
version * 100,
Address::zero(),
format!("Version {}", version),
)
}
#[test]
fn test_record_version() {
let mut tracker = HistoryTracker::new();
let version = create_test_version(1);
assert!(tracker.record_version(&version).is_ok());
assert_eq!(tracker.record_count(), 1);
}
#[test]
fn test_query_by_type() {
let mut tracker = HistoryTracker::new();
let version = create_test_version(1);
tracker.record_version(&version).unwrap();
tracker.record_proposal(&version, &Address::zero()).unwrap();
let filter = HistoryFilter {
record_type: Some(HistoryRecordType::VersionCreated),
..Default::default()
};
let results = tracker.query(filter).unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0].record_type, HistoryRecordType::VersionCreated);
}
#[test]
fn test_query_by_version() {
let mut tracker = HistoryTracker::new();
tracker.record_version(&create_test_version(1)).unwrap();
tracker.record_version(&create_test_version(2)).unwrap();
let filter = HistoryFilter {
version: Some(1),
..Default::default()
};
let results = tracker.query(filter).unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0].version, 1);
}
#[test]
fn test_audit_log() {
let mut tracker = HistoryTracker::new();
let version = create_test_version(1);
tracker.record_version(&version).unwrap();
let logs = tracker.get_audit_log(1, 1).unwrap();
assert_eq!(logs.len(), 1);
assert_eq!(logs[0].id, 1);
}
}