lssa/wallet/src/helperfunctions.rs

203 lines
5.9 KiB
Rust
Raw Normal View History

2025-12-03 00:17:12 +03:00
use std::{path::PathBuf, str::FromStr};
2025-08-07 14:07:34 +03:00
2025-08-13 13:42:00 +03:00
use anyhow::Result;
2025-11-26 00:27:20 +03:00
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
2025-12-03 00:17:12 +03:00
use key_protocol::key_protocol_core::NSSAUserData;
use nssa::Account;
2025-11-26 00:27:20 +03:00
use nssa_core::account::Nonce;
use rand::{RngCore, rngs::OsRng};
use serde::Serialize;
2025-08-07 14:07:34 +03:00
2025-08-19 14:14:09 +03:00
use crate::{
2025-12-03 00:17:12 +03:00
HOME_DIR_ENV_VAR,
2025-09-11 18:32:46 +03:00
config::{
InitialAccountData, InitialAccountDataPrivate, InitialAccountDataPublic,
PersistentAccountDataPrivate, PersistentAccountDataPublic, PersistentStorage,
2025-09-11 18:32:46 +03:00
},
2025-08-19 14:14:09 +03:00
};
2025-08-07 14:07:34 +03:00
/// Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed.
fn get_home_nssa_var() -> Result<PathBuf> {
2025-08-07 14:07:34 +03:00
Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?)
}
2025-10-30 15:33:58 +02:00
/// Get home dir for wallet. Env var `HOME` must be set before execution to succeed.
fn get_home_default_path() -> Result<PathBuf> {
2025-10-30 15:33:58 +02:00
std::env::home_dir()
.map(|path| path.join(".nssa").join("wallet"))
.ok_or(anyhow::anyhow!("Failed to get HOME"))
2025-10-29 13:23:07 +02:00
}
2025-10-30 15:33:58 +02:00
/// Get home dir for wallet.
pub fn get_home() -> Result<PathBuf> {
if let Ok(home) = get_home_nssa_var() {
Ok(home)
} else {
get_home_default_path()
}
}
/// Fetch config path from default home
pub fn fetch_config_path() -> Result<PathBuf> {
let home = get_home()?;
let config_path = home.join("wallet_config.json");
Ok(config_path)
2025-12-08 18:26:35 +03:00
}
/// Fetch path to data storage from default home
2025-08-08 15:22:04 +03:00
///
2025-11-26 07:32:35 +02:00
/// File must be created through setup beforehand.
pub fn fetch_persistent_storage_path() -> Result<PathBuf> {
2025-08-08 15:22:04 +03:00
let home = get_home()?;
2025-10-28 16:02:30 +02:00
let accs_path = home.join("storage.json");
Ok(accs_path)
2025-08-08 15:22:04 +03:00
}
2025-08-20 17:16:51 +03:00
2025-10-28 16:02:30 +02:00
/// Produces data for storage
pub fn produce_data_for_storage(
user_data: &NSSAUserData,
last_synced_block: u64,
) -> PersistentStorage {
2025-08-20 17:16:51 +03:00
let mut vec_for_storage = vec![];
for (account_id, key) in &user_data.public_key_tree.account_id_map {
2025-11-10 16:29:33 +02:00
if let Some(data) = user_data.public_key_tree.key_map.get(key) {
2025-11-11 12:15:20 +02:00
vec_for_storage.push(
PersistentAccountDataPublic {
account_id: *account_id,
2025-11-11 12:15:20 +02:00
chain_index: key.clone(),
data: data.clone(),
}
.into(),
);
2025-11-10 16:29:33 +02:00
}
2025-09-11 18:32:46 +03:00
}
for (account_id, key) in &user_data.private_key_tree.account_id_map {
2025-11-10 16:29:33 +02:00
if let Some(data) = user_data.private_key_tree.key_map.get(key) {
2025-11-11 12:15:20 +02:00
vec_for_storage.push(
PersistentAccountDataPrivate {
account_id: *account_id,
2025-11-11 12:15:20 +02:00
chain_index: key.clone(),
data: data.clone(),
}
.into(),
);
2025-11-10 16:29:33 +02:00
}
2025-08-20 17:16:51 +03:00
}
for (account_id, key) in &user_data.default_pub_account_signing_keys {
2025-11-11 12:15:20 +02:00
vec_for_storage.push(
InitialAccountData::Public(InitialAccountDataPublic {
account_id: *account_id,
2025-11-11 12:15:20 +02:00
pub_sign_key: key.clone(),
})
.into(),
)
}
for (account_id, (key_chain, account)) in &user_data.default_user_private_accounts {
2025-11-11 12:15:20 +02:00
vec_for_storage.push(
InitialAccountData::Private(InitialAccountDataPrivate {
account_id: *account_id,
2025-11-11 12:15:20 +02:00
account: account.clone(),
key_chain: key_chain.clone(),
})
.into(),
)
}
2025-10-28 16:02:30 +02:00
PersistentStorage {
accounts: vec_for_storage,
last_synced_block,
}
2025-08-20 17:16:51 +03:00
}
2025-08-26 09:16:46 +03:00
pub(crate) fn produce_random_nonces(size: usize) -> Vec<Nonce> {
let mut result = vec![[0; 16]; size];
result.iter_mut().for_each(|bytes| OsRng.fill_bytes(bytes));
2025-10-03 08:08:54 -03:00
result.into_iter().map(Nonce::from_le_bytes).collect()
}
2025-10-24 15:26:30 +03:00
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AccountPrivacyKind {
2025-10-24 15:26:30 +03:00
Public,
Private,
}
pub(crate) fn parse_addr_with_privacy_prefix(
account_base58: &str,
) -> Result<(String, AccountPrivacyKind)> {
if account_base58.starts_with("Public/") {
2025-10-24 15:26:30 +03:00
Ok((
account_base58.strip_prefix("Public/").unwrap().to_string(),
AccountPrivacyKind::Public,
2025-10-24 15:26:30 +03:00
))
} else if account_base58.starts_with("Private/") {
2025-10-24 15:26:30 +03:00
Ok((
account_base58.strip_prefix("Private/").unwrap().to_string(),
AccountPrivacyKind::Private,
2025-10-24 15:26:30 +03:00
))
} else {
anyhow::bail!("Unsupported privacy kind, available variants is Public/ and Private/");
}
}
/// Human-readable representation of an account.
#[derive(Serialize)]
pub(crate) struct HumanReadableAccount {
balance: u128,
program_owner_b64: String,
data_b64: String,
nonce: u128,
}
impl From<Account> for HumanReadableAccount {
fn from(account: Account) -> Self {
let program_owner_b64 = BASE64.encode(bytemuck::cast_slice(&account.program_owner));
let data_b64 = BASE64.encode(account.data);
Self {
balance: account.balance,
program_owner_b64,
data_b64,
nonce: account.nonce,
}
}
}
2025-08-26 09:16:46 +03:00
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_home_get_env_var() {
2025-09-04 14:38:41 +03:00
unsafe {
std::env::set_var(HOME_DIR_ENV_VAR, "/path/to/configs");
}
2025-08-26 09:16:46 +03:00
let home = get_home().unwrap();
assert_eq!(PathBuf::from_str("/path/to/configs").unwrap(), home);
2025-09-04 14:38:41 +03:00
unsafe {
std::env::remove_var(HOME_DIR_ENV_VAR);
}
2025-08-26 09:16:46 +03:00
}
2025-10-24 15:26:30 +03:00
#[test]
fn test_addr_parse_with_privacy() {
let addr_base58 = "Public/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap();
assert_eq!(addr_kind, AccountPrivacyKind::Public);
2025-10-24 15:26:30 +03:00
let addr_base58 = "Private/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap();
assert_eq!(addr_kind, AccountPrivacyKind::Private);
2025-10-24 15:26:30 +03:00
let addr_base58 = "asdsada/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
assert!(parse_addr_with_privacy_prefix(addr_base58).is_err());
}
2025-08-26 09:16:46 +03:00
}