fix: update to pr 104

This commit is contained in:
Oleksandr Pravdyvyi 2025-09-02 09:01:33 +03:00
parent 4363a16a62
commit 6967c0c22f
No known key found for this signature in database
GPG Key ID: 9F8955C63C443871
9 changed files with 137 additions and 75 deletions

View File

@ -7,4 +7,5 @@ source env.sh
cargo test --release cargo test --release
cd integration_tests cd integration_tests
export NSSA_WALLET_HOME_DIR=$(pwd)/configs/debug/wallet/ export NSSA_WALLET_HOME_DIR=$(pwd)/configs/debug/wallet/
export RUST_LOG=info
cargo run $(pwd)/configs/debug all cargo run $(pwd)/configs/debug all

View File

@ -66,6 +66,8 @@ pub enum ExecutionFailureKind {
ProveError(anyhow::Error), ProveError(anyhow::Error),
#[error("Failed to decode data from VM: {0:?}")] #[error("Failed to decode data from VM: {0:?}")]
DecodeError(String), DecodeError(String),
#[error("Failed to get account data from sequencer")]
SequencerError,
#[error("Inputs amounts does not match outputs")] #[error("Inputs amounts does not match outputs")]
AmountMismatchError, AmountMismatchError,
#[error("Accounts key not found")] #[error("Accounts key not found")]

View File

@ -84,7 +84,6 @@ pub async fn post_test(residual: (ServerHandle, JoinHandle<Result<()>>, TempDir)
pub async fn test_success() { pub async fn test_success() {
let command = Command::SendNativeTokenTransfer { let command = Command::SendNativeTokenTransfer {
from: ACC_SENDER.to_string(), from: ACC_SENDER.to_string(),
nonce: 0,
to: ACC_RECEIVER.to_string(), to: ACC_RECEIVER.to_string(),
amount: 100, amount: 100,
}; };
@ -144,7 +143,6 @@ pub async fn test_success_move_to_another_account() {
let command = Command::SendNativeTokenTransfer { let command = Command::SendNativeTokenTransfer {
from: ACC_SENDER.to_string(), from: ACC_SENDER.to_string(),
nonce: 0,
to: new_persistent_account_addr.clone(), to: new_persistent_account_addr.clone(),
amount: 100, amount: 100,
}; };
@ -176,7 +174,6 @@ pub async fn test_success_move_to_another_account() {
pub async fn test_failure() { pub async fn test_failure() {
let command = Command::SendNativeTokenTransfer { let command = Command::SendNativeTokenTransfer {
from: ACC_SENDER.to_string(), from: ACC_SENDER.to_string(),
nonce: 0,
to: ACC_RECEIVER.to_string(), to: ACC_RECEIVER.to_string(),
amount: 1000000, amount: 1000000,
}; };
@ -214,7 +211,6 @@ pub async fn test_failure() {
pub async fn test_success_two_transactions() { pub async fn test_success_two_transactions() {
let command = Command::SendNativeTokenTransfer { let command = Command::SendNativeTokenTransfer {
from: ACC_SENDER.to_string(), from: ACC_SENDER.to_string(),
nonce: 0,
to: ACC_RECEIVER.to_string(), to: ACC_RECEIVER.to_string(),
amount: 100, amount: 100,
}; };
@ -248,7 +244,6 @@ pub async fn test_success_two_transactions() {
let command = Command::SendNativeTokenTransfer { let command = Command::SendNativeTokenTransfer {
from: ACC_SENDER.to_string(), from: ACC_SENDER.to_string(),
nonce: 1,
to: ACC_RECEIVER.to_string(), to: ACC_RECEIVER.to_string(),
amount: 100, amount: 100,
}; };

View File

@ -1,3 +1,5 @@
use std::collections::HashMap;
use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit}; use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit};
use constants_types::{CipherText, Nonce}; use constants_types::{CipherText, Nonce};
use elliptic_curve::point::AffineCoordinates; use elliptic_curve::point::AffineCoordinates;
@ -18,6 +20,8 @@ pub mod secret_holders;
pub struct KeyChain { pub struct KeyChain {
top_secret_key_holder: TopSecretKeyHolder, top_secret_key_holder: TopSecretKeyHolder,
pub utxo_secret_key_holder: UTXOSecretKeyHolder, pub utxo_secret_key_holder: UTXOSecretKeyHolder,
///Map for all users accounts
pub pub_account_signing_keys: HashMap<nssa::Address, nssa::PrivateKey>,
pub nullifer_public_key: PublicKey, pub nullifer_public_key: PublicKey,
pub viewing_public_key: PublicKey, pub viewing_public_key: PublicKey,
} }
@ -39,9 +43,47 @@ impl KeyChain {
utxo_secret_key_holder, utxo_secret_key_holder,
nullifer_public_key, nullifer_public_key,
viewing_public_key, viewing_public_key,
pub_account_signing_keys: HashMap::new(),
} }
} }
pub fn new_os_random_with_accounts(accounts: HashMap<nssa::Address, nssa::PrivateKey>) -> 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( pub fn calculate_shared_secret_receiver(
&self, &self,
ephemeral_public_key_sender: AffinePoint, ephemeral_public_key_sender: AffinePoint,

View File

@ -49,7 +49,7 @@ impl NSSAUserData {
} }
pub fn get_account_signing_key(&self, address: &nssa::Address) -> Option<&nssa::PrivateKey> { pub fn get_account_signing_key(&self, address: &nssa::Address) -> Option<&nssa::PrivateKey> {
self.accounts.get(address).map(|(key, _)| key) self.key_holder.get_pub_account_signing_key(address)
} }
} }

View File

@ -4,7 +4,7 @@ use anyhow::Result;
use common::merkle_tree_public::merkle_tree::UTXOCommitmentsMerkleTree; use common::merkle_tree_public::merkle_tree::UTXOCommitmentsMerkleTree;
use key_protocol::key_protocol_core::NSSAUserData; use key_protocol::key_protocol_core::NSSAUserData;
use crate::config::{InitialAccountData, WalletConfig}; use crate::config::{PersistentAccountData, WalletConfig};
pub struct WalletChainStore { pub struct WalletChainStore {
pub user_data: NSSAUserData, pub user_data: NSSAUserData,
@ -30,10 +30,11 @@ impl WalletChainStore {
}) })
} }
pub(crate) fn insert_account_data(&mut self, acc_data: InitialAccountData) { pub(crate) fn insert_account_data(&mut self, acc_data: PersistentAccountData) {
self.user_data self.user_data
.accounts .key_holder
.insert(acc_data.address, (acc_data.pub_sign_key, acc_data.account)); .pub_account_signing_keys
.insert(acc_data.address, acc_data.pub_sign_key);
} }
} }

View File

@ -8,6 +8,12 @@ pub struct InitialAccountData {
pub pub_sign_key: nssa::PrivateKey, pub pub_sign_key: nssa::PrivateKey,
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersistentAccountData {
pub address: nssa::Address,
pub pub_sign_key: nssa::PrivateKey,
}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GasConfig { pub struct GasConfig {
/// Gas spent per deploying one byte of data /// Gas spent per deploying one byte of data

View File

@ -5,7 +5,7 @@ use key_protocol::key_protocol_core::NSSAUserData;
use nssa::Address; use nssa::Address;
use crate::{ use crate::{
config::{InitialAccountData, WalletConfig}, config::{PersistentAccountData, WalletConfig},
HOME_DIR_ENV_VAR, HOME_DIR_ENV_VAR,
}; };
@ -31,7 +31,7 @@ pub fn produce_account_addr_from_hex(hex_str: String) -> Result<Address> {
///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 /// If file not present, it is considered as empty list of persistent accounts
pub fn fetch_persistent_accounts() -> Result<Vec<InitialAccountData>> { pub fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> {
let home = get_home()?; let home = get_home()?;
let accs_path = home.join("curr_accounts.json"); let accs_path = home.join("curr_accounts.json");
@ -50,13 +50,12 @@ pub fn fetch_persistent_accounts() -> Result<Vec<InitialAccountData>> {
} }
///Produces a list of accounts for storage ///Produces a list of accounts for storage
pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<InitialAccountData> { pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccountData> {
let mut vec_for_storage = vec![]; let mut vec_for_storage = vec![];
for (addr, (key, account)) in &user_data.accounts { for (addr, key) in &user_data.key_holder.pub_account_signing_keys {
vec_for_storage.push(InitialAccountData { vec_for_storage.push(PersistentAccountData {
address: *addr, address: *addr,
account: account.clone(),
pub_sign_key: key.clone(), pub_sign_key: key.clone(),
}); });
} }

View File

@ -1,4 +1,4 @@
use std::{fs::File, io::Write, path::PathBuf, sync::Arc}; use std::{fs::File, io::Write, path::PathBuf, str::FromStr, sync::Arc};
use base64::Engine; use base64::Engine;
use common::{ use common::{
@ -47,7 +47,12 @@ impl WalletCore {
client: client.clone(), client: client.clone(),
}; };
let storage = WalletChainStore::new(config)?; let mut storage = WalletChainStore::new(config)?;
let persistent_accounts = fetch_persistent_accounts()?;
for pers_acc_data in persistent_accounts {
storage.insert_account_data(pers_acc_data);
}
Ok(Self { Ok(Self {
storage, storage,
@ -88,45 +93,65 @@ impl WalletCore {
pub async fn send_public_native_token_transfer( pub async fn send_public_native_token_transfer(
&self, &self,
from: Address, from: Address,
nonce: u128,
to: Address, to: Address,
balance_to_move: u128, balance_to_move: u128,
) -> Result<SendTxResponse, ExecutionFailureKind> { ) -> Result<SendTxResponse, ExecutionFailureKind> {
let account = self.search_for_initial_account(from); if let Ok(balance) = self.get_account_balance(from).await {
if balance >= balance_to_move {
if let Ok(nonces) = self.get_accounts_nonces(vec![from]).await {
let addresses = vec![from, to];
let program_id = nssa::program::Program::authenticated_transfer_program().id();
let message = nssa::public_transaction::Message::try_new(
program_id,
addresses,
nonces,
balance_to_move,
)
.unwrap();
if let Some(account) = account { let signing_key = self.storage.user_data.get_account_signing_key(&from);
if account.balance >= balance_to_move {
let addresses = vec![from, to];
let nonces = vec![nonce];
let program_id = nssa::program::Program::authenticated_transfer_program().id();
let message = nssa::public_transaction::Message::try_new(
program_id,
addresses,
nonces,
balance_to_move,
)
.unwrap();
let signing_key = self.storage.user_data.get_account_signing_key(&from); if let Some(signing_key) = signing_key {
let witness_set = nssa::public_transaction::WitnessSet::for_message(
&message,
&[signing_key],
);
if let Some(signing_key) = signing_key { let tx = nssa::PublicTransaction::new(message, witness_set);
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
let tx = nssa::PublicTransaction::new(message, witness_set); Ok(self.sequencer_client.send_tx(tx).await?)
} else {
Ok(self.sequencer_client.send_tx(tx).await?) Err(ExecutionFailureKind::KeyNotFoundError)
}
} else { } else {
Err(ExecutionFailureKind::KeyNotFoundError) Err(ExecutionFailureKind::SequencerError)
} }
} else { } else {
Err(ExecutionFailureKind::InsufficientFundsError) Err(ExecutionFailureKind::InsufficientFundsError)
} }
} else { } else {
Err(ExecutionFailureKind::AmountMismatchError) Err(ExecutionFailureKind::SequencerError)
} }
} }
///Get account balance
pub async fn get_account_balance(&self, acc: Address) -> Result<u128> {
Ok(self
.sequencer_client
.get_account_balance(acc.to_string())
.await?
.balance)
}
///Get accounts nonces
pub async fn get_accounts_nonces(&self, accs: Vec<Address>) -> Result<Vec<u128>> {
Ok(self
.sequencer_client
.get_accounts_nonces(accs.into_iter().map(|acc| acc.to_string()).collect())
.await?
.nonces)
}
///Poll transactions ///Poll transactions
pub async fn poll_public_native_token_transfer( pub async fn poll_public_native_token_transfer(
&self, &self,
@ -139,27 +164,6 @@ impl WalletCore {
Ok(pub_tx) Ok(pub_tx)
} }
///Execute native token transfer at wallet accounts
pub fn execute_native_token_transfer(
&mut self,
from: Address,
to: Address,
balance_to_move: u128,
) {
self.storage.user_data.increment_account_nonce(from);
self.storage.user_data.increment_account_nonce(to);
let from_bal = self.storage.user_data.get_account_balance(&from);
let to_bal = self.storage.user_data.get_account_balance(&to);
self.storage
.user_data
.update_account_balance(from, from_bal - balance_to_move);
self.storage
.user_data
.update_account_balance(to, to_bal + balance_to_move);
}
} }
///Represents CLI command for a wallet ///Represents CLI command for a wallet
@ -171,9 +175,6 @@ pub enum Command {
///from - valid 32 byte hex string ///from - valid 32 byte hex string
#[arg(long)] #[arg(long)]
from: String, from: String,
///nonce - u128 integer
#[arg(long)]
nonce: u128,
///to - valid 32 byte hex string ///to - valid 32 byte hex string
#[arg(long)] #[arg(long)]
to: String, to: String,
@ -188,6 +189,16 @@ pub enum Command {
#[arg(short, long)] #[arg(short, long)]
tx_hash: String, tx_hash: String,
}, },
///Get account `addr` balance
GetAccountBalance {
#[arg(short, long)]
addr: String,
},
///Get account `addr` nonce
GetAccountNonce {
#[arg(short, long)]
addr: String,
},
} }
///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config ///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config
@ -201,20 +212,15 @@ pub struct Args {
pub async fn execute_subcommand(command: Command) -> Result<()> { pub async fn execute_subcommand(command: Command) -> Result<()> {
let wallet_config = fetch_config()?; let wallet_config = fetch_config()?;
let mut wallet_core = WalletCore::start_from_config_update_chain(wallet_config).await?; let mut wallet_core = WalletCore::start_from_config_update_chain(wallet_config)?;
match command { match command {
Command::SendNativeTokenTransfer { Command::SendNativeTokenTransfer { from, to, amount } => {
from,
nonce,
to,
amount,
} => {
let from = produce_account_addr_from_hex(from)?; let from = produce_account_addr_from_hex(from)?;
let to = produce_account_addr_from_hex(to)?; let to = produce_account_addr_from_hex(to)?;
let res = wallet_core let res = wallet_core
.send_public_native_token_transfer(from, nonce, to, amount) .send_public_native_token_transfer(from, to, amount)
.await?; .await?;
info!("Results of tx send is {res:#?}"); info!("Results of tx send is {res:#?}");
@ -224,8 +230,6 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
.await?; .await?;
info!("Transaction data is {transfer_tx:?}"); info!("Transaction data is {transfer_tx:?}");
wallet_core.execute_native_token_transfer(from, to, amount);
} }
Command::RegisterAccount {} => { Command::RegisterAccount {} => {
let addr = wallet_core.create_new_account(); let addr = wallet_core.create_new_account();
@ -243,6 +247,18 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
info!("Transaction object {tx_obj:#?}"); info!("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}");
}
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}");
}
} }
wallet_core.store_persistent_accounts()?; wallet_core.store_persistent_accounts()?;