diff --git a/src/builder.rs b/src/builder.rs index 3a6b1e6b4..e26244f87 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::types::{ ChainMonitor, ChannelManager, FakeMessageRouter, GossipSync, KeysManager, NetworkGraph, OnionMessenger, PeerManager, @@ -735,6 +736,23 @@ 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(&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 { @@ -747,6 +765,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 ce75d673e..cdcacb937 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,6 +1,4 @@ -use crate::{ - hex_utils, ChannelManager, Config, Error, KeysManager, NetworkGraph, UserChannelId, Wallet, -}; +use crate::{hex_utils, ChannelManager, Config, Error, NetworkGraph, UserChannelId, Wallet}; use crate::payment_store::{ PaymentDetails, PaymentDetailsUpdate, PaymentDirection, PaymentStatus, PaymentStore, @@ -10,9 +8,10 @@ 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 crate::types::Sweeper; -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; @@ -22,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; @@ -246,8 +245,8 @@ where event_queue: Arc>, channel_manager: Arc>, network_graph: Arc, - keys_manager: Arc, payment_store: Arc>, + output_sweeper: Arc>, runtime: Arc>>, logger: L, config: Arc, @@ -260,7 +259,7 @@ where pub fn new( wallet: Arc>, event_queue: Arc>, channel_manager: Arc>, network_graph: Arc, - keys_manager: Arc, payment_store: Arc>, + payment_store: Arc>, output_sweeper: Arc>, runtime: Arc>>, logger: L, config: Arc, ) -> Self { Self { @@ -268,8 +267,8 @@ where wallet, channel_manager, network_graph, - keys_manager, payment_store, + output_sweeper, logger, runtime, config, @@ -574,39 +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(Some(spending_tx)) => self.wallet.broadcast_transactions(&[&spending_tx]), - Ok(None) => { - log_debug!(self.logger, "Omitted spending static outputs: {:?}", outputs); - } - 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 e75724568..34be513b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,7 +119,9 @@ use gossip::GossipSource; use payment_store::PaymentStore; pub use payment_store::{PaymentDetails, PaymentDirection, PaymentStatus}; use peer_store::{PeerInfo, PeerStore}; -use types::{ChainMonitor, ChannelManager, KeysManager, NetworkGraph, PeerManager, Router, Scorer}; +use types::{ + ChainMonitor, ChannelManager, KeysManager, NetworkGraph, PeerManager, Router, Scorer, Sweeper, +}; pub use types::{ChannelDetails, PeerDetails, UserChannelId}; use wallet::Wallet; @@ -290,6 +292,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, @@ -413,6 +416,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 = @@ -430,6 +434,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 { @@ -652,8 +657,8 @@ impl Node { Arc::clone(&self.event_queue), Arc::clone(&self.channel_manager), 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), @@ -989,10 +994,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 d4b8f6054..ccf0c410a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,4 +1,5 @@ use crate::logger::FilesystemLogger; +use crate::sweep::OutputSweeper; use crate::wallet::{Wallet, WalletKeysManager}; use lightning::chain::chainmonitor; @@ -104,6 +105,9 @@ impl lightning::onion_message::MessageRouter for FakeMessageRouter { } } +pub(crate) type Sweeper = + OutputSweeper>>, Arc>; + /// A local, potentially user-provided, identifier of a channel. /// /// By default, this will be randomly generated for the user to ensure local uniqueness.