From 88446b17f9f735fcae4c768061ff9744c3f475c5 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 15 Oct 2025 15:17:30 +0300 Subject: [PATCH] feat: automatic mode added --- common/src/sequencer_client/mod.rs | 17 +++++- wallet/src/lib.rs | 93 +++++++++++++++++++++++++++++- wallet/src/main.rs | 10 +++- 3 files changed, 114 insertions(+), 6 deletions(-) diff --git a/common/src/sequencer_client/mod.rs b/common/src/sequencer_client/mod.rs index 1aec903..3c27cae 100644 --- a/common/src/sequencer_client/mod.rs +++ b/common/src/sequencer_client/mod.rs @@ -9,8 +9,8 @@ use serde_json::Value; use crate::rpc_primitives::requests::{ GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, - GetProofForCommitmentRequest, GetProofForCommitmentResponse, GetTransactionByHashRequest, - GetTransactionByHashResponse, + GetLastBlockRequest, GetLastBlockResponse, GetProofForCommitmentRequest, + GetProofForCommitmentResponse, GetTransactionByHashRequest, GetTransactionByHashResponse, }; use crate::sequencer_client::json::AccountInitialData; use crate::transaction::{EncodedTransaction, NSSATransaction}; @@ -74,6 +74,19 @@ impl SequencerClient { Ok(resp_deser) } + ///Get last known `blokc_id` from sequencer + pub async fn get_last_block(&self) -> Result { + let block_req = GetLastBlockRequest {}; + + let req = serde_json::to_value(block_req)?; + + let resp = self.call_method_with_payload("get_last_block", req).await?; + + let resp_deser = serde_json::from_value(resp)?; + + Ok(resp_deser) + } + ///Get account public balance for `address`. `address` must be a valid hex-string for 32 bytes. pub async fn get_account_balance( &self, diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 65eca41..36e78e6 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -2,6 +2,7 @@ use std::{fs::File, io::Write, path::PathBuf, sync::Arc}; use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use common::{ + block::HashableBlockData, sequencer_client::SequencerClient, transaction::{EncodedTransaction, NSSATransaction}, }; @@ -10,7 +11,7 @@ use anyhow::Result; use chain_storage::WalletChainStore; use config::WalletConfig; use log::info; -use nssa::{Account, Address}; +use nssa::{Account, Address, privacy_preserving_transaction::message::EncryptedAccountData}; use clap::{Parser, Subcommand}; use nssa_core::Commitment; @@ -202,9 +203,12 @@ pub enum Command { #[derive(Parser, Debug)] #[clap(version, about)] pub struct Args { + /// Continious run flag + #[arg(short, long)] + pub continious_run: bool, /// Wallet command #[command(subcommand)] - pub command: Command, + pub command: Option, } #[derive(Debug, Clone)] @@ -240,3 +244,88 @@ pub async fn execute_subcommand(command: Command) -> Result Result<()> { + let config = fetch_config()?; + let seq_client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?); + let mut wallet_core = WalletCore::start_from_config_update_chain(config.clone())?; + + let mut latest_block_num = seq_client.get_last_block().await?.last_block; + let mut curr_last_block = latest_block_num; + + loop { + for block_id in curr_last_block..(latest_block_num + 1) { + let block = borsh::from_slice::( + &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.store_persistent_accounts()?; + + println!( + "Block at id {block_id} with timestamp {} parsed", + block.timestamp + ); + } + + curr_last_block = latest_block_num + 1; + + tokio::time::sleep(std::time::Duration::from_millis( + config.seq_poll_timeout_millis, + )) + .await; + + latest_block_num = seq_client.get_last_block().await?.last_block; + } +} diff --git a/wallet/src/main.rs b/wallet/src/main.rs index b296400..9cab532 100644 --- a/wallet/src/main.rs +++ b/wallet/src/main.rs @@ -1,7 +1,7 @@ use anyhow::Result; use clap::Parser; use tokio::runtime::Builder; -use wallet::{Args, execute_subcommand}; +use wallet::{Args, execute_continious_run, execute_subcommand}; pub const NUM_THREADS: usize = 2; @@ -17,7 +17,13 @@ fn main() -> Result<()> { env_logger::init(); runtime.block_on(async move { - execute_subcommand(args.command).await.unwrap(); + if let Some(command) = args.command { + execute_subcommand(command).await.unwrap(); + } else if args.continious_run { + execute_continious_run().await.unwrap(); + } else { + println!("NOTHING TO DO"); + } }); Ok(())