From 1d627ce5b961a49a138881ee65a7b1ad5fc07fa7 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Thu, 4 Sep 2025 13:33:17 +0300 Subject: [PATCH] fix: suggestions 1 --- common/src/rpc_primitives/requests.rs | 14 ++++ sequencer_rpc/src/process.rs | 100 +++++++++++++++++++++++--- wallet/src/lib.rs | 68 ++++++++---------- wallet/src/poller.rs | 12 ++++ 4 files changed, 145 insertions(+), 49 deletions(-) diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs index 674c077..a4c18d7 100644 --- a/common/src/rpc_primitives/requests.rs +++ b/common/src/rpc_primitives/requests.rs @@ -48,6 +48,11 @@ pub struct GetAccountsNoncesRequest { pub addresses: Vec, } +#[derive(Serialize, Deserialize, Debug)] +pub struct GetAccountDataRequest { + pub address: String, +} + parse_request!(HelloRequest); parse_request!(RegisterAccountRequest); parse_request!(SendTxRequest); @@ -58,6 +63,7 @@ parse_request!(GetInitialTestnetAccountsRequest); parse_request!(GetAccountBalanceRequest); parse_request!(GetTransactionByHashRequest); parse_request!(GetAccountsNoncesRequest); +parse_request!(GetAccountDataRequest); #[derive(Serialize, Deserialize, Debug)] pub struct HelloResponse { @@ -104,3 +110,11 @@ pub struct GetAccountsNoncesResponse { pub struct GetTransactionByHashResponse { pub transaction: Option, } + +#[derive(Serialize, Deserialize, Debug)] +pub struct GetAccountDataResponse { + pub balance: u128, + pub nonce: u128, + pub program_owner: [u32; 8], + pub data: Vec, +} diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index d994210..5d7b4be 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -12,9 +12,10 @@ use common::{ message::{Message, Request}, parser::RpcRequest, requests::{ - GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountsNoncesRequest, - GetAccountsNoncesResponse, GetInitialTestnetAccountsRequest, - GetTransactionByHashRequest, GetTransactionByHashResponse, + GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountDataRequest, + GetAccountDataResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, + GetInitialTestnetAccountsRequest, GetTransactionByHashRequest, + GetTransactionByHashResponse, }, }, }; @@ -35,6 +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 HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER"; @@ -181,14 +183,9 @@ impl JsonHandler { let get_account_nonces_req = GetAccountsNoncesRequest::parse(Some(request.params))?; let mut addresses = vec![]; for address_raw in get_account_nonces_req.addresses { - let address_bytes = hex::decode(address_raw) - .map_err(|_| RpcError::invalid_params("invalid hex".to_string()))?; - - let address = nssa::Address::new( - address_bytes - .try_into() - .map_err(|_| RpcError::invalid_params("invalid length".to_string()))?, - ); + let address = address_raw + .parse::() + .map_err(|e| RpcError::invalid_params(e.to_string()))?; addresses.push(address); } @@ -207,6 +204,32 @@ impl JsonHandler { respond(helperstruct) } + ///Returns account struct for give 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))?; + + let address = get_account_nonces_req + .address + .parse::() + .map_err(|e| RpcError::invalid_params(e.to_string()))?; + + let account = { + let state = self.sequencer_state.lock().await; + + 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, + }; + + respond(helperstruct) + } + /// Returns the transaction corresponding to the given hash, if it exists in the blockchain. /// The hash must be a valid hex string of the correct length. async fn process_get_transaction_by_hash(&self, request: Request) -> Result { @@ -242,6 +265,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_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await, _ => Err(RpcErr(RpcError::method_not_found(request.method))), } @@ -505,6 +529,60 @@ mod tests { assert_eq!(response, expected_response); } + #[actix_web::test] + async fn test_get_account_data_for_non_existent_account() { + let (json_handler, _, _) = components_for_tests(); + let request = serde_json::json!({ + "jsonrpc": "2.0", + "method": "get_account_data", + "params": { "address": "efac".repeat(16) }, + "id": 1 + }); + let expected_response = serde_json::json!({ + "id": 1, + "jsonrpc": "2.0", + "result": { + "balance": 0, + "nonce": 0, + "program_owner": [ 0, 0, 0, 0, 0, 0, 0, 0], + "data": [], + } + }); + + let response = call_rpc_handler_with_json(json_handler, request).await; + + assert_eq!(response, expected_response); + } + + #[actix_web::test] + async fn test_get_account_data_for_existent_account() { + let (json_handler, initial_accounts, _) = components_for_tests(); + + let acc_1_addr = initial_accounts[0].addr.clone(); + + let request = serde_json::json!({ + "jsonrpc": "2.0", + "method": "get_account_data", + "params": { "address": acc_1_addr }, + "id": 1 + }); + + let expected_response = serde_json::json!({ + "id": 1, + "jsonrpc": "2.0", + "result": { + "balance": 9990, + "nonce": 1, + "program_owner": [ 1793544791, 852173979, 3315478100u32, 4158236927u32, 146723505, 3793635251u32, 999304864, 2535706995u32], + "data": [], + } + }); + + let response = call_rpc_handler_with_json(json_handler, request).await; + + assert_eq!(response, expected_response); + } + #[actix_web::test] async fn test_get_transaction_by_hash_for_non_existent_hash() { let (json_handler, _, _) = components_for_tests(); diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 7ce7955..8d4efc8 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -39,13 +39,7 @@ pub struct WalletCore { impl WalletCore { pub fn start_from_config_update_chain(config: WalletConfig) -> Result { let client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?); - let tx_poller = TxPoller { - polling_delay_millis: config.seq_poll_timeout_millis, - polling_max_blocks_to_query: config.seq_poll_max_blocks, - polling_max_error_attempts: config.seq_poll_max_retries, - polling_error_delay_millis: config.seq_poll_retry_delay_millis, - client: client.clone(), - }; + let tx_poller = TxPoller::new(config.clone(), client.clone()); let mut storage = WalletChainStore::new(config)?; @@ -61,7 +55,7 @@ impl WalletCore { }) } - ///Stre persistent accounts at home + ///Store persistent accounts at home pub fn store_persistent_accounts(&self) -> Result { let home = get_home()?; let accs_path = home.join("curr_accounts.json"); @@ -96,41 +90,39 @@ impl WalletCore { to: Address, balance_to_move: u128, ) -> Result { - 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(); + let Ok(balance) = self.get_account_balance(from).await else { + return Err(ExecutionFailureKind::SequencerError); + }; - let signing_key = self.storage.user_data.get_account_signing_key(&from); + if balance >= balance_to_move { + let Ok(nonces) = self.get_accounts_nonces(vec![from]).await else { + return Err(ExecutionFailureKind::SequencerError); + }; - if let Some(signing_key) = signing_key { - let witness_set = nssa::public_transaction::WitnessSet::for_message( - &message, - &[signing_key], - ); + 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(); - let tx = nssa::PublicTransaction::new(message, witness_set); + let signing_key = self.storage.user_data.get_account_signing_key(&from); - Ok(self.sequencer_client.send_tx(tx).await?) - } else { - Err(ExecutionFailureKind::KeyNotFoundError) - } - } else { - Err(ExecutionFailureKind::SequencerError) - } - } else { - Err(ExecutionFailureKind::InsufficientFundsError) - } + let Some(signing_key) = signing_key else { + return Err(ExecutionFailureKind::KeyNotFoundError); + }; + + 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 { - Err(ExecutionFailureKind::SequencerError) + Err(ExecutionFailureKind::InsufficientFundsError) } } diff --git a/wallet/src/poller.rs b/wallet/src/poller.rs index 8fd219f..279197f 100644 --- a/wallet/src/poller.rs +++ b/wallet/src/poller.rs @@ -4,6 +4,8 @@ use anyhow::Result; use common::sequencer_client::SequencerClient; use log::{info, warn}; +use crate::config::WalletConfig; + #[derive(Clone)] ///Helperstruct to poll transactions pub struct TxPoller { @@ -15,6 +17,16 @@ pub struct TxPoller { } impl TxPoller { + pub fn new(config: WalletConfig, client: Arc) -> Self { + Self { + polling_delay_millis: config.seq_poll_timeout_millis, + polling_max_blocks_to_query: config.seq_poll_max_blocks, + polling_max_error_attempts: config.seq_poll_max_retries, + polling_error_delay_millis: config.seq_poll_retry_delay_millis, + client: client.clone(), + } + } + pub async fn poll_tx(&self, tx_hash: String) -> Result { let max_blocks_to_query = self.polling_max_blocks_to_query;