diff --git a/common/src/sequencer_client/mod.rs b/common/src/sequencer_client/mod.rs index a131033..196713f 100644 --- a/common/src/sequencer_client/mod.rs +++ b/common/src/sequencer_client/mod.rs @@ -7,6 +7,7 @@ use json::{SendTxRequest, SendTxResponse, SequencerRpcRequest, SequencerRpcRespo use reqwest::Client; use serde_json::Value; +use crate::rpc_primitives::requests::{GetTransactionByHashRequest, GetTransactionByHashResponse}; use crate::sequencer_client::json::AccountInitialData; use crate::{SequencerClientError, SequencerRpcError}; @@ -137,4 +138,22 @@ impl SequencerClient { Ok(resp_deser) } + + ///Get tx data for `tx_hash` from sequencer + pub async fn get_transaction_by_hash( + &self, + tx_hash: String, + ) -> Result { + let block_req = GetTransactionByHashRequest { hash: tx_hash }; + + let req = serde_json::to_value(block_req)?; + + let resp = self + .call_method_with_payload("get_transaction_by_hash", req) + .await?; + + let resp_deser = serde_json::from_value(resp)?; + + Ok(resp_deser) + } } diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index bc6d14c..5702b38 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit}; use constants_types::{CipherText, Nonce}; use elliptic_curve::point::AffineCoordinates; @@ -20,8 +18,6 @@ pub mod secret_holders; pub struct KeyChain { top_secret_key_holder: TopSecretKeyHolder, pub utxo_secret_key_holder: UTXOSecretKeyHolder, - ///Map for all users accounts - pub_account_signing_keys: HashMap, pub nullifer_public_key: PublicKey, pub viewing_public_key: PublicKey, } @@ -43,47 +39,9 @@ impl KeyChain { utxo_secret_key_holder, nullifer_public_key, viewing_public_key, - pub_account_signing_keys: HashMap::new(), } } - pub fn new_os_random_with_accounts(accounts: HashMap) -> Self { - //Currently dropping SeedHolder at the end of initialization. - //Now entirely sure if we need it in the future. - let seed_holder = SeedHolder::new_os_random(); - let top_secret_key_holder = seed_holder.produce_top_secret_key_holder(); - - let utxo_secret_key_holder = top_secret_key_holder.produce_utxo_secret_holder(); - - let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key(); - let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key(); - - Self { - top_secret_key_holder, - utxo_secret_key_holder, - nullifer_public_key, - viewing_public_key, - pub_account_signing_keys: accounts, - } - } - - pub fn generate_new_private_key(&mut self) -> nssa::Address { - let private_key = nssa::PrivateKey::new_os_random(); - let address = nssa::Address::from(&nssa::PublicKey::new_from_private_key(&private_key)); - - self.pub_account_signing_keys.insert(address, private_key); - - address - } - - /// Returns the signing key for public transaction signatures - pub fn get_pub_account_signing_key( - &self, - address: &nssa::Address, - ) -> Option<&nssa::PrivateKey> { - self.pub_account_signing_keys.get(address) - } - pub fn calculate_shared_secret_receiver( &self, ephemeral_public_key_sender: AffinePoint, @@ -341,19 +299,6 @@ mod tests { assert_eq!(decrypted_data, plaintext); } - #[test] - fn test_get_public_account_signing_key() { - let mut address_key_holder = KeyChain::new_os_random(); - - let address = address_key_holder.generate_new_private_key(); - - let is_private_key_generated = address_key_holder - .get_pub_account_signing_key(&address) - .is_some(); - - assert!(is_private_key_generated); - } - #[test] fn key_generation_test() { let seed_holder = SeedHolder::new_os_random(); diff --git a/key_protocol/src/key_protocol_core/mod.rs b/key_protocol/src/key_protocol_core/mod.rs index 3b8092e..5362095 100644 --- a/key_protocol/src/key_protocol_core/mod.rs +++ b/key_protocol/src/key_protocol_core/mod.rs @@ -15,7 +15,8 @@ pub type PublicKey = AffinePoint; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct NSSAUserData { pub key_holder: KeyChain, - pub accounts: HashMap, + ///Map for all users accounts + pub accounts: HashMap, } ///A strucure, which represents all the visible(public) information @@ -56,21 +57,22 @@ impl NSSAUserData { } pub fn new_with_accounts( - accounts_keys: HashMap, - accounts: HashMap, + accounts_data: HashMap, ) -> Self { - let key_holder = KeyChain::new_os_random_with_accounts(accounts_keys); + let key_holder = KeyChain::new_os_random(); Self { key_holder, - accounts, + accounts: accounts_data, } } pub fn generate_new_account(&mut self) -> nssa::Address { - let address = self.key_holder.generate_new_private_key(); - self.accounts - .insert(address, nssa_core::account::Account::default()); + let private_key = nssa::PrivateKey::new_os_random(); + let address = nssa::Address::from(&nssa::PublicKey::new_from_private_key(&private_key)); + let account = nssa_core::account::Account::default(); + + self.accounts.insert(address, (private_key, account)); address } @@ -78,16 +80,16 @@ impl NSSAUserData { pub fn get_account_balance(&self, address: &nssa::Address) -> u128 { self.accounts .get(address) - .map(|acc| acc.balance) + .map(|(_, acc)| acc.balance) .unwrap_or(0) } pub fn get_account(&self, address: &nssa::Address) -> Option<&nssa_core::account::Account> { - self.accounts.get(address) + self.accounts.get(address).map(|(_, acc)| acc) } pub fn get_account_signing_key(&self, address: &nssa::Address) -> Option<&nssa::PrivateKey> { - self.key_holder.get_pub_account_signing_key(address) + self.accounts.get(address).map(|(key, _)| key) } pub fn encrypt_data( @@ -111,8 +113,7 @@ impl NSSAUserData { pub fn update_account_balance(&mut self, address: nssa::Address, new_balance: u128) { self.accounts .entry(address) - .and_modify(|acc| acc.balance = new_balance) - .or_default(); + .and_modify(|(_, acc)| acc.balance = new_balance); } //ToDo: Part of a private keys update diff --git a/wallet/src/chain_storage/mod.rs b/wallet/src/chain_storage/mod.rs index 40c9ddc..daa51bf 100644 --- a/wallet/src/chain_storage/mod.rs +++ b/wallet/src/chain_storage/mod.rs @@ -14,24 +14,23 @@ pub struct WalletChainStore { impl WalletChainStore { pub fn new(config: WalletConfig) -> Result { - let accounts: HashMap = config - .initial_accounts - .clone() - .into_iter() - .map(|init_acc_data| (init_acc_data.address, init_acc_data.account)) - .collect(); - - let accounts_keys: HashMap = config - .initial_accounts - .clone() - .into_iter() - .map(|init_acc_data| (init_acc_data.address, init_acc_data.pub_sign_key)) - .collect(); + let accounts_data: HashMap = + config + .initial_accounts + .clone() + .into_iter() + .map(|init_acc_data| { + ( + init_acc_data.address, + (init_acc_data.pub_sign_key, init_acc_data.account), + ) + }) + .collect(); let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]); Ok(Self { - user_data: NSSAUserData::new_with_accounts(accounts_keys, accounts), + user_data: NSSAUserData::new_with_accounts(accounts_data), utxo_commitments_store, wallet_config: config, }) diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index 51b9d9d..e41c325 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -1,6 +1,7 @@ use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr}; use anyhow::Result; +use key_protocol::key_protocol_core::NSSAUserData; use nssa::Address; use crate::{ @@ -47,3 +48,17 @@ pub fn fetch_persistent_accounts() -> Result> { }, } } + +pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec { + let mut vec_for_storage = vec![]; + + for (addr, (key, account)) in &user_data.accounts { + vec_for_storage.push(InitialAccountData { + address: *addr, + account: account.clone(), + pub_sign_key: key.clone(), + }); + } + + vec_for_storage +} diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 2c4b711..c6d0704 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{fs::File, io::Write, path::PathBuf, sync::Arc}; use common::{ sequencer_client::{json::SendTxResponse, SequencerClient}, @@ -14,7 +14,8 @@ use nssa::Address; use clap::{Parser, Subcommand}; use crate::helperfunctions::{ - fetch_config, fetch_persistent_accounts, produce_account_addr_from_hex, + fetch_config, fetch_persistent_accounts, get_home, produce_account_addr_from_hex, + produce_data_for_storage, }; pub const HOME_DIR_ENV_VAR: &str = "NSSA_WALLET_HOME_DIR"; @@ -35,6 +36,9 @@ impl WalletCore { let mut storage = WalletChainStore::new(config)?; + //Updating user data with stored accounts + //We do not store/update any key data connected to private executions + //ToDo: Add this into persistent data let persistent_accounts = fetch_persistent_accounts()?; for acc in persistent_accounts { storage @@ -48,7 +52,20 @@ impl WalletCore { }) } - pub async fn create_new_account(&mut self) -> Address { + pub fn store_persistent_accounts(&self) -> Result { + let home = get_home()?; + let accs_path = home.join("curr_accounts.json"); + let accs = serde_json::to_vec(&produce_data_for_storage(&self.storage.user_data))?; + + let mut accs_file = File::create(accs_path.as_path())?; + accs_file.write_all(&accs)?; + + info!("Stored accounts data at {accs_path:#?}"); + + Ok(accs_path) + } + + pub fn create_new_account(&mut self) -> Address { self.storage.user_data.generate_new_account() } @@ -114,6 +131,13 @@ pub enum Command { #[arg(long)] amount: u128, }, + ///Register new account + RegisterAccount {}, + ///Fetch transaction by `hash` + FetchTx { + #[arg(short, long)] + tx_hash: String, + }, } ///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config @@ -126,6 +150,9 @@ pub struct Args { } pub async fn execute_subcommand(command: Command) -> Result<()> { + let wallet_config = fetch_config()?; + let mut wallet_core = WalletCore::start_from_config_update_chain(wallet_config).await?; + match command { Command::SendNativeTokenTransfer { from, @@ -133,13 +160,9 @@ pub async fn execute_subcommand(command: Command) -> Result<()> { to, amount, } => { - let wallet_config = fetch_config()?; - let from = produce_account_addr_from_hex(from)?; let to = produce_account_addr_from_hex(to)?; - let wallet_core = WalletCore::start_from_config_update_chain(wallet_config).await?; - let res = wallet_core .send_public_native_token_transfer(from, nonce, to, amount) .await?; @@ -148,7 +171,25 @@ pub async fn execute_subcommand(command: Command) -> Result<()> { //ToDo: Insert transaction polling logic here } + Command::RegisterAccount {} => { + let addr = wallet_core.create_new_account(); + + let key = wallet_core.storage.user_data.get_account_signing_key(&addr); + + info!("Generated new account with addr {addr:#?}"); + info!("With key {key:#?}"); + } + Command::FetchTx { tx_hash } => { + let tx_obj = wallet_core + .sequencer_client + .get_transaction_by_hash(tx_hash) + .await?; + + info!("Transaction object {tx_obj:#?}"); + } } + wallet_core.store_persistent_accounts()?; + Ok(()) }