fix: cli full refactor

This commit is contained in:
Oleksandr Pravdyvyi 2025-10-28 16:02:30 +02:00
parent b3e4b9a8ca
commit 5840f9b779
No known key found for this signature in database
GPG Key ID: 9F8955C63C443871
11 changed files with 324 additions and 316 deletions

View File

@ -8,3 +8,5 @@ pub mod transaction;
//TODO: Compile only for tests //TODO: Compile only for tests
pub mod test_utils; pub mod test_utils;
pub type HashType = [u8; 32]; pub type HashType = [u8; 32];
pub const PINATA_BASE58: &str = "EfQhKQAkX2FJiwNii2WFQsGndjvF1Mzd7RuVe7QdPLw7";

View File

@ -43,11 +43,11 @@ pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin"); pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin");
fn make_public_account_input_from_str(addr: &str) -> String { fn make_public_account_input_from_str(addr: &str) -> String {
format!("Public/{addr:?}") format!("Public/{addr}")
} }
fn make_private_account_input_from_str(addr: &str) -> String { fn make_private_account_input_from_str(addr: &str) -> String {
format!("Private/{addr:?}") format!("Private/{addr}")
} }
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
@ -92,7 +92,7 @@ pub async fn post_test(residual: (ServerHandle, JoinHandle<Result<()>>, TempDir)
seq_http_server_handle.stop(true).await; seq_http_server_handle.stop(true).await;
let wallet_home = wallet::helperfunctions::get_home().unwrap(); let wallet_home = wallet::helperfunctions::get_home().unwrap();
let persistent_data_home = wallet_home.join("curr_accounts.json"); let persistent_data_home = wallet_home.join("storage.json");
//Removing persistent accounts after run to not affect other executions //Removing persistent accounts after run to not affect other executions
//Not necessary an error, if fails as there is tests for failure scenario //Not necessary an error, if fails as there is tests for failure scenario
@ -163,3 +163,20 @@ async fn verify_commitment_is_in_state(
Ok(Some(_)) Ok(Some(_))
) )
} }
#[cfg(test)]
mod tests {
use crate::{make_private_account_input_from_str, make_public_account_input_from_str};
#[test]
fn correct_addr_from_prefix() {
let addr1 = "cafecafe";
let addr2 = "deadbeaf";
let addr1_pub = make_public_account_input_from_str(addr1);
let addr2_priv = make_private_account_input_from_str(addr2);
assert_eq!(addr1_pub, "Public/cafecafe".to_string());
assert_eq!(addr2_priv, "Private/deadbeaf".to_string());
}
}

View File

