NAC_Blockchain/nac-upgrade-framework/src/helpers.rs

169 lines
5.5 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.

//! 升级实现助手模块
//!
//! 提供通用的升级实现辅助函数和宏
/// 为模块生成基础的Upgradeable实现
#[macro_export]
macro_rules! impl_upgradeable {
($struct_name:ident, $module_name:expr, $initial_version:expr) => {
impl $crate::traits::Upgradeable for $struct_name {
fn module_name(&self) -> &str {
$module_name
}
fn current_version(&self) -> $crate::Version {
self.version.clone()
}
fn can_upgrade_to(&self, target: &$crate::Version) -> $crate::Result<bool> {
if !self.version.can_upgrade_to(target) {
return Err($crate::UpgradeError::DowngradeNotAllowed {
from: self.version.to_string(),
to: target.to_string(),
});
}
Ok(true)
}
fn upgrade(&mut self, target: $crate::Version, data: $crate::UpgradeData) -> $crate::Result<()> {
// 检查是否可以升级
self.can_upgrade_to(&target)?;
// 创建快照
let snapshot = self.create_snapshot()?;
// 执行升级
match self.do_upgrade(target.clone(), data) {
Ok(_) => {
// 记录升级历史
let record = $crate::UpgradeRecord::new(
self.upgrade_history.len() as u64 + 1,
$module_name.to_string(),
self.version.clone(),
target.clone(),
"system".to_string(),
);
let mut record = record;
record.mark_success(snapshot.snapshot_id.clone());
self.upgrade_history.push(record);
// 更新版本
self.version = target;
Ok(())
}
Err(e) => {
// 升级失败,回滚
self.rollback(snapshot)?;
Err(e)
}
}
}
fn create_snapshot(&self) -> $crate::Result<$crate::Snapshot> {
let state_data = serde_json::to_vec(&self)
.map_err(|e| $crate::UpgradeError::SerializationError(e))?;
Ok($crate::Snapshot::new(
$module_name.to_string(),
self.version.clone(),
state_data,
))
}
fn rollback(&mut self, snapshot: $crate::Snapshot) -> $crate::Result<()> {
let restored: Self = serde_json::from_slice(&snapshot.state_data)
.map_err(|e| $crate::UpgradeError::SerializationError(e))?;
*self = restored;
Ok(())
}
fn upgrade_history(&self) -> Vec<$crate::UpgradeRecord> {
self.upgrade_history.clone()
}
fn validate_state(&self) -> $crate::Result<bool> {
// 默认实现总是返回true
// 各模块可以override这个方法
Ok(true)
}
}
};
}
/// 为模块添加必要的升级字段
#[macro_export]
macro_rules! add_upgrade_fields {
() => {
/// 当前版本
pub version: $crate::Version,
/// 升级历史
pub upgrade_history: Vec<$crate::UpgradeRecord>,
};
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{traits::Upgradeable, UpgradeData, UpgradeRecord, Version};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
struct TestModule {
version: Version,
upgrade_history: Vec<UpgradeRecord>,
data: String,
}
impl TestModule {
fn new() -> Self {
Self {
version: Version::new(1, 0, 0),
upgrade_history: Vec::new(),
data: "initial".to_string(),
}
}
fn do_upgrade(&mut self, _target: Version, _data: UpgradeData) -> crate::Result<()> {
self.data = "upgraded".to_string();
Ok(())
}
}
impl_upgradeable!(TestModule, "test-module", Version::new(1, 0, 0));
#[test]
fn test_macro_generated_impl() {
let mut module = TestModule::new();
assert_eq!(module.module_name(), "test-module");
assert_eq!(module.current_version(), Version::new(1, 0, 0));
let target = Version::new(1, 1, 0);
let data = UpgradeData {
migration_script: None,
config_changes: HashMap::new(),
state_migrations: vec![],
breaking_changes: vec![],
};
assert!(module.upgrade(target.clone(), data).is_ok());
assert_eq!(module.current_version(), target);
assert_eq!(module.data, "upgraded");
assert_eq!(module.upgrade_history().len(), 1);
}
#[test]
fn test_snapshot_and_rollback() {
let mut module = TestModule::new();
module.data = "original".to_string();
let snapshot = module.create_snapshot().unwrap();
module.data = "modified".to_string();
assert_eq!(module.data, "modified");
module.rollback(snapshot).unwrap();
assert_eq!(module.data, "original");
}
}