diff --git a/src/builder.rs b/src/builder.rs index 0314810c2..a7a09e02b 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -7,6 +7,7 @@ use crate::io::{KVStore, CHANNEL_MANAGER_PERSISTENCE_KEY, CHANNEL_MANAGER_PERSIS 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, NetAddress, NetworkGraph, OnionMessenger, PeerManager, @@ -716,6 +717,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 { @@ -728,6 +746,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 31a115da5..a38b55ba9 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,6 +1,5 @@ use crate::{ - hex_utils, ChannelId, ChannelManager, Config, Error, KeysManager, NetworkGraph, UserChannelId, - Wallet, + hex_utils, ChannelId, ChannelManager, Config, Error, NetworkGraph, UserChannelId, Wallet, }; use crate::payment_store::{ @@ -8,9 +7,10 @@ use crate::payment_store::{ }; use crate::io::{KVStore, EVENT_QUEUE_PERSISTENCE_KEY, EVENT_QUEUE_PERSISTENCE_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; @@ -19,8 +19,8 @@ use lightning::routing::gossip::NodeId; use lightning::util::errors::APIError; 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; @@ -227,8 +227,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, @@ -241,7 +241,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 { @@ -249,8 +249,8 @@ where wallet, channel_manager, network_graph, - keys_manager, payment_store, + output_sweeper, logger, runtime, config, @@ -552,40 +552,7 @@ where }); } } - LdkEvent::SpendableOutputs { outputs } => { - // 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::Normal); - - // 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); - } - } - } + LdkEvent::SpendableOutputs { outputs } => self.output_sweeper.add_outputs(outputs), LdkEvent::OpenChannelRequest { temporary_channel_id, counterparty_node_id, diff --git a/src/lib.rs b/src/lib.rs index e1ec214f2..d4bfd7825 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -120,7 +120,9 @@ use io::KVStore; 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, ChannelId, PeerDetails, UserChannelId}; use wallet::Wallet; @@ -280,6 +282,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, @@ -403,6 +406,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 = @@ -420,6 +424,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 { @@ -642,8 +647,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), @@ -974,10 +979,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 b031dec69..b28f9741b 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; @@ -107,6 +108,9 @@ impl lightning::onion_message::MessageRouter for FakeMessageRouter { } } +pub(crate) type Sweeper = + OutputSweeper>>, Arc>; + /// The global identifier of a channel. /// /// Note that this will start out to be a temporary ID until channel funding negotiation is