@ -1,25 +1,21 @@
use std::{collections::HashMap, path::PathBuf, pin::Pin, time::Duration}; use std::{collections::HashMap, path::PathBuf, pin::Pin, time::Duration};
use common::sequencer_client::SequencerClient; use common::{PINATA_BASE58, sequencer_client::SequencerClient};
use log::info; use log::info;
use nssa::{Address, ProgramDeploymentTransaction, program::Program}; use nssa::{Address, ProgramDeploymentTransaction, program::Program};
use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point}; use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point};
use wallet::{ use wallet::{
Command, SubcommandReturnValue, WalletCore, Command, SubcommandReturnValue, WalletCore,
cli::{ cli::{
account::{AccountSubcommand, FetchSubcommand, NewSubcommand}, account::{AccountSubcommand, NewSubcommand},
native_token_transfer_program::AuthTransferSubcommand, native_token_transfer_program::AuthTransferSubcommand,
pinata_program::{ pinata_program::PinataProgramAgnosticSubcommand,
PinataProgramSubcommand, PinataProgramSubcommandPrivate, PinataProgramSubcommandPublic,
},
token_program::TokenProgramAgnosticSubcommand, token_program::TokenProgramAgnosticSubcommand,
}, },
config::PersistentAccountData, config::{PersistentAccountData, PersistentStorage},
helperfunctions::{fetch_config, fetch_persistent_accounts}, helperfunctions::{fetch_config, fetch_persistent_storage},
}; };
use sequencer_core::sequencer_store::PINATA_BASE58;
use crate::{ use crate::{
ACC_RECEIVER, ACC_RECEIVER_PRIVATE, ACC_SENDER, ACC_SENDER_PRIVATE, ACC_RECEIVER, ACC_RECEIVER_PRIVATE, ACC_SENDER, ACC_SENDER_PRIVATE,
NSSA_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, NSSA_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS,
@ -83,7 +79,10 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
wallet::execute_subcommand(command).await.unwrap(); wallet::execute_subcommand(command).await.unwrap();
let persistent_accounts = fetch_persistent_accounts().await.unwrap(); let PersistentStorage {
accounts: persistent_accounts,
last_synced_block: _,
} = fetch_persistent_storage().await.unwrap();
let mut new_persistent_account_addr = String::new(); let mut new_persistent_account_addr = String::new();
@ -290,7 +289,10 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
.await .await
.unwrap(); .unwrap();
let persistent_accounts = fetch_persistent_accounts().await.unwrap(); let PersistentStorage {
accounts: persistent_accounts,
last_synced_block: _,
} = fetch_persistent_storage().await.unwrap();
let mut new_persistent_accounts_addr = Vec::new(); let mut new_persistent_accounts_addr = Vec::new();
@ -668,7 +670,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
amount: 7, amount: 7,
}; };
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash: _ } =
wallet::execute_subcommand(Command::Token(subcommand)) wallet::execute_subcommand(Command::Token(subcommand))
.await .await
.unwrap() .unwrap()
@ -679,11 +681,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
info!("Waiting for next block creation"); info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let command = Command::Account(AccountSubcommand::Fetch(FetchSubcommand::PrivateAccount { let command = Command::Account(AccountSubcommand::SyncPrivate {});
tx_hash,
acc_addr: recipient_addr.to_string(),
output_id: 1,
}));
wallet::execute_subcommand(command).await.unwrap(); wallet::execute_subcommand(command).await.unwrap();
@ -1096,11 +1094,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await;
let command = Command::Account(AccountSubcommand::Fetch(FetchSubcommand::PrivateAccount { let command = Command::Account(AccountSubcommand::SyncPrivate {});
tx_hash,
acc_addr: to_addr.to_string(),
output_id: 1,
}));
wallet::execute_subcommand(command).await.unwrap(); wallet::execute_subcommand(command).await.unwrap();
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
.await .await
@ -1335,13 +1329,10 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
let pinata_addr = PINATA_BASE58; let pinata_addr = PINATA_BASE58;
let pinata_prize = 150; let pinata_prize = 150;
let solution = 989106; let solution = 989106;
let command = Command::Pinata(PinataProgramSubcommand::Public( let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
PinataProgramSubcommandPublic::Claim { to_addr: make_public_account_input_from_str(ACC_SENDER),
pinata_addr: pinata_addr.to_string(), solution,
winner_addr: ACC_SENDER.to_string(), });
solution,
},
));
let wallet_config = fetch_config().await.unwrap(); let wallet_config = fetch_config().await.unwrap();
@ -1427,14 +1418,18 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
#[nssa_integration_test] #[nssa_integration_test]
pub async fn test_authenticated_transfer_initialize_function() { pub async fn test_authenticated_transfer_initialize_function() {
info!("test initialize account for authenticated transfer"); info!("test initialize account for authenticated transfer");
let command = Command::AuthenticatedTransferInitializePublicAccount {}; let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {}));
let SubcommandReturnValue::RegisterAccount { addr } = let SubcommandReturnValue::RegisterAccount { addr } =
wallet::execute_subcommand(command).await.unwrap() wallet::execute_subcommand(command).await.unwrap()
else { else {
panic!("Error creating account"); panic!("Error creating account");
}; };
let command = Command::AuthTransfer(AuthTransferSubcommand::Init {
addr: addr.to_string(),
});
wallet::execute_subcommand(command).await.unwrap();
info!("Checking correct execution"); info!("Checking correct execution");
let wallet_config = fetch_config().await.unwrap(); let wallet_config = fetch_config().await.unwrap();
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
@ -1463,13 +1458,10 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
let pinata_prize = 150; let pinata_prize = 150;
let solution = 989106; let solution = 989106;
let command = Command::Pinata(PinataProgramSubcommand::Private( let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
PinataProgramSubcommandPrivate::ClaimPrivateOwned { to_addr: make_private_account_input_from_str(ACC_SENDER_PRIVATE),
pinata_addr: pinata_addr.to_string(), solution,
winner_addr: ACC_SENDER_PRIVATE.to_string(), });
solution,
},
));
let wallet_config = fetch_config().await.unwrap(); let wallet_config = fetch_config().await.unwrap();
@ -1481,7 +1473,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
.unwrap() .unwrap()
.balance; .balance;
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash: _ } =
wallet::execute_subcommand(command).await.unwrap() wallet::execute_subcommand(command).await.unwrap()
else { else {
panic!("invalid subcommand return value"); panic!("invalid subcommand return value");
@ -1497,11 +1489,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
.unwrap() .unwrap()
.balance; .balance;
let command = Command::Account(AccountSubcommand::Fetch(FetchSubcommand::PrivateAccount { let command = Command::Account(AccountSubcommand::SyncPrivate {});
tx_hash: tx_hash.clone(),
acc_addr: ACC_SENDER_PRIVATE.to_string(),
output_id: 0,
}));
wallet::execute_subcommand(command).await.unwrap(); wallet::execute_subcommand(command).await.unwrap();
let wallet_config = fetch_config().await.unwrap(); let wallet_config = fetch_config().await.unwrap();
@ -1538,13 +1526,10 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
panic!("invalid subcommand return value"); panic!("invalid subcommand return value");
}; };
let command = Command::Pinata(PinataProgramSubcommand::Private( let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
PinataProgramSubcommandPrivate::ClaimPrivateOwned { to_addr: make_private_account_input_from_str(&winner_addr.to_string()),
pinata_addr: pinata_addr.to_string(), solution,
winner_addr: winner_addr.to_string(), });
solution,
},
));
let wallet_config = fetch_config().await.unwrap(); let wallet_config = fetch_config().await.unwrap();

