NAC_Blockchain/nac-acc-1410/src/partition.rs

188 lines
5.5 KiB
Rust

//! Partition Manager
use crate::error::{Acc1410Error, Result};
use crate::types::{ExtendedGNACS, Partition, PartitionInfo, PartitionType};
use sha3::{Digest, Sha3_256};
use std::collections::HashMap;
#[derive(Debug)]
pub struct PartitionManager {
partitions: HashMap<String, Partition>,
account_partitions: HashMap<String, Vec<String>>,
}
impl PartitionManager {
pub fn new() -> Self {
Self {
partitions: HashMap::new(),
account_partitions: HashMap::new(),
}
}
pub fn create_partition(
&mut self,
name: String,
extended_gnacs: ExtendedGNACS,
partition_type: PartitionType,
) -> Result<[u8; 32]> {
let mut hasher = Sha3_256::new();
hasher.update(name.as_bytes());
hasher.update(&extended_gnacs.encode());
let hash_result = hasher.finalize();
let mut partition_id = [0u8; 32];
partition_id.copy_from_slice(&hash_result);
let partition_id_hex = hex::encode(partition_id);
if self.partitions.contains_key(&partition_id_hex) {
return Err(Acc1410Error::PartitionAlreadyExists(partition_id_hex));
}
let partition = Partition::new(
partition_id,
extended_gnacs,
name,
partition_type,
Self::current_timestamp(),
);
self.partitions.insert(partition_id_hex, partition);
Ok(partition_id)
}
pub fn close_partition(&mut self, partition_id: &[u8; 32]) -> Result<()> {
let partition_id_hex = hex::encode(partition_id);
let partition = self
.partitions
.get_mut(&partition_id_hex)
.ok_or_else(|| Acc1410Error::PartitionNotFound(partition_id_hex.clone()))?;
partition.info.is_active = false;
Ok(())
}
pub fn get_partition_info(&self, partition_id: &[u8; 32]) -> Result<PartitionInfo> {
let partition_id_hex = hex::encode(partition_id);
let partition = self
.partitions
.get(&partition_id_hex)
.ok_or_else(|| Acc1410Error::PartitionNotFound(partition_id_hex))?;
Ok(partition.info.clone())
}
pub fn balance_of_by_partition(
&self,
partition_id: &[u8; 32],
account: &str,
) -> Result<u64> {
let partition_id_hex = hex::encode(partition_id);
let partition = self
.partitions
.get(&partition_id_hex)
.ok_or_else(|| Acc1410Error::PartitionNotFound(partition_id_hex))?;
Ok(partition.balance_of(account))
}
pub fn partitions_of(&self, account: &str) -> Vec<[u8; 32]> {
self.account_partitions
.get(account)
.map(|partition_ids| {
partition_ids
.iter()
.filter_map(|id_hex| {
let bytes = hex::decode(id_hex).ok()?;
if bytes.len() == 32 {
let mut arr = [0u8; 32];
arr.copy_from_slice(&bytes);
Some(arr)
} else {
None
}
})
.collect()
})
.unwrap_or_default()
}
pub fn add_balance(
&mut self,
partition_id: &[u8; 32],
account: &str,
amount: u64,
) -> Result<()> {
let partition_id_hex = hex::encode(partition_id);
let partition = self
.partitions
.get_mut(&partition_id_hex)
.ok_or_else(|| Acc1410Error::PartitionNotFound(partition_id_hex.clone()))?;
if !partition.info.is_active {
return Err(Acc1410Error::PartitionClosed(partition_id_hex));
}
partition.add_balance(account, amount);
self.account_partitions
.entry(account.to_string())
.or_insert_with(Vec::new)
.push(partition_id_hex);
Ok(())
}
pub fn sub_balance(
&mut self,
partition_id: &[u8; 32],
account: &str,
amount: u64,
) -> Result<()> {
let partition_id_hex = hex::encode(partition_id);
let partition = self
.partitions
.get_mut(&partition_id_hex)
.ok_or_else(|| Acc1410Error::PartitionNotFound(partition_id_hex.clone()))?;
if !partition.info.is_active {
return Err(Acc1410Error::PartitionClosed(partition_id_hex));
}
let available = partition.balance_of(account);
if available < amount {
return Err(Acc1410Error::InsufficientBalance {
account: account.to_string(),
required: amount,
available,
});
}
partition.sub_balance(account, amount);
Ok(())
}
pub fn get_all_partition_ids(&self) -> Vec<[u8; 32]> {
self.partitions
.keys()
.filter_map(|id_hex| {
let bytes = hex::decode(id_hex).ok()?;
if bytes.len() == 32 {
let mut arr = [0u8; 32];
arr.copy_from_slice(&bytes);
Some(arr)
} else {
None
}
})
.collect()
}
fn current_timestamp() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
}
}
impl Default for PartitionManager {
fn default() -> Self {
Self::new()
}
}