435 lines
13 KiB
Rust
435 lines
13 KiB
Rust
//! Transfer Manager
|
|
//! 转账管理器 - 处理分区间转账和操作员授权
|
|
|
|
use crate::error::{Acc1410Error, Result};
|
|
use crate::partition::PartitionManager;
|
|
use crate::types::{TransferResult, TransferStatus};
|
|
use std::collections::{HashMap, HashSet};
|
|
|
|
/// 操作员授权管理器
|
|
#[derive(Debug)]
|
|
pub struct OperatorManager {
|
|
/// 全局操作员授权(账户 -> 操作员集合)
|
|
global_operators: HashMap<String, HashSet<String>>,
|
|
/// 分区级操作员授权(账户 -> 分区ID -> 操作员集合)
|
|
partition_operators: HashMap<String, HashMap<String, HashSet<String>>>,
|
|
}
|
|
|
|
impl OperatorManager {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
global_operators: HashMap::new(),
|
|
partition_operators: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
/// 授权全局操作员
|
|
pub fn authorize_operator(&mut self, account: &str, operator: &str) {
|
|
self.global_operators
|
|
.entry(account.to_string())
|
|
.or_insert_with(HashSet::new)
|
|
.insert(operator.to_string());
|
|
}
|
|
|
|
/// 撤销全局操作员
|
|
pub fn revoke_operator(&mut self, account: &str, operator: &str) {
|
|
if let Some(operators) = self.global_operators.get_mut(account) {
|
|
operators.remove(operator);
|
|
}
|
|
}
|
|
|
|
/// 授权分区级操作员
|
|
pub fn authorize_operator_by_partition(
|
|
&mut self,
|
|
account: &str,
|
|
partition_id: &[u8; 32],
|
|
operator: &str,
|
|
) {
|
|
let partition_id_hex = hex::encode(partition_id);
|
|
self.partition_operators
|
|
.entry(account.to_string())
|
|
.or_insert_with(HashMap::new)
|
|
.entry(partition_id_hex)
|
|
.or_insert_with(HashSet::new)
|
|
.insert(operator.to_string());
|
|
}
|
|
|
|
/// 撤销分区级操作员
|
|
pub fn revoke_operator_by_partition(
|
|
&mut self,
|
|
account: &str,
|
|
partition_id: &[u8; 32],
|
|
operator: &str,
|
|
) {
|
|
let partition_id_hex = hex::encode(partition_id);
|
|
if let Some(partitions) = self.partition_operators.get_mut(account) {
|
|
if let Some(operators) = partitions.get_mut(&partition_id_hex) {
|
|
operators.remove(operator);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 检查是否为全局操作员
|
|
pub fn is_operator_for(&self, account: &str, operator: &str) -> bool {
|
|
self.global_operators
|
|
.get(account)
|
|
.map(|ops| ops.contains(operator))
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
/// 检查是否为分区级操作员
|
|
pub fn is_operator_for_partition(
|
|
&self,
|
|
account: &str,
|
|
partition_id: &[u8; 32],
|
|
operator: &str,
|
|
) -> bool {
|
|
let partition_id_hex = hex::encode(partition_id);
|
|
self.partition_operators
|
|
.get(account)
|
|
.and_then(|partitions| partitions.get(&partition_id_hex))
|
|
.map(|ops| ops.contains(operator))
|
|
.unwrap_or(false)
|
|
}
|
|
}
|
|
|
|
impl Default for OperatorManager {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
/// 转账管理器
|
|
#[derive(Debug)]
|
|
pub struct TransferManager {
|
|
/// 分区管理器
|
|
partition_manager: PartitionManager,
|
|
/// 操作员管理器
|
|
operator_manager: OperatorManager,
|
|
/// 转账是否暂停
|
|
transfers_halted: bool,
|
|
/// 账户锁定期(账户 -> 解锁时间戳)
|
|
account_locks: HashMap<String, u64>,
|
|
}
|
|
|
|
impl TransferManager {
|
|
pub fn new(partition_manager: PartitionManager) -> Self {
|
|
Self {
|
|
partition_manager,
|
|
operator_manager: OperatorManager::new(),
|
|
transfers_halted: false,
|
|
account_locks: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
/// 获取分区管理器的引用
|
|
pub fn partition_manager(&self) -> &PartitionManager {
|
|
&self.partition_manager
|
|
}
|
|
|
|
/// 获取分区管理器的可变引用
|
|
pub fn partition_manager_mut(&mut self) -> &mut PartitionManager {
|
|
&mut self.partition_manager
|
|
}
|
|
|
|
/// 获取操作员管理器的引用
|
|
pub fn operator_manager(&self) -> &OperatorManager {
|
|
&self.operator_manager
|
|
}
|
|
|
|
/// 获取操作员管理器的可变引用
|
|
pub fn operator_manager_mut(&mut self) -> &mut OperatorManager {
|
|
&mut self.operator_manager
|
|
}
|
|
|
|
/// 暂停所有转账
|
|
pub fn halt_transfers(&mut self) {
|
|
self.transfers_halted = true;
|
|
}
|
|
|
|
/// 恢复转账
|
|
pub fn resume_transfers(&mut self) {
|
|
self.transfers_halted = false;
|
|
}
|
|
|
|
/// 锁定账户
|
|
pub fn lock_account(&mut self, account: &str, unlock_time: u64) {
|
|
self.account_locks.insert(account.to_string(), unlock_time);
|
|
}
|
|
|
|
/// 解锁账户
|
|
pub fn unlock_account(&mut self, account: &str) {
|
|
self.account_locks.remove(account);
|
|
}
|
|
|
|
/// 检查账户是否被锁定
|
|
fn is_account_locked(&self, account: &str) -> Option<u64> {
|
|
self.account_locks.get(account).copied().and_then(|unlock_time| {
|
|
let now = Self::current_timestamp();
|
|
if now < unlock_time {
|
|
Some(unlock_time)
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
}
|
|
|
|
/// 分区间转账
|
|
pub fn transfer_by_partition(
|
|
&mut self,
|
|
from: &str,
|
|
to: &str,
|
|
amount: u64,
|
|
partition_id: &[u8; 32],
|
|
) -> Result<TransferResult> {
|
|
// 预检查
|
|
self.pre_transfer_check(from, to, partition_id)?;
|
|
|
|
// 执行转账
|
|
self.partition_manager.sub_balance(partition_id, from, amount)?;
|
|
self.partition_manager.add_balance(partition_id, to, amount)?;
|
|
|
|
Ok(TransferResult {
|
|
status: TransferStatus::Success,
|
|
reason: None,
|
|
destination_partition: Some(*partition_id),
|
|
})
|
|
}
|
|
|
|
/// 操作员代理转账
|
|
pub fn operator_transfer_by_partition(
|
|
&mut self,
|
|
operator: &str,
|
|
from: &str,
|
|
to: &str,
|
|
amount: u64,
|
|
partition_id: &[u8; 32],
|
|
) -> Result<TransferResult> {
|
|
// 检查操作员权限
|
|
if !self.operator_manager.is_operator_for(from, operator)
|
|
&& !self.operator_manager.is_operator_for_partition(from, partition_id, operator)
|
|
{
|
|
return Err(Acc1410Error::UnauthorizedOperator {
|
|
operator: operator.to_string(),
|
|
account: from.to_string(),
|
|
});
|
|
}
|
|
|
|
// 预检查
|
|
self.pre_transfer_check(from, to, partition_id)?;
|
|
|
|
// 执行转账
|
|
self.partition_manager.sub_balance(partition_id, from, amount)?;
|
|
self.partition_manager.add_balance(partition_id, to, amount)?;
|
|
|
|
Ok(TransferResult {
|
|
status: TransferStatus::Success,
|
|
reason: None,
|
|
destination_partition: Some(*partition_id),
|
|
})
|
|
}
|
|
|
|
/// 转账前检查
|
|
fn pre_transfer_check(
|
|
&self,
|
|
from: &str,
|
|
to: &str,
|
|
partition_id: &[u8; 32],
|
|
) -> Result<()> {
|
|
// 检查转账是否暂停
|
|
if self.transfers_halted {
|
|
return Err(Acc1410Error::TransfersHalted);
|
|
}
|
|
|
|
// 检查发送方是否被锁定
|
|
if let Some(unlock_time) = self.is_account_locked(from) {
|
|
return Err(Acc1410Error::FundsLocked {
|
|
account: from.to_string(),
|
|
unlock_time,
|
|
});
|
|
}
|
|
|
|
// 检查接收方是否有效(简单验证非空)
|
|
if to.is_empty() {
|
|
return Err(Acc1410Error::InvalidReceiver(to.to_string()));
|
|
}
|
|
|
|
// 检查发送方是否有效
|
|
if from.is_empty() {
|
|
return Err(Acc1410Error::InvalidSender(from.to_string()));
|
|
}
|
|
|
|
// 检查分区是否存在且激活
|
|
let info = self.partition_manager.get_partition_info(partition_id)?;
|
|
if !info.is_active {
|
|
return Err(Acc1410Error::PartitionClosed(hex::encode(partition_id)));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// 获取当前时间戳
|
|
fn current_timestamp() -> u64 {
|
|
std::time::SystemTime::now()
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_secs()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::types::{ExtendedGNACS, GNACSExtension, PartitionType};
|
|
|
|
fn create_test_partition(manager: &mut PartitionManager) -> [u8; 32] {
|
|
let extended_gnacs = ExtendedGNACS {
|
|
base_gnacs: vec![0; 6],
|
|
extension: GNACSExtension {
|
|
partition_type: 0x01,
|
|
vesting_years: 0,
|
|
voting_multiplier: 1,
|
|
dividend_priority: 1,
|
|
},
|
|
};
|
|
|
|
manager
|
|
.create_partition(
|
|
"Test Partition".to_string(),
|
|
extended_gnacs,
|
|
PartitionType::CommonStock,
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn test_operator_authorization() {
|
|
let mut op_manager = OperatorManager::new();
|
|
|
|
// 授权全局操作员
|
|
op_manager.authorize_operator("user1", "operator1");
|
|
assert!(op_manager.is_operator_for("user1", "operator1"));
|
|
|
|
// 撤销全局操作员
|
|
op_manager.revoke_operator("user1", "operator1");
|
|
assert!(!op_manager.is_operator_for("user1", "operator1"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_partition_operator_authorization() {
|
|
let mut op_manager = OperatorManager::new();
|
|
let partition_id = [1u8; 32];
|
|
|
|
// 授权分区级操作员
|
|
op_manager.authorize_operator_by_partition("user1", &partition_id, "operator1");
|
|
assert!(op_manager.is_operator_for_partition("user1", &partition_id, "operator1"));
|
|
|
|
// 撤销分区级操作员
|
|
op_manager.revoke_operator_by_partition("user1", &partition_id, "operator1");
|
|
assert!(!op_manager.is_operator_for_partition("user1", &partition_id, "operator1"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_transfer_by_partition() {
|
|
let mut partition_manager = PartitionManager::new();
|
|
let partition_id = create_test_partition(&mut partition_manager);
|
|
|
|
// 初始化余额
|
|
partition_manager.add_balance(&partition_id, "user1", 1000).unwrap();
|
|
|
|
let mut transfer_manager = TransferManager::new(partition_manager);
|
|
|
|
// 执行转账
|
|
let result = transfer_manager
|
|
.transfer_by_partition("user1", "user2", 300, &partition_id)
|
|
.unwrap();
|
|
|
|
assert_eq!(result.status, TransferStatus::Success);
|
|
assert_eq!(
|
|
transfer_manager
|
|
.partition_manager()
|
|
.balance_of_by_partition(&partition_id, "user1")
|
|
.unwrap(),
|
|
700
|
|
);
|
|
assert_eq!(
|
|
transfer_manager
|
|
.partition_manager()
|
|
.balance_of_by_partition(&partition_id, "user2")
|
|
.unwrap(),
|
|
300
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_operator_transfer() {
|
|
let mut partition_manager = PartitionManager::new();
|
|
let partition_id = create_test_partition(&mut partition_manager);
|
|
|
|
partition_manager.add_balance(&partition_id, "user1", 1000).unwrap();
|
|
|
|
let mut transfer_manager = TransferManager::new(partition_manager);
|
|
|
|
// 授权操作员
|
|
transfer_manager
|
|
.operator_manager_mut()
|
|
.authorize_operator("user1", "operator1");
|
|
|
|
// 操作员代理转账
|
|
let result = transfer_manager
|
|
.operator_transfer_by_partition("operator1", "user1", "user2", 200, &partition_id)
|
|
.unwrap();
|
|
|
|
assert_eq!(result.status, TransferStatus::Success);
|
|
assert_eq!(
|
|
transfer_manager
|
|
.partition_manager()
|
|
.balance_of_by_partition(&partition_id, "user1")
|
|
.unwrap(),
|
|
800
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_transfers_halted() {
|
|
let mut partition_manager = PartitionManager::new();
|
|
let partition_id = create_test_partition(&mut partition_manager);
|
|
|
|
partition_manager.add_balance(&partition_id, "user1", 1000).unwrap();
|
|
|
|
let mut transfer_manager = TransferManager::new(partition_manager);
|
|
|
|
// 暂停转账
|
|
transfer_manager.halt_transfers();
|
|
|
|
// 尝试转账应失败
|
|
let result = transfer_manager.transfer_by_partition("user1", "user2", 100, &partition_id);
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_account_lock() {
|
|
let mut partition_manager = PartitionManager::new();
|
|
let partition_id = create_test_partition(&mut partition_manager);
|
|
|
|
partition_manager.add_balance(&partition_id, "user1", 1000).unwrap();
|
|
|
|
let mut transfer_manager = TransferManager::new(partition_manager);
|
|
|
|
// 锁定账户
|
|
let future_time = TransferManager::current_timestamp() + 3600; // 1小时后
|
|
transfer_manager.lock_account("user1", future_time);
|
|
|
|
// 尝试转账应失败
|
|
let result = transfer_manager.transfer_by_partition("user1", "user2", 100, &partition_id);
|
|
assert!(result.is_err());
|
|
|
|
// 解锁账户
|
|
transfer_manager.unlock_account("user1");
|
|
|
|
// 现在应该可以转账
|
|
let result = transfer_manager.transfer_by_partition("user1", "user2", 100, &partition_id);
|
|
assert!(result.is_ok());
|
|
}
|
|
}
|