Skip to content

Commit d88f7d6

Browse files
authored
feat: add wallet state (#6763)
Description --- Adds a wallet state grpc call which returns the balance, scanned height and wallet state
1 parent 8f65540 commit d88f7d6

File tree

4 files changed

+108
-10
lines changed

4 files changed

+108
-10
lines changed

applications/minotari_app_grpc/proto/wallet.proto

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import "network.proto";
3333
service Wallet {
3434
// This returns the current version
3535
rpc GetVersion (GetVersionRequest) returns (GetVersionResponse);
36+
// This returns the current state of the wallet
37+
rpc GetState (GetStateRequest) returns (GetStateResponse);
3638
// This checks if the wallet is healthy and running
3739
rpc CheckConnectivity(GetConnectivityRequest) returns (CheckConnectivityResponse);
3840
// Check for new updates
@@ -241,13 +243,21 @@ message GetCompletedTransactionsResponse {
241243

242244
message GetBalanceRequest {}
243245

246+
message GetStateRequest {}
247+
244248
message GetBalanceResponse {
245249
uint64 available_balance = 1;
246250
uint64 pending_incoming_balance = 2;
247251
uint64 pending_outgoing_balance = 3;
248252
uint64 timelocked_balance = 4;
249253
}
250254

255+
message GetStateResponse {
256+
uint64 scanned_height = 1;
257+
GetBalanceResponse balance = 2;
258+
NetworkStatusResponse network = 3;
259+
}
260+
251261
message GetUnspentAmountsResponse {
252262
repeated uint64 amount = 1;
253263
}

applications/minotari_console_wallet/src/grpc/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2022 The Tari Project
22
// SPDX-License-Identifier: BSD-3-Clause
33

4-
mod get_balance_debounced;
4+
mod wallet_debouncer;
55
mod wallet_grpc_server;
66

77
use minotari_app_grpc::tari_rpc::TransactionEvent;

applications/minotari_console_wallet/src/grpc/get_balance_debounced.rs renamed to applications/minotari_console_wallet/src/grpc/wallet_debouncer.rs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use minotari_wallet::{
3131
service::Balance,
3232
},
3333
transaction_service::handle::{TransactionEvent, TransactionServiceHandle},
34+
utxo_scanner_service::handle::{UtxoScannerEvent, UtxoScannerHandle},
3435
};
3536
use tari_shutdown::ShutdownSignal;
3637
use tokio::sync::Mutex;
@@ -44,22 +45,25 @@ const LOG_TARGET: &str = "wallet::ui::grpc::get_balance_debounced";
4445
/// balance needs to be updated. When ever a client requests the balance, it will be fetched from the backend if the
4546
/// flag is set and clear the flag, otherwise the cached balance will be returned.
4647
#[derive(Clone)]
47-
pub struct GetBalanceDebounced {
48+
pub struct WalletDebouncer {
4849
balance: Arc<Mutex<Balance>>,
50+
scanned_height: Arc<Mutex<u64>>,
4951
refresh_needed: Arc<Mutex<bool>>,
5052
output_manager_service: OutputManagerHandle,
5153
transaction_service: TransactionServiceHandle,
5254
wallet_connectivity: WalletConnectivityHandle,
55+
utxo_scanner_handle: UtxoScannerHandle,
5356
shutdown_signal: ShutdownSignal,
5457
event_monitor_started: Arc<Mutex<bool>>,
5558
}
5659

57-
impl GetBalanceDebounced {
58-
/// Create a new GetBalanceDebounced instance.
60+
impl WalletDebouncer {
61+
/// Create a new WalletDebouncer instance.
5962
pub fn new(
6063
output_manager_service: OutputManagerHandle,
6164
transaction_service: TransactionServiceHandle,
6265
wallet_connectivity: WalletConnectivityHandle,
66+
utxo_scanner_handle: UtxoScannerHandle,
6367
shutdown_signal: ShutdownSignal,
6468
) -> Self {
6569
Self {
@@ -70,9 +74,11 @@ impl GetBalanceDebounced {
7074
time_locked_balance: None,
7175
})),
7276
refresh_needed: Arc::new(Mutex::new(true)),
77+
scanned_height: Arc::new(Mutex::new(0)),
7378
output_manager_service,
7479
transaction_service,
7580
wallet_connectivity,
81+
utxo_scanner_handle,
7682
shutdown_signal,
7783
event_monitor_started: Arc::new(Mutex::new(false)),
7884
}
@@ -138,11 +144,27 @@ impl GetBalanceDebounced {
138144
}
139145
}
140146

147+
async fn update_scanned_height(&self, scanned_height: u64) {
148+
let mut lock = self.scanned_height.lock().await;
149+
if *lock != scanned_height {
150+
trace!(target: LOG_TARGET, "set_scanned_height '{}'", scanned_height);
151+
*lock = scanned_height;
152+
}
153+
}
154+
155+
pub async fn get_scanned_height(&mut self) -> u64 {
156+
if !self.is_event_monitor_started().await {
157+
self.start_event_monitor().await;
158+
}
159+
*self.scanned_height.lock().await
160+
}
161+
141162
async fn monitor_events(&self) {
142163
let mut shutdown_signal = self.shutdown_signal.clone();
143164
let mut transaction_service_events = self.transaction_service.get_event_stream();
144165
let mut base_node_changed = self.wallet_connectivity.clone().get_current_base_node_watcher();
145166
let mut output_manager_service_events = self.output_manager_service.get_event_stream();
167+
let mut utxo_scanner_events = self.utxo_scanner_handle.clone().get_event_receiver();
146168

147169
loop {
148170
tokio::select! {
@@ -187,6 +209,29 @@ impl GetBalanceDebounced {
187209
},
188210
}
189211
},
212+
result = utxo_scanner_events.recv() => {
213+
match result {
214+
Ok(event) => {
215+
match event {
216+
UtxoScannerEvent::Progress {
217+
current_height,..
218+
}=> {
219+
self.update_scanned_height(current_height).await;
220+
}
221+
UtxoScannerEvent::Completed {
222+
final_height,
223+
..
224+
}=> {
225+
self.update_scanned_height(final_height).await;
226+
},
227+
_ => {}
228+
}
229+
},
230+
Err(e) => {
231+
warn!(target: LOG_TARGET, "Problem with utxo scanner: {}",e);
232+
},
233+
}
234+
},
190235
_ = shutdown_signal.wait() => {
191236
info!(
192237
target: LOG_TARGET,

applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ use minotari_app_grpc::tari_rpc::{
5656
GetConnectivityRequest,
5757
GetIdentityRequest,
5858
GetIdentityResponse,
59+
GetStateRequest,
60+
GetStateResponse,
5961
GetTransactionInfoRequest,
6062
GetTransactionInfoResponse,
6163
GetUnspentAmountsResponse,
@@ -122,7 +124,7 @@ use tokio::{
122124
use tonic::{Request, Response, Status};
123125

124126
use crate::{
125-
grpc::{convert_to_transaction_event, get_balance_debounced::GetBalanceDebounced, TransactionWrapper},
127+
grpc::{convert_to_transaction_event, wallet_debouncer::WalletDebouncer, TransactionWrapper},
126128
notifier::{CANCELLED, CONFIRMATION, MINED, QUEUED, RECEIVED, SENT},
127129
};
128130

@@ -146,23 +148,24 @@ async fn send_transaction_event(
146148
pub struct WalletGrpcServer {
147149
wallet: WalletSqlite,
148150
rules: ConsensusManager,
149-
get_balance_debounced: Arc<Mutex<GetBalanceDebounced>>,
151+
debouncer: Arc<Mutex<WalletDebouncer>>,
150152
}
151153

152154
impl WalletGrpcServer {
153155
#[allow(dead_code)]
154156
pub fn new(wallet: WalletSqlite) -> Result<Self, ConsensusBuilderError> {
155157
let rules = ConsensusManager::builder(wallet.network.as_network()).build()?;
156-
let get_balance = GetBalanceDebounced::new(
158+
let debouncer = WalletDebouncer::new(
157159
wallet.output_manager_service.clone(),
158160
wallet.transaction_service.clone(),
159161
wallet.wallet_connectivity.clone(),
162+
wallet.utxo_scanner_service.clone(),
160163
wallet.comms.shutdown_signal(),
161164
);
162165
Ok(Self {
163166
wallet,
164167
rules,
165-
get_balance_debounced: Arc::new(Mutex::new(get_balance)),
168+
debouncer: Arc::new(Mutex::new(debouncer)),
166169
})
167170
}
168171

@@ -281,16 +284,56 @@ impl wallet_server::Wallet for WalletGrpcServer {
281284
async fn get_balance(&self, _request: Request<GetBalanceRequest>) -> Result<Response<GetBalanceResponse>, Status> {
282285
let start = std::time::Instant::now();
283286
let balance = {
284-
let mut get_balance = self.get_balance_debounced.lock().await;
287+
let mut get_balance = self.debouncer.lock().await;
285288
match get_balance.get_balance().await {
286289
Ok(b) => b,
287-
Err(e) => return Err(Status::not_found(format!("GetBalanceDebounced error! {}", e))),
290+
Err(e) => return Err(Status::not_found(format!("WalletDebouncer error! {}", e))),
288291
}
289292
};
290293
trace!(target: LOG_TARGET, "'get_balance' completed in {:.2?}", start.elapsed());
291294
Ok(Response::new(balance))
292295
}
293296

297+
async fn get_state(&self, _request: Request<GetStateRequest>) -> Result<Response<GetStateResponse>, Status> {
298+
let start = std::time::Instant::now();
299+
let (balance, scanned_height) = {
300+
let mut debouncer = self.debouncer.lock().await;
301+
let balance = match debouncer.get_balance().await {
302+
Ok(b) => b,
303+
Err(e) => return Err(Status::not_found(format!("WalletDebouncer error! {}", e))),
304+
};
305+
let scanned_height = debouncer.get_scanned_height().await;
306+
(Some(balance), scanned_height)
307+
};
308+
309+
let status = self
310+
.comms()
311+
.connectivity()
312+
.get_connectivity_status()
313+
.await
314+
.map_err(|err| Status::internal(err.to_string()))?;
315+
let mut base_node_service = self.wallet.base_node_service.clone();
316+
317+
let network = Some(tari_rpc::NetworkStatusResponse {
318+
status: tari_rpc::ConnectivityStatus::from(status) as i32,
319+
avg_latency_ms: base_node_service
320+
.get_base_node_latency()
321+
.await
322+
.map_err(|err| Status::internal(err.to_string()))?
323+
.map(|d| u32::try_from(d.as_millis()).unwrap_or(u32::MAX))
324+
.unwrap_or_default(),
325+
num_node_connections: u32::try_from(status.num_connected_nodes())
326+
.map_err(|_| Status::internal("Count not convert u64 to usize".to_string()))?,
327+
});
328+
329+
trace!(target: LOG_TARGET, "'get_state' completed in {:.2?}", start.elapsed());
330+
Ok(Response::new(GetStateResponse {
331+
scanned_height,
332+
balance,
333+
network,
334+
}))
335+
}
336+
294337
async fn get_unspent_amounts(
295338
&self,
296339
_: Request<tari_rpc::Empty>,

0 commit comments

Comments
 (0)