From 9dd737b98c74ff9e815b06ed20c35840f4eddb66 Mon Sep 17 00:00:00 2001 From: Michael Mallan Date: Thu, 10 Oct 2024 12:46:06 +0100 Subject: [PATCH 1/3] gui: upgrade liana dependency --- gui/Cargo.lock | 2 +- gui/src/lianalite/client/backend/mod.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gui/Cargo.lock b/gui/Cargo.lock index 7bcd7837..34de9297 100644 --- a/gui/Cargo.lock +++ b/gui/Cargo.lock @@ -2624,7 +2624,7 @@ dependencies = [ [[package]] name = "liana" version = "7.0.0" -source = "git+https://github.com/wizardsardine/liana?branch=master#18950c219a9233e584fabb1f5b168e17fa450902" +source = "git+https://github.com/wizardsardine/liana?branch=master#c2ce025a78891307e1f0d83c52cb983eb098d41d" dependencies = [ "backtrace", "bdk_coin_select", diff --git a/gui/src/lianalite/client/backend/mod.rs b/gui/src/lianalite/client/backend/mod.rs index b572aa17..957871cc 100644 --- a/gui/src/lianalite/client/backend/mod.rs +++ b/gui/src/lianalite/client/backend/mod.rs @@ -584,6 +584,8 @@ impl Daemon for BackendWalletClient { sync: 1.0, rescan_progress: None, timestamp: wallet.created_at as u32, + // We can ignore this field for remote backend as the wallet should remain synced. + last_poll_timestamp: None, }) } From f7314aa26ebb75fdbc016e7519eed52a827782a6 Mon Sep 17 00:00:00 2001 From: Michael Mallan Date: Thu, 10 Oct 2024 13:12:38 +0100 Subject: [PATCH 2/3] gui(cache): include last poll timestamp --- gui/src/app/cache.rs | 2 ++ gui/src/app/mod.rs | 1 + gui/src/loader.rs | 1 + gui/src/main.rs | 1 + 4 files changed, 5 insertions(+) diff --git a/gui/src/app/cache.rs b/gui/src/app/cache.rs index 1a26bc67..1ab235a4 100644 --- a/gui/src/app/cache.rs +++ b/gui/src/app/cache.rs @@ -9,6 +9,7 @@ pub struct Cache { pub blockheight: i32, pub coins: Vec, pub rescan_progress: Option, + pub last_poll_timestamp: Option, } /// only used for tests. @@ -20,6 +21,7 @@ impl std::default::Default for Cache { blockheight: 0, coins: Vec::new(), rescan_progress: None, + last_poll_timestamp: None, } } } diff --git a/gui/src/app/mod.rs b/gui/src/app/mod.rs index 4d818e68..ed582920 100644 --- a/gui/src/app/mod.rs +++ b/gui/src/app/mod.rs @@ -281,6 +281,7 @@ impl App { network: info.network, blockheight: info.block_height, rescan_progress: info.rescan_progress, + last_poll_timestamp: info.last_poll_timestamp, }) }, Message::UpdateCache, diff --git a/gui/src/loader.rs b/gui/src/loader.rs index f08b59d7..a7de1c19 100644 --- a/gui/src/loader.rs +++ b/gui/src/loader.rs @@ -380,6 +380,7 @@ pub async fn load_application( network: info.network, blockheight: info.block_height, coins, + last_poll_timestamp: info.last_poll_timestamp, ..Default::default() }; diff --git a/gui/src/main.rs b/gui/src/main.rs index ab33981e..7aac5a0a 100644 --- a/gui/src/main.rs +++ b/gui/src/main.rs @@ -461,6 +461,7 @@ pub fn create_app_with_remote_backend( rescan_progress: None, datadir_path: datadir.clone(), blockheight: wallet.tip_height.unwrap_or(0), + last_poll_timestamp: None, // We ignore this field for remote backend. }, Arc::new( Wallet::new(wallet.descriptor) From ec7556ee12f13c87229974769667bb892695889c Mon Sep 17 00:00:00 2001 From: Michael Mallan Date: Sat, 19 Oct 2024 11:12:35 +0100 Subject: [PATCH 3/3] gui(home): indicate existing wallet is syncing If opening an existing wallet that uses a local backend, indicate that it is checking for new transactions until the first poll completes. A remote backend is always synced after the initial scan. --- gui/src/app/mod.rs | 1 + gui/src/app/state/mod.rs | 50 ++++++++++++++++++++++++++++++++++++---- gui/src/app/view/home.rs | 26 ++++++++++++++------- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/gui/src/app/mod.rs b/gui/src/app/mod.rs index ed582920..92386340 100644 --- a/gui/src/app/mod.rs +++ b/gui/src/app/mod.rs @@ -67,6 +67,7 @@ impl Panels { wallet.clone(), &cache.coins, cache.blockheight, + cache.last_poll_timestamp, daemon_backend.clone(), ), coins: CoinsPanel::new(&cache.coins, wallet.main_descriptor.first_timelock_value()), diff --git a/gui/src/app/state/mod.rs b/gui/src/app/state/mod.rs index d9e13729..0a78d24b 100644 --- a/gui/src/app/state/mod.rs +++ b/gui/src/app/state/mod.rs @@ -69,8 +69,17 @@ pub fn redirect(menu: Menu) -> Command { }) } -fn wallet_is_syncing(daemon_backend: DaemonBackend, blockheight: i32) -> bool { +fn wallet_is_syncing( + daemon_backend: DaemonBackend, + blockheight: i32, + last_poll: Option, + last_poll_at_startup: Option, +) -> bool { match daemon_backend { + // If remote, the wallet is always synced except before the first scan + // after creation. + DaemonBackend::RemoteBackend => blockheight <= 0, + // If blockheight <= 0, then this is a newly created wallet. // If user imported descriptor and is using a local bitcoind, a rescan // will need to be performed in order to see past transactions and so the // syncing status could be misleading as it could suggest the rescan is @@ -79,14 +88,29 @@ fn wallet_is_syncing(daemon_backend: DaemonBackend, blockheight: i32) -> bool { // treat it the same as bitcoind to be sure we don't mislead the user. DaemonBackend::EmbeddedLianad(Some(NodeType::Bitcoind)) | DaemonBackend::EmbeddedLianad(None) - | DaemonBackend::ExternalLianad => false, - _ => blockheight <= 0, + | DaemonBackend::ExternalLianad + if blockheight <= 0 => + { + false + } + // If external daemon, we cannot be sure it will return last poll + // as it depends on the version, so assume it won't unless the + // last poll at startup is set. + // TODO: should we check the daemon version at GUI startup? + DaemonBackend::ExternalLianad if last_poll_at_startup.is_none() => false, + // For an existing wallet with any local node type, the first poll + // completing means the wallet has caught up with the tip. + // For a new wallet with a non-bitcoind local node, the first poll + // completing also means that the initial rescan has completed. + _ => last_poll <= last_poll_at_startup, } } pub struct Home { wallet: Arc, wallet_is_syncing: bool, + blockheight: i32, + last_poll_at_startup: Option, balance: Amount, unconfirmed_balance: Amount, remaining_sequence: Option, @@ -105,6 +129,7 @@ impl Home { wallet: Arc, coins: &[Coin], blockheight: i32, + last_poll: Option, daemon_backend: DaemonBackend, ) -> Self { let (balance, unconfirmed_balance) = coins.iter().fold( @@ -120,11 +145,14 @@ impl Home { }, ); - let wallet_is_syncing = wallet_is_syncing(daemon_backend, blockheight); + let wallet_is_syncing = + wallet_is_syncing(daemon_backend, blockheight, last_poll, last_poll); Self { wallet, wallet_is_syncing, + last_poll_at_startup: last_poll, + blockheight, balance, unconfirmed_balance, remaining_sequence: None, @@ -138,6 +166,15 @@ impl Home { processing: false, } } + + fn wallet_is_syncing(&self, daemon_backend: DaemonBackend, last_poll: Option) -> bool { + wallet_is_syncing( + daemon_backend, + self.blockheight, + last_poll, + self.last_poll_at_startup, + ) + } } impl State for Home { @@ -170,6 +207,7 @@ impl State for Home { self.is_last_page, self.processing, self.wallet_is_syncing, + self.blockheight, ), ) } @@ -248,7 +286,9 @@ impl State for Home { }, Message::UpdatePanelCache(is_current, Ok(cache)) => { let wallet_was_syncing = self.wallet_is_syncing; - self.wallet_is_syncing = wallet_is_syncing(daemon.backend(), cache.blockheight); + self.blockheight = cache.blockheight; + self.wallet_is_syncing = + self.wallet_is_syncing(daemon.backend(), cache.last_poll_timestamp); // If this is the current panel, reload it if wallet is no longer syncing. if is_current && wallet_was_syncing && !self.wallet_is_syncing { return self.reload(daemon, self.wallet.clone()); diff --git a/gui/src/app/view/home.rs b/gui/src/app/view/home.rs index 70889d6e..731d04d2 100644 --- a/gui/src/app/view/home.rs +++ b/gui/src/app/view/home.rs @@ -36,6 +36,7 @@ pub fn home_view<'a>( is_last_page: bool, processing: bool, wallet_is_syncing: bool, + blockheight: i32, ) -> Element<'a, Message> { Column::new() .push(h3("Balance")) @@ -58,14 +59,23 @@ pub fn home_view<'a>( )) }) .push_maybe(if wallet_is_syncing { - Some(Row::new().push(text("Syncing").style(color::GREY_2)).push( - spinner::typing_text_carousel( - "...", - true, - Duration::from_millis(2000), - |content| text(content).style(color::GREY_2), - ), - )) + Some( + Row::new() + .push( + text(if blockheight <= 0 { + "Syncing" + } else { + "Checking for new transactions" + }) + .style(color::GREY_2), + ) + .push(spinner::typing_text_carousel( + "...", + true, + Duration::from_millis(2000), + |content| text(content).style(color::GREY_2), + )), + ) } else { None })