@@ -32,6 +32,7 @@ use lightning::routing::scoring::{
3232 ProbabilisticScoringFeeParameters ,
3333} ;
3434use lightning:: sign:: { EntropySource , NodeSigner } ;
35+ use lightning:: util:: config:: HTLCInterceptionFlags ;
3536use lightning:: util:: persist:: {
3637 KVStore , CHANNEL_MANAGER_PERSISTENCE_KEY , CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE ,
3738 CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE ,
@@ -55,12 +56,14 @@ use crate::gossip::GossipSource;
5556use crate :: io:: sqlite_store:: SqliteStore ;
5657use crate :: io:: utils:: {
5758 read_event_queue, read_external_pathfinding_scores_from_cache, read_network_graph,
58- read_node_metrics, read_output_sweeper, read_payments, read_peer_info, read_scorer ,
59- write_node_metrics,
59+ read_node_metrics, read_output_sweeper, read_payments, read_peer_info, read_pending_payments ,
60+ read_scorer , write_node_metrics,
6061} ;
6162use crate :: io:: vss_store:: VssStoreBuilder ;
6263use crate :: io:: {
6364 self , PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE , PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE ,
65+ PENDING_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE ,
66+ PENDING_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE ,
6467} ;
6568use crate :: liquidity:: {
6669 LSPS1ClientConfig , LSPS2ClientConfig , LSPS2ServiceConfig , LiquiditySourceBuilder ,
@@ -73,8 +76,8 @@ use crate::runtime::{Runtime, RuntimeSpawner};
7376use crate :: tx_broadcaster:: TransactionBroadcaster ;
7477use crate :: types:: {
7578 AsyncPersister , ChainMonitor , ChannelManager , DynStore , DynStoreWrapper , GossipSync , Graph ,
76- KeysManager , MessageRouter , OnionMessenger , PaymentStore , PeerManager , Persister ,
77- SyncAndAsyncKVStore ,
79+ KeysManager , MessageRouter , OnionMessenger , PaymentStore , PeerManager , PendingPaymentStore ,
80+ Persister , SyncAndAsyncKVStore ,
7881} ;
7982use crate :: wallet:: persist:: KVStoreWalletPersister ;
8083use crate :: wallet:: Wallet ;
@@ -241,6 +244,7 @@ pub struct NodeBuilder {
241244 async_payments_role : Option < AsyncPaymentsRole > ,
242245 runtime_handle : Option < tokio:: runtime:: Handle > ,
243246 pathfinding_scores_sync_config : Option < PathfindingScoresSyncConfig > ,
247+ recovery_mode : bool ,
244248}
245249
246250impl NodeBuilder {
@@ -258,6 +262,7 @@ impl NodeBuilder {
258262 let log_writer_config = None ;
259263 let runtime_handle = None ;
260264 let pathfinding_scores_sync_config = None ;
265+ let recovery_mode = false ;
261266 Self {
262267 config,
263268 chain_data_source_config,
@@ -267,6 +272,7 @@ impl NodeBuilder {
267272 runtime_handle,
268273 async_payments_role : None ,
269274 pathfinding_scores_sync_config,
275+ recovery_mode,
270276 }
271277 }
272278
@@ -541,6 +547,16 @@ impl NodeBuilder {
541547 Ok ( self )
542548 }
543549
550+ /// Configures the [`Node`] to resync chain data from genesis on first startup, recovering any
551+ /// historical wallet funds.
552+ ///
553+ /// This should only be set on first startup when importing an older wallet from a previously
554+ /// used [`NodeEntropy`].
555+ pub fn set_wallet_recovery_mode ( & mut self ) -> & mut Self {
556+ self . recovery_mode = true ;
557+ self
558+ }
559+
544560 /// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
545561 /// previously configured.
546562 pub fn build ( & self , node_entropy : NodeEntropy ) -> Result < Node , BuildError > {
@@ -676,6 +692,7 @@ impl NodeBuilder {
676692 self . liquidity_source_config . as_ref ( ) ,
677693 self . pathfinding_scores_sync_config . as_ref ( ) ,
678694 self . async_payments_role ,
695+ self . recovery_mode ,
679696 seed_bytes,
680697 runtime,
681698 logger,
@@ -916,6 +933,15 @@ impl ArcedNodeBuilder {
916933 self . inner . write ( ) . unwrap ( ) . set_async_payments_role ( role) . map ( |_| ( ) )
917934 }
918935
936+ /// Configures the [`Node`] to resync chain data from genesis on first startup, recovering any
937+ /// historical wallet funds.
938+ ///
939+ /// This should only be set on first startup when importing an older wallet from a previously
940+ /// used [`NodeEntropy`].
941+ pub fn set_wallet_recovery_mode ( & self ) {
942+ self . inner . write ( ) . unwrap ( ) . set_wallet_recovery_mode ( ) ;
943+ }
944+
919945 /// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
920946 /// previously configured.
921947 pub fn build ( & self , node_entropy : Arc < NodeEntropy > ) -> Result < Arc < Node > , BuildError > {
@@ -1030,8 +1056,8 @@ fn build_with_store_internal(
10301056 gossip_source_config : Option < & GossipSourceConfig > ,
10311057 liquidity_source_config : Option < & LiquiditySourceConfig > ,
10321058 pathfinding_scores_sync_config : Option < & PathfindingScoresSyncConfig > ,
1033- async_payments_role : Option < AsyncPaymentsRole > , seed_bytes : [ u8 ; 64 ] , runtime : Arc < Runtime > ,
1034- logger : Arc < Logger > , kv_store : Arc < DynStore > ,
1059+ async_payments_role : Option < AsyncPaymentsRole > , recovery_mode : bool , seed_bytes : [ u8 ; 64 ] ,
1060+ runtime : Arc < Runtime > , logger : Arc < Logger > , kv_store : Arc < DynStore > ,
10351061) -> Result < Node , BuildError > {
10361062 optionally_install_rustls_cryptoprovider ( ) ;
10371063
@@ -1057,12 +1083,14 @@ fn build_with_store_internal(
10571083
10581084 let kv_store_ref = Arc :: clone ( & kv_store) ;
10591085 let logger_ref = Arc :: clone ( & logger) ;
1060- let ( payment_store_res, node_metris_res) = runtime. block_on ( async move {
1061- tokio:: join!(
1062- read_payments( & * kv_store_ref, Arc :: clone( & logger_ref) ) ,
1063- read_node_metrics( & * kv_store_ref, Arc :: clone( & logger_ref) ) ,
1064- )
1065- } ) ;
1086+ let ( payment_store_res, node_metris_res, pending_payment_store_res) =
1087+ runtime. block_on ( async move {
1088+ tokio:: join!(
1089+ read_payments( & * kv_store_ref, Arc :: clone( & logger_ref) ) ,
1090+ read_node_metrics( & * kv_store_ref, Arc :: clone( & logger_ref) ) ,
1091+ read_pending_payments( & * kv_store_ref, Arc :: clone( & logger_ref) )
1092+ )
1093+ } ) ;
10661094
10671095 // Initialize the status fields.
10681096 let node_metrics = match node_metris_res {
@@ -1225,32 +1253,52 @@ fn build_with_store_internal(
12251253 BuildError :: WalletSetupFailed
12261254 } ) ?;
12271255
1228- if let Some ( best_block) = chain_tip_opt {
1229- // Insert the first checkpoint if we have it, to avoid resyncing from genesis.
1230- // TODO: Use a proper wallet birthday once BDK supports it.
1231- let mut latest_checkpoint = wallet. latest_checkpoint ( ) ;
1232- let block_id =
1233- bdk_chain:: BlockId { height : best_block. height , hash : best_block. block_hash } ;
1234- latest_checkpoint = latest_checkpoint. insert ( block_id) ;
1235- let update =
1236- bdk_wallet:: Update { chain : Some ( latest_checkpoint) , ..Default :: default ( ) } ;
1237- wallet. apply_update ( update) . map_err ( |e| {
1238- log_error ! ( logger, "Failed to apply checkpoint during wallet setup: {}" , e) ;
1239- BuildError :: WalletSetupFailed
1240- } ) ?;
1256+ if !recovery_mode {
1257+ if let Some ( best_block) = chain_tip_opt {
1258+ // Insert the first checkpoint if we have it, to avoid resyncing from genesis.
1259+ // TODO: Use a proper wallet birthday once BDK supports it.
1260+ let mut latest_checkpoint = wallet. latest_checkpoint ( ) ;
1261+ let block_id = bdk_chain:: BlockId {
1262+ height : best_block. height ,
1263+ hash : best_block. block_hash ,
1264+ } ;
1265+ latest_checkpoint = latest_checkpoint. insert ( block_id) ;
1266+ let update =
1267+ bdk_wallet:: Update { chain : Some ( latest_checkpoint) , ..Default :: default ( ) } ;
1268+ wallet. apply_update ( update) . map_err ( |e| {
1269+ log_error ! ( logger, "Failed to apply checkpoint during wallet setup: {}" , e) ;
1270+ BuildError :: WalletSetupFailed
1271+ } ) ?;
1272+ }
12411273 }
12421274 wallet
12431275 } ,
12441276 } ;
12451277
1278+ let pending_payment_store = match pending_payment_store_res {
1279+ Ok ( pending_payments) => Arc :: new ( PendingPaymentStore :: new (
1280+ pending_payments,
1281+ PENDING_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE . to_string ( ) ,
1282+ PENDING_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE . to_string ( ) ,
1283+ Arc :: clone ( & kv_store) ,
1284+ Arc :: clone ( & logger) ,
1285+ ) ) ,
1286+ Err ( e) => {
1287+ log_error ! ( logger, "Failed to read pending payment data from store: {}" , e) ;
1288+ return Err ( BuildError :: ReadFailed ) ;
1289+ } ,
1290+ } ;
1291+
12461292 let wallet = Arc :: new ( Wallet :: new (
12471293 bdk_wallet,
12481294 wallet_persister,
12491295 Arc :: clone ( & tx_broadcaster) ,
12501296 Arc :: clone ( & fee_estimator) ,
1297+ Arc :: clone ( & chain_source) ,
12511298 Arc :: clone ( & payment_store) ,
12521299 Arc :: clone ( & config) ,
12531300 Arc :: clone ( & logger) ,
1301+ Arc :: clone ( & pending_payment_store) ,
12541302 ) ) ;
12551303
12561304 // Initialize the KeysManager
@@ -1415,7 +1463,7 @@ fn build_with_store_internal(
14151463 if liquidity_source_config. and_then ( |lsc| lsc. lsps2_service . as_ref ( ) ) . is_some ( ) {
14161464 // If we act as an LSPS2 service, we need to be able to intercept HTLCs and forward the
14171465 // information to the service handler.
1418- user_config. accept_intercept_htlcs = true ;
1466+ user_config. htlc_interception_flags = HTLCInterceptionFlags :: ToInterceptSCIDs . into ( ) ;
14191467
14201468 // If we act as an LSPS2 service, we allow forwarding to unannounced channels.
14211469 user_config. accept_forwards_to_priv_channels = true ;
0 commit comments