diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs index a566ee2..f62d567 100644 --- a/common/src/rpc_primitives/requests.rs +++ b/common/src/rpc_primitives/requests.rs @@ -49,7 +49,7 @@ pub struct GetAccountsNoncesRequest { } #[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountDataRequest { +pub struct GetAccountRequest { pub address: String, } @@ -63,7 +63,7 @@ parse_request!(GetInitialTestnetAccountsRequest); parse_request!(GetAccountBalanceRequest); parse_request!(GetTransactionByHashRequest); parse_request!(GetAccountsNoncesRequest); -parse_request!(GetAccountDataRequest); +parse_request!(GetAccountRequest); #[derive(Serialize, Deserialize, Debug)] pub struct HelloResponse { @@ -112,9 +112,6 @@ pub struct GetTransactionByHashResponse { } #[derive(Serialize, Deserialize, Debug)] -pub struct GetAccountDataResponse { - pub balance: u128, - pub nonce: u128, - pub program_owner: [u32; 8], - pub data: Vec, +pub struct GetAccountResponse { + pub account: nssa::Account, } diff --git a/common/src/sequencer_client/mod.rs b/common/src/sequencer_client/mod.rs index ad66d82..3e29156 100644 --- a/common/src/sequencer_client/mod.rs +++ b/common/src/sequencer_client/mod.rs @@ -8,8 +8,8 @@ use reqwest::Client; use serde_json::Value; use crate::rpc_primitives::requests::{ - GetAccountsNoncesRequest, GetAccountsNoncesResponse, GetTransactionByHashRequest, - GetTransactionByHashResponse, + GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, + GetAccountsNoncesResponse, GetTransactionByHashRequest, GetTransactionByHashResponse, }; use crate::sequencer_client::json::AccountInitialData; use crate::{SequencerClientError, SequencerRpcError}; @@ -108,6 +108,23 @@ impl SequencerClient { Ok(resp_deser) } + pub async fn get_account( + &self, + address: String, + ) -> Result { + let block_req = GetAccountRequest { address }; + + let req = serde_json::to_value(block_req)?; + + let resp = self + .call_method_with_payload("get_account", req) + .await?; + + let resp_deser = serde_json::from_value(resp)?; + + Ok(resp_deser) + } + ///Get transaction details for `hash`. pub async fn get_transaction_by_hash( &self, diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index ed88047..387a82d 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -7,6 +7,7 @@ pub mod public_transaction; mod signature; mod state; +pub use nssa_core::account::Account; pub use address::Address; pub use privacy_preserving_transaction::{ PrivacyPreservingTransaction, circuit::execute_and_prove, diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 2f55dd2..1a5e2ca 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -12,8 +12,8 @@ use common::{ message::{Message, Request}, parser::RpcRequest, requests::{ - GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountDataRequest, - GetAccountDataResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, + GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest, + GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, GetInitialTestnetAccountsRequest, GetTransactionByHashRequest, GetTransactionByHashResponse, }, @@ -36,7 +36,7 @@ pub const GET_LAST_BLOCK: &str = "get_last_block"; pub const GET_ACCOUNT_BALANCE: &str = "get_account_balance"; pub const GET_TRANSACTION_BY_HASH: &str = "get_transaction_by_hash"; pub const GET_ACCOUNTS_NONCES: &str = "get_accounts_nonces"; -pub const GET_ACCOUNT_DATA: &str = "get_account_data"; +pub const GET_ACCOUNT: &str = "get_account"; pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER"; @@ -204,10 +204,10 @@ impl JsonHandler { respond(helperstruct) } - ///Returns account struct for give address. + /// Returns account struct for given address. /// Address must be a valid hex string of the correct length. - async fn process_get_account_data(&self, request: Request) -> Result { - let get_account_nonces_req = GetAccountDataRequest::parse(Some(request.params))?; + async fn process_get_account(&self, request: Request) -> Result { + let get_account_nonces_req = GetAccountRequest::parse(Some(request.params))?; let address = get_account_nonces_req .address @@ -220,12 +220,7 @@ impl JsonHandler { state.store.state.get_account_by_address(&address) }; - let helperstruct = GetAccountDataResponse { - balance: account.balance, - nonce: account.nonce, - program_owner: account.program_owner, - data: account.data, - }; + let helperstruct = GetAccountResponse { account }; respond(helperstruct) } @@ -265,7 +260,7 @@ impl JsonHandler { GET_INITIAL_TESTNET_ACCOUNTS => self.get_initial_testnet_accounts(request).await, GET_ACCOUNT_BALANCE => self.process_get_account_balance(request).await, GET_ACCOUNTS_NONCES => self.process_get_accounts_nonces(request).await, - GET_ACCOUNT_DATA => self.process_get_account_data(request).await, + GET_ACCOUNT => self.process_get_account(request).await, GET_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await, _ => Err(RpcErr(RpcError::method_not_found(request.method))), } @@ -534,7 +529,7 @@ mod tests { let (json_handler, _, _) = components_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", - "method": "get_account_data", + "method": "get_account", "params": { "address": "efac".repeat(16) }, "id": 1 }); @@ -542,10 +537,12 @@ mod tests { "id": 1, "jsonrpc": "2.0", "result": { - "balance": 0, - "nonce": 0, - "program_owner": [ 0, 0, 0, 0, 0, 0, 0, 0], - "data": [], + "account": { + "balance": 0, + "nonce": 0, + "program_owner": [ 0, 0, 0, 0, 0, 0, 0, 0], + "data": [], + } } }); diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 2caa7ff..e37586b 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -14,6 +14,7 @@ tempfile.workspace = true clap.workspace = true nssa-core = { path = "../nssa/core" } base64.workspace = true +bytemuck = "1.23.2" [dependencies.key_protocol] path = "../key_protocol" diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index 8a7b7b6..dc5b2f6 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -1,20 +1,22 @@ +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr}; use anyhow::Result; use key_protocol::key_protocol_core::NSSAUserData; -use nssa::Address; +use nssa::{Account, Address}; +use serde::Serialize; use crate::{ HOME_DIR_ENV_VAR, config::{PersistentAccountData, WalletConfig}, }; -///Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed. +/// Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed. pub fn get_home() -> Result { Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?) } -///Fetch config from `NSSA_WALLET_HOME_DIR` +/// Fetch config from `NSSA_WALLET_HOME_DIR` pub fn fetch_config() -> Result { let config_home = get_home()?; let file = File::open(config_home.join("wallet_config.json"))?; @@ -23,12 +25,12 @@ pub fn fetch_config() -> Result { Ok(serde_json::from_reader(reader)?) } -//ToDo: Replace with structures conversion in future +// ToDo: Replace with structures conversion in future pub fn produce_account_addr_from_hex(hex_str: String) -> Result
{ Ok(hex_str.parse()?) } -///Fetch list of accounts stored at `NSSA_WALLET_HOME_DIR/curr_accounts.json` +/// Fetch list of accounts stored at `NSSA_WALLET_HOME_DIR/curr_accounts.json` /// /// If file not present, it is considered as empty list of persistent accounts pub fn fetch_persistent_accounts() -> Result> { @@ -49,7 +51,7 @@ pub fn fetch_persistent_accounts() -> Result> { } } -///Produces a list of accounts for storage +/// Produces a list of accounts for storage pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec { let mut vec_for_storage = vec![]; @@ -63,6 +65,28 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec 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, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 3814925..3bea629 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -1,6 +1,6 @@ use std::{fs::File, io::Write, path::PathBuf, str::FromStr, sync::Arc}; -use base64::Engine; +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use common::{ ExecutionFailureKind, sequencer_client::{SequencerClient, json::SendTxResponse}, @@ -17,8 +17,8 @@ use nssa_core::account::Account; use crate::{ helperfunctions::{ - fetch_config, fetch_persistent_accounts, get_home, produce_account_addr_from_hex, - produce_data_for_storage, + HumanReadableAccount, fetch_config, fetch_persistent_accounts, get_home, + produce_account_addr_from_hex, produce_data_for_storage, }, poller::TxPoller, }; @@ -144,14 +144,19 @@ impl WalletCore { .nonces) } + ///Get account + pub async fn get_account(&self, addr: Address) -> Result { + let response = self.sequencer_client.get_account(addr.to_string()).await?; + Ok(response.account) + } + ///Poll transactions pub async fn poll_public_native_token_transfer( &self, hash: String, ) -> Result { let transaction_encoded = self.poller.poll_tx(hash).await?; - let tx_base64_decode = - base64::engine::general_purpose::STANDARD.decode(transaction_encoded)?; + let tx_base64_decode = BASE64.decode(transaction_encoded)?; let pub_tx = nssa::PublicTransaction::from_bytes(&tx_base64_decode)?; Ok(pub_tx) @@ -191,6 +196,11 @@ pub enum Command { #[arg(short, long)] addr: String, }, + ///Get account at address `addr` + GetAccount { + #[arg(short, long)] + addr: String, + }, } ///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config @@ -215,21 +225,19 @@ pub async fn execute_subcommand(command: Command) -> Result<()> { .send_public_native_token_transfer(from, to, amount) .await?; - info!("Results of tx send is {res:#?}"); + println!("Results of tx send is {res:#?}"); let transfer_tx = wallet_core .poll_public_native_token_transfer(res.tx_hash) .await?; - info!("Transaction data is {transfer_tx:?}"); + println!("Transaction data is {transfer_tx:?}"); } Command::RegisterAccount {} => { let addr = wallet_core.create_new_account(); + wallet_core.store_persistent_accounts()?; - let key = wallet_core.storage.user_data.get_account_signing_key(&addr); - - info!("Generated new account with addr {addr:#?}"); - info!("With key {key:#?}"); + println!("Generated new account with addr {addr}"); } Command::FetchTx { tx_hash } => { let tx_obj = wallet_core @@ -237,23 +245,26 @@ pub async fn execute_subcommand(command: Command) -> Result<()> { .get_transaction_by_hash(tx_hash) .await?; - info!("Transaction object {tx_obj:#?}"); + println!("Transaction object {tx_obj:#?}"); } Command::GetAccountBalance { addr } => { let addr = Address::from_str(&addr)?; let balance = wallet_core.get_account_balance(addr).await?; - info!("Accounts {addr:#?} balance is {balance}"); + println!("Accounts {addr} balance is {balance}"); } Command::GetAccountNonce { addr } => { let addr = Address::from_str(&addr)?; let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0]; - info!("Accounts {addr:#?} nonce is {nonce}"); + println!("Accounts {addr} nonce is {nonce}"); + } + Command::GetAccount { addr } => { + let addr: Address = addr.parse()?; + let account: HumanReadableAccount = wallet_core.get_account(addr).await?.into(); + println!("{}", serde_json::to_string(&account).unwrap()); } } - wallet_core.store_persistent_accounts()?; - Ok(()) }