Skip to content

Commit ac6462f

Browse files
Use new OutputSweeper to sweep spendable outputs.
1 parent f2b3c97 commit ac6462f

File tree

2 files changed

+86
-34
lines changed

2 files changed

+86
-34
lines changed

src/bitcoind_client.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use bitcoin::{Network, OutPoint, TxOut, WPubkeyHash};
1818
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
1919
use lightning::events::bump_transaction::{Utxo, WalletSource};
2020
use lightning::log_error;
21+
use lightning::sign::ChangeDestinationSource;
2122
use lightning::util::logger::Logger;
2223
use lightning_block_sync::http::HttpEndpoint;
2324
use lightning_block_sync::rpc::RpcClient;
@@ -317,6 +318,14 @@ impl BroadcasterInterface for BitcoindClient {
317318
}
318319
}
319320

321+
impl ChangeDestinationSource for BitcoindClient {
322+
fn get_change_destination_script(&self) -> Result<ScriptBuf, ()> {
323+
tokio::task::block_in_place(move || {
324+
Ok(self.handle.block_on(async move { self.get_new_address().await.script_pubkey() }))
325+
})
326+
}
327+
}
328+
320329
impl WalletSource for BitcoindClient {
321330
fn list_confirmed_utxos(&self) -> Result<Vec<Utxo>, ()> {
322331
let utxos = tokio::task::block_in_place(move || {

src/main.rs

Lines changed: 77 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use bitcoin::BlockHash;
1515
use bitcoin_bech32::WitnessProgram;
1616
use disk::{INBOUND_PAYMENTS_FNAME, OUTBOUND_PAYMENTS_FNAME};
1717
use lightning::chain::{chainmonitor, ChannelMonitorUpdateStatus};
18-
use lightning::chain::{Filter, Watch};
18+
use lightning::chain::{BestBlock, Filter, Watch};
1919
use lightning::events::bump_transaction::{BumpTransactionEventHandler, Wallet};
2020
use lightning::events::{Event, PaymentFailureReason, PaymentPurpose};
2121
use lightning::ln::channelmanager::{self, RecentPaymentDetails};
@@ -30,10 +30,14 @@ use lightning::routing::gossip;
3030
use lightning::routing::gossip::{NodeId, P2PGossipSync};
3131
use lightning::routing::router::DefaultRouter;
3232
use lightning::routing::scoring::ProbabilisticScoringFeeParameters;
33-
use lightning::sign::{EntropySource, InMemorySigner, KeysManager, SpendableOutputDescriptor};
33+
use lightning::sign::{EntropySource, InMemorySigner, KeysManager};
3434
use lightning::util::config::UserConfig;
35-
use lightning::util::persist::{self, KVStore, MonitorUpdatingPersister};
35+
use lightning::util::persist::{
36+
self, KVStore, MonitorUpdatingPersister, OUTPUT_SWEEPER_PERSISTENCE_KEY,
37+
OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE, OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE,
38+
};
3639
use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer};
40+
use lightning::util::sweep as ldk_sweep;
3741
use lightning::{chain, impl_writeable_tlv_based, impl_writeable_tlv_based_enum};
3842
use lightning_background_processor::{process_events_async, GossipSync};
3943
use lightning_block_sync::init;
@@ -172,13 +176,23 @@ pub(crate) type BumpTxEventHandler = BumpTransactionEventHandler<
172176
Arc<FilesystemLogger>,
173177
>;
174178

179+
pub(crate) type OutputSweeper = ldk_sweep::OutputSweeper<
180+
Arc<BitcoindClient>,
181+
Arc<BitcoindClient>,
182+
Arc<BitcoindClient>,
183+
Arc<dyn Filter + Send + Sync>,
184+
Arc<FilesystemStore>,
185+
Arc<FilesystemLogger>,
186+
Arc<KeysManager>,
187+
>;
188+
175189
async fn handle_ldk_events(
176190
channel_manager: Arc<ChannelManager>, bitcoind_client: &BitcoindClient,
177191
network_graph: &NetworkGraph, keys_manager: &KeysManager,
178192
bump_tx_event_handler: &BumpTxEventHandler, peer_manager: Arc<PeerManager>,
179193
inbound_payments: Arc<Mutex<InboundPaymentInfoStorage>>,
180194
outbound_payments: Arc<Mutex<OutboundPaymentInfoStorage>>, fs_store: Arc<FilesystemStore>,
181-
network: Network, event: Event,
195+
output_sweeper: Arc<OutputSweeper>, network: Network, event: Event,
182196
) {
183197
match event {
184198
Event::FundingGenerationReady {
@@ -461,22 +475,8 @@ async fn handle_ldk_events(
461475
forwarding_channel_manager.process_pending_htlc_forwards();
462476
});
463477
},
464-
Event::SpendableOutputs { outputs, channel_id: _ } => {
465-
// SpendableOutputDescriptors, of which outputs is a vec of, are critical to keep track
466-
// of! While a `StaticOutput` descriptor is just an output to a static, well-known key,
467-
// other descriptors are not currently ever regenerated for you by LDK. Once we return
468-
// from this method, the descriptor will be gone, and you may lose track of some funds.
469-
//
470-
// Here we simply persist them to disk, with a background task running which will try
471-
// to spend them regularly (possibly duplicatively/RBF'ing them). These can just be
472-
// treated as normal funds where possible - they are only spendable by us and there is
473-
// no rush to claim them.
474-
for output in outputs {
475-
let key = hex_utils::hex_str(&keys_manager.get_secure_random_bytes());
476-
// Note that if the type here changes our read code needs to change as well.
477-
let output: SpendableOutputDescriptor = output;
478-
fs_store.write(PENDING_SPENDABLE_OUTPUT_DIR, "", &key, &output.encode()).unwrap();
479-
}
478+
Event::SpendableOutputs { outputs, channel_id } => {
479+
output_sweeper.track_spendable_outputs(outputs, channel_id, false, None).unwrap();
480480
},
481481
Event::ChannelPending { channel_id, counterparty_node_id, .. } => {
482482
println!(
@@ -743,14 +743,50 @@ async fn start_ldk() {
743743
}
744744
};
745745

746-
// Step 12: Sync ChannelMonitors and ChannelManager to chain tip
746+
// Step 12: Initialize the OutputSweeper.
747+
let (sweeper_best_block, output_sweeper) = match fs_store.read(
748+
OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE,
749+
OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE,
750+
OUTPUT_SWEEPER_PERSISTENCE_KEY,
751+
) {
752+
Err(e) if e.kind() == io::ErrorKind::NotFound => {
753+
let sweeper = OutputSweeper::new(
754+
channel_manager.current_best_block(),
755+
broadcaster.clone(),
756+
fee_estimator.clone(),
757+
None,
758+
keys_manager.clone(),
759+
bitcoind_client.clone(),
760+
fs_store.clone(),
761+
logger.clone(),
762+
);
763+
(channel_manager.current_best_block(), sweeper)
764+
},
765+
Ok(mut bytes) => {
766+
let read_args = (
767+
broadcaster.clone(),
768+
fee_estimator.clone(),
769+
None,
770+
keys_manager.clone(),
771+
bitcoind_client.clone(),
772+
fs_store.clone(),
773+
logger.clone(),
774+
);
775+
let mut reader = io::Cursor::new(&mut bytes);
776+
<(BestBlock, OutputSweeper)>::read(&mut reader, read_args)
777+
.expect("Failed to deserialize OutputSweeper")
778+
},
779+
Err(e) => panic!("Failed to read OutputSweeper with {}", e),
780+
};
781+
782+
// Step 13: Sync ChannelMonitors, ChannelManager and OutputSweeper to chain tip
747783
let mut chain_listener_channel_monitors = Vec::new();
748784
let mut cache = UnboundedCache::new();
749785
let chain_tip = if restarting_node {
750-
let mut chain_listeners = vec![(
751-
channel_manager_blockhash,
752-
&channel_manager as &(dyn chain::Listen + Send + Sync),
753-
)];
786+
let mut chain_listeners = vec![
787+
(channel_manager_blockhash, &channel_manager as &(dyn chain::Listen + Send + Sync)),
788+
(sweeper_best_block.block_hash, &output_sweeper as &(dyn chain::Listen + Send + Sync)),
789+
];
754790

755791
for (blockhash, channel_monitor) in channelmonitors.drain(..) {
756792
let outpoint = channel_monitor.get_funding_txo().0;
@@ -780,7 +816,7 @@ async fn start_ldk() {
780816
polled_chain_tip
781817
};
782818

783-
// Step 13: Give ChannelMonitors to ChainMonitor
819+
// Step 14: Give ChannelMonitors to ChainMonitor
784820
for item in chain_listener_channel_monitors.drain(..) {
785821
let channel_monitor = item.1 .0;
786822
let funding_outpoint = item.2;
@@ -790,11 +826,11 @@ async fn start_ldk() {
790826
);
791827
}
792828

793-
// Step 14: Optional: Initialize the P2PGossipSync
829+
// Step 15: Optional: Initialize the P2PGossipSync
794830
let gossip_sync =
795831
Arc::new(P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger)));
796832

797-
// Step 15: Initialize the PeerManager
833+
// Step 16: Initialize the PeerManager
798834
let channel_manager: Arc<ChannelManager> = Arc::new(channel_manager);
799835
let onion_messenger: Arc<OnionMessenger> = Arc::new(OnionMessenger::new(
800836
Arc::clone(&keys_manager),
@@ -832,7 +868,7 @@ async fn start_ldk() {
832868
gossip_sync.add_utxo_lookup(Some(utxo_lookup));
833869

834870
// ## Running LDK
835-
// Step 16: Initialize networking
871+
// Step 17: Initialize networking
836872

837873
let peer_manager_connection_handler = peer_manager.clone();
838874
let listening_port = args.ldk_peer_listening_port;
@@ -858,14 +894,17 @@ async fn start_ldk() {
858894
}
859895
});
860896

861-
// Step 17: Connect and Disconnect Blocks
897+
// Step 18: Connect and Disconnect Blocks
898+
let output_sweeper: Arc<OutputSweeper> = Arc::new(output_sweeper);
862899
let channel_manager_listener = channel_manager.clone();
863900
let chain_monitor_listener = chain_monitor.clone();
901+
let output_sweeper_listener = output_sweeper.clone();
864902
let bitcoind_block_source = bitcoind_client.clone();
865903
let network = args.network;
866904
tokio::spawn(async move {
867905
let chain_poller = poll::ChainPoller::new(bitcoind_block_source.as_ref(), network);
868-
let chain_listener = (chain_monitor_listener, channel_manager_listener);
906+
let chain_listener =
907+
(chain_monitor_listener, &(channel_manager_listener, output_sweeper_listener));
869908
let mut spv_client = SpvClient::new(chain_tip, chain_poller, &mut cache, &chain_listener);
870909
loop {
871910
spv_client.poll_best_tip().await.unwrap();
@@ -904,7 +943,7 @@ async fn start_ldk() {
904943
.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.lock().unwrap().encode())
905944
.unwrap();
906945

907-
// Step 18: Handle LDK Events
946+
// Step 19: Handle LDK Events
908947
let channel_manager_event_listener = Arc::clone(&channel_manager);
909948
let bitcoind_client_event_listener = Arc::clone(&bitcoind_client);
910949
let network_graph_event_listener = Arc::clone(&network_graph);
@@ -913,6 +952,7 @@ async fn start_ldk() {
913952
let outbound_payments_event_listener = Arc::clone(&outbound_payments);
914953
let fs_store_event_listener = Arc::clone(&fs_store);
915954
let peer_manager_event_listener = Arc::clone(&peer_manager);
955+
let output_sweeper_event_listener = Arc::clone(&output_sweeper);
916956
let network = args.network;
917957
let event_handler = move |event: Event| {
918958
let channel_manager_event_listener = Arc::clone(&channel_manager_event_listener);
@@ -924,6 +964,7 @@ async fn start_ldk() {
924964
let outbound_payments_event_listener = Arc::clone(&outbound_payments_event_listener);
925965
let fs_store_event_listener = Arc::clone(&fs_store_event_listener);
926966
let peer_manager_event_listener = Arc::clone(&peer_manager_event_listener);
967+
let output_sweeper_event_listener = Arc::clone(&output_sweeper_event_listener);
927968
async move {
928969
handle_ldk_events(
929970
channel_manager_event_listener,
@@ -935,17 +976,18 @@ async fn start_ldk() {
935976
inbound_payments_event_listener,
936977
outbound_payments_event_listener,
937978
fs_store_event_listener,
979+
output_sweeper_event_listener,
938980
network,
939981
event,
940982
)
941983
.await;
942984
}
943985
};
944986

945-
// Step 19: Persist ChannelManager and NetworkGraph
987+
// Step 20: Persist ChannelManager and NetworkGraph
946988
let persister = Arc::new(FilesystemStore::new(ldk_data_dir.clone().into()));
947989

948-
// Step 20: Background Processing
990+
// Step 21: Background Processing
949991
let (bp_exit, bp_exit_check) = tokio::sync::watch::channel(());
950992
let mut background_processor = tokio::spawn(process_events_async(
951993
Arc::clone(&persister),
@@ -1034,6 +1076,7 @@ async fn start_ldk() {
10341076
}
10351077
});
10361078

1079+
// TODO: remove after a few months since the new `OutputSweeper` was added in LDK v0.0.123.
10371080
tokio::spawn(sweep::periodic_sweep(
10381081
ldk_data_dir.clone(),
10391082
Arc::clone(&keys_manager),

0 commit comments

Comments
 (0)