@@ -43,15 +43,17 @@ use crate::error::MutinyError;
43
43
pub use crate :: gossip:: { GOSSIP_SYNC_TIME_KEY , NETWORK_GRAPH_KEY , PROB_SCORER_KEY } ;
44
44
pub use crate :: keymanager:: generate_seed;
45
45
pub use crate :: ldkstorage:: {
46
- BROADCAST_TX_1_IN_MULTI_OUT , CHANNEL_CLOSURE_BUMP_PREFIX , CHANNEL_CLOSURE_PREFIX ,
47
- CHANNEL_MANAGER_KEY , MONITORS_PREFIX_KEY ,
46
+ ACTIVE_NODE_ID_KEY , CHANNEL_CLOSURE_BUMP_PREFIX , CHANNEL_CLOSURE_PREFIX , CHANNEL_MANAGER_KEY ,
47
+ MONITORS_PREFIX_KEY ,
48
48
} ;
49
+ use crate :: lsp:: lndchannel:: fetch_lnd_channels_snapshot;
50
+ use crate :: messagehandler:: CommonLnEventCallback ;
49
51
use crate :: nodemanager:: NodeManager ;
50
52
use crate :: nodemanager:: { ChannelClosure , MutinyBip21RawMaterials } ;
51
53
pub use crate :: onchain:: BroadcastTx1InMultiOut ;
52
- use crate :: storage:: get_invoice_by_hash;
53
- use crate :: utils:: sleep;
54
- use crate :: utils :: spawn ;
54
+ use crate :: storage:: { get_invoice_by_hash, LND_CHANNELS_SNAPSHOT_KEY } ;
55
+ use crate :: utils:: { now , sleep, spawn , spawn_with_handle , StopHandle } ;
56
+ use crate :: vss :: VSS_MANAGER ;
55
57
use crate :: { authclient:: MutinyAuthClient , logging:: MutinyLogger } ;
56
58
use crate :: {
57
59
event:: { HTLCStatus , MillisatAmount , PaymentInfo } ,
@@ -67,7 +69,7 @@ use crate::{
67
69
PAYMENT_INBOUND_PREFIX_KEY , PAYMENT_OUTBOUND_PREFIX_KEY , TRANSACTION_DETAILS_PREFIX_KEY ,
68
70
} ,
69
71
} ;
70
- use anyhow :: Context ;
72
+
71
73
use bdk_chain:: ConfirmationTime ;
72
74
use bip39:: Mnemonic ;
73
75
pub use bitcoin;
@@ -77,6 +79,7 @@ use bitcoin::{bip32::Xpriv, Transaction};
77
79
use bitcoin:: { hashes:: sha256, Network , Txid } ;
78
80
use bitcoin:: { hashes:: Hash , Address } ;
79
81
82
+ use anyhow:: Context ;
80
83
use futures_util:: lock:: Mutex ;
81
84
use hex_conservative:: { DisplayHex , FromHex } ;
82
85
use itertools:: Itertools ;
@@ -87,10 +90,8 @@ use lightning::util::logger::Logger;
87
90
use lightning:: { log_debug, log_error, log_info, log_trace, log_warn} ;
88
91
pub use lightning_invoice;
89
92
use lightning_invoice:: { Bolt11Invoice , Bolt11InvoiceDescription } ;
90
-
91
- use messagehandler:: CommonLnEventCallback ;
93
+ use reqwest:: Client ;
92
94
use serde:: { Deserialize , Serialize } ;
93
- use utils:: { spawn_with_handle, StopHandle } ;
94
95
95
96
use std:: collections:: HashMap ;
96
97
use std:: collections:: HashSet ;
@@ -99,7 +100,6 @@ use std::sync::Arc;
99
100
use std:: time:: Duration ;
100
101
#[ cfg( not( target_arch = "wasm32" ) ) ]
101
102
use std:: time:: Instant ;
102
-
103
103
#[ cfg( target_arch = "wasm32" ) ]
104
104
use web_time:: Instant ;
105
105
@@ -548,6 +548,7 @@ pub struct MutinyWalletConfigBuilder {
548
548
skip_device_lock : bool ,
549
549
pub safe_mode : bool ,
550
550
skip_hodl_invoices : bool ,
551
+ check_lnd_snapshot : bool ,
551
552
}
552
553
553
554
impl MutinyWalletConfigBuilder {
@@ -572,6 +573,7 @@ impl MutinyWalletConfigBuilder {
572
573
skip_device_lock : false ,
573
574
safe_mode : false ,
574
575
skip_hodl_invoices : true ,
576
+ check_lnd_snapshot : false ,
575
577
}
576
578
}
577
579
@@ -647,6 +649,10 @@ impl MutinyWalletConfigBuilder {
647
649
self . skip_hodl_invoices = false ;
648
650
}
649
651
652
+ pub fn do_check_lnd_snapshot ( & mut self ) {
653
+ self . check_lnd_snapshot = true ;
654
+ }
655
+
650
656
pub fn build ( self ) -> MutinyWalletConfig {
651
657
let network = self . network . expect ( "network is required" ) ;
652
658
@@ -670,6 +676,7 @@ impl MutinyWalletConfigBuilder {
670
676
skip_device_lock : self . skip_device_lock ,
671
677
safe_mode : self . safe_mode ,
672
678
skip_hodl_invoices : self . skip_hodl_invoices ,
679
+ check_lnd_snapshot : self . check_lnd_snapshot ,
673
680
}
674
681
}
675
682
}
@@ -695,6 +702,7 @@ pub struct MutinyWalletConfig {
695
702
skip_device_lock : bool ,
696
703
pub safe_mode : bool ,
697
704
skip_hodl_invoices : bool ,
705
+ check_lnd_snapshot : bool ,
698
706
}
699
707
700
708
pub struct MutinyWalletBuilder < S : MutinyStorage > {
@@ -817,7 +825,7 @@ impl<S: MutinyStorage> MutinyWalletBuilder<S> {
817
825
let network = self
818
826
. network
819
827
. map_or_else ( || Err ( MutinyError :: InvalidArgumentsError ) , Ok ) ?;
820
- let config = self . config . unwrap_or (
828
+ let config = self . config . clone ( ) . unwrap_or (
821
829
MutinyWalletConfigBuilder :: new ( self . xprivkey )
822
830
. with_network ( network)
823
831
. build ( ) ,
@@ -844,12 +852,15 @@ impl<S: MutinyStorage> MutinyWalletBuilder<S> {
844
852
845
853
// Need to prevent other devices from running at the same time
846
854
log_debug ! ( logger, "checking device lock" ) ;
855
+ let lsp_url = config. lsp_url . clone ( ) ;
847
856
if !config. skip_device_lock {
848
857
let start = Instant :: now ( ) ;
849
858
if let Some ( lock) = self . storage . get_device_lock ( ) ? {
850
859
log_info ! ( logger, "Current device lock: {lock:?}" ) ;
851
860
}
852
- self . storage . set_device_lock ( & logger) ?;
861
+ self . storage
862
+ . set_device_lock ( & logger, lsp_url. clone ( ) , config. check_lnd_snapshot )
863
+ . await ?;
853
864
log_debug ! (
854
865
logger,
855
866
"Device lock set: took {}ms" ,
@@ -905,15 +916,83 @@ impl<S: MutinyStorage> MutinyWalletBuilder<S> {
905
916
loop {
906
917
if stop_signal. stopping ( ) {
907
918
log_debug ! ( logger_clone, "stopping claim device lock" ) ;
919
+ while VSS_MANAGER . has_in_progress ( ) {
920
+ log_debug ! ( logger_clone, "waiting for VSS to finish" ) ;
921
+ sleep ( 300 ) . await ;
922
+ }
908
923
if let Err ( e) = storage_clone. release_device_lock ( & logger_clone) {
909
924
log_error ! ( logger_clone, "Error releasing device lock: {e}" ) ;
910
925
}
911
926
break ;
912
927
}
913
- if let Err ( e) = storage_clone. set_device_lock ( & logger_clone) {
928
+
929
+ let config = self . config . as_ref ( ) . expect ( "config is required" ) ;
930
+ if let ( Some ( lsp_url) , Ok ( Some ( node_id) ) ) =
931
+ ( config. lsp_url . as_ref ( ) , storage_clone. get_node_id ( ) )
932
+ {
933
+ match fetch_lnd_channels_snapshot (
934
+ & Client :: new ( ) ,
935
+ lsp_url,
936
+ & node_id,
937
+ & logger_clone,
938
+ )
939
+ . await
940
+ {
941
+ Ok ( first_lnd_snapshot) => {
942
+ log_debug ! (
943
+ logger_clone,
944
+ "First fetched lnd snapshot: {:?}" ,
945
+ first_lnd_snapshot
946
+ ) ;
947
+ if !VSS_MANAGER . has_in_progress ( ) {
948
+ if let Ok ( second_lnd_snapshot) = fetch_lnd_channels_snapshot (
949
+ & Client :: new ( ) ,
950
+ lsp_url,
951
+ & node_id,
952
+ & logger_clone,
953
+ )
954
+ . await
955
+ {
956
+ log_debug ! (
957
+ logger_clone,
958
+ "Second fetched lnd snapshot: {:?}" ,
959
+ second_lnd_snapshot
960
+ ) ;
961
+ if first_lnd_snapshot. snapshot == second_lnd_snapshot. snapshot {
962
+ log_debug ! ( logger_clone, "Saving lnd snapshot" ) ;
963
+ if let Err ( e) = storage_clone. write_data (
964
+ LND_CHANNELS_SNAPSHOT_KEY . to_string ( ) ,
965
+ & second_lnd_snapshot,
966
+ Some ( now ( ) . as_secs ( ) as u32 ) ,
967
+ ) {
968
+ log_error ! (
969
+ logger_clone,
970
+ "Error saving lnd snapshot: {e}"
971
+ ) ;
972
+ }
973
+ }
974
+ }
975
+ }
976
+ }
977
+ Err ( e) => {
978
+ log_error ! ( logger_clone, "Error fetching lnd channels: {e}" ) ;
979
+ }
980
+ }
981
+ }
982
+
983
+ if let Err ( e) = storage_clone
984
+ . set_device_lock ( & logger_clone, lsp_url. clone ( ) , config. check_lnd_snapshot )
985
+ . await
986
+ {
914
987
log_error ! ( logger_clone, "Error setting device lock: {e}" ) ;
915
988
}
916
989
990
+ log_debug ! (
991
+ logger_clone,
992
+ "Vss pending writes: {:?}" ,
993
+ VSS_MANAGER . get_pending_writes( )
994
+ ) ;
995
+
917
996
let mut remained_sleep_ms = ( DEVICE_LOCK_INTERVAL_SECS * 1000 ) as i32 ;
918
997
while !stop_signal. stopping ( ) && remained_sleep_ms > 0 {
919
998
let sleep_ms = 300 ;
0 commit comments