NAC_Blockchain/nac-bridge-ethereum/src/security.rs

287 lines
7.8 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.

//! 安全机制模块
use crate::error::{BridgeError, BridgeResult};
use chrono::Datelike;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// 安全配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityConfig {
/// 单笔交易上限
pub max_transaction_amount: u128,
/// 每日交易上限
pub daily_limit: u128,
/// 是否暂停
pub paused: bool,
/// 紧急提款启用
pub emergency_withdrawal_enabled: bool,
/// 审计日志启用
pub audit_log_enabled: bool,
}
impl Default for SecurityConfig {
fn default() -> Self {
Self {
max_transaction_amount: 1_000_000_000_000_000_000, // 1 ETH
daily_limit: 10_000_000_000_000_000_000, // 10 ETH
paused: false,
emergency_withdrawal_enabled: true,
audit_log_enabled: true,
}
}
}
/// 审计日志条目
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditLogEntry {
/// 日志ID
pub log_id: String,
/// 操作类型
pub operation: String,
/// 操作者
pub operator: String,
/// 时间戳
pub timestamp: u64,
/// 详细信息
pub details: HashMap<String, String>,
/// 结果
pub result: OperationResult,
}
/// 操作结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OperationResult {
/// 成功
Success,
/// 失败
Failure(String),
}
/// 每日交易统计
#[derive(Debug, Clone)]
struct DailyStats {
/// 日期YYYYMMDD
date: u32,
/// 总金额
total_amount: u128,
}
/// 安全管理器
pub struct SecurityManager {
/// 安全配置
config: SecurityConfig,
/// 审计日志
audit_logs: Vec<AuditLogEntry>,
/// 每日统计
daily_stats: HashMap<String, DailyStats>,
}
impl SecurityManager {
/// 创建新的安全管理器
pub fn new(config: SecurityConfig) -> Self {
Self {
config,
audit_logs: Vec::new(),
daily_stats: HashMap::new(),
}
}
/// 检查是否暂停
pub fn is_paused(&self) -> bool {
self.config.paused
}
/// 暂停桥接
pub fn pause(&mut self, operator: &str) -> BridgeResult<()> {
if self.config.paused {
return Err(BridgeError::SecurityError(
"Bridge already paused".to_string()
));
}
self.config.paused = true;
self.log_operation(AuditLogEntry {
log_id: format!("pause_{}", chrono::Utc::now().timestamp()),
operation: "pause".to_string(),
operator: operator.to_string(),
timestamp: chrono::Utc::now().timestamp() as u64,
details: HashMap::new(),
result: OperationResult::Success,
});
Ok(())
}
/// 恢复桥接
pub fn unpause(&mut self, operator: &str) -> BridgeResult<()> {
if !self.config.paused {
return Err(BridgeError::SecurityError(
"Bridge not paused".to_string()
));
}
self.config.paused = false;
self.log_operation(AuditLogEntry {
log_id: format!("unpause_{}", chrono::Utc::now().timestamp()),
operation: "unpause".to_string(),
operator: operator.to_string(),
timestamp: chrono::Utc::now().timestamp() as u64,
details: HashMap::new(),
result: OperationResult::Success,
});
Ok(())
}
/// 验证交易金额
pub fn validate_amount(&mut self, amount: u128, token: &str) -> BridgeResult<()> {
// 检查单笔上限
if amount > self.config.max_transaction_amount {
return Err(BridgeError::SecurityError(
format!("Amount exceeds max transaction limit: {} > {}",
amount, self.config.max_transaction_amount)
));
}
// 检查每日限额
let today = self.get_today();
let stats = self.daily_stats.entry(token.to_string())
.or_insert(DailyStats {
date: today,
total_amount: 0,
});
// 如果是新的一天,重置统计
if stats.date != today {
stats.date = today;
stats.total_amount = 0;
}
if stats.total_amount + amount > self.config.daily_limit {
return Err(BridgeError::SecurityError(
format!("Amount exceeds daily limit: {} + {} > {}",
stats.total_amount, amount, self.config.daily_limit)
));
}
// 更新统计
stats.total_amount += amount;
Ok(())
}
/// 紧急提款
pub fn emergency_withdraw(
&mut self,
operator: &str,
amount: u128,
destination: &str,
) -> BridgeResult<()> {
if !self.config.emergency_withdrawal_enabled {
return Err(BridgeError::SecurityError(
"Emergency withdrawal not enabled".to_string()
));
}
let mut details = HashMap::new();
details.insert("amount".to_string(), amount.to_string());
details.insert("destination".to_string(), destination.to_string());
self.log_operation(AuditLogEntry {
log_id: format!("emergency_withdraw_{}", chrono::Utc::now().timestamp()),
operation: "emergency_withdraw".to_string(),
operator: operator.to_string(),
timestamp: chrono::Utc::now().timestamp() as u64,
details,
result: OperationResult::Success,
});
Ok(())
}
/// 记录审计日志
pub fn log_operation(&mut self, entry: AuditLogEntry) {
if self.config.audit_log_enabled {
self.audit_logs.push(entry);
}
}
/// 查询审计日志
pub fn query_audit_logs(&self, operation: Option<&str>, operator: Option<&str>) -> Vec<&AuditLogEntry> {
self.audit_logs.iter()
.filter(|entry| {
if let Some(op) = operation {
if entry.operation != op {
return false;
}
}
if let Some(opr) = operator {
if entry.operator != opr {
return false;
}
}
true
})
.collect()
}
/// 获取今天的日期YYYYMMDD
fn get_today(&self) -> u32 {
let now = chrono::Utc::now();
(now.year() as u32) * 10000 + (now.month() * 100) + now.day()
}
/// 获取配置
pub fn config(&self) -> &SecurityConfig {
&self.config
}
/// 更新配置
pub fn update_config(&mut self, config: SecurityConfig) {
self.config = config;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pause_unpause() {
let mut manager = SecurityManager::new(SecurityConfig::default());
assert!(!manager.is_paused());
assert!(manager.pause("admin").is_ok());
assert!(manager.is_paused());
assert!(manager.unpause("admin").is_ok());
assert!(!manager.is_paused());
}
#[test]
fn test_validate_amount() {
let mut manager = SecurityManager::new(SecurityConfig::default());
// 测试单笔上限
let result = manager.validate_amount(2_000_000_000_000_000_000, "ETH");
assert!(result.is_err());
// 测试正常金额
let result = manager.validate_amount(500_000_000_000_000_000, "ETH");
assert!(result.is_ok());
}
#[test]
fn test_audit_log() {
let mut manager = SecurityManager::new(SecurityConfig::default());
manager.pause("admin").unwrap();
let logs = manager.query_audit_logs(Some("pause"), None);
assert_eq!(logs.len(), 1);
assert_eq!(logs[0].operator, "admin");
}
}