Merge #1614: show rescan warning after restoring wallet from backup
d812ad63a1f367bb304d2edf60103e62effca0bc show rescan warning after restoring wallet from backup (Michael Mallan)
Pull request description:
This adds a warning on the home page if the wallet has been restored from a backup and the user is using a local bitcoind node.
This warning has a button to jump to the rescan page and another button to dismiss the warning, which is the only way to remove it (rescanning does not automatically remove it).
Whether the wallet was restored from a backup is not saved after closing the GUI, so this warning will only be shown in the same user session as that in which the wallet was restored.
The warning will not currently be shown when importing a descriptor.
ACKs for top commit:
edouardparis:
ACK d812ad63a1f367bb304d2edf60103e62effca0bc
Tree-SHA512: 55c8becd30f231a9c9ea1a8818a3df23b98c5f69206e522ae1fee7e5e0679b200e5f1728e67e538ed613236e7925b025286b0e3f4719abcfad3d1ff2a1968df6
This commit is contained in:
commit
d4448b6479
@ -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,
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -24,6 +24,7 @@ pub enum Message {
|
||||
CreateRbf(CreateRbfMessage),
|
||||
ShowQrCode(usize),
|
||||
ImportExport(ImportExportMessage),
|
||||
HideRescanWarning,
|
||||
}
|
||||
|
||||
impl Close for Message {
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -103,6 +103,7 @@ pub enum Message {
|
||||
),
|
||||
Error,
|
||||
>,
|
||||
/* restored_from_backup */ bool,
|
||||
),
|
||||
Started(StartedResult),
|
||||
Loaded(Result<(Arc<dyn Daemon + Sync + Send>, GetInfoResult), Error>),
|
||||
|
||||
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user