show rescan warning after restoring wallet from backup

This commit is contained in:
Michael Mallan 2025-03-26 11:31:05 +00:00
parent 05b848c5d2
commit d812ad63a1
No known key found for this signature in database
GPG Key ID: 5177CDCEDB0EABEB
8 changed files with 114 additions and 10 deletions

View File

@ -7,9 +7,16 @@ pub enum Menu {
Transactions,
TransactionPreSelected(Txid),
Settings,
SettingsPreSelected(SettingsOption),
Coins,
CreateSpendTx,
Recovery,
RefreshCoins(Vec<OutPoint>),
PsbtPreSelected(Txid),
}
/// Pre-selectable settings options.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SettingsOption {
Node,
}

View File

@ -38,7 +38,7 @@ use wallet::{sync_status, SyncStatus};
use crate::{
app::{cache::Cache, error::Error, menu::Menu, wallet::Wallet},
daemon::{embedded::EmbeddedDaemon, Daemon, DaemonBackend},
node::bitcoind::Bitcoind,
node::{bitcoind::Bitcoind, NodeType},
};
use self::state::SettingsState;
@ -63,7 +63,15 @@ impl Panels {
daemon_backend: DaemonBackend,
internal_bitcoind: Option<&Bitcoind>,
config: Arc<Config>,
restored_from_backup: bool,
) -> Panels {
let show_rescan_warning = restored_from_backup
&& daemon_backend.is_lianad()
&& daemon_backend
.node_type()
.map(|nt| nt == NodeType::Bitcoind)
// We don't know the node type for external lianad so assume it's bitcoind.
.unwrap_or(true);
Self {
current: Menu::Home,
home: Home::new(
@ -77,6 +85,7 @@ impl Panels {
cache.last_poll_at_startup,
),
cache.blockheight,
show_rescan_warning,
),
coins: CoinsPanel::new(&cache.coins, wallet.main_descriptor.first_timelock_value()),
transactions: TransactionsPanel::new(wallet.clone()),
@ -106,7 +115,7 @@ impl Panels {
Menu::PSBTs => &self.psbts,
Menu::Transactions => &self.transactions,
Menu::TransactionPreSelected(_) => &self.transactions,
Menu::Settings => &self.settings,
Menu::Settings | Menu::SettingsPreSelected(_) => &self.settings,
Menu::Coins => &self.coins,
Menu::CreateSpendTx => &self.create_spend,
Menu::Recovery => &self.recovery,
@ -122,7 +131,7 @@ impl Panels {
Menu::PSBTs => &mut self.psbts,
Menu::Transactions => &mut self.transactions,
Menu::TransactionPreSelected(_) => &mut self.transactions,
Menu::Settings => &mut self.settings,
Menu::Settings | Menu::SettingsPreSelected(_) => &mut self.settings,
Menu::Coins => &mut self.coins,
Menu::CreateSpendTx => &mut self.create_spend,
Menu::Recovery => &mut self.recovery,
@ -150,6 +159,7 @@ impl App {
daemon: Arc<dyn Daemon + Sync + Send>,
data_dir: PathBuf,
internal_bitcoind: Option<Bitcoind>,
restored_from_backup: bool,
) -> (App, Task<Message>) {
let config = Arc::new(config);
let mut panels = Panels::new(
@ -159,6 +169,7 @@ impl App {
daemon.backend(),
internal_bitcoind.as_ref(),
config.clone(),
restored_from_backup,
);
let cmd = panels.home.reload(daemon.clone(), wallet.clone());
(
@ -205,6 +216,16 @@ impl App {
return Task::none();
};
}
menu::Menu::SettingsPreSelected(setting) => {
self.panels.current = menu.clone();
return self.panels.current_mut().update(
self.daemon.clone(),
&self.cache,
Message::View(view::Message::Settings(match setting {
&menu::SettingsOption::Node => view::SettingsMessage::EditBitcoindSettings,
})),
);
}
menu::Menu::RefreshCoins(preselected) => {
self.panels.create_spend = CreateSpendPanel::new_self_send(
self.wallet.clone(),

View File

@ -135,6 +135,7 @@ pub struct Home {
selected_event: Option<(HistoryTransaction, usize)>,
labels_edited: LabelsEdited,
warning: Option<Error>,
show_rescan_warning: bool,
}
impl Home {
@ -143,6 +144,7 @@ impl Home {
coins: &[Coin],
sync_status: SyncStatus,
tip_height: i32,
show_rescan_warning: bool,
) -> Self {
let (balance, unconfirmed_balance, expiring_coins, remaining_seq) = coins_summary(
coins,
@ -163,6 +165,7 @@ impl Home {
warning: None,
is_last_page: false,
processing: false,
show_rescan_warning,
}
}
}
@ -191,6 +194,7 @@ impl State for Home {
self.is_last_page,
self.processing,
&self.sync_status,
self.show_rescan_warning,
),
)
}
@ -276,6 +280,9 @@ impl State for Home {
self.warning = Some(e);
}
},
Message::View(view::Message::HideRescanWarning) => {
self.show_rescan_warning = false;
}
Message::View(view::Message::SelectPayment(outpoint)) => {
return Task::perform(
async move {

View File

@ -4,14 +4,16 @@ use std::{collections::HashMap, time::Duration, vec};
use iced::{
alignment,
widget::{Container, Row, Space},
Alignment, Length,
Alignment::{self, Center},
Length,
};
use liana::miniscript::bitcoin;
use liana_ui::{
color,
component::{amount::*, button, card, event, form, spinner, text::*},
icon, theme,
icon::{self, cross_icon},
theme,
widget::*,
};
@ -19,13 +21,46 @@ use crate::{
app::{
cache::Cache,
error::Error,
menu::Menu,
menu::{self, Menu},
view::{coins, dashboard, label, message::Message},
wallet::SyncStatus,
},
daemon::model::{HistoryTransaction, Payment, PaymentKind, TransactionKind},
};
const RESCAN_WARNING: &str = "As this wallet was restored from a backup, you may need to rescan the blockchain to see past transactions.";
fn rescan_warning<'a>() -> Element<'a, Message> {
Container::new(
Column::new()
.spacing(10)
.push(
Row::new()
.spacing(5)
.push(icon::warning_icon().style(theme::text::warning))
.push(text(RESCAN_WARNING).style(theme::text::warning))
.align_y(Center),
)
.push(
Row::new()
.spacing(5)
.push(Space::with_width(Length::Fill))
.push(
button::secondary(None, "Go to rescan").on_press(Message::Menu(
Menu::SettingsPreSelected(menu::SettingsOption::Node),
)),
)
.push(
button::secondary(Some(cross_icon()), "Dismiss")
.on_press(Message::HideRescanWarning),
),
),
)
.padding(25)
.style(theme::card::border)
.into()
}
#[allow(clippy::too_many_arguments)]
pub fn home_view<'a>(
balance: &'a bitcoin::Amount,
@ -36,6 +71,7 @@ pub fn home_view<'a>(
is_last_page: bool,
processing: bool,
sync_status: &SyncStatus,
show_rescan_warning: bool,
) -> Element<'a, Message> {
Column::new()
.push(h3("Balance"))
@ -99,6 +135,7 @@ pub fn home_view<'a>(
},
),
)
.push_maybe(show_rescan_warning.then_some(rescan_warning()))
.push_maybe(if expiring_coins.is_empty() {
remaining_sequence.map(|sequence| {
Container::new(

View File

@ -24,6 +24,7 @@ pub enum Message {
CreateRbf(CreateRbfMessage),
ShowQrCode(usize),
ImportExport(ImportExportMessage),
HideRescanWarning,
}
impl Close for Message {

View File

@ -76,6 +76,21 @@ impl DaemonBackend {
pub fn is_embedded(&self) -> bool {
matches!(self, DaemonBackend::EmbeddedLianad(_))
}
pub fn is_lianad(&self) -> bool {
matches!(
self,
DaemonBackend::EmbeddedLianad(_) | DaemonBackend::ExternalLianad
)
}
pub fn node_type(&self) -> Option<node::NodeType> {
if let DaemonBackend::EmbeddedLianad(node_type) = self {
*node_type
} else {
None
}
}
}
#[async_trait]

View File

@ -103,6 +103,7 @@ pub enum Message {
),
Error,
>,
/* restored_from_backup */ bool,
),
Started(StartedResult),
Loaded(Result<(Arc<dyn Daemon + Sync + Send>, GetInfoResult), Error>),

View File

@ -369,7 +369,9 @@ impl GUI {
},
|r| {
let r = r.map_err(loader::Error::RestoreBackup);
Message::Load(Box::new(loader::Message::App(r)))
Message::Load(Box::new(loader::Message::App(
r, /* restored_from_backup */ true,
)))
},
)
} else {
@ -380,17 +382,29 @@ impl GUI {
daemon,
loader.datadir_path.clone(),
bitcoind,
false,
);
self.state = State::App(app);
command.map(|msg| Message::Run(Box::new(msg)))
}
}
loader::Message::App(Ok((cache, wallet, config, daemon, datadir, bitcoind))) => {
let (app, command) = App::new(cache, wallet, config, daemon, datadir, bitcoind);
loader::Message::App(
Ok((cache, wallet, config, daemon, datadir, bitcoind)),
restored_from_backup,
) => {
let (app, command) = App::new(
cache,
wallet,
config,
daemon,
datadir,
bitcoind,
restored_from_backup,
);
self.state = State::App(app);
command.map(|msg| Message::Run(Box::new(msg)))
}
loader::Message::App(Err(e)) => {
loader::Message::App(Err(e), _) => {
tracing::error!("Fail to import backup: {e}");
Task::none()
}
@ -506,6 +520,7 @@ pub fn create_app_with_remote_backend(
Arc::new(remote_backend),
datadir,
None,
false,
)
}