@@ -967,6 +967,148 @@ pub async fn import_backup(
967
967
send_progress ! ( sender, Ended ) ;
968
968
}
969
969
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
+
970
1112
pub async fn export_labels (
971
1113
sender : Sender < Progress > ,
972
1114
daemon : Option < Arc < dyn Daemon + Sync + Send > > ,
0 commit comments