Skip to content

Commit 615144e

Browse files
committed
import: implement import_backup_at_launch()
1 parent 54aae9a commit 615144e

File tree

3 files changed

+146
-1
lines changed

3 files changed

+146
-1
lines changed

liana-gui/src/app/error.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use lianad::config::ConfigError;
77
use crate::{
88
app::{settings::SettingsError, wallet::WalletError},
99
daemon::DaemonError,
10-
export,
10+
export::{self, RestoreBackupError},
1111
};
1212

1313
#[derive(Debug)]
@@ -20,6 +20,7 @@ pub enum Error {
2020
Desc(LianaDescError),
2121
Spend(SpendCreationError),
2222
ImportExport(export::Error),
23+
RestoreBackup(RestoreBackupError),
2324
}
2425

2526
impl std::fmt::Display for Error {
@@ -61,6 +62,7 @@ impl std::fmt::Display for Error {
6162
Self::HardwareWallet(e) => write!(f, "error: {}\nPlease check if the device is still connected and unlocked with the correct firmware open for the current network and no other application is accessing the device.", e),
6263
Self::Desc(e) => write!(f, "Liana descriptor error: {}", e),
6364
Self::ImportExport(e) => write!(f, "{e}"),
65+
Self::RestoreBackup(e) => write!(f, "{e}"),
6466
}
6567
}
6668
}

liana-gui/src/app/view/warning.rs

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ impl From<&Error> for WarningMessage {
5050
Error::Desc(e) => WarningMessage(format!("Descriptor analysis error: '{}'.", e)),
5151
Error::Spend(e) => WarningMessage(format!("Spend creation error: '{}'.", e)),
5252
Error::ImportExport(e) => WarningMessage(format!("{e}")),
53+
Error::RestoreBackup(e) => WarningMessage(format!("Fail to restore backup: {e}")),
5354
}
5455
}
5556
}

liana-gui/src/export.rs

+142
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,148 @@ pub async fn import_backup(
967967
send_progress!(sender, Ended);
968968
}
969969

