From e3e8b3d284ee6ec4d938503d9278434ed66c0f95 Mon Sep 17 00:00:00 2001 From: Philip Date: Wed, 2 Mar 2022 17:20:03 +0200 Subject: [PATCH] feat: update console wallet notifications This PR creates console wallet notifications for transaction events and also adds a hotkey to clear notifications. A bug was also spotted in the way that Faux transaction were validated that resulted in the last Faux transaction confirmed event to be emitted after each validation. The validation was updated to only emit this event if the transaction was previously not confirmed. --- .../src/ui/components/notification_tab.rs | 20 ++++++++- .../src/ui/state/app_state.rs | 11 +++++ .../src/ui/state/wallet_event_monitor.rs | 21 +++++++-- .../tasks/check_faux_transaction_status.rs | 43 +++++++++++-------- 4 files changed, 71 insertions(+), 24 deletions(-) diff --git a/applications/tari_console_wallet/src/ui/components/notification_tab.rs b/applications/tari_console_wallet/src/ui/components/notification_tab.rs index e0866d2c8f..f993eee965 100644 --- a/applications/tari_console_wallet/src/ui/components/notification_tab.rs +++ b/applications/tari_console_wallet/src/ui/components/notification_tab.rs @@ -29,13 +29,21 @@ impl NotificationTab { fn draw_notifications(&mut self, f: &mut Frame, area: Rect, app_state: &AppState) where B: Backend { + let span_vec = vec![ + Span::raw("Press "), + Span::styled("C", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to clear notifications"), + ]; + + let instructions = Paragraph::new(Spans::from(span_vec)).wrap(Wrap { trim: false }); + let block = Block::default().borders(Borders::ALL).title(Span::styled( "Notifications", Style::default().fg(Color::White).add_modifier(Modifier::BOLD), )); f.render_widget(block, area); let notifications_area = Layout::default() - .constraints([Constraint::Min(42)].as_ref()) + .constraints([Constraint::Length(1), Constraint::Min(42)].as_ref()) .margin(1) .split(area); let text = app_state @@ -53,7 +61,9 @@ impl NotificationTab { }) .collect::>(); let paragraph = Paragraph::new(text).wrap(Wrap { trim: true }); - f.render_widget(paragraph, notifications_area[0]); + + f.render_widget(instructions, notifications_area[0]); + f.render_widget(paragraph, notifications_area[1]); } } @@ -80,4 +90,10 @@ impl Component for NotificationTab { false => Spans::from(Span::styled(title.to_owned(), Style::default().fg(Color::White))), } } + + fn on_key(&mut self, app_state: &mut AppState, c: char) { + if c == 'c' { + Handle::current().block_on(app_state.clear_notifications()); + } + } } 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 58e517cfc0..5f27e595ec 100644 --- a/applications/tari_console_wallet/src/ui/state/app_state.rs +++ b/applications/tari_console_wallet/src/ui/state/app_state.rs @@ -529,6 +529,11 @@ impl AppState { } } + pub async fn clear_notifications(&mut self) { + let mut inner = self.inner.write().await; + inner.clear_notifications(); + } + pub fn get_default_fee_per_gram(&self) -> MicroTari { // this should not be empty as we this should have been created, but lets just be safe and use the default value // from the config @@ -962,6 +967,12 @@ impl AppStateInner { self.updated = true; } + pub fn clear_notifications(&mut self) { + self.data.notifications.clear(); + self.data.new_notification_count = 0; + self.updated = true; + } + pub fn get_software_updater(&self) -> SoftwareUpdaterHandle { self.wallet.get_software_updater() } diff --git a/applications/tari_console_wallet/src/ui/state/wallet_event_monitor.rs b/applications/tari_console_wallet/src/ui/state/wallet_event_monitor.rs index 862bf4c886..bd5f036e63 100644 --- a/applications/tari_console_wallet/src/ui/state/wallet_event_monitor.rs +++ b/applications/tari_console_wallet/src/ui/state/wallet_event_monitor.rs @@ -96,6 +96,7 @@ impl WalletEventMonitor { self.trigger_tx_state_refresh(tx_id).await; self.trigger_balance_refresh(); notifier.transaction_received(tx_id); + self.add_notification(format!("Finalized Transaction Received - TxId: {}", tx_id)).await; }, TransactionEvent::TransactionMinedUnconfirmed{tx_id, num_confirmations, is_valid: _} | TransactionEvent::FauxTransactionUnconfirmed{tx_id, num_confirmations, is_valid: _}=> { @@ -103,6 +104,7 @@ impl WalletEventMonitor { self.trigger_tx_state_refresh(tx_id).await; self.trigger_balance_refresh(); notifier.transaction_mined_unconfirmed(tx_id, num_confirmations); + self.add_notification(format!("Transaction Mined Unconfirmed with {} confirmations - TxId: {}", num_confirmations, tx_id)).await; }, TransactionEvent::TransactionMined{tx_id, is_valid: _} | TransactionEvent::FauxTransactionConfirmed{tx_id, is_valid: _}=> { @@ -110,15 +112,28 @@ impl WalletEventMonitor { self.trigger_tx_state_refresh(tx_id).await; self.trigger_balance_refresh(); notifier.transaction_mined(tx_id); + self.add_notification(format!("Transaction Confirmed - TxId: {}", tx_id)).await; }, TransactionEvent::TransactionCancelled(tx_id, _) => { self.trigger_tx_state_refresh(tx_id).await; self.trigger_balance_refresh(); notifier.transaction_cancelled(tx_id); }, - TransactionEvent::ReceivedTransaction(tx_id) | - TransactionEvent::ReceivedTransactionReply(tx_id) | - TransactionEvent::TransactionBroadcast(tx_id) | + TransactionEvent::ReceivedTransaction(tx_id) => { + self.trigger_tx_state_refresh(tx_id).await; + self.trigger_balance_refresh(); + self.add_notification(format!("Transaction Received - TxId: {}", tx_id)).await; + }, + TransactionEvent::ReceivedTransactionReply(tx_id) => { + self.trigger_tx_state_refresh(tx_id).await; + self.trigger_balance_refresh(); + self.add_notification(format!("Transaction Reply Received - TxId: {}", tx_id)).await; + }, + TransactionEvent::TransactionBroadcast(tx_id) => { + self.trigger_tx_state_refresh(tx_id).await; + self.trigger_balance_refresh(); + self.add_notification(format!("Transaction Broadcast to Mempool - TxId: {}", tx_id)).await; + }, TransactionEvent::TransactionMinedRequestTimedOut(tx_id) | TransactionEvent::TransactionImported(tx_id) => { self.trigger_tx_state_refresh(tx_id).await; diff --git a/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs b/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs index 370a0c941f..726d5a19e3 100644 --- a/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs +++ b/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs @@ -23,7 +23,7 @@ use std::sync::Arc; use log::*; -use tari_common_types::types::BlockHash; +use tari_common_types::{transaction::TransactionStatus, types::BlockHash}; use crate::{ output_manager_service::{handle::OutputManagerHandle, storage::OutputStatus}, @@ -112,6 +112,7 @@ pub async fn check_faux_transactions( vec![0u8; 32] }; let is_valid = tip_height >= mined_height; + let was_confirmed = tx.status == TransactionStatus::FauxConfirmed; let is_confirmed = tip_height.saturating_sub(mined_height) >= TransactionServiceConfig::default().num_confirmations_required; let num_confirmations = tip_height - mined_height; @@ -141,25 +142,29 @@ pub async fn check_faux_transactions( "Error setting faux transaction to mined confirmed: {}", e ); } else { - let transaction_event = match is_confirmed { - false => TransactionEvent::FauxTransactionUnconfirmed { - tx_id: tx.tx_id, - num_confirmations: 0, - is_valid, - }, - true => TransactionEvent::FauxTransactionConfirmed { - tx_id: tx.tx_id, - is_valid, - }, - }; - let _ = event_publisher.send(Arc::new(transaction_event)).map_err(|e| { - trace!( - target: LOG_TARGET, - "Error sending event, usually because there are no subscribers: {:?}", + // Only send an event if the transaction was not previously confirmed OR was previously confirmed and is + // now not confirmed (i.e. confirmation changed) + if !(was_confirmed && is_confirmed) { + let transaction_event = match is_confirmed { + false => TransactionEvent::FauxTransactionUnconfirmed { + tx_id: tx.tx_id, + num_confirmations: 0, + is_valid, + }, + true => TransactionEvent::FauxTransactionConfirmed { + tx_id: tx.tx_id, + is_valid, + }, + }; + let _ = event_publisher.send(Arc::new(transaction_event)).map_err(|e| { + trace!( + target: LOG_TARGET, + "Error sending event, usually because there are no subscribers: {:?}", + e + ); e - ); - e - }); + }); + } } } }