diff --git a/src/builder.rs b/src/builder.rs index 63dfa6f32..69b5eb2a8 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -5,6 +5,7 @@ use crate::io::sqlite_store::SqliteStore; use crate::logger::{log_error, FilesystemLogger, Logger}; use crate::payment_store::PaymentStore; use crate::peer_store::PeerStore; +use crate::sweep::OutputSweeper; use crate::tx_broadcaster::TransactionBroadcaster; use crate::types::{ ChainMonitor, ChannelManager, FakeMessageRouter, GossipSync, KeysManager, NetworkGraph, @@ -771,6 +772,25 @@ fn build_with_store_internal( } }; + let best_block = channel_manager.current_best_block(); + let output_sweeper = + match io::utils::read_spendable_outputs(Arc::clone(&kv_store), Arc::clone(&logger)) { + Ok(outputs) => Arc::new(OutputSweeper::new( + outputs, + Arc::clone(&wallet), + Arc::clone(&tx_broadcaster), + Arc::clone(&wallet), + Arc::clone(&keys_manager), + Arc::clone(&kv_store), + best_block, + Some(Arc::clone(&tx_sync)), + Arc::clone(&logger), + )), + Err(_) => { + return Err(BuildError::ReadFailed); + } + }; + let (stop_sender, stop_receiver) = tokio::sync::watch::channel(()); Ok(Node { @@ -784,6 +804,7 @@ fn build_with_store_internal( event_queue, channel_manager, chain_monitor, + output_sweeper, peer_manager, keys_manager, network_graph, diff --git a/src/event.rs b/src/event.rs index 7b76d7868..9fc842760 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,5 +1,5 @@ -use crate::types::{Broadcaster, Wallet}; -use crate::{hex_utils, ChannelManager, Config, Error, KeysManager, NetworkGraph, UserChannelId}; +use crate::types::{Sweeper, Wallet}; +use crate::{hex_utils, ChannelManager, Config, Error, NetworkGraph, UserChannelId}; use crate::payment_store::{ PaymentDetails, PaymentDetailsUpdate, PaymentDirection, PaymentStatus, PaymentStore, @@ -9,9 +9,9 @@ use crate::io::{ EVENT_QUEUE_PERSISTENCE_KEY, EVENT_QUEUE_PERSISTENCE_PRIMARY_NAMESPACE, EVENT_QUEUE_PERSISTENCE_SECONDARY_NAMESPACE, }; -use crate::logger::{log_debug, log_error, log_info, Logger}; +use crate::logger::{log_error, log_info, Logger}; -use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; +use lightning::chain::chaininterface::ConfirmationTarget; use lightning::events::Event as LdkEvent; use lightning::events::PaymentPurpose; use lightning::impl_writeable_tlv_based_enum; @@ -21,8 +21,8 @@ use lightning::util::errors::APIError; use lightning::util::persist::KVStore; use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer}; -use bitcoin::secp256k1::{PublicKey, Secp256k1}; -use bitcoin::{LockTime, OutPoint, PackedLockTime}; +use bitcoin::secp256k1::PublicKey; +use bitcoin::{LockTime, OutPoint}; use rand::{thread_rng, Rng}; use std::collections::VecDeque; use std::ops::Deref; @@ -244,10 +244,9 @@ where event_queue: Arc>, wallet: Arc, channel_manager: Arc>, - tx_broadcaster: Arc, network_graph: Arc, - keys_manager: Arc, payment_store: Arc>, + output_sweeper: Arc>, runtime: Arc>>, logger: L, config: Arc, @@ -259,19 +258,17 @@ where { pub fn new( event_queue: Arc>, wallet: Arc, - channel_manager: Arc>, tx_broadcaster: Arc, - network_graph: Arc, keys_manager: Arc, - payment_store: Arc>, + channel_manager: Arc>, network_graph: Arc, + payment_store: Arc>, output_sweeper: Arc>, runtime: Arc>>, logger: L, config: Arc, ) -> Self { Self { event_queue, wallet, channel_manager, - tx_broadcaster, network_graph, - keys_manager, payment_store, + output_sweeper, logger, runtime, config, @@ -576,36 +573,7 @@ where } } LdkEvent::SpendableOutputs { outputs, channel_id: _ } => { - // TODO: We should eventually remember the outputs and supply them to the wallet's coin selection, once BDK allows us to do so. - let destination_address = self.wallet.get_new_address().unwrap_or_else(|e| { - log_error!(self.logger, "Failed to get destination address: {}", e); - panic!("Failed to get destination address"); - }); - - let output_descriptors = &outputs.iter().collect::>(); - let tx_feerate = self - .wallet - .get_est_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee); - - // We set nLockTime to the current height to discourage fee sniping. - let cur_height = self.channel_manager.current_best_block().height(); - let locktime: PackedLockTime = - LockTime::from_height(cur_height).map_or(PackedLockTime::ZERO, |l| l.into()); - let res = self.keys_manager.spend_spendable_outputs( - output_descriptors, - Vec::new(), - destination_address.script_pubkey(), - tx_feerate, - Some(locktime), - &Secp256k1::new(), - ); - - match res { - Ok(spending_tx) => self.tx_broadcaster.broadcast_transactions(&[&spending_tx]), - Err(err) => { - log_error!(self.logger, "Error spending outputs: {:?}", err); - } - } + self.output_sweeper.add_outputs(outputs) } LdkEvent::OpenChannelRequest { temporary_channel_id, diff --git a/src/lib.rs b/src/lib.rs index 4c59e537a..f41d78fcd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,7 +122,8 @@ pub use payment_store::{PaymentDetails, PaymentDirection, PaymentStatus}; use peer_store::{PeerInfo, PeerStore}; use tx_broadcaster::TransactionBroadcaster; use types::{ - ChainMonitor, ChannelManager, KeysManager, NetworkGraph, PeerManager, Router, Scorer, Wallet, + ChainMonitor, ChannelManager, KeysManager, NetworkGraph, PeerManager, Router, Scorer, Sweeper, + Wallet, }; pub use types::{ChannelDetails, PeerDetails, UserChannelId}; @@ -294,6 +295,7 @@ pub struct Node { event_queue: Arc>>, channel_manager: Arc>, chain_monitor: Arc>, + output_sweeper: Arc>, peer_manager: Arc>, keys_manager: Arc, network_graph: Arc, @@ -417,6 +419,7 @@ impl Node { let tx_sync = Arc::clone(&self.tx_sync); let sync_cman = Arc::clone(&self.channel_manager); let sync_cmon = Arc::clone(&self.chain_monitor); + let sync_sweeper = Arc::clone(&self.output_sweeper); let sync_logger = Arc::clone(&self.logger); let mut stop_sync = self.stop_receiver.clone(); let wallet_sync_interval_secs = @@ -434,6 +437,7 @@ impl Node { let confirmables = vec![ &*sync_cman as &(dyn Confirm + Sync + Send), &*sync_cmon as &(dyn Confirm + Sync + Send), + &*sync_sweeper as &(dyn Confirm + Sync + Send), ]; let now = Instant::now(); match tx_sync.sync(confirmables).await { @@ -673,10 +677,9 @@ impl Node { Arc::clone(&self.event_queue), Arc::clone(&self.wallet), Arc::clone(&self.channel_manager), - Arc::clone(&self.tx_broadcaster), Arc::clone(&self.network_graph), - Arc::clone(&self.keys_manager), Arc::clone(&self.payment_store), + Arc::clone(&self.output_sweeper), Arc::clone(&self.runtime), Arc::clone(&self.logger), Arc::clone(&self.config), @@ -1012,10 +1015,12 @@ impl Node { let tx_sync = Arc::clone(&self.tx_sync); let sync_cman = Arc::clone(&self.channel_manager); let sync_cmon = Arc::clone(&self.chain_monitor); + let sync_sweeper = Arc::clone(&self.output_sweeper); let sync_logger = Arc::clone(&self.logger); let confirmables = vec![ &*sync_cman as &(dyn Confirm + Sync + Send), &*sync_cmon as &(dyn Confirm + Sync + Send), + &*sync_sweeper as &(dyn Confirm + Sync + Send), ]; tokio::task::block_in_place(move || { diff --git a/src/types.rs b/src/types.rs index fa2ef123e..35c591fe0 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,4 +1,5 @@ use crate::logger::FilesystemLogger; +use crate::sweep::OutputSweeper; use lightning::chain::chainmonitor; use lightning::ln::channelmanager::ChannelDetails as LdkChannelDetails; @@ -111,6 +112,14 @@ impl lightning::onion_message::MessageRouter for FakeMessageRouter { } } +pub(crate) type Sweeper = OutputSweeper< + K, + Arc, + Arc, + Arc>>, + Arc, +>; + /// A local, potentially user-provided, identifier of a channel. /// /// By default, this will be randomly generated for the user to ensure local uniqueness.