From c51fe940ad4804883317dc67796ff4945e4f7ec3 Mon Sep 17 00:00:00 2001 From: Hansie Odendaal Date: Mon, 27 Sep 2021 18:12:02 +0200 Subject: [PATCH 1/2] Reduce console wallet TUI memory usage --- .../src/ui/components/transactions_tab.rs | 36 ++------ .../src/ui/state/app_state.rs | 87 ++++++++++++++++--- 2 files changed, 82 insertions(+), 41 deletions(-) diff --git a/applications/tari_console_wallet/src/ui/components/transactions_tab.rs b/applications/tari_console_wallet/src/ui/components/transactions_tab.rs index 179d97195e..05aa673611 100644 --- a/applications/tari_console_wallet/src/ui/components/transactions_tab.rs +++ b/applications/tari_console_wallet/src/ui/components/transactions_tab.rs @@ -2,17 +2,12 @@ use std::collections::HashMap; use crate::ui::{ components::{balance::Balance, Component}, - state::AppState, + state::{AppState, CompletedTransactionInfo}, widgets::{draw_dialog, MultiColumnList, WindowedListState}, MAX_WIDTH, }; use chrono::{DateTime, Local}; -use tari_crypto::tari_utilities::hex::Hex; -use tari_wallet::transaction_service::storage::models::{ - CompletedTransaction, - TransactionDirection, - TransactionStatus, -}; +use tari_wallet::transaction_service::storage::models::{TransactionDirection, TransactionStatus}; use tokio::runtime::Handle; use tui::{ backend::Backend, @@ -28,7 +23,7 @@ pub struct TransactionsTab { selected_tx_list: SelectedTransactionList, pending_list_state: WindowedListState, completed_list_state: WindowedListState, - detailed_transaction: Option, + detailed_transaction: Option, error_message: Option, confirmation_dialog: bool, } @@ -197,16 +192,11 @@ impl TransactionsTab { app_state.get_alias(&t.source_public_key), Style::default().fg(text_color), ))); - let maturity = if let Some(output) = t.transaction.body.outputs().first() { - output.features.maturity - } else { - 0 - }; let color = match (t.cancelled, chain_height) { // cancelled (true, _) => Color::DarkGray, // not mature yet - (_, Some(height)) if maturity > height => Color::Yellow, + (_, Some(height)) if t.maturity > height => Color::Yellow, // default _ => Color::Green, }; @@ -357,12 +347,7 @@ impl TransactionsTab { format!("{}", local_time.format("%Y-%m-%d %H:%M:%S")), Style::default().fg(Color::White), ); - let excess_hex = tx - .transaction - .first_kernel_excess_sig() - .map(|s| s.get_signature().to_hex()) - .unwrap_or_default(); - let excess = Span::styled(excess_hex.as_str(), Style::default().fg(Color::White)); + let excess = Span::styled(tx.excess_signature.as_str(), Style::default().fg(Color::White)); let confirmation_count = app_state.get_confirmations(&tx.tx_id); let confirmations_msg = if tx.status == TransactionStatus::MinedConfirmed && !tx.cancelled { format!("{} required confirmations met", required_confirmations) @@ -382,15 +367,8 @@ impl TransactionsTab { .unwrap_or_else(|| "N/A".to_string()), Style::default().fg(Color::White), ); - let maturity = tx - .transaction - .body - .outputs() - .first() - .map(|o| o.features.maturity) - .unwrap_or_else(|| 0); - let maturity = if maturity > 0 { - format!("Spendable at Block #{}", maturity) + let maturity = if tx.maturity > 0 { + format!("Spendable at Block #{}", tx.maturity) } else { "N/A".to_string() }; diff --git a/applications/tari_console_wallet/src/ui/state/app_state.rs b/applications/tari_console_wallet/src/ui/state/app_state.rs index 420a7abb4e..3461e7b47e 100644 --- a/applications/tari_console_wallet/src/ui/state/app_state.rs +++ b/applications/tari_console_wallet/src/ui/state/app_state.rs @@ -27,7 +27,7 @@ use std::{ }; use bitflags::bitflags; -use chrono::{DateTime, Local}; +use chrono::{DateTime, Local, NaiveDateTime}; use log::*; use qrcode::{render::unicode, QrCode}; use tari_crypto::{ristretto::RistrettoPublicKey, tari_utilities::hex::Hex}; @@ -75,7 +75,10 @@ use crate::{ utils::db::{CUSTOM_BASE_NODE_ADDRESS_KEY, CUSTOM_BASE_NODE_PUBLIC_KEY_KEY}, wallet_modes::PeerConfig, }; -use tari_wallet::output_manager_service::handle::OutputManagerHandle; +use tari_wallet::{ + output_manager_service::handle::OutputManagerHandle, + transaction_service::storage::models::TransactionDirection, +}; const LOG_TARGET: &str = "wallet::console_wallet::app_state"; @@ -320,11 +323,11 @@ impl AppState { &self.cached_data.contacts[start..end] } - pub fn get_pending_txs(&self) -> &Vec { + pub fn get_pending_txs(&self) -> &Vec { &self.cached_data.pending_txs } - pub fn get_pending_txs_slice(&self, start: usize, end: usize) -> &[CompletedTransaction] { + pub fn get_pending_txs_slice(&self, start: usize, end: usize) -> &[CompletedTransactionInfo] { if self.cached_data.pending_txs.is_empty() || start > end || end > self.cached_data.pending_txs.len() { return &[]; } @@ -332,7 +335,7 @@ impl AppState { &self.cached_data.pending_txs[start..end] } - pub fn get_pending_tx(&self, index: usize) -> Option<&CompletedTransaction> { + pub fn get_pending_tx(&self, index: usize) -> Option<&CompletedTransactionInfo> { if index < self.cached_data.pending_txs.len() { Some(&self.cached_data.pending_txs[index]) } else { @@ -340,7 +343,7 @@ impl AppState { } } - pub fn get_completed_txs(&self) -> Vec<&CompletedTransaction> { + pub fn get_completed_txs(&self) -> Vec<&CompletedTransactionInfo> { if self .completed_tx_filter .contains(TransactionFilter::ABANDONED_COINBASES) @@ -359,7 +362,7 @@ impl AppState { (&self.cached_data.confirmations).get(tx_id) } - pub fn get_completed_tx(&self, index: usize) -> Option<&CompletedTransaction> { + pub fn get_completed_tx(&self, index: usize) -> Option<&CompletedTransactionInfo> { let filtered_completed_txs = self.get_completed_txs(); if index < filtered_completed_txs.len() { Some(filtered_completed_txs[index]) @@ -519,7 +522,10 @@ impl AppStateInner { pending_transactions.sort_by(|a: &CompletedTransaction, b: &CompletedTransaction| { b.timestamp.partial_cmp(&a.timestamp).unwrap() }); - self.data.pending_txs = pending_transactions; + self.data.pending_txs = pending_transactions + .iter() + .map(|tx| CompletedTransactionInfo::from(tx.clone())) + .collect(); let mut completed_transactions: Vec = Vec::new(); completed_transactions.extend( @@ -548,7 +554,10 @@ impl AppStateInner { .expect("Should be able to compare timestamps") }); - self.data.completed_txs = completed_transactions; + self.data.completed_txs = completed_transactions + .iter() + .map(|tx| CompletedTransactionInfo::from(tx.clone())) + .collect(); self.updated = true; Ok(()) } @@ -590,7 +599,7 @@ impl AppStateInner { }); }, Some(tx) => { - let tx = CompletedTransaction::from(tx); + let tx = CompletedTransactionInfo::from(CompletedTransaction::from(tx)); if let Some(index) = self.data.pending_txs.iter().position(|i| i.tx_id == tx_id) { if tx.status == TransactionStatus::Pending && !tx.cancelled { self.data.pending_txs[index] = tx; @@ -852,10 +861,64 @@ impl AppStateInner { } } +#[derive(Clone)] +pub struct CompletedTransactionInfo { + pub tx_id: TxId, + pub source_public_key: CommsPublicKey, + pub destination_public_key: CommsPublicKey, + pub amount: MicroTari, + pub fee: MicroTari, + pub excess_signature: String, + pub maturity: u64, + pub status: TransactionStatus, + pub message: String, + pub timestamp: NaiveDateTime, + pub cancelled: bool, + pub direction: TransactionDirection, + pub valid: bool, + pub mined_height: Option, +} + +impl From for CompletedTransactionInfo { + fn from(completed_transaction: CompletedTransaction) -> Self { + let excess_signature = if completed_transaction.transaction.body.kernels().is_empty() { + "".to_string() + } else { + completed_transaction.transaction.body.kernels()[0] + .excess_sig + .get_signature() + .to_hex() + }; + + Self { + tx_id: completed_transaction.tx_id, + source_public_key: completed_transaction.source_public_key, + destination_public_key: completed_transaction.destination_public_key, + amount: completed_transaction.amount, + fee: completed_transaction.fee, + excess_signature, + maturity: completed_transaction + .transaction + .body + .outputs() + .first() + .map(|o| o.features.maturity) + .unwrap_or_else(|| 0), + status: completed_transaction.status, + message: completed_transaction.message, + timestamp: completed_transaction.timestamp, + cancelled: completed_transaction.cancelled, + direction: completed_transaction.direction, + valid: completed_transaction.valid, + mined_height: completed_transaction.mined_height, + } + } +} + #[derive(Clone)] struct AppStateData { - pending_txs: Vec, - completed_txs: Vec, + pending_txs: Vec, + completed_txs: Vec, confirmations: HashMap, my_identity: MyIdentity, contacts: Vec, From db078178fe5957247e48adc1476da094e2cfa844 Mon Sep 17 00:00:00 2001 From: Hansie Odendaal Date: Thu, 30 Sep 2021 15:30:18 +0200 Subject: [PATCH 2/2] Updated after conflicts with #3393 --- .../src/ui/components/transactions_tab.rs | 6 ++---- .../src/ui/state/app_state.rs | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/applications/tari_console_wallet/src/ui/components/transactions_tab.rs b/applications/tari_console_wallet/src/ui/components/transactions_tab.rs index 05aa673611..f50dc0b7b9 100644 --- a/applications/tari_console_wallet/src/ui/components/transactions_tab.rs +++ b/applications/tari_console_wallet/src/ui/components/transactions_tab.rs @@ -316,15 +316,13 @@ impl TransactionsTab { }; let direction = Span::styled(format!("{}", tx.direction), Style::default().fg(Color::White)); let amount = Span::styled(format!("{}", tx.amount), Style::default().fg(Color::White)); - let fee_details = if tx.is_coinbase() { + let fee_details = if tx.is_coinbase { Span::raw("") } else { Span::styled( format!( " (weight: {}g, #inputs: {}, #outputs: {})", - tx.transaction.calculate_weight(), - tx.transaction.body.inputs().len(), - tx.transaction.body.outputs().len() + tx.weight, tx.inputs_count, tx.outputs_count ), Style::default().fg(Color::Gray), ) diff --git a/applications/tari_console_wallet/src/ui/state/app_state.rs b/applications/tari_console_wallet/src/ui/state/app_state.rs index 3461e7b47e..449ea4ffd6 100644 --- a/applications/tari_console_wallet/src/ui/state/app_state.rs +++ b/applications/tari_console_wallet/src/ui/state/app_state.rs @@ -877,6 +877,10 @@ pub struct CompletedTransactionInfo { pub direction: TransactionDirection, pub valid: bool, pub mined_height: Option, + pub is_coinbase: bool, + pub weight: u64, + pub inputs_count: usize, + pub outputs_count: usize, } impl From for CompletedTransactionInfo { @@ -892,8 +896,8 @@ impl From for CompletedTransactionInfo { Self { tx_id: completed_transaction.tx_id, - source_public_key: completed_transaction.source_public_key, - destination_public_key: completed_transaction.destination_public_key, + source_public_key: completed_transaction.source_public_key.clone(), + destination_public_key: completed_transaction.destination_public_key.clone(), amount: completed_transaction.amount, fee: completed_transaction.fee, excess_signature, @@ -904,13 +908,17 @@ impl From for CompletedTransactionInfo { .first() .map(|o| o.features.maturity) .unwrap_or_else(|| 0), - status: completed_transaction.status, - message: completed_transaction.message, + status: completed_transaction.status.clone(), + message: completed_transaction.message.clone(), timestamp: completed_transaction.timestamp, cancelled: completed_transaction.cancelled, - direction: completed_transaction.direction, + direction: completed_transaction.direction.clone(), valid: completed_transaction.valid, mined_height: completed_transaction.mined_height, + is_coinbase: completed_transaction.is_coinbase(), + weight: completed_transaction.transaction.calculate_weight(), + inputs_count: completed_transaction.transaction.body.inputs().len(), + outputs_count: completed_transaction.transaction.body.outputs().len(), } } }