mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-14 11:13:12 +00:00
add wallet account label feature
- can add a label to own account via `wallet` CLI - labels are displayed with `wallet account get` command - labels are displayed with `wallet account list` command - labels are persisted.
This commit is contained in:
parent
1d09afd9e0
commit
5dac6d6e31
@ -16,12 +16,14 @@ use crate::config::{InitialAccountData, PersistentAccountData, WalletConfig};
|
||||
pub struct WalletChainStore {
|
||||
pub user_data: NSSAUserData,
|
||||
pub wallet_config: WalletConfig,
|
||||
pub labels: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl WalletChainStore {
|
||||
pub fn new(
|
||||
config: WalletConfig,
|
||||
persistent_accounts: Vec<PersistentAccountData>,
|
||||
labels: HashMap<String, String>,
|
||||
) -> Result<Self> {
|
||||
if persistent_accounts.is_empty() {
|
||||
anyhow::bail!("Roots not found; please run setup beforehand");
|
||||
@ -85,6 +87,7 @@ impl WalletChainStore {
|
||||
private_tree,
|
||||
)?,
|
||||
wallet_config: config,
|
||||
labels,
|
||||
})
|
||||
}
|
||||
|
||||
@ -120,6 +123,7 @@ impl WalletChainStore {
|
||||
private_tree,
|
||||
)?,
|
||||
wallet_config: config,
|
||||
labels: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -291,6 +295,6 @@ mod tests {
|
||||
let config = create_sample_wallet_config();
|
||||
let accs = create_sample_persistent_accounts();
|
||||
|
||||
let _ = WalletChainStore::new(config.clone(), accs).unwrap();
|
||||
let _ = WalletChainStore::new(config.clone(), accs, HashMap::new()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,15 @@ pub enum AccountSubcommand {
|
||||
/// List all accounts owned by the wallet
|
||||
#[command(visible_alias = "ls")]
|
||||
List {},
|
||||
/// Set a label for an account
|
||||
Label {
|
||||
/// Valid 32 byte base58 string with privacy prefix
|
||||
#[arg(short, long)]
|
||||
account_id: String,
|
||||
/// The label to assign to the account
|
||||
#[arg(short, long)]
|
||||
label: String,
|
||||
},
|
||||
}
|
||||
|
||||
/// Represents generic register CLI subcommand
|
||||
@ -158,9 +167,13 @@ impl WalletSubcommand for AccountSubcommand {
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
AccountSubcommand::Get { raw, account_id } => {
|
||||
let (account_id, addr_kind) = parse_addr_with_privacy_prefix(&account_id)?;
|
||||
let (account_id_str, addr_kind) = parse_addr_with_privacy_prefix(&account_id)?;
|
||||
|
||||
let account_id = account_id.parse()?;
|
||||
let account_id: nssa::AccountId = account_id_str.parse()?;
|
||||
|
||||
if let Some(label) = wallet_core.storage.labels.get(&account_id_str) {
|
||||
println!("Label: {label}");
|
||||
}
|
||||
|
||||
let account = match addr_kind {
|
||||
AccountPrivacyKind::Public => {
|
||||
@ -254,35 +267,57 @@ impl WalletSubcommand for AccountSubcommand {
|
||||
}
|
||||
AccountSubcommand::List {} => {
|
||||
let user_data = &wallet_core.storage.user_data;
|
||||
let labels = &wallet_core.storage.labels;
|
||||
|
||||
let format_with_label = |prefix: &str, id: &nssa::AccountId| {
|
||||
let id_str = id.to_string();
|
||||
if let Some(label) = labels.get(&id_str) {
|
||||
format!("{prefix} [{label}]")
|
||||
} else {
|
||||
prefix.to_string()
|
||||
}
|
||||
};
|
||||
|
||||
let accounts = user_data
|
||||
.default_pub_account_signing_keys
|
||||
.keys()
|
||||
.map(|id| format!("Preconfigured Public/{id}"))
|
||||
.map(|id| format_with_label(&format!("Preconfigured Public/{id}"), id))
|
||||
.chain(
|
||||
user_data
|
||||
.default_user_private_accounts
|
||||
.keys()
|
||||
.map(|id| format!("Preconfigured Private/{id}")),
|
||||
)
|
||||
.chain(
|
||||
user_data
|
||||
.public_key_tree
|
||||
.account_id_map
|
||||
.iter()
|
||||
.map(|(id, chain_index)| format!("{chain_index} Public/{id}")),
|
||||
)
|
||||
.chain(
|
||||
user_data
|
||||
.private_key_tree
|
||||
.account_id_map
|
||||
.iter()
|
||||
.map(|(id, chain_index)| format!("{chain_index} Private/{id}")),
|
||||
.map(|id| format_with_label(&format!("Preconfigured Private/{id}"), id)),
|
||||
)
|
||||
.chain(user_data.public_key_tree.account_id_map.iter().map(
|
||||
|(id, chain_index)| {
|
||||
format_with_label(&format!("{chain_index} Public/{id}"), id)
|
||||
},
|
||||
))
|
||||
.chain(user_data.private_key_tree.account_id_map.iter().map(
|
||||
|(id, chain_index)| {
|
||||
format_with_label(&format!("{chain_index} Private/{id}"), id)
|
||||
},
|
||||
))
|
||||
.format(",\n");
|
||||
|
||||
println!("{accounts}");
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
AccountSubcommand::Label { account_id, label } => {
|
||||
let (account_id_str, _) = parse_addr_with_privacy_prefix(&account_id)?;
|
||||
|
||||
wallet_core
|
||||
.storage
|
||||
.labels
|
||||
.insert(account_id_str.clone(), label.clone());
|
||||
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Label '{label}' set for account {account_id_str}");
|
||||
println!("Stored persistent data at {path:#?}");
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::str::FromStr;
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
|
||||
use key_protocol::key_management::{
|
||||
KeyChain,
|
||||
@ -103,6 +103,9 @@ pub enum PersistentAccountData {
|
||||
pub struct PersistentStorage {
|
||||
pub accounts: Vec<PersistentAccountData>,
|
||||
pub last_synced_block: u64,
|
||||
/// Account labels keyed by account ID string (e.g., "2rnKprXqWGWJTkDZKsQbFXa4ctKRbapsdoTKQFnaVGG8")
|
||||
#[serde(default)]
|
||||
pub labels: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl InitialAccountData {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
use std::{collections::HashMap, path::PathBuf, str::FromStr};
|
||||
|
||||
use anyhow::Result;
|
||||
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||
@ -134,6 +134,7 @@ pub async fn fetch_persistent_storage() -> Result<PersistentStorage> {
|
||||
pub fn produce_data_for_storage(
|
||||
user_data: &NSSAUserData,
|
||||
last_synced_block: u64,
|
||||
labels: HashMap<String, String>,
|
||||
) -> PersistentStorage {
|
||||
let mut vec_for_storage = vec![];
|
||||
|
||||
@ -187,6 +188,7 @@ pub fn produce_data_for_storage(
|
||||
PersistentStorage {
|
||||
accounts: vec_for_storage,
|
||||
last_synced_block,
|
||||
labels,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -145,9 +145,10 @@ impl WalletCore {
|
||||
let PersistentStorage {
|
||||
accounts: persistent_accounts,
|
||||
last_synced_block,
|
||||
labels,
|
||||
} = fetch_persistent_storage().await?;
|
||||
|
||||
let storage = WalletChainStore::new(config, persistent_accounts)?;
|
||||
let storage = WalletChainStore::new(config, persistent_accounts, labels)?;
|
||||
|
||||
Ok(Self {
|
||||
storage,
|
||||
@ -186,7 +187,11 @@ impl WalletCore {
|
||||
let home = get_home()?;
|
||||
let storage_path = home.join("storage.json");
|
||||
|
||||
let data = produce_data_for_storage(&self.storage.user_data, self.last_synced_block);
|
||||
let data = produce_data_for_storage(
|
||||
&self.storage.user_data,
|
||||
self.last_synced_block,
|
||||
self.storage.labels.clone(),
|
||||
);
|
||||
let storage = serde_json::to_vec_pretty(&data)?;
|
||||
|
||||
let mut storage_file = tokio::fs::File::create(storage_path.as_path()).await?;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user