970+
#[derive(Debug)]
971+
pub enum RestoreBackupError {
972+
Daemon(DaemonError),
973+
Network,
974+
InvalidDescriptor,
975+
WrongDescriptor,
976+
NoAccount,
977+
SeveralAccounts,
978+
LianaConnectNotSupported,
979+
GetLabels,
980+
LabelsNotEmpty,
981+
NotImplemented,
982+
InvalidPsbt,
983+
}
984+
985+
impl Display for RestoreBackupError {
986+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
987+
match self {
988+
RestoreBackupError::Daemon(e) => write!(f, "Daemon error during restore process: {e}"),
989+
RestoreBackupError::Network => write!(f, "Backup & wallet network don't matches"),
990+
RestoreBackupError::InvalidDescriptor => write!(f, "The backup descriptor is invalid"),
991+
RestoreBackupError::WrongDescriptor => {
992+
write!(f, "Backup & wallet descriptor don't matches")
993+
}
994+
RestoreBackupError::NoAccount => write!(f, "There is no account in the backup"),
995+
RestoreBackupError::SeveralAccounts => {
996+
write!(f, "There is several accounts in the backup")
997+
}
998+
RestoreBackupError::LianaConnectNotSupported => {
999+
write!(f, "Restore a backup to Liana-connect is not yet supported")
1000+
}
1001+
RestoreBackupError::GetLabels => write!(f, "Fails to get labels during backup restore"),
1002+
RestoreBackupError::LabelsNotEmpty => write!(
1003+
f,
1004+
"Cannot load labels: there is already labels into the database"
1005+
),
1006+
RestoreBackupError::NotImplemented => write!(f, "Not implemented"),
1007+
RestoreBackupError::InvalidPsbt => write!(f, "Psbt is invalid"),
1008+
}
1009+
}
1010+
}
1011+
1012+
impl From<DaemonError> for RestoreBackupError {
1013+
fn from(value: DaemonError) -> Self {
1014+
Self::Daemon(value)
1015+
}
1016+
}
1017+
1018+
#[allow(unused)]
1019+
/// Import backup data if wallet created from a backup
1020+
/// - check if networks matches
1021+
/// - check if descriptors matches
1022+
/// - check if labels are empty
1023+
/// - update receive and change indexes
1024+
/// - parse psbt from backup
1025+
/// - import PSBTs
1026+
/// - import labels
1027+
async fn import_backup_at_launch(
1028+
backup: Backup,
1029+
daemon: Arc<dyn Daemon + Sync + Send>,
1030+
) -> Result<(), RestoreBackupError> {
1031+
// TODO: drop after support for restore to liana-connect
1032+
if matches!(daemon.backend(), DaemonBackend::RemoteBackend) {
1033+
return Err(RestoreBackupError::LianaConnectNotSupported);
1034+
}
1035+
1036+
// get backend info
1037+
let info = daemon.get_info().await?;
1038+
1039+
// check if networks matches
1040+
let network = info.network;
1041+
if backup.network != network {
1042+
return Err(RestoreBackupError::Network);
1043+
}
1044+
1045+
// check if descriptors matches
1046+
let descriptor = info.descriptors.main;
1047+
let account = match backup.accounts.len() {
1048+
0 => return Err(RestoreBackupError::NoAccount),
1049+
1 => backup.accounts.first().expect("already checked"),
1050+
_ => return Err(RestoreBackupError::SeveralAccounts),
1051+
};
1052+
1053+
let backup_descriptor = LianaDescriptor::from_str(&account.descriptor)
1054+
.map_err(|_| RestoreBackupError::InvalidDescriptor)?;
1055+
1056+
if backup_descriptor != descriptor {
1057+
return Err(RestoreBackupError::WrongDescriptor);
1058+
}
1059+
1060+
// check there is no labels in DB
1061+
if account.labels.is_some()
1062+
&& !daemon
1063+
.get_labels_bip329(0, u32::MAX)
1064+
.await
1065+
.map_err(|_| RestoreBackupError::GetLabels)?
1066+
.to_vec()
1067+
.is_empty()
1068+
{
1069+
return Err(RestoreBackupError::LabelsNotEmpty);
1070+
}
1071+
1072+
// parse PSBTs
1073+
let mut psbts = Vec::new();
1074+
for psbt_str in &account.psbts {
1075+
psbts.push(Psbt::from_str(psbt_str).map_err(|_| RestoreBackupError::InvalidPsbt)?);
1076+
}
1077+
1078+
// update receive & change index
1079+
let db_receive = info.receive_index;
1080+
let i = account.receive_index.unwrap_or(0);
1081+
let receive = if db_receive < i { Some(i) } else { None };
1082+
1083+
let db_change = info.change_index;
1084+
let i = account.change_index.unwrap_or(0);
1085+
let change = if db_change < i { Some(i) } else { None };
1086+
1087+
daemon.update_deriv_indexes(receive, change).await?;
1088+
1089+
// import PSBTs
1090+
for psbt in psbts {
1091+
daemon.update_spend_tx(&psbt).await?;
1092+
}
1093+
1094+
// import labels
1095+
if let Some(labels) = account.labels.clone().map(|l| l.into_vec()) {
1096+
let labels: HashMap<LabelItem, Option<String>> = labels
1097+
.into_iter()
1098+
.filter_map(|l| {
1099+
if let Some((item, label)) = LabelItem::from_bip329(&l, network) {
1100+
Some((item, Some(label)))
1101+
} else {
1102+
None
1103+
}
1104+
})
1105+
.collect();
1106+
daemon.update_labels(&labels).await?;
1107+
}
1108+
1109+
Err(RestoreBackupError::NotImplemented)
1110+
}
1111+
9701112
pub async fn export_labels(
9711113
sender: Sender<Progress>,
9721114
daemon: Option<Arc<dyn Daemon + Sync + Send>>,

0 commit comments

Comments
 (0)