use std::collections::HashMap; use anyhow::Result; use common::{merkle_tree_public::TreeHashType, transaction::Tag}; use k256::AffinePoint; use log::info; use nssa::Address; use serde::{Deserialize, Serialize}; use utxo::utxo_core::UTXO; use crate::key_management::{ constants_types::{CipherText, Nonce}, ephemeral_key_holder::EphemeralKeyHolder, AddressKeyHolder, }; pub type PublicKey = AffinePoint; #[derive(Clone, Debug)] pub struct Account { pub key_holder: AddressKeyHolder, pub address: Address, pub balance: u64, pub utxos: HashMap, } #[derive(Serialize, Deserialize, Clone, Debug)] pub struct AccountForSerialization { pub key_holder: AddressKeyHolder, pub address: String, pub balance: u64, pub utxos: HashMap, } impl From for AccountForSerialization { fn from(value: Account) -> Self { AccountForSerialization { key_holder: value.key_holder, balance: value.balance, address: value.address.to_string(), utxos: value .utxos .into_iter() .map(|(key, val)| (hex::encode(key), val)) .collect(), } } } impl From for Account { fn from(value: AccountForSerialization) -> Self { let public_key = nssa::PublicKey::new_from_private_key(value.key_holder.get_pub_account_signing_key()); let address = nssa::Address::from(&public_key); Account { key_holder: value.key_holder, address, balance: value.balance, utxos: value .utxos .into_iter() .map(|(key, val)| (hex::decode(key).unwrap().try_into().unwrap(), val)) .collect(), } } } impl Serialize for Account { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { let account_for_serialization: AccountForSerialization = From::from(self.clone()); account_for_serialization.serialize(serializer) } } impl<'de> Deserialize<'de> for Account { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let account_for_serialization = ::deserialize(deserializer)?; Ok(account_for_serialization.into()) } } impl Account { pub fn new() -> Self { let key_holder = AddressKeyHolder::new_os_random(); let public_key = nssa::PublicKey::new_from_private_key(key_holder.get_pub_account_signing_key()); let address = nssa::Address::from(&public_key); let balance = 0; let utxos = HashMap::new(); Self { key_holder, address, balance, utxos, } } pub fn new_with_balance(balance: u64) -> Self { let key_holder = AddressKeyHolder::new_os_random(); let public_key = nssa::PublicKey::new_from_private_key(key_holder.get_pub_account_signing_key()); let address = nssa::Address::from(&public_key); let utxos = HashMap::new(); Self { key_holder, address, balance, utxos, } } pub fn encrypt_data( ephemeral_key_holder: &EphemeralKeyHolder, viewing_public_key_receiver: AffinePoint, data: &[u8], ) -> (CipherText, Nonce) { ephemeral_key_holder.encrypt_data(viewing_public_key_receiver, data) } pub fn decrypt_data( &self, ephemeral_public_key_sender: AffinePoint, ciphertext: CipherText, nonce: Nonce, ) -> Result, aes_gcm::Error> { self.key_holder .decrypt_data(ephemeral_public_key_sender, ciphertext, nonce) } pub fn add_new_utxo_outputs(&mut self, utxos: Vec) -> Result<()> { for utxo in utxos { if self.utxos.contains_key(&utxo.hash) { return Err(anyhow::anyhow!("UTXO already exists")); } self.utxos.insert(utxo.hash, utxo); } Ok(()) } pub fn update_public_balance(&mut self, new_balance: u64) { self.balance = new_balance; } pub fn add_asset( &mut self, asset: Asset, amount: u128, privacy_flag: bool, ) -> Result<()> { let asset_utxo = UTXO::new( *self.address.value(), serde_json::to_vec(&asset)?, amount, privacy_flag, ); self.utxos.insert(asset_utxo.hash, asset_utxo); Ok(()) } pub fn log(&self) { info!("Keys generated"); info!("Account address is {:?}", hex::encode(self.address)); info!("Account balance is {:?}", self.balance); } pub fn make_tag(&self) -> Tag { self.address.value()[0] } } impl Default for Account { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> UTXO { UTXO::new(address, vec![], amount, false) } #[test] fn test_new_account() { let account = Account::new(); assert_eq!(account.balance, 0); } #[test] fn test_add_new_utxo_outputs() { let mut account = Account::new(); let utxo1 = generate_dummy_utxo(*account.address.value(), 100); let utxo2 = generate_dummy_utxo(*account.address.value(), 200); let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]); assert!(result.is_ok()); assert_eq!(account.utxos.len(), 2); } #[test] fn test_update_public_balance() { let mut account = Account::new(); account.update_public_balance(500); assert_eq!(account.balance, 500); } }