404 lines
12 KiB
Rust
404 lines
12 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)
|
|
.expect("mainnet: handle error")
|
|
.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)
|
|
.expect("mainnet: handle error")
|
|
.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).expect("mainnet: handle error");
|
|
tracker.record_proposal(&version, &Address::zero()).expect("mainnet: handle error");
|
|
|
|
let filter = HistoryFilter {
|
|
record_type: Some(HistoryRecordType::VersionCreated),
|
|
..Default::default()
|
|
};
|
|
|
|
let results = tracker.query(filter).expect("mainnet: handle error");
|
|
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)).expect("mainnet: handle error");
|
|
tracker.record_version(&create_test_version(2)).expect("mainnet: handle error");
|
|
|
|
let filter = HistoryFilter {
|
|
version: Some(1),
|
|
..Default::default()
|
|
};
|
|
|
|
let results = tracker.query(filter).expect("mainnet: handle error");
|
|
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).expect("mainnet: handle error");
|
|
|
|
let logs = tracker.get_audit_log(1, 1).expect("mainnet: handle error");
|
|
assert_eq!(logs.len(), 1);
|
|
assert_eq!(logs[0].id, 1);
|
|
}
|
|
}
|