mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 13:23:10 +00:00
Merge pull request #117 from vacp2p/schouhy/add-get-account-command
Add `get-account` wallet command.
This commit is contained in:
commit
bf95a4112e
@ -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<u8>,
|
||||
pub struct GetAccountResponse {
|
||||
pub account: nssa::Account,
|
||||
}
|
||||
|
||||
@ -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,21 @@ impl SequencerClient {
|
||||
Ok(resp_deser)
|
||||
}
|
||||
|
||||
pub async fn get_account(
|
||||
&self,
|
||||
address: String,
|
||||
) -> Result<GetAccountResponse, SequencerClientError> {
|
||||
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,
|
||||
|
||||
@ -29,3 +29,6 @@ path = "../wallet"
|
||||
|
||||
[dependencies.common]
|
||||
path = "../common"
|
||||
|
||||
[dependencies.nssa]
|
||||
path = "../nssa"
|
||||
|
||||
@ -5,6 +5,7 @@ use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use common::sequencer_client::SequencerClient;
|
||||
use log::{info, warn};
|
||||
use nssa::program::Program;
|
||||
use sequencer_core::config::SequencerConfig;
|
||||
use sequencer_runner::startup_sequencer;
|
||||
use tempfile::TempDir;
|
||||
@ -272,6 +273,36 @@ pub async fn test_success_two_transactions() {
|
||||
info!("Second TX Success!");
|
||||
}
|
||||
|
||||
pub async fn test_get_account_wallet_command() {
|
||||
let command = Command::GetAccount {
|
||||
addr: ACC_SENDER.to_string(),
|
||||
};
|
||||
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
info!("Checking correct account");
|
||||
let account = seq_client
|
||||
.get_account(ACC_SENDER.to_string())
|
||||
.await
|
||||
.unwrap()
|
||||
.account;
|
||||
|
||||
assert_eq!(
|
||||
account.program_owner,
|
||||
Program::authenticated_transfer_program().id()
|
||||
);
|
||||
assert_eq!(account.balance, 10000);
|
||||
assert!(account.data.is_empty());
|
||||
assert_eq!(account.nonce, 0);
|
||||
}
|
||||
|
||||
macro_rules! test_cleanup_wrap {
|
||||
($home_dir:ident, $test_func:ident) => {{
|
||||
let res = pre_test($home_dir.clone()).await.unwrap();
|
||||
@ -304,6 +335,9 @@ pub async fn main_tests_runner() -> Result<()> {
|
||||
"test_failure" => {
|
||||
test_cleanup_wrap!(home_dir, test_failure);
|
||||
}
|
||||
"test_get_account_wallet_command" => {
|
||||
test_cleanup_wrap!(home_dir, test_get_account_wallet_command);
|
||||
}
|
||||
"test_success_two_transactions" => {
|
||||
test_cleanup_wrap!(home_dir, test_success_two_transactions);
|
||||
}
|
||||
@ -312,6 +346,7 @@ pub async fn main_tests_runner() -> Result<()> {
|
||||
test_cleanup_wrap!(home_dir, test_success);
|
||||
test_cleanup_wrap!(home_dir, test_failure);
|
||||
test_cleanup_wrap!(home_dir, test_success_two_transactions);
|
||||
test_cleanup_wrap!(home_dir, test_get_account_wallet_command);
|
||||
}
|
||||
_ => {
|
||||
anyhow::bail!("Unknown test name");
|
||||
|
||||
@ -8,6 +8,7 @@ mod signature;
|
||||
mod state;
|
||||
|
||||
pub use address::Address;
|
||||
pub use nssa_core::account::Account;
|
||||
pub use privacy_preserving_transaction::{
|
||||
PrivacyPreservingTransaction, circuit::execute_and_prove,
|
||||
};
|
||||
|
||||
@ -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<Value, RpcErr> {
|
||||
let get_account_nonces_req = GetAccountDataRequest::parse(Some(request.params))?;
|
||||
async fn process_get_account(&self, request: Request) -> Result<Value, RpcErr> {
|
||||
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": [],
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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<PathBuf> {
|
||||
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<WalletConfig> {
|
||||
let config_home = get_home()?;
|
||||
let file = File::open(config_home.join("wallet_config.json"))?;
|
||||
@ -23,12 +25,12 @@ pub fn fetch_config() -> Result<WalletConfig> {
|
||||
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<Address> {
|
||||
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<Vec<PersistentAccountData>> {
|
||||
@ -49,7 +51,7 @@ pub fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> {
|
||||
}
|
||||
}
|
||||
|
||||
///Produces a list of accounts for storage
|
||||
/// Produces a list of accounts for storage
|
||||
pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccountData> {
|
||||
let mut vec_for_storage = vec![];
|
||||
|
||||
@ -63,6 +65,28 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccou
|
||||
vec_for_storage
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@ -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<Account> {
|
||||
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<nssa::PublicTransaction> {
|
||||
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(())
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user