View File

@ -9,8 +9,6 @@ use crate::config::AccountInitialData;
pub mod block_store; pub mod block_store;
pub const PINATA_BASE58: &str = "EfQhKQAkX2FJiwNii2WFQsGndjvF1Mzd7RuVe7QdPLw7";
pub struct SequecerChainStore { pub struct SequecerChainStore {
pub state: nssa::V02State, pub state: nssa::V02State,
pub block_store: SequecerBlockStore, pub block_store: SequecerBlockStore,
@ -35,6 +33,8 @@ impl SequecerChainStore {
#[cfg(feature = "testnet")] #[cfg(feature = "testnet")]
let state = { let state = {
use common::PINATA_BASE58;
let mut this = let mut this =
nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments); nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments);
this.add_pinata_program(PINATA_BASE58.parse().unwrap()); this.add_pinata_program(PINATA_BASE58.parse().unwrap());

View File

@ -1,7 +1,6 @@
use anyhow::Result; use anyhow::Result;
use base58::ToBase58; use base58::ToBase58;
use clap::Subcommand; use clap::Subcommand;
use common::transaction::NSSATransaction;
use nssa::{Address, program::Program}; use nssa::{Address, program::Program};
use serde::Serialize; use serde::Serialize;
@ -9,6 +8,7 @@ use crate::{
SubcommandReturnValue, WalletCore, SubcommandReturnValue, WalletCore,
cli::WalletSubcommand, cli::WalletSubcommand,
helperfunctions::{AddressPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix}, helperfunctions::{AddressPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix},
parse_block_range,
}; };
const TOKEN_DEFINITION_TYPE: u8 = 0; const TOKEN_DEFINITION_TYPE: u8 = 0;
@ -76,9 +76,6 @@ pub enum AccountSubcommand {
#[arg(short, long)] #[arg(short, long)]
addr: String, addr: String,
}, },
///Fetch
#[command(subcommand)]
Fetch(FetchSubcommand),
///New ///New
#[command(subcommand)] #[command(subcommand)]
New(NewSubcommand), New(NewSubcommand),
@ -86,28 +83,6 @@ pub enum AccountSubcommand {
SyncPrivate {}, SyncPrivate {},
} }
///Represents generic getter CLI subcommand
#[derive(Subcommand, Debug, Clone)]
pub enum FetchSubcommand {
///Fetch transaction by `hash`
Tx {
#[arg(short, long)]
tx_hash: String,
},
///Claim account `acc_addr` generated in transaction `tx_hash`, using secret `sh_secret` at ciphertext id `ciph_id`
PrivateAccount {
///tx_hash - valid 32 byte hex string
#[arg(long)]
tx_hash: String,
///acc_addr - valid 32 byte hex string
#[arg(long)]
acc_addr: String,
///output_id - id of the output in the transaction
#[arg(long)]
output_id: usize,
},
}
///Represents generic register CLI subcommand ///Represents generic register CLI subcommand
#[derive(Subcommand, Debug, Clone)] #[derive(Subcommand, Debug, Clone)]
pub enum NewSubcommand { pub enum NewSubcommand {
@ -117,74 +92,6 @@ pub enum NewSubcommand {
Private {}, Private {},
} }
impl WalletSubcommand for FetchSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
FetchSubcommand::Tx { tx_hash } => {
let tx_obj = wallet_core
.sequencer_client
.get_transaction_by_hash(tx_hash)
.await?;
println!("Transaction object {tx_obj:#?}");
Ok(SubcommandReturnValue::Empty)
}
FetchSubcommand::PrivateAccount {
tx_hash,
acc_addr,
output_id: ciph_id,
} => {
let acc_addr: Address = acc_addr.parse().unwrap();
let account_key_chain = wallet_core
.storage
.user_data
.user_private_accounts
.get(&acc_addr);
let Some((account_key_chain, _)) = account_key_chain else {
anyhow::bail!("Account not found");
};
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let to_ebc = tx.message.encrypted_private_post_states[ciph_id].clone();
let to_comm = tx.message.new_commitments[ciph_id].clone();
let shared_secret =
account_key_chain.calculate_shared_secret_receiver(to_ebc.epk);
let res_acc_to = nssa_core::EncryptionScheme::decrypt(
&to_ebc.ciphertext,
&shared_secret,
&to_comm,
ciph_id as u32,
)
.unwrap();
println!("RES acc to {res_acc_to:#?}");
println!("Transaction data is {:?}", tx.message);
wallet_core
.storage
.insert_private_account_data(acc_addr, res_acc_to);
}
let path = wallet_core.store_persistent_accounts().await?;
println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::Empty)
}
}
}
}
impl WalletSubcommand for NewSubcommand { impl WalletSubcommand for NewSubcommand {
async fn handle_subcommand( async fn handle_subcommand(
self, self,
@ -196,7 +103,7 @@ impl WalletSubcommand for NewSubcommand {
println!("Generated new account with addr {addr}"); println!("Generated new account with addr {addr}");
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -221,7 +128,7 @@ impl WalletSubcommand for NewSubcommand {
hex::encode(key.incoming_viewing_public_key.to_bytes()) hex::encode(key.incoming_viewing_public_key.to_bytes())
); );
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -287,6 +194,8 @@ impl WalletSubcommand for AccountSubcommand {
AccountSubcommand::Get { raw, addr } => { AccountSubcommand::Get { raw, addr } => {
let (addr, addr_kind) = parse_addr_with_privacy_prefix(&addr)?; let (addr, addr_kind) = parse_addr_with_privacy_prefix(&addr)?;
let addr = addr.parse()?;
let account = match addr_kind { let account = match addr_kind {
AddressPrivacyKind::Public => wallet_core.get_account_public(addr).await?, AddressPrivacyKind::Public => wallet_core.get_account_public(addr).await?,
AddressPrivacyKind::Private => wallet_core AddressPrivacyKind::Private => wallet_core
@ -333,14 +242,39 @@ impl WalletSubcommand for AccountSubcommand {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
AccountSubcommand::Fetch(fetch_subcommand) => {
fetch_subcommand.handle_subcommand(wallet_core).await
}
AccountSubcommand::New(new_subcommand) => { AccountSubcommand::New(new_subcommand) => {
new_subcommand.handle_subcommand(wallet_core).await new_subcommand.handle_subcommand(wallet_core).await
} }
AccountSubcommand::SyncPrivate {} => { AccountSubcommand::SyncPrivate {} => {
todo!(); let last_synced_block = wallet_core.last_synced_block;
let curr_last_block = wallet_core
.sequencer_client
.get_last_block()
.await?
.last_block;
if !wallet_core
.storage
.user_data
.user_private_accounts
.is_empty()
{
parse_block_range(
last_synced_block,
curr_last_block,
wallet_core.sequencer_client.clone(),
wallet_core,
)
.await?;
} else {
wallet_core.last_synced_block = curr_last_block;
let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent data at {path:#?}");
}
Ok(SubcommandReturnValue::SyncedToBlock(curr_last_block))
} }
} }
} }

View File

@ -60,11 +60,13 @@ impl WalletSubcommand for AuthTransferSubcommand {
println!("Transaction data is {transfer_tx:?}"); println!("Transaction data is {transfer_tx:?}");
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
} }
AddressPrivacyKind::Private => { AddressPrivacyKind::Private => {
let addr = addr.parse()?;
let (res, [secret]) = wallet_core let (res, [secret]) = wallet_core
.register_account_under_authenticated_transfers_programs_private(addr) .register_account_under_authenticated_transfers_programs_private(addr)
.await?; .await?;
@ -85,7 +87,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
} }
@ -120,33 +122,29 @@ impl WalletSubcommand for AuthTransferSubcommand {
match (from_privacy, to_privacy) { match (from_privacy, to_privacy) {
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => {
NativeTokenTransferProgramSubcommand::Public { NativeTokenTransferProgramSubcommand::Public { from, to, amount }
from: from.to_string(),
to: to.to_string(),
amount,
}
} }
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => {
NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { NativeTokenTransferProgramSubcommandPrivate::PrivateOwned {
from: from.to_string(), from,
to: to.to_string(), to,
amount, amount,
}, },
) )
} }
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => {
NativeTokenTransferProgramSubcommand::Deshielded { NativeTokenTransferProgramSubcommand::Deshielded {
from: from.to_string(), from,
to: to.to_string(), to,
amount, amount,
} }
} }
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => {
NativeTokenTransferProgramSubcommand::Shielded( NativeTokenTransferProgramSubcommand::Shielded(
NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { NativeTokenTransferProgramSubcommandShielded::ShieldedOwned {
from: from.to_string(), from,
to: to.to_string(), to,
amount, amount,
}, },
) )
@ -160,7 +158,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
AddressPrivacyKind::Private => { AddressPrivacyKind::Private => {
NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
from: from.to_string(), from,
to_npk, to_npk,
to_ipk, to_ipk,
amount, amount,
@ -170,7 +168,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
AddressPrivacyKind::Public => { AddressPrivacyKind::Public => {
NativeTokenTransferProgramSubcommand::Shielded( NativeTokenTransferProgramSubcommand::Shielded(
NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { NativeTokenTransferProgramSubcommandShielded::ShieldedForeign {
from: from.to_string(), from,
to_npk, to_npk,
to_ipk, to_ipk,
amount, amount,
@ -340,7 +338,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -384,7 +382,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -434,7 +432,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -467,7 +465,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
let tx_hash = res.tx_hash; let tx_hash = res.tx_hash;
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -513,7 +511,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -533,7 +531,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
println!("Transaction data is {transfer_tx:?}"); println!("Transaction data is {transfer_tx:?}");
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");

View File

@ -1,9 +1,59 @@
use anyhow::Result; use anyhow::Result;
use clap::Subcommand; use clap::Subcommand;
use common::transaction::NSSATransaction; use common::{PINATA_BASE58, transaction::NSSATransaction};
use log::info; use log::info;
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; use crate::{
SubcommandReturnValue, WalletCore,
cli::WalletSubcommand,
helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix},
};
///Represents generic CLI subcommand for a wallet working with pinata program
#[derive(Subcommand, Debug, Clone)]
pub enum PinataProgramAgnosticSubcommand {
///Claim
Claim {
///to_addr - valid 32 byte base58 string
#[arg(long)]
to_addr: String,
///solution - solution to pinata challenge
#[arg(long)]
solution: u128,
},
}
impl WalletSubcommand for PinataProgramAgnosticSubcommand {
async fn handle_subcommand(
self,
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
let underlying_subcommand = match self {
PinataProgramAgnosticSubcommand::Claim { to_addr, solution } => {
let (to_addr, to_addr_privacy) = parse_addr_with_privacy_prefix(&to_addr)?;
match to_addr_privacy {
AddressPrivacyKind::Public => {
PinataProgramSubcommand::Public(PinataProgramSubcommandPublic::Claim {
pinata_addr: PINATA_BASE58.to_string(),
winner_addr: to_addr,
solution,
})
}
AddressPrivacyKind::Private => PinataProgramSubcommand::Private(
PinataProgramSubcommandPrivate::ClaimPrivateOwned {
pinata_addr: PINATA_BASE58.to_string(),
winner_addr: to_addr,
solution,
},
),
}
}
};
underlying_subcommand.handle_subcommand(wallet_core).await
}
}
///Represents generic CLI subcommand for a wallet working with pinata program ///Represents generic CLI subcommand for a wallet working with pinata program
#[derive(Subcommand, Debug, Clone)] #[derive(Subcommand, Debug, Clone)]
@ -131,7 +181,7 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");

View File

@ -64,8 +64,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => {
TokenProgramSubcommand::Public( TokenProgramSubcommand::Public(
TokenProgramSubcommandPublic::CreateNewToken { TokenProgramSubcommandPublic::CreateNewToken {
definition_addr: definition_addr.to_string(), definition_addr,
supply_addr: supply_addr.to_string(), supply_addr,
name, name,
total_supply, total_supply,
}, },
@ -74,18 +74,20 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => {
TokenProgramSubcommand::Private( TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned {
definition_addr: definition_addr.to_string(), definition_addr,
supply_addr: supply_addr.to_string(), supply_addr,
name, name,
total_supply, total_supply,
}, },
) )
} }
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => {
todo!(); //ToDo: maybe implement this one. It is not immediately clear why definition should be private.
anyhow::bail!("Unavailable privacy pairing")
} }
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => {
todo!(); //Probably valid. If definition is not public, but supply is it is very suspicious.
anyhow::bail!("Unavailable privacy pairing")
} }
}; };
@ -120,8 +122,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => {
TokenProgramSubcommand::Public( TokenProgramSubcommand::Public(
TokenProgramSubcommandPublic::TransferToken { TokenProgramSubcommandPublic::TransferToken {
sender_addr: from.to_string(), sender_addr: from,
recipient_addr: to.to_string(), recipient_addr: to,
balance_to_move: amount, balance_to_move: amount,
}, },
) )
@ -129,8 +131,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => {
TokenProgramSubcommand::Private( TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { TokenProgramSubcommandPrivate::TransferTokenPrivateOwned {
sender_addr: from.to_string(), sender_addr: from,
recipient_addr: to.to_string(), recipient_addr: to,
balance_to_move: amount, balance_to_move: amount,
}, },
) )
@ -138,8 +140,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => {
TokenProgramSubcommand::Deshielded( TokenProgramSubcommand::Deshielded(
TokenProgramSubcommandDeshielded::TransferTokenDeshielded { TokenProgramSubcommandDeshielded::TransferTokenDeshielded {
sender_addr: from.to_string(), sender_addr: from,
recipient_addr: to.to_string(), recipient_addr: to,
balance_to_move: amount, balance_to_move: amount,
}, },
) )
@ -147,8 +149,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => {
TokenProgramSubcommand::Shielded( TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::TransferTokenShieldedOwned { TokenProgramSubcommandShielded::TransferTokenShieldedOwned {
sender_addr: from.to_string(), sender_addr: from,
recipient_addr: to.to_string(), recipient_addr: to,
balance_to_move: amount, balance_to_move: amount,
}, },
) )
@ -161,7 +163,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
match from_privacy { match from_privacy {
AddressPrivacyKind::Private => TokenProgramSubcommand::Private( AddressPrivacyKind::Private => TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateForeign { TokenProgramSubcommandPrivate::TransferTokenPrivateForeign {
sender_addr: from.to_string(), sender_addr: from,
recipient_npk: to_npk, recipient_npk: to_npk,
recipient_ipk: to_ipk, recipient_ipk: to_ipk,
balance_to_move: amount, balance_to_move: amount,
@ -169,7 +171,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
), ),
AddressPrivacyKind::Public => TokenProgramSubcommand::Shielded( AddressPrivacyKind::Public => TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::TransferTokenShieldedForeign { TokenProgramSubcommandShielded::TransferTokenShieldedForeign {
sender_addr: from.to_string(), sender_addr: from,
recipient_npk: to_npk, recipient_npk: to_npk,
recipient_ipk: to_ipk, recipient_ipk: to_ipk,
balance_to_move: amount, balance_to_move: amount,
@ -401,7 +403,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -458,7 +460,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -508,7 +510,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -556,7 +558,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -611,7 +613,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
println!("Transaction data is {:?}", tx.message); println!("Transaction data is {:?}", tx.message);
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
@ -665,7 +667,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
)?; )?;
} }
let path = wallet_core.store_persistent_accounts().await?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");

View File

@ -46,6 +46,12 @@ pub enum PersistentAccountData {
Private(PersistentAccountDataPrivate), Private(PersistentAccountDataPrivate),
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersistentStorage {
pub accounts: Vec<PersistentAccountData>,
pub last_synced_block: u64,
}
impl InitialAccountData { impl InitialAccountData {
pub fn address(&self) -> nssa::Address { pub fn address(&self) -> nssa::Address {
match &self { match &self {

View File

@ -12,8 +12,7 @@ use serde::Serialize;
use crate::{ use crate::{
HOME_DIR_ENV_VAR, HOME_DIR_ENV_VAR,
config::{ config::{
PersistentAccountData, PersistentAccountDataPrivate, PersistentAccountDataPublic, PersistentAccountDataPrivate, PersistentAccountDataPublic, PersistentStorage, WalletConfig,
WalletConfig,
}, },
}; };
@ -30,21 +29,24 @@ pub async fn fetch_config() -> Result<WalletConfig> {
Ok(serde_json::from_slice(&config_contents)?) Ok(serde_json::from_slice(&config_contents)?)
} }
/// Fetch list of accounts stored at `NSSA_WALLET_HOME_DIR/curr_accounts.json` /// Fetch data stored at `NSSA_WALLET_HOME_DIR/storage.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 async fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> { pub async fn fetch_persistent_storage() -> Result<PersistentStorage> {
let home = get_home()?; let home = get_home()?;
let accs_path = home.join("curr_accounts.json"); let accs_path = home.join("storage.json");
let mut persistent_accounts_content = vec![]; let mut storage_content = vec![];
match tokio::fs::File::open(accs_path).await { match tokio::fs::File::open(accs_path).await {
Ok(mut file) => { Ok(mut file) => {
file.read_to_end(&mut persistent_accounts_content).await?; file.read_to_end(&mut storage_content).await?;
Ok(serde_json::from_slice(&persistent_accounts_content)?) Ok(serde_json::from_slice(&storage_content)?)
} }
Err(err) => match err.kind() { Err(err) => match err.kind() {
std::io::ErrorKind::NotFound => Ok(vec![]), std::io::ErrorKind::NotFound => Ok(PersistentStorage {
accounts: vec![],
last_synced_block: 0,
}),
_ => { _ => {
anyhow::bail!("IO error {err:#?}"); anyhow::bail!("IO error {err:#?}");
} }
@ -52,8 +54,11 @@ pub async fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> {
} }
} }
/// Produces a list of accounts for storage /// Produces data for storage
pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccountData> { pub fn produce_data_for_storage(
user_data: &NSSAUserData,
last_synced_block: u64,
) -> PersistentStorage {
let mut vec_for_storage = vec![]; let mut vec_for_storage = vec![];
for (addr, key) in &user_data.pub_account_signing_keys { for (addr, key) in &user_data.pub_account_signing_keys {
@ -77,7 +82,10 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccou
); );
} }
vec_for_storage PersistentStorage {
accounts: vec_for_storage,
last_synced_block,
}
} }
pub(crate) fn produce_random_nonces(size: usize) -> Vec<Nonce> { pub(crate) fn produce_random_nonces(size: usize) -> Vec<Nonce> {

View File

@ -20,15 +20,18 @@ use clap::{Parser, Subcommand};
use nssa_core::{Commitment, MembershipProof}; use nssa_core::{Commitment, MembershipProof};
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use crate::cli::{ use crate::{
WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand, cli::{
native_token_transfer_program::AuthTransferSubcommand, pinata_program::PinataProgramSubcommand, WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand,
token_program::TokenProgramAgnosticSubcommand, native_token_transfer_program::AuthTransferSubcommand,
pinata_program::PinataProgramAgnosticSubcommand,
token_program::TokenProgramAgnosticSubcommand,
},
config::PersistentStorage,
helperfunctions::fetch_persistent_storage,
}; };
use crate::{ use crate::{
helperfunctions::{ helperfunctions::{fetch_config, get_home, produce_data_for_storage},
fetch_config, fetch_persistent_accounts, get_home, produce_data_for_storage,
},
poller::TxPoller, poller::TxPoller,
}; };
@ -48,6 +51,7 @@ pub struct WalletCore {
pub storage: WalletChainStore, pub storage: WalletChainStore,
pub poller: TxPoller, pub poller: TxPoller,
pub sequencer_client: Arc<SequencerClient>, pub sequencer_client: Arc<SequencerClient>,
pub last_synced_block: u64,
} }
impl WalletCore { impl WalletCore {
@ -57,7 +61,10 @@ impl WalletCore {
let mut storage = WalletChainStore::new(config)?; let mut storage = WalletChainStore::new(config)?;
let persistent_accounts = fetch_persistent_accounts().await?; let PersistentStorage {
accounts: persistent_accounts,
last_synced_block,
} = fetch_persistent_storage().await?;
for pers_acc_data in persistent_accounts { for pers_acc_data in persistent_accounts {
storage.insert_account_data(pers_acc_data); storage.insert_account_data(pers_acc_data);
} }
@ -66,23 +73,24 @@ impl WalletCore {
storage, storage,
poller: tx_poller, poller: tx_poller,
sequencer_client: client.clone(), sequencer_client: client.clone(),
last_synced_block,
}) })
} }
///Store persistent accounts at home ///Store persistent data at home
pub async fn store_persistent_accounts(&self) -> Result<PathBuf> { pub async fn store_persistent_data(&self) -> Result<PathBuf> {
let home = get_home()?; let home = get_home()?;
let accs_path = home.join("curr_accounts.json"); let storage_path = home.join("storage.json");
let data = produce_data_for_storage(&self.storage.user_data); let data = produce_data_for_storage(&self.storage.user_data, self.last_synced_block);
let accs = serde_json::to_vec_pretty(&data)?; let storage = serde_json::to_vec_pretty(&data)?;
let mut accs_file = tokio::fs::File::create(accs_path.as_path()).await?; let mut storage_file = tokio::fs::File::create(storage_path.as_path()).await?;
accs_file.write_all(&accs).await?; storage_file.write_all(&storage).await?;
info!("Stored accounts data at {accs_path:#?}"); info!("Stored data at {storage_path:#?}");
Ok(accs_path) Ok(storage_path)
} }
pub fn create_new_account_public(&mut self) -> Address { pub fn create_new_account_public(&mut self) -> Address {
@ -201,11 +209,10 @@ pub enum Command {
Account(AccountSubcommand), Account(AccountSubcommand),
///Pinata command ///Pinata command
#[command(subcommand)] #[command(subcommand)]
Pinata(PinataProgramSubcommand), Pinata(PinataProgramAgnosticSubcommand),
///Token command ///Token command
#[command(subcommand)] #[command(subcommand)]
Token(TokenProgramAgnosticSubcommand), Token(TokenProgramAgnosticSubcommand),
AuthenticatedTransferInitializePublicAccount {},
// Check the wallet can connect to the node and builtin local programs // Check the wallet can connect to the node and builtin local programs
// match the remote versions // match the remote versions
CheckHealth {}, CheckHealth {},
@ -229,6 +236,7 @@ pub enum SubcommandReturnValue {
RegisterAccount { addr: nssa::Address }, RegisterAccount { addr: nssa::Address },
Account(nssa::Account), Account(nssa::Account),
Empty, Empty,
SyncedToBlock(u64),
} }
pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValue> { pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValue> {
@ -284,25 +292,6 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
SubcommandReturnValue::Empty SubcommandReturnValue::Empty
} }
Command::AuthenticatedTransferInitializePublicAccount {} => {
let addr = wallet_core.create_new_account_public();
println!("Generated new account with addr {addr}");
let path = wallet_core.store_persistent_accounts().await?;
println!("Stored persistent accounts at {path:#?}");
let res = wallet_core
.register_account_under_authenticated_transfers_programs(addr)
.await?;
println!("Results of tx send is {res:#?}");
let _transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?;
SubcommandReturnValue::RegisterAccount { addr }
}
Command::Token(token_subcommand) => { Command::Token(token_subcommand) => {
token_subcommand.handle_subcommand(&mut wallet_core).await? token_subcommand.handle_subcommand(&mut wallet_core).await?
} }
@ -311,6 +300,80 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
Ok(subcommand_ret) Ok(subcommand_ret)
} }
pub async fn parse_block_range(
start: u64,
stop: u64,
seq_client: Arc<SequencerClient>,
wallet_core: &mut WalletCore,
) -> Result<()> {
for block_id in start..(stop + 1) {
let block =
borsh::from_slice::<HashableBlockData>(&seq_client.get_block(block_id).await?.block)?;
for tx in block.transactions {
let nssa_tx = NSSATransaction::try_from(&tx)?;
if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx {
let mut affected_accounts = vec![];
for (acc_addr, (key_chain, _)) in
&wallet_core.storage.user_data.user_private_accounts
{
let view_tag = EncryptedAccountData::compute_view_tag(
key_chain.nullifer_public_key.clone(),
key_chain.incoming_viewing_public_key.clone(),
);
for (ciph_id, encrypted_data) in tx
.message()
.encrypted_private_post_states
.iter()
.enumerate()
{
if encrypted_data.view_tag == view_tag {
let ciphertext = &encrypted_data.ciphertext;
let commitment = &tx.message.new_commitments[ciph_id];
let shared_secret = key_chain
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
let res_acc = nssa_core::EncryptionScheme::decrypt(
ciphertext,
&shared_secret,
commitment,
ciph_id as u32,
);
if let Some(res_acc) = res_acc {
println!(
"Received new account for addr {acc_addr:#?} with account object {res_acc:#?}"
);
affected_accounts.push((*acc_addr, res_acc));
}
}
}
}
for (affected_addr, new_acc) in affected_accounts {
wallet_core
.storage
.insert_private_account_data(affected_addr, new_acc);
}
}
}
wallet_core.last_synced_block = block_id;
wallet_core.store_persistent_data().await?;
println!(
"Block at id {block_id} with timestamp {} parsed",
block.timestamp
);
}
Ok(())
}
pub async fn execute_continious_run() -> Result<()> { pub async fn execute_continious_run() -> Result<()> {
let config = fetch_config().await?; let config = fetch_config().await?;
let seq_client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?); let seq_client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?);
@ -320,70 +383,13 @@ pub async fn execute_continious_run() -> Result<()> {
let mut curr_last_block = latest_block_num; let mut curr_last_block = latest_block_num;
loop { loop {
for block_id in curr_last_block..(latest_block_num + 1) { parse_block_range(
let block = borsh::from_slice::<HashableBlockData>( curr_last_block,
&seq_client.get_block(block_id).await?.block, latest_block_num,
)?; seq_client.clone(),
&mut wallet_core,
for tx in block.transactions { )
let nssa_tx = NSSATransaction::try_from(&tx)?; .await?;
if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx {
let mut affected_accounts = vec![];
for (acc_addr, (key_chain, _)) in
&wallet_core.storage.user_data.user_private_accounts
{
let view_tag = EncryptedAccountData::compute_view_tag(
key_chain.nullifer_public_key.clone(),
key_chain.incoming_viewing_public_key.clone(),
);
for (ciph_id, encrypted_data) in tx
.message()
.encrypted_private_post_states
.iter()
.enumerate()
{
if encrypted_data.view_tag == view_tag {
let ciphertext = &encrypted_data.ciphertext;
let commitment = &tx.message.new_commitments[ciph_id];
let shared_secret = key_chain
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
let res_acc = nssa_core::EncryptionScheme::decrypt(
ciphertext,
&shared_secret,
commitment,
ciph_id as u32,
);
if let Some(res_acc) = res_acc {
println!(
"Received new account for addr {acc_addr:#?} with account object {res_acc:#?}"
);
affected_accounts.push((*acc_addr, res_acc));
}
}
}
}
for (affected_addr, new_acc) in affected_accounts {
wallet_core
.storage
.insert_private_account_data(affected_addr, new_acc);
}
}
}
wallet_core.store_persistent_accounts().await?;
println!(
"Block at id {block_id} with timestamp {} parsed",
block.timestamp
);
}
curr_last_block = latest_block_num + 1; curr_last_block = latest_block_num + 1;