Skip to content

Commit

Permalink
chore: emit wallet events
Browse files Browse the repository at this point in the history
  • Loading branch information
mmrrnn committed Dec 16, 2024
1 parent 90109ac commit dffe5fb
Show file tree
Hide file tree
Showing 14 changed files with 203 additions and 193 deletions.
35 changes: 2 additions & 33 deletions src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ pub struct MinerMetrics {

#[derive(Debug, Serialize, Clone)]
pub struct TariWalletDetails {
wallet_balance: Option<WalletBalance>,
tari_address_base58: String,
tari_address_emoji: String,
}
Expand Down Expand Up @@ -641,45 +640,15 @@ pub async fn get_tari_wallet_details(
state: tauri::State<'_, UniverseAppState>,
) -> Result<TariWalletDetails, String> {
let timer = Instant::now();
if state.is_getting_wallet_balance.load(Ordering::SeqCst) {
let read = state.cached_wallet_details.read().await;
if let Some(details) = &*read {
warn!(target: LOG_TARGET, "Already getting wallet balance, returning cached value");
return Ok(details.clone());
}
warn!(target: LOG_TARGET, "Already getting wallet balance");
return Err("Already getting wallet balance".to_string());
}
state
.is_getting_wallet_balance
.store(true, Ordering::SeqCst);
let wallet_balance = match state.wallet_manager.get_balance().await {
Ok(w) => Some(w),
Err(e) => {
if !matches!(e, WalletManagerError::WalletNotStarted) {
warn!(target: LOG_TARGET, "Error getting wallet balance: {}", e);
}

None
}
};
let tari_address = state.tari_address.read().await;

if timer.elapsed() > MAX_ACCEPTABLE_COMMAND_TIME {
warn!(target: LOG_TARGET, "get_tari_wallet_details took too long: {:?}", timer.elapsed());
}
let result = TariWalletDetails {
wallet_balance,
Ok(TariWalletDetails {
tari_address_base58: tari_address.to_base58(),
tari_address_emoji: tari_address.to_emoji_string(),
};
let mut lock = state.cached_wallet_details.write().await;
*lock = Some(result.clone());
state
.is_getting_wallet_balance
.store(false, Ordering::SeqCst);

Ok(result)
})
}

#[tauri::command]
Expand Down
5 changes: 5 additions & 0 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,11 @@ async fn setup_inner(
.inspect_err(|e| error!(target: LOG_TARGET, "Could not emit event 'message': {:?}", e)),
);

state
.wallet_manager
.initialize_wallet_relay(app.clone())
.await;

let move_handle = app.clone();
tauri::async_runtime::spawn(async move {
let mut interval: time::Interval = time::interval(Duration::from_secs(1));
Expand Down
44 changes: 26 additions & 18 deletions src-tauri/src/node_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ impl ProcessAdapter for MinotariNodeAdapter {
last_block_height: 0,
last_sha3_estimated_hashrate: 0,
last_randomx_estimated_hashrate: 0,
last_block_reward: 0,
},
))
}
Expand Down Expand Up @@ -241,6 +242,7 @@ pub struct MinotariNodeStatusMonitor {
last_block_height: u64,
last_sha3_estimated_hashrate: u64,
last_randomx_estimated_hashrate: u64,
last_block_reward: u64,
}

