@@ -15,7 +15,9 @@ use bitcoin::BlockHash;
1515use bitcoin_bech32:: WitnessProgram ;
1616use lightning:: chain;
1717use lightning:: chain:: chaininterface:: { BroadcasterInterface , ConfirmationTarget , FeeEstimator } ;
18- use lightning:: chain:: keysinterface:: { EntropySource , InMemorySigner , KeysManager } ;
18+ use lightning:: chain:: keysinterface:: {
19+ EntropySource , InMemorySigner , KeysManager , SpendableOutputDescriptor
20+ } ;
1921use lightning:: chain:: { chainmonitor, ChannelMonitorUpdateStatus } ;
2022use lightning:: chain:: { Filter , Watch } ;
2123use lightning:: events:: { Event , PaymentFailureReason , PaymentPurpose } ;
@@ -30,7 +32,9 @@ use lightning::routing::gossip;
3032use lightning:: routing:: gossip:: { NodeId , P2PGossipSync } ;
3133use lightning:: routing:: router:: DefaultRouter ;
3234use lightning:: util:: config:: UserConfig ;
33- use lightning:: util:: ser:: ReadableArgs ;
35+ use lightning:: util:: logger:: Logger ;
36+ use lightning:: util:: persist:: KVStorePersister ;
37+ use lightning:: util:: ser:: { Readable , ReadableArgs , WithoutLength } ;
3438use lightning_background_processor:: { process_events_async, GossipSync } ;
3539use lightning_block_sync:: init;
3640use lightning_block_sync:: poll;
@@ -46,8 +50,8 @@ use std::fmt;
4650use std:: fs;
4751use std:: fs:: File ;
4852use std:: io;
49- use std:: io:: Write ;
50- use std:: path:: Path ;
53+ use std:: io:: { Read , Seek , SeekFrom , Write } ;
54+ use std:: path:: { Path , PathBuf } ;
5155use std:: sync:: atomic:: { AtomicBool , Ordering } ;
5256use std:: sync:: { Arc , Mutex } ;
5357use std:: time:: { Duration , SystemTime } ;
@@ -107,7 +111,7 @@ async fn handle_ldk_events(
107111 channel_manager : & Arc < ChannelManager > , bitcoind_client : & BitcoindClient ,
108112 network_graph : & NetworkGraph , keys_manager : & KeysManager ,
109113 inbound_payments : & PaymentInfoStorage , outbound_payments : & PaymentInfoStorage ,
110- network : Network , event : Event ,
114+ persister : & Arc < FilesystemPersister > , network : Network , event : Event ,
111115) {
112116 match event {
113117 Event :: FundingGenerationReady {
@@ -331,20 +335,21 @@ async fn handle_ldk_events(
331335 } ) ;
332336 }
333337 Event :: SpendableOutputs { outputs } => {
334- let destination_address = bitcoind_client. get_new_address ( ) . await ;
335- let output_descriptors = & outputs. iter ( ) . map ( |a| a) . collect :: < Vec < _ > > ( ) ;
336- let tx_feerate =
337- bitcoind_client. get_est_sat_per_1000_weight ( ConfirmationTarget :: Normal ) ;
338- let spending_tx = keys_manager
339- . spend_spendable_outputs (
340- output_descriptors,
341- Vec :: new ( ) ,
342- destination_address. script_pubkey ( ) ,
343- tx_feerate,
344- & Secp256k1 :: new ( ) ,
345- )
346- . unwrap ( ) ;
347- bitcoind_client. broadcast_transaction ( & spending_tx) ;
338+ // SpendableOutputDescriptors, of which outputs is a vec of, are critical to keep track
339+ // of! While a `StaticOutput` descriptor is just an output to a static, well-known key,
340+ // other descriptors are not currently ever regenerated for you by LDK. Once we return
341+ // from this method, the descriptor will be gone, and you may lose track of some funds.
342+ //
343+ // Here we simply persist them to disk, with a background task running which will try
344+ // to spend them regularly (possibly duplicatively/RBF'ing them). These can just be
345+ // treated as normal funds where possible - they are only spendable by us and there is
346+ // no rush to claim them.
347+ for output in outputs {
348+ let key = hex_utils:: hex_str ( & keys_manager. get_secure_random_bytes ( ) ) ;
349+ // Note that if the type here changes our read code needs to change as well.
350+ let output: SpendableOutputDescriptor = output;
351+ persister. persist ( & format ! ( "pending_spendable_outputs/{}" , key) , & output) . unwrap ( ) ;
352+ }
348353 }
349354 Event :: ChannelPending { channel_id, counterparty_node_id, .. } => {
350355 println ! (
@@ -693,6 +698,7 @@ async fn start_ldk() {
693698 let keys_manager_event_listener = Arc :: clone ( & keys_manager) ;
694699 let inbound_payments_event_listener = Arc :: clone ( & inbound_payments) ;
695700 let outbound_payments_event_listener = Arc :: clone ( & outbound_payments) ;
701+ let persister_event_listener = Arc :: clone ( & persister) ;
696702 let network = args. network ;
697703 let event_handler = move |event : Event | {
698704 let channel_manager_event_listener = Arc :: clone ( & channel_manager_event_listener) ;
@@ -701,6 +707,7 @@ async fn start_ldk() {
701707 let keys_manager_event_listener = Arc :: clone ( & keys_manager_event_listener) ;
702708 let inbound_payments_event_listener = Arc :: clone ( & inbound_payments_event_listener) ;
703709 let outbound_payments_event_listener = Arc :: clone ( & outbound_payments_event_listener) ;
710+ let persister_event_listener = Arc :: clone ( & persister_event_listener) ;
704711 async move {
705712 handle_ldk_events (
706713 & channel_manager_event_listener,
@@ -709,6 +716,7 @@ async fn start_ldk() {
709716 & keys_manager_event_listener,
710717 & inbound_payments_event_listener,
711718 & outbound_payments_event_listener,
719+ & persister_event_listener,
712720 network,
713721 event,
714722 )
@@ -722,7 +730,7 @@ async fn start_ldk() {
722730 // Step 20: Background Processing
723731 let ( bp_exit, bp_exit_check) = tokio:: sync:: watch:: channel ( ( ) ) ;
724732 let background_processor = tokio:: spawn ( process_events_async (
725- persister,
733+ Arc :: clone ( & persister) ,
726734 event_handler,
727735 chain_monitor. clone ( ) ,
728736 channel_manager. clone ( ) ,
@@ -800,6 +808,90 @@ async fn start_ldk() {
800808 }
801809 } ) ;
802810
811+ // Regularly claim outputs which are exclusively spendable by us and send them to Bitcoin Core.
812+ // Note that if you more tightly integrate your wallet with LDK you may not need to do this -
813+ // these outputs can just be treated as normal outputs during coin selection.
814+ let pending_spendables_dir = format ! ( "{}/pending_spendable_outputs" , ldk_data_dir) ;
815+ let processing_spendables_dir = format ! ( "{}/processing_spendable_outputs" , ldk_data_dir) ;
816+ let spendables_dir = format ! ( "{}/spendable_outputs" , ldk_data_dir) ;
817+ let spending_keys_manager = Arc :: clone ( & keys_manager) ;
818+ let spending_logger = Arc :: clone ( & logger) ;
819+ tokio:: spawn ( async move {
820+ let mut interval = tokio:: time:: interval ( Duration :: from_secs ( 3600 ) ) ;
821+ loop {
822+ interval. tick ( ) . await ;
823+ if let Ok ( dir_iter) = fs:: read_dir ( & pending_spendables_dir) {
824+ // Move any spendable descriptors from pending folder so that we don't have any
825+ // races with new files being added.
826+ for file_res in dir_iter {
827+ let file = file_res. unwrap ( ) ;
828+ // Only move a file if its a 32-byte-hex'd filename, otherwise it might be a
829+ // temporary file.
830+ if file. file_name ( ) . len ( ) == 64 {
831+ fs:: create_dir_all ( & processing_spendables_dir) . unwrap ( ) ;
832+ let mut holding_path = PathBuf :: new ( ) ;
833+ holding_path. push ( & processing_spendables_dir) ;
834+ holding_path. push ( & file. file_name ( ) ) ;
835+ fs:: rename ( file. path ( ) , holding_path) . unwrap ( ) ;
836+ }
837+ }
838+ // Now concatenate all the pending files we moved into one file in the
839+ // `spendable_outputs` directory and drop the processing directory.
840+ let mut outputs = Vec :: new ( ) ;
841+ if let Ok ( processing_iter) = fs:: read_dir ( & processing_spendables_dir) {
842+ for file_res in processing_iter {
843+ outputs. append ( & mut fs:: read ( file_res. unwrap ( ) . path ( ) ) . unwrap ( ) ) ;
844+ }
845+ }
846+ if !outputs. is_empty ( ) {
847+ let key = hex_utils:: hex_str ( & spending_keys_manager. get_secure_random_bytes ( ) ) ;
848+ persister
849+ . persist ( & format ! ( "spendable_outputs/{}" , key) , & WithoutLength ( & outputs) )
850+ . unwrap ( ) ;
851+ fs:: remove_dir_all ( & processing_spendables_dir) . unwrap ( ) ;
852+ }
853+ }
854+ // Iterate over all the sets of spendable outputs in `spendables_dir` and try to claim
855+ // them.
856+ if let Ok ( dir_iter) = fs:: read_dir ( & spendables_dir) {
857+ for file_res in dir_iter {
858+ let mut outputs: Vec < SpendableOutputDescriptor > = Vec :: new ( ) ;
859+ let mut file = File :: open ( file_res. unwrap ( ) . path ( ) ) . unwrap ( ) ;
860+ loop {
861+ // Check if there are any bytes left to read, and if so read a descriptor.
862+ match file. read_exact ( & mut [ 0 ; 1 ] ) {
863+ Ok ( _) => {
864+ file. seek ( SeekFrom :: Current ( -1 ) ) . unwrap ( ) ;
865+ } ,
866+ Err ( e) if e. kind ( ) == io:: ErrorKind :: UnexpectedEof => break ,
867+ Err ( e) => Err ( e) . unwrap ( ) ,
868+ }
869+ outputs. push ( Readable :: read ( & mut file) . unwrap ( ) ) ;
870+ }
871+ let destination_address = bitcoind_client. get_new_address ( ) . await ;
872+ let output_descriptors = & outputs. iter ( ) . map ( |a| a) . collect :: < Vec < _ > > ( ) ;
873+ let tx_feerate =
874+ bitcoind_client. get_est_sat_per_1000_weight ( ConfirmationTarget :: Normal ) ;
875+ if let Ok ( spending_tx) = spending_keys_manager. spend_spendable_outputs (
876+ output_descriptors,
877+ Vec :: new ( ) ,
878+ destination_address. script_pubkey ( ) ,
879+ tx_feerate,
880+ & Secp256k1 :: new ( ) ,
881+ ) {
882+ // Note that, most likely, we've already sweeped this set of outputs
883+ // and they're already confirmed on-chain, so this broadcast will fail.
884+ bitcoind_client. broadcast_transaction ( & spending_tx) ;
885+ } else {
886+ lightning:: log_error!(
887+ spending_logger,
888+ "Failed to sweep spendable outputs! This may indicate the outputs are dust. Will try again in an hour." ) ;
889+ }
890+ }
891+ }
892+ }
893+ } ) ;
894+
803895 // Start the CLI.
804896 cli:: poll_for_user_input (
805897 Arc :: clone ( & peer_manager) ,
@@ -809,7 +901,7 @@ async fn start_ldk() {
809901 Arc :: clone ( & onion_messenger) ,
810902 inbound_payments,
811903 outbound_payments,
812- ldk_data_dir. clone ( ) ,
904+ ldk_data_dir,
813905 network,
814906 Arc :: clone ( & logger) ,
815907 )
0 commit comments