Skip to content

Commit c394d2f

Browse files
Use new OutputSweeper to sweep spendable outputs.
1 parent b1bc2aa commit c394d2f

File tree

2 files changed

+89
-34
lines changed

2 files changed

+89
-34
lines changed

src/bitcoind_client.rs

+9
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

+80-34
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,26 @@ 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+
189+
// Needed due to rust-lang/rust#63033.
190+
struct OutputSweeperWrapper(Arc<OutputSweeper>);
191+
175192
async fn handle_ldk_events(
176193
channel_manager: Arc<ChannelManager>, bitcoind_client: &BitcoindClient,
177194
network_graph: &NetworkGraph, keys_manager: &KeysManager,
178195
bump_tx_event_handler: &BumpTxEventHandler, peer_manager: Arc<PeerManager>,
179196
inbound_payments: Arc<Mutex<InboundPaymentInfoStorage>>,
180197
outbound_payments: Arc<Mutex<OutboundPaymentInfoStorage>>, fs_store: Arc<FilesystemStore>,
181-
network: Network, event: Event,
198+
output_sweeper: OutputSweeperWrapper, network: Network, event: Event,
182199
) {
183200
match event {
184201
Event::FundingGenerationReady {
@@ -461,22 +478,8 @@ async fn handle_ldk_events(
461478
forwarding_channel_manager.process_pending_htlc_forwards();
462479
});
463480
},
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-
}
481+
Event::SpendableOutputs { outputs, channel_id } => {
482+
output_sweeper.0.track_spendable_outputs(outputs, channel_id, false, None).unwrap();
480483
},
481484
Event::ChannelPending { channel_id, counterparty_node_id, .. } => {
482485
println!(
@@ -743,14 +746,50 @@ async fn start_ldk() {
743746
}
744747
};
745748

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

755794
for (blockhash, channel_monitor) in channelmonitors.drain(..) {
756795
let outpoint = channel_monitor.get_funding_txo().0;
@@ -780,7 +819,7 @@ async fn start_ldk() {
780819
polled_chain_tip
781820
};
782821

783-
// Step 13: Give ChannelMonitors to ChainMonitor
822+
// Step 14: Give ChannelMonitors to ChainMonitor
784823
for item in chain_listener_channel_monitors.drain(..) {
785824
let channel_monitor = item.1 .0;
786825
let funding_outpoint = item.2;
@@ -790,11 +829,11 @@ async fn start_ldk() {
790829
);
791830
}
792831

793-
// Step 14: Optional: Initialize the P2PGossipSync
832+
// Step 15: Optional: Initialize the P2PGossipSync
794833
let gossip_sync =
795834
Arc::new(P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger)));
796835

797-
// Step 15: Initialize the PeerManager
836+
// Step 16: Initialize the PeerManager
798837
let channel_manager: Arc<ChannelManager> = Arc::new(channel_manager);
799838
let onion_messenger: Arc<OnionMessenger> = Arc::new(OnionMessenger::new(
800839
Arc::clone(&keys_manager),
@@ -832,7 +871,7 @@ async fn start_ldk() {
832871
gossip_sync.add_utxo_lookup(Some(utxo_lookup));
833872

834873
// ## Running LDK
835-
// Step 16: Initialize networking
874+
// Step 17: Initialize networking
836875

837876
let peer_manager_connection_handler = peer_manager.clone();
838877
let listening_port = args.ldk_peer_listening_port;
@@ -858,14 +897,17 @@ async fn start_ldk() {
858897
}
859898
});
860899

861-
// Step 17: Connect and Disconnect Blocks
900+
// Step 18: Connect and Disconnect Blocks
901+
let output_sweeper: Arc<OutputSweeper> = Arc::new(output_sweeper);
862902
let channel_manager_listener = channel_manager.clone();
863903
let chain_monitor_listener = chain_monitor.clone();
904+
let output_sweeper_listener = output_sweeper.clone();
864905
let bitcoind_block_source = bitcoind_client.clone();
865906
let network = args.network;
866907
tokio::spawn(async move {
867908
let chain_poller = poll::ChainPoller::new(bitcoind_block_source.as_ref(), network);
868-
let chain_listener = (chain_monitor_listener, channel_manager_listener);
909+
let chain_listener =
910+
(chain_monitor_listener, &(channel_manager_listener, output_sweeper_listener));
869911
let mut spv_client = SpvClient::new(chain_tip, chain_poller, &mut cache, &chain_listener);
870912
loop {
871913
spv_client.poll_best_tip().await.unwrap();
@@ -904,7 +946,7 @@ async fn start_ldk() {
904946
.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.lock().unwrap().encode())
905947
.unwrap();
906948

907-
// Step 18: Handle LDK Events
949+
// Step 19: Handle LDK Events
908950
let channel_manager_event_listener = Arc::clone(&channel_manager);
909951
let bitcoind_client_event_listener = Arc::clone(&bitcoind_client);
910952
let network_graph_event_listener = Arc::clone(&network_graph);
@@ -913,6 +955,7 @@ async fn start_ldk() {
913955
let outbound_payments_event_listener = Arc::clone(&outbound_payments);
914956
let fs_store_event_listener = Arc::clone(&fs_store);
915957
let peer_manager_event_listener = Arc::clone(&peer_manager);
958+
let output_sweeper_event_listener = Arc::clone(&output_sweeper);
916959
let network = args.network;
917960
let event_handler = move |event: Event| {
918961
let channel_manager_event_listener = Arc::clone(&channel_manager_event_listener);
@@ -924,6 +967,7 @@ async fn start_ldk() {
924967
let outbound_payments_event_listener = Arc::clone(&outbound_payments_event_listener);
925968
let fs_store_event_listener = Arc::clone(&fs_store_event_listener);
926969
let peer_manager_event_listener = Arc::clone(&peer_manager_event_listener);
970+
let output_sweeper_event_listener = Arc::clone(&output_sweeper_event_listener);
927971
async move {
928972
handle_ldk_events(
929973
channel_manager_event_listener,
@@ -935,17 +979,18 @@ async fn start_ldk() {
935979
inbound_payments_event_listener,
936980
outbound_payments_event_listener,
937981
fs_store_event_listener,
982+
OutputSweeperWrapper(output_sweeper_event_listener),
938983
network,
939984
event,
940985
)
941986
.await;
942987
}
943988
};
944989

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

948-
// Step 20: Background Processing
993+
// Step 21: Background Processing
949994
let (bp_exit, bp_exit_check) = tokio::sync::watch::channel(());
950995
let mut background_processor = tokio::spawn(process_events_async(
951996
Arc::clone(&persister),
@@ -1033,6 +1078,7 @@ async fn start_ldk() {
10331078
}
10341079
});
10351080

1081+
// TODO: remove this, since the new `OutputSweeper` was added in LDK v0.0.123.
10361082
tokio::spawn(sweep::periodic_sweep(
10371083
ldk_data_dir.clone(),
10381084
Arc::clone(&keys_manager),

0 commit comments

Comments
 (0)