#[async_trait]
Expand All @@ -264,22 +266,6 @@ impl MinotariNodeStatusMonitor {
.await
.map_err(|_| MinotariNodeStatusMonitorError::NodeNotStarted)?;

let res = client
.get_new_block_template(NewBlockTemplateRequest {
algo: Some(PowAlgo { pow_algo: 1 }),
max_weight: 0,
})
.await
.map_err(|e| MinotariNodeStatusMonitorError::UnknownError(e.into()))?;
let res = res.into_inner();

let reward = res
.miner_data
.ok_or_else(|| {
MinotariNodeStatusMonitorError::UnknownError(anyhow!("No miner data found"))
})?
.reward;

let res = client
.get_tip_info(Empty {})
.await
Expand All @@ -300,17 +286,38 @@ impl MinotariNodeStatusMonitor {
metadata.timestamp,
);

if sync_achieved && (block_height <= self.last_block_height) {
if sync_achieved
&& (block_height <= self.last_block_height)
&& self.last_sha3_estimated_hashrate > 0
&& self.last_randomx_estimated_hashrate > 0
&& self.last_block_reward > 0
{
return Ok((
self.last_sha3_estimated_hashrate,
self.last_randomx_estimated_hashrate,
MicroMinotari(reward),
MicroMinotari(self.last_block_reward),
block_height,
block_time,
sync_achieved,
));
}

let res = client
.get_new_block_template(NewBlockTemplateRequest {
algo: Some(PowAlgo { pow_algo: 1 }),
max_weight: 0,
})
.await
.map_err(|e| MinotariNodeStatusMonitorError::UnknownError(e.into()))?;
let res = res.into_inner();

let reward = res
.miner_data
.ok_or_else(|| {
MinotariNodeStatusMonitorError::UnknownError(anyhow!("No miner data found"))
})?
.reward;

// First try with 10 blocks
let blocks = [10, 100];
let mut result = Err(anyhow::anyhow!("No difficulty found"));
Expand Down Expand Up @@ -359,6 +366,7 @@ impl MinotariNodeStatusMonitor {
}

self.last_block_height = block_height;
self.last_block_reward = reward;
Ok(result?)
}

Expand Down
83 changes: 79 additions & 4 deletions src-tauri/src/wallet_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,20 @@ use anyhow::Error;
use async_trait::async_trait;
use log::{info, warn};
use minotari_node_grpc_client::grpc::wallet_client::WalletClient;
use minotari_node_grpc_client::grpc::{GetBalanceRequest, GetCompletedTransactionsRequest};
use minotari_node_grpc_client::grpc::{
GetBalanceRequest, GetCompletedTransactionsRequest, TransactionEventRequest,
};
use serde::Serialize;
use std::path::PathBuf;
use std::sync::Arc;
use tari_common::configuration::Network;
use tari_common_types::tari_address::{TariAddress, TariAddressError};
use tari_core::transactions::tari_amount::MicroMinotari;
use tari_crypto::ristretto::RistrettoPublicKey;
use tari_shutdown::Shutdown;
use tari_utilities::hex::Hex;
use tauri::Emitter;
use tokio::sync::RwLock;

#[cfg(target_os = "windows")]
use crate::utils::setup_utils::setup_utils::add_firewall_rule;
Expand Down Expand Up @@ -196,6 +201,8 @@ impl ProcessAdapter for WalletAdapter {
},
WalletStatusMonitor {
grpc_port: self.grpc_port,
confirmed_transactions: Arc::new(RwLock::new(Vec::new())),
wallet_balance: Arc::new(RwLock::new(WalletBalance::default())),
},
))
}
Expand All @@ -222,6 +229,8 @@ pub enum WalletStatusMonitorError {
#[derive(Clone)]
pub struct WalletStatusMonitor {
grpc_port: u16,
pub confirmed_transactions: Arc<RwLock<Vec<TransactionInfo>>>,
pub wallet_balance: Arc<RwLock<WalletBalance>>,
}

#[async_trait]
Expand All @@ -243,7 +252,18 @@ pub struct WalletBalance {
pub pending_outgoing_balance: MicroMinotari,
}

#[derive(Debug, Serialize)]
impl Default for WalletBalance {
fn default() -> Self {
WalletBalance {
available_balance: MicroMinotari(0),
timelocked_balance: MicroMinotari(0),
pending_incoming_balance: MicroMinotari(0),
pending_outgoing_balance: MicroMinotari(0),
}
}
}

#[derive(Debug, Serialize, Clone)]
pub struct TransactionInfo {
pub tx_id: u64,
pub source_address: String,
Expand All @@ -264,7 +284,62 @@ impl WalletStatusMonitor {
format!("http://127.0.0.1:{}", self.grpc_port)
}

pub async fn get_balance(&self) -> Result<WalletBalance, WalletStatusMonitorError> {
pub async fn initialize_wallet_relay(&self, app_handle: tauri::AppHandle) {
let app_handle_clone = app_handle.clone();
self.clone().update_wallet_data(app_handle_clone).await;
let monitor = self.clone();
let app_handle_clone = app_handle.clone();

tokio::spawn(async move {
let mut client = WalletClient::connect(monitor.wallet_grpc_address())
.await
.map_err(|_e| WalletStatusMonitorError::WalletNotStarted)?;
let res = client
.stream_transaction_events(TransactionEventRequest {})
.await
.map_err(|e| WalletStatusMonitorError::UnknownError(e.into()))?;

let mut stream = res.into_inner();
while let Some(message) = stream
.message()
.await
.map_err(|e| WalletStatusMonitorError::UnknownError(e.into()))?
{
let tx = message.transaction.expect("Transaction not found");

monitor
.clone()
.update_wallet_data(app_handle_clone.clone())
.await;
}

Ok::<(), WalletStatusMonitorError>(())
});
}

async fn update_wallet_data(self, app_handle: tauri::AppHandle) {
match self.fetch_transaction_history().await {
Ok(transactions) => {
*self.confirmed_transactions.write().await = transactions.clone();
let _ = app_handle.emit("transaction_history_updated", transactions);
}
Err(e) => {
warn!(target: LOG_TARGET, "Failed to fetch transaction history: {:?}", e);
}
}

match self.get_balance().await {
Ok(balance) => {
*self.wallet_balance.write().await = balance.clone();
let _ = app_handle.emit("wallet_balance_updated", balance);
}
Err(e) => {
warn!(target: LOG_TARGET, "Failed to fetch balance: {:?}", e);
}
}
}

async fn get_balance(&self) -> Result<WalletBalance, WalletStatusMonitorError> {
let mut client = WalletClient::connect(self.wallet_grpc_address())
.await
.map_err(|_e| WalletStatusMonitorError::WalletNotStarted)?;
Expand All @@ -282,7 +357,7 @@ impl WalletStatusMonitor {
})
}

pub async fn get_transaction_history(
async fn fetch_transaction_history(
&self,
) -> Result<Vec<TransactionInfo>, WalletStatusMonitorError> {
let mut client = WalletClient::connect(self.wallet_grpc_address())
Expand Down
36 changes: 24 additions & 12 deletions src-tauri/src/wallet_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,21 @@ impl WalletManager {
)
.await?;
process_watcher.wait_ready().await?;

Ok(())
}

pub async fn initialize_wallet_relay(&self, app_handle: tauri::AppHandle) {
let process_watcher = self.watcher.read().await;
process_watcher
.status_monitor
.as_ref()
.ok_or_else(|| WalletManagerError::WalletNotStarted)
.unwrap()
.initialize_wallet_relay(app_handle)
.await;
}

pub async fn set_view_private_key_and_spend_key(
&self,
view_private_key: String,
Expand All @@ -118,32 +130,32 @@ impl WalletManager {

pub async fn get_balance(&self) -> Result<WalletBalance, WalletManagerError> {
let process_watcher = self.watcher.read().await;
process_watcher
let wallet_balance = process_watcher
.status_monitor
.as_ref()
.ok_or_else(|| WalletManagerError::WalletNotStarted)?
.get_balance()
.wallet_balance
.read()
.await
.map_err(|e| match e {
WalletStatusMonitorError::WalletNotStarted => WalletManagerError::WalletNotStarted,
_ => WalletManagerError::UnknownError(e.into()),
})
.clone();

Ok(wallet_balance)
}

pub async fn get_transaction_history(
&self,
) -> Result<Vec<TransactionInfo>, WalletManagerError> {
let process_watcher = self.watcher.read().await;
process_watcher
let tx_history = process_watcher
.status_monitor
.as_ref()
.ok_or_else(|| WalletManagerError::WalletNotStarted)?
.get_transaction_history()
.confirmed_transactions
.read()
.await
.map_err(|e| match e {
WalletStatusMonitorError::WalletNotStarted => WalletManagerError::WalletNotStarted,
_ => WalletManagerError::UnknownError(e.into()),
})
.clone();

Ok(tx_history)
}

pub async fn stop(&self) -> Result<i32, WalletManagerError> {
Expand Down
8 changes: 3 additions & 5 deletions src/containers/main/SideBar/components/Wallet/History.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useWalletStore } from '@app/store/useWalletStore';
import { CircularProgress } from '@app/components/elements/CircularProgress';

import HistoryItem from './HistoryItem';
import { ListLabel } from './HistoryItem.styles';
Expand All @@ -17,15 +15,15 @@ const container = {

export default function History() {
const { t } = useTranslation('sidebar', { useSuspense: false });
const isTransactionLoading = useWalletStore((s) => s.isTransactionLoading);
const transactions = useWalletStore((s) => s.transactions);
const txMarkup = useMemo(() => transactions.map((tx) => <HistoryItem key={tx.tx_id} item={tx} />), [transactions]);

return (
<HistoryContainer initial="hidden" animate="visible" exit="hidden" variants={container}>
<HistoryPadding>
<ListLabel>{t('recent-wins')}</ListLabel>
{isTransactionLoading && !transactions?.length ? <CircularProgress /> : txMarkup}
{transactions.map((tx) => (
<HistoryItem key={tx.tx_id} item={tx} />
))}
</HistoryPadding>
</HistoryContainer>
);
Expand Down
Loading

0 comments on commit dffe5fb

Please sign in to comment.