diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index dd13a35b46f..a8db7945f33 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -13,6 +13,7 @@ use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use lightning::chain::chainmonitor::ChainMonitor; use lightning::chain::channelmonitor; use lightning::chain::keysinterface::{Sign, KeysInterface}; +use lightning::chain::utxointerface::UtxoPool; use lightning::ln::channelmanager::ChannelManager; use lightning::ln::msgs::{ChannelMessageHandler, RoutingMessageHandler}; use lightning::ln::peer_handler::{PeerManager, SocketDescriptor}; @@ -111,12 +112,13 @@ impl BackgroundProcessor { F: 'static + Deref + Send + Sync, L: 'static + Deref + Send + Sync, P: 'static + Deref + Send + Sync, + U: 'static + Deref + Send + Sync, Descriptor: 'static + SocketDescriptor + Send + Sync, CMH: 'static + Deref + Send + Sync, RMH: 'static + Deref + Send + Sync, EH: 'static + EventHandler + Send + Sync, CMP: 'static + Send + ChannelManagerPersister, - M: 'static + Deref> + Send + Sync, + M: 'static + Deref> + Send + Sync, CM: 'static + Deref> + Send + Sync, PM: 'static + Deref> + Send + Sync, > @@ -128,6 +130,7 @@ impl BackgroundProcessor { K::Target: 'static + KeysInterface, F::Target: 'static + FeeEstimator, L::Target: 'static + Logger, + U::Target: 'static + UtxoPool, P::Target: 'static + channelmonitor::Persist, CMH::Target: 'static + ChannelMessageHandler, RMH::Target: 'static + RoutingMessageHandler, @@ -207,7 +210,7 @@ mod tests { fn disconnect_socket(&mut self) {} } - type ChainMonitor = chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc>; + type ChainMonitor = chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc, Arc>; struct Node { node: Arc>, @@ -241,13 +244,14 @@ mod tests { let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))}); let fee_estimator = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 }); let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet)); + let utxo_pool = Arc::new(test_utils::TestPool::new()); let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i))); let persister = Arc::new(FilesystemPersister::new(format!("{}_persister_{}", persist_dir, i))); let seed = [i as u8; 32]; let network = Network::Testnet; let now = Duration::from_secs(genesis_block(network).header.time as u64); let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos())); - let chain_monitor = Arc::new(chainmonitor::ChainMonitor::new(Some(chain_source.clone()), tx_broadcaster.clone(), logger.clone(), fee_estimator.clone(), persister.clone())); + let chain_monitor = Arc::new(chainmonitor::ChainMonitor::new(Some(chain_source.clone()), tx_broadcaster.clone(), logger.clone(), fee_estimator.clone(), persister.clone(), utxo_pool.clone())); let best_block = BestBlock::from_genesis(network); let params = ChainParameters { network, best_block }; let manager = Arc::new(ChannelManager::new(fee_estimator.clone(), chain_monitor.clone(), tx_broadcaster.clone(), logger.clone(), keys_manager.clone(), UserConfig::default(), params)); diff --git a/lightning-block-sync/src/init.rs b/lightning-block-sync/src/init.rs index d51cd3ba606..f0ebd174522 100644 --- a/lightning-block-sync/src/init.rs +++ b/lightning-block-sync/src/init.rs @@ -47,6 +47,7 @@ BlockSourceResult { /// use lightning::chain::chaininterface::FeeEstimator; /// use lightning::chain::keysinterface; /// use lightning::chain::keysinterface::KeysInterface; +/// use lightning::chain::utxointerface::UtxoPool; /// use lightning::ln::channelmanager::ChannelManager; /// use lightning::ln::channelmanager::ChannelManagerReadArgs; /// use lightning::util::config::UserConfig; @@ -64,11 +65,12 @@ BlockSourceResult { /// T: BroadcasterInterface, /// F: FeeEstimator, /// L: Logger, +/// U: UtxoPool, /// C: chain::Filter, /// P: channelmonitor::Persist, /// >( /// block_source: &mut B, -/// chain_monitor: &ChainMonitor, +/// chain_monitor: &ChainMonitor, /// config: UserConfig, /// keys_manager: &K, /// tx_broadcaster: &T, diff --git a/lightning-net-tokio/src/lib.rs b/lightning-net-tokio/src/lib.rs index d102778a460..3d65e24e828 100644 --- a/lightning-net-tokio/src/lib.rs +++ b/lightning-net-tokio/src/lib.rs @@ -35,7 +35,8 @@ //! type ChainAccess = dyn lightning::chain::Access + Send + Sync; //! type ChainFilter = dyn lightning::chain::Filter + Send + Sync; //! type DataPersister = dyn lightning::chain::channelmonitor::Persist + Send + Sync; -//! type ChainMonitor = lightning::chain::chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc>; +//! type UtxoPool = dyn lightning::chain::utxointerface::UtxoPool + Send + Sync; +//! type ChainMonitor = lightning::chain::chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc, Arc>; //! type ChannelManager = Arc>; //! type PeerManager = Arc>; //! diff --git a/lightning-persister/src/lib.rs b/lightning-persister/src/lib.rs index d68a06d71b4..997c443ffd6 100644 --- a/lightning-persister/src/lib.rs +++ b/lightning-persister/src/lib.rs @@ -216,8 +216,8 @@ mod tests { let persister_1 = FilesystemPersister::new("test_filesystem_persister_1".to_string()); let chanmon_cfgs = create_chanmon_cfgs(2); let mut node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - let chain_mon_0 = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[0].chain_source), &chanmon_cfgs[0].tx_broadcaster, &chanmon_cfgs[0].logger, &chanmon_cfgs[0].fee_estimator, &persister_0, &node_cfgs[0].keys_manager); - let chain_mon_1 = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[1].chain_source), &chanmon_cfgs[1].tx_broadcaster, &chanmon_cfgs[1].logger, &chanmon_cfgs[1].fee_estimator, &persister_1, &node_cfgs[1].keys_manager); + let chain_mon_0 = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[0].chain_source), &chanmon_cfgs[0].tx_broadcaster, &chanmon_cfgs[0].logger, &chanmon_cfgs[0].fee_estimator, &persister_0, &node_cfgs[0].keys_manager, &chanmon_cfgs[0].utxo_pool); + let chain_mon_1 = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[1].chain_source), &chanmon_cfgs[1].tx_broadcaster, &chanmon_cfgs[1].logger, &chanmon_cfgs[1].fee_estimator, &persister_1, &node_cfgs[1].keys_manager, &chanmon_cfgs[0].utxo_pool); node_cfgs[0].chain_monitor = chain_mon_0; node_cfgs[1].chain_monitor = chain_mon_1; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index a3365f2b64f..985da27a12b 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -33,6 +33,7 @@ use chain::channelmonitor; use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateErr, MonitorEvent, Persist, TransactionOutputs}; use chain::transaction::{OutPoint, TransactionData}; use chain::keysinterface::Sign; +use chain::utxointerface::UtxoPool; use util::logger::Logger; use util::events; use util::events::EventHandler; @@ -51,12 +52,13 @@ use core::ops::Deref; /// /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager /// [module-level documentation]: crate::chain::chainmonitor -pub struct ChainMonitor +pub struct ChainMonitor where C::Target: chain::Filter, T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, P::Target: channelmonitor::Persist, + U::Target: UtxoPool, { /// The monitors pub monitors: RwLock>>, @@ -65,14 +67,16 @@ pub struct ChainMonitor ChainMonitor +impl ChainMonitor where C::Target: chain::Filter, T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, P::Target: channelmonitor::Persist, + U::Target: UtxoPool { /// Dispatches to per-channel monitors, which are responsible for updating their on-chain view /// of a channel and reacting accordingly based on transactions in the given chain data. See @@ -130,7 +134,7 @@ where C::Target: chain::Filter, /// pre-filter blocks or only fetch blocks matching a compact filter. Otherwise, clients may /// always need to fetch full blocks absent another means for determining which blocks contain /// transactions relevant to the watched channels. - pub fn new(chain_source: Option, broadcaster: T, logger: L, feeest: F, persister: P) -> Self { + pub fn new(chain_source: Option, broadcaster: T, logger: L, feeest: F, persister: P, utxo_pool: U) -> Self { Self { monitors: RwLock::new(HashMap::new()), chain_source, @@ -138,6 +142,7 @@ where C::Target: chain::Filter, logger, fee_estimator: feeest, persister, + utxo_pool } } @@ -151,21 +156,22 @@ where C::Target: chain::Filter, } } -impl -chain::Listen for ChainMonitor +impl +chain::Listen for ChainMonitor where C::Target: chain::Filter, T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, P::Target: channelmonitor::Persist, + U::Target: UtxoPool { fn block_connected(&self, block: &Block, height: u32) { let header = &block.header; let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); self.process_chain_data(header, &txdata, |monitor, txdata| { monitor.block_connected( - header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger) + header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger, &*self.utxo_pool) }); } @@ -173,31 +179,32 @@ where let monitors = self.monitors.read().unwrap(); for monitor in monitors.values() { monitor.block_disconnected( - header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger); + header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger, &*self.utxo_pool); } } } -impl -chain::Confirm for ChainMonitor +impl +chain::Confirm for ChainMonitor where C::Target: chain::Filter, T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, P::Target: channelmonitor::Persist, + U::Target: UtxoPool, { fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { self.process_chain_data(header, txdata, |monitor, txdata| { monitor.transactions_confirmed( - header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger) + header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger, &*self.utxo_pool) }); } fn transaction_unconfirmed(&self, txid: &Txid) { let monitors = self.monitors.read().unwrap(); for monitor in monitors.values() { - monitor.transaction_unconfirmed(txid, &*self.broadcaster, &*self.fee_estimator, &*self.logger); + monitor.transaction_unconfirmed(txid, &*self.broadcaster, &*self.fee_estimator, &*self.logger, &*self.utxo_pool); } } @@ -207,7 +214,7 @@ where // it's still possible if a chain::Filter implementation returns a transaction. debug_assert!(txdata.is_empty()); monitor.best_block_updated( - header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger) + header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger, &*self.utxo_pool) }); } @@ -224,13 +231,14 @@ where } } -impl -chain::Watch for ChainMonitor +impl +chain::Watch for ChainMonitor where C::Target: chain::Filter, T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, P::Target: channelmonitor::Persist, + U::Target: UtxoPool, { /// Adds the monitor that watches the channel referred to by the given outpoint. /// @@ -281,7 +289,7 @@ where C::Target: chain::Filter, }, Some(monitor) => { log_trace!(self.logger, "Updating Channel Monitor for channel {}", log_funding_info!(monitor)); - let update_res = monitor.update_monitor(&update, &self.broadcaster, &self.fee_estimator, &self.logger); + let update_res = monitor.update_monitor(&update, &self.broadcaster, &self.fee_estimator, &self.logger, &self.utxo_pool); if let Err(e) = &update_res { log_error!(self.logger, "Failed to update channel monitor: {:?}", e); } @@ -309,12 +317,13 @@ where C::Target: chain::Filter, } } -impl events::EventsProvider for ChainMonitor +impl events::EventsProvider for ChainMonitor where C::Target: chain::Filter, T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, P::Target: channelmonitor::Persist, + U::Target: UtxoPool { /// Processes [`SpendableOutputs`] events produced from each [`ChannelMonitor`] upon maturity. /// @@ -366,10 +375,14 @@ mod tests { }; // Set expectations on nodes[1]'s chain source to return dependent transactions. - let htlc_output = TxOutReference(commitment_tx.clone(), 0); - let to_local_output = TxOutReference(commitment_tx.clone(), 1); + let anchor_a_output = TxOutReference(commitment_tx.clone(), 0); + let anchor_b_output = TxOutReference(commitment_tx.clone(), 1); + let htlc_output = TxOutReference(commitment_tx.clone(), 2); + let to_local_output = TxOutReference(commitment_tx.clone(), 3); let htlc_timeout_output = TxOutReference(htlc_tx.clone(), 0); nodes[1].chain_source + .expect(OnRegisterOutput { with: anchor_a_output, returns: None }) + .expect(OnRegisterOutput { with: anchor_b_output, returns: None }) .expect(OnRegisterOutput { with: htlc_output, returns: Some((1, htlc_tx)) }) .expect(OnRegisterOutput { with: to_local_output, returns: None }) .expect(OnRegisterOutput { with: htlc_timeout_output, returns: None }); diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index a0f5eb71d7b..f028f84096a 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -45,6 +45,7 @@ use chain::transaction::{OutPoint, TransactionData}; use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface}; use chain::onchaintx::OnchainTxHandler; use chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput}; +use chain::utxointerface::UtxoPool; use chain::Filter; use util::logger::Logger; use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48, OptionDeserWrapper}; @@ -932,20 +933,22 @@ impl ChannelMonitor { } #[cfg(test)] - pub(crate) fn provide_payment_preimage( + pub(crate) fn provide_payment_preimage( &self, payment_hash: &PaymentHash, payment_preimage: &PaymentPreimage, broadcaster: &B, fee_estimator: &F, logger: &L, + utxo_pool: &U, ) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { self.inner.lock().unwrap().provide_payment_preimage( - payment_hash, payment_preimage, broadcaster, fee_estimator, logger) + payment_hash, payment_preimage, broadcaster, fee_estimator, logger, utxo_pool) } pub(crate) fn broadcast_latest_holder_commitment_txn( @@ -963,19 +966,21 @@ impl ChannelMonitor { /// itself. /// /// panics if the given update is not the next update by update_id. - pub fn update_monitor( + pub fn update_monitor( &self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &L, + utxo_pool: &U, ) -> Result<(), MonitorUpdateError> where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool { - self.inner.lock().unwrap().update_monitor(updates, broadcaster, fee_estimator, logger) + self.inner.lock().unwrap().update_monitor(updates, broadcaster, fee_estimator, logger, utxo_pool) } /// Gets the update_id from the latest ChannelMonitorUpdate which was applied to this @@ -1076,7 +1081,7 @@ impl ChannelMonitor { /// [`get_outputs_to_watch`]. /// /// [`get_outputs_to_watch`]: #method.get_outputs_to_watch - pub fn block_connected( + pub fn block_connected( &self, header: &BlockHeader, txdata: &TransactionData, @@ -1084,32 +1089,36 @@ impl ChannelMonitor { broadcaster: B, fee_estimator: F, logger: L, + utxo_pool: U, ) -> Vec where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { self.inner.lock().unwrap().block_connected( - header, txdata, height, broadcaster, fee_estimator, logger) + header, txdata, height, broadcaster, fee_estimator, logger, utxo_pool) } /// Determines if the disconnected block contained any transactions of interest and updates /// appropriately. - pub fn block_disconnected( + pub fn block_disconnected( &self, header: &BlockHeader, height: u32, broadcaster: B, fee_estimator: F, logger: L, + utxo_pool: U, ) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { self.inner.lock().unwrap().block_disconnected( - header, height, broadcaster, fee_estimator, logger) + header, height, broadcaster, fee_estimator, logger, utxo_pool) } /// Processes transactions confirmed in a block with the given header and height, returning new @@ -1119,7 +1128,7 @@ impl ChannelMonitor { /// blocks. See [`chain::Confirm`] for calling expectations. /// /// [`block_connected`]: Self::block_connected - pub fn transactions_confirmed( + pub fn transactions_confirmed( &self, header: &BlockHeader, txdata: &TransactionData, @@ -1127,14 +1136,16 @@ impl ChannelMonitor { broadcaster: B, fee_estimator: F, logger: L, + utxo_pool: U, ) -> Vec where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { self.inner.lock().unwrap().transactions_confirmed( - header, txdata, height, broadcaster, fee_estimator, logger) + header, txdata, height, broadcaster, fee_estimator, logger, utxo_pool) } /// Processes a transaction that was reorganized out of the chain. @@ -1143,19 +1154,21 @@ impl ChannelMonitor { /// than blocks. See [`chain::Confirm`] for calling expectations. /// /// [`block_disconnected`]: Self::block_disconnected - pub fn transaction_unconfirmed( + pub fn transaction_unconfirmed( &self, txid: &Txid, broadcaster: B, fee_estimator: F, logger: L, + utxo_pool: U, ) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { self.inner.lock().unwrap().transaction_unconfirmed( - txid, broadcaster, fee_estimator, logger); + txid, broadcaster, fee_estimator, logger, utxo_pool); } /// Updates the monitor with the current best chain tip, returning new outputs to watch. See @@ -1165,21 +1178,23 @@ impl ChannelMonitor { /// blocks. See [`chain::Confirm`] for calling expectations. /// /// [`block_connected`]: Self::block_connected - pub fn best_block_updated( + pub fn best_block_updated( &self, header: &BlockHeader, height: u32, broadcaster: B, fee_estimator: F, logger: L, + utxo_pool: U, ) -> Vec where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { self.inner.lock().unwrap().best_block_updated( - header, height, broadcaster, fee_estimator, logger) + header, height, broadcaster, fee_estimator, logger, utxo_pool) } /// Returns the set of txids that should be monitored for re-organization out of the chain. @@ -1324,10 +1339,11 @@ impl ChannelMonitorImpl { /// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all /// commitment_tx_infos which contain the payment hash have been revoked. - fn provide_payment_preimage(&mut self, payment_hash: &PaymentHash, payment_preimage: &PaymentPreimage, broadcaster: &B, fee_estimator: &F, logger: &L) + fn provide_payment_preimage(&mut self, payment_hash: &PaymentHash, payment_preimage: &PaymentPreimage, broadcaster: &B, fee_estimator: &F, logger: &L, utxo_pool: &U) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone()); @@ -1336,7 +1352,7 @@ impl ChannelMonitorImpl { macro_rules! claim_htlcs { ($commitment_number: expr, $txid: expr) => { let htlc_claim_reqs = self.get_counterparty_htlc_output_claim_reqs($commitment_number, $txid, None); - self.onchain_tx_handler.update_claims_view(&Vec::new(), htlc_claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger); + self.onchain_tx_handler.update_claims_view(&Vec::new(), htlc_claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger, utxo_pool); } } if let Some(txid) = self.current_counterparty_commitment_txid { @@ -1359,10 +1375,10 @@ impl ChannelMonitorImpl { // holder commitment transactions. if self.broadcasted_holder_revokable_script.is_some() { let (claim_reqs, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, 0); - self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger); + self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger, utxo_pool); if let Some(ref tx) = self.prev_holder_signed_commitment_tx { let (claim_reqs, _) = self.get_broadcasted_holder_claims(&tx, 0); - self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger); + self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger, utxo_pool); } } } @@ -1378,10 +1394,11 @@ impl ChannelMonitorImpl { self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0)); } - pub fn update_monitor(&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &L) -> Result<(), MonitorUpdateError> + pub fn update_monitor(&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &L, utxo_pool: &U) -> Result<(), MonitorUpdateError> where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { // ChannelMonitor updates may be applied after force close if we receive a // preimage for a broadcasted commitment transaction HTLC output that we'd @@ -1409,7 +1426,7 @@ impl ChannelMonitorImpl { }, ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage } => { log_trace!(logger, "Updating ChannelMonitor with payment preimage"); - self.provide_payment_preimage(&PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()), &payment_preimage, broadcaster, fee_estimator, logger) + self.provide_payment_preimage(&PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()), &payment_preimage, broadcaster, fee_estimator, logger, utxo_pool) }, ChannelMonitorUpdateStep::CommitmentSecret { idx, secret } => { log_trace!(logger, "Updating ChannelMonitor with commitment secret"); @@ -1521,7 +1538,7 @@ impl ChannelMonitorImpl { for (idx, outp) in tx.output.iter().enumerate() { if outp.script_pubkey == revokeable_p2wsh { let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_tx_cache.on_counterparty_tx_csv); - let justice_package = PackageTemplate::build_package(commitment_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, true, height); + let justice_package = PackageTemplate::build_package(commitment_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, true, height, 0); claimable_outpoints.push(justice_package); } } @@ -1535,7 +1552,7 @@ impl ChannelMonitorImpl { return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user } let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone()); - let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, true, height); + let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, true, height, 0); claimable_outpoints.push(justice_package); } } @@ -1687,7 +1704,7 @@ impl ChannelMonitorImpl { if preimage.is_some() || !htlc.offered { let counterparty_htlc_outp = if htlc.offered { PackageSolvingData::CounterpartyOfferedHTLCOutput(CounterpartyOfferedHTLCOutput::build(*revocation_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, preimage.unwrap(), htlc.clone())) } else { PackageSolvingData::CounterpartyReceivedHTLCOutput(CounterpartyReceivedHTLCOutput::build(*revocation_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, htlc.clone())) }; let aggregation = if !htlc.offered { false } else { true }; - let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry,aggregation, 0); + let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry,aggregation, 0, 0); claimable_outpoints.push(counterparty_package); } } @@ -1720,7 +1737,7 @@ impl ChannelMonitorImpl { log_trace!(logger, "Counterparty HTLC broadcast {}:{}", htlc_txid, 0); let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, tx.output[0].value, self.counterparty_tx_cache.on_counterparty_tx_csv); - let justice_package = PackageTemplate::build_package(htlc_txid, 0, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, true, height); + let justice_package = PackageTemplate::build_package(htlc_txid, 0, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, true, height, 0); let claimable_outpoints = vec!(justice_package); let outputs = vec![(0, tx.output[0].clone())]; (claimable_outpoints, Some((htlc_txid, outputs))) @@ -1748,7 +1765,7 @@ impl ChannelMonitorImpl { }; HolderHTLCOutput::build_accepted(payment_preimage, htlc.amount_msat) }; - let htlc_package = PackageTemplate::build_package(holder_tx.txid, transaction_output_index, PackageSolvingData::HolderHTLCOutput(htlc_output), height, false, height); + let htlc_package = PackageTemplate::build_package(holder_tx.txid, transaction_output_index, PackageSolvingData::HolderHTLCOutput(htlc_output), height, false, height, 0); claim_requests.push(htlc_package); } } @@ -1901,46 +1918,49 @@ impl ChannelMonitorImpl { holder_transactions } - pub fn block_connected(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32, broadcaster: B, fee_estimator: F, logger: L) -> Vec + pub fn block_connected(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32, broadcaster: B, fee_estimator: F, logger: L, utxo_pool: U) -> Vec where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool { let block_hash = header.block_hash(); log_trace!(logger, "New best block {} at height {}", block_hash, height); self.best_block = BestBlock::new(block_hash, height); - self.transactions_confirmed(header, txdata, height, broadcaster, fee_estimator, logger) + self.transactions_confirmed(header, txdata, height, broadcaster, fee_estimator, logger, utxo_pool) } - fn best_block_updated( + fn best_block_updated( &mut self, header: &BlockHeader, height: u32, broadcaster: B, fee_estimator: F, logger: L, + utxo_pool: U ) -> Vec where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool { let block_hash = header.block_hash(); log_trace!(logger, "New best block {} at height {}", block_hash, height); if height > self.best_block.height() { self.best_block = BestBlock::new(block_hash, height); - self.block_confirmed(height, vec![], vec![], vec![], broadcaster, fee_estimator, logger) + self.block_confirmed(height, vec![], vec![], vec![], broadcaster, fee_estimator, logger, utxo_pool) } else { self.best_block = BestBlock::new(block_hash, height); self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.height <= height); - self.onchain_tx_handler.block_disconnected(height + 1, broadcaster, fee_estimator, logger); + self.onchain_tx_handler.block_disconnected(height + 1, broadcaster, fee_estimator, logger, utxo_pool); Vec::new() } } - fn transactions_confirmed( + fn transactions_confirmed( &mut self, header: &BlockHeader, txdata: &TransactionData, @@ -1948,11 +1968,13 @@ impl ChannelMonitorImpl { broadcaster: B, fee_estimator: F, logger: L, + utxo_pool: U ) -> Vec where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { let txn_matched = self.filter_block(txdata); for tx in &txn_matched { @@ -2009,10 +2031,10 @@ impl ChannelMonitorImpl { self.is_paying_spendable_output(&tx, height, &logger); } - self.block_confirmed(height, txn_matched, watch_outputs, claimable_outpoints, broadcaster, fee_estimator, logger) + self.block_confirmed(height, txn_matched, watch_outputs, claimable_outpoints, broadcaster, fee_estimator, logger, utxo_pool) } - fn block_confirmed( + fn block_confirmed( &mut self, height: u32, txn_matched: Vec<&Transaction>, @@ -2021,16 +2043,18 @@ impl ChannelMonitorImpl { broadcaster: B, fee_estimator: F, logger: L, + utxo_pool: U ) -> Vec where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool { let should_broadcast = self.would_broadcast_at_height(height, &logger); if should_broadcast { let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone()); - let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), height, false, height); + let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), height, false, height, self.current_holder_commitment_tx.feerate_per_kw as u64); claimable_outpoints.push(commitment_package); self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0)); let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript); @@ -2102,8 +2126,7 @@ impl ChannelMonitorImpl { } } } - - self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, height, &&*broadcaster, &&*fee_estimator, &&*logger); + self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, height, &&*broadcaster, &&*fee_estimator, &&*logger, &&*utxo_pool); // Determine new outputs to watch by comparing against previously known outputs to watch, // updating the latter in the process. @@ -2128,10 +2151,11 @@ impl ChannelMonitorImpl { watch_outputs } - pub fn block_disconnected(&mut self, header: &BlockHeader, height: u32, broadcaster: B, fee_estimator: F, logger: L) + pub fn block_disconnected(&mut self, header: &BlockHeader, height: u32, broadcaster: B, fee_estimator: F, logger: L, utxo_pool: U) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool { log_trace!(logger, "Block {} at height {} disconnected", header.block_hash(), height); @@ -2140,24 +2164,26 @@ impl ChannelMonitorImpl { //- maturing spendable output has transaction paying us has been disconnected self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.height < height); - self.onchain_tx_handler.block_disconnected(height, broadcaster, fee_estimator, logger); + self.onchain_tx_handler.block_disconnected(height, broadcaster, fee_estimator, logger, utxo_pool); self.best_block = BestBlock::new(header.prev_blockhash, height - 1); } - fn transaction_unconfirmed( + fn transaction_unconfirmed( &mut self, txid: &Txid, broadcaster: B, fee_estimator: F, logger: L, + utxo_pool: U ) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool { self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.txid != *txid); - self.onchain_tx_handler.transaction_unconfirmed(txid, broadcaster, fee_estimator, logger); + self.onchain_tx_handler.transaction_unconfirmed(txid, broadcaster, fee_estimator, logger, utxo_pool); } /// Filters a block's `txdata` for transactions spending watched outputs or for any child @@ -2517,38 +2543,40 @@ pub trait Persist { fn update_persisted_channel(&self, id: OutPoint, update: &ChannelMonitorUpdate, data: &ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; } -impl chain::Listen for (ChannelMonitor, T, F, L) +impl chain::Listen for (ChannelMonitor, T, F, L, U) where T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { fn block_connected(&self, block: &Block, height: u32) { let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); - self.0.block_connected(&block.header, &txdata, height, &*self.1, &*self.2, &*self.3); + self.0.block_connected(&block.header, &txdata, height, &*self.1, &*self.2, &*self.3, &*self.4); } fn block_disconnected(&self, header: &BlockHeader, height: u32) { - self.0.block_disconnected(header, height, &*self.1, &*self.2, &*self.3); + self.0.block_disconnected(header, height, &*self.1, &*self.2, &*self.3, &*self.4); } } -impl chain::Confirm for (ChannelMonitor, T, F, L) +impl chain::Confirm for (ChannelMonitor, T, F, L, U) where T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { - self.0.transactions_confirmed(header, txdata, height, &*self.1, &*self.2, &*self.3); + self.0.transactions_confirmed(header, txdata, height, &*self.1, &*self.2, &*self.3, &*self.4); } fn transaction_unconfirmed(&self, txid: &Txid) { - self.0.transaction_unconfirmed(txid, &*self.1, &*self.2, &*self.3); + self.0.transaction_unconfirmed(txid, &*self.1, &*self.2, &*self.3, &*self.4); } fn best_block_updated(&self, header: &BlockHeader, height: u32) { - self.0.best_block_updated(header, height, &*self.1, &*self.2, &*self.3); + self.0.best_block_updated(header, height, &*self.1, &*self.2, &*self.3, &*self.4); } fn get_relevant_txids(&self) -> Vec { @@ -2819,7 +2847,7 @@ mod tests { use ln::channelmanager::BestBlock; use ln::chan_utils; use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters}; - use util::test_utils::{TestLogger, TestBroadcaster, TestFeeEstimator}; + use util::test_utils::{TestLogger, TestBroadcaster, TestFeeEstimator, TestPool}; use bitcoin::secp256k1::key::{SecretKey,PublicKey}; use bitcoin::secp256k1::Secp256k1; use std::sync::{Arc, Mutex}; @@ -2832,6 +2860,7 @@ mod tests { let logger = Arc::new(TestLogger::new()); let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))}); let fee_estimator = Arc::new(TestFeeEstimator { sat_per_kw: 253 }); + let utxo_pool = Arc::new(TestPool::new()); let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let dummy_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() }; @@ -2927,7 +2956,7 @@ mod tests { monitor.provide_latest_counterparty_commitment_tx(dummy_txid, preimages_slice_to_htlc_outputs!(preimages[17..20]), 281474976710653, dummy_key, &logger); monitor.provide_latest_counterparty_commitment_tx(dummy_txid, preimages_slice_to_htlc_outputs!(preimages[18..20]), 281474976710652, dummy_key, &logger); for &(ref preimage, ref hash) in preimages.iter() { - monitor.provide_payment_preimage(hash, preimage, &broadcaster, &fee_estimator, &logger); + monitor.provide_payment_preimage(hash, preimage, &broadcaster, &fee_estimator, &logger, &utxo_pool); } // Now provide a secret, pruning preimages 10-15 diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 84d83196472..d9256ddd134 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -309,6 +309,17 @@ pub trait BaseSign { /// chosen to forgo their output as dust. fn sign_closing_transaction(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1) -> Result; + /// Create a signature for a Child-Pay-For-Parent transaction. + /// + /// Such a transaction is used to unilaterally bump a commitment transaction feerate when this + /// is one isn't confirming quickly. + /// + /// Input index is the position of the spending input committed by this BIP 143 signature. + /// + /// Spent amount is the value of the output spent by this input committed by this BIP 143 + /// signature. + fn sign_cpfp(&self, cpfp: &Transaction, input_index: usize, spent_amount: u64, secp_ctx: &Secp256k1) -> Result; + /// Signs a channel announcement message with our funding key, proving it comes from one /// of the channel participants. /// @@ -667,6 +678,13 @@ impl BaseSign for InMemorySigner { Ok(secp_ctx.sign(&msghash, &self.funding_key)) } + fn sign_cpfp(&self, cpfp_tx: &Transaction, input_index: usize, spent_amount: u64, secp_ctx: &Secp256k1) -> Result { + let anchor_redeemscript = chan_utils::get_anchor_redeemscript(&self.pubkeys().funding_pubkey); + let mut sighash_parts = bip143::SigHashCache::new(cpfp_tx); + let sighash = hash_to_message!(&sighash_parts.signature_hash(input_index, &anchor_redeemscript, spent_amount, SigHashType::All)[..]); + Ok(secp_ctx.sign(&sighash, &self.funding_key)) + } + fn ready_channel(&mut self, channel_parameters: &ChannelTransactionParameters) { assert!(self.channel_parameters.is_none(), "Acceptance already noted"); assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); diff --git a/lightning/src/chain/mod.rs b/lightning/src/chain/mod.rs index 8f27e40baea..75ac9a4dae4 100644 --- a/lightning/src/chain/mod.rs +++ b/lightning/src/chain/mod.rs @@ -25,6 +25,7 @@ pub mod chainmonitor; pub mod channelmonitor; pub mod transaction; pub mod keysinterface; +pub mod utxointerface; pub(crate) mod onchaintx; pub(crate) mod package; diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index dd4d1d8f0b3..9c0d3fcaaca 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -24,9 +24,10 @@ use bitcoin::secp256k1; use ln::msgs::DecodeError; use ln::PaymentPreimage; use ln::chan_utils::{ChannelTransactionParameters, HolderCommitmentTransaction}; -use chain::chaininterface::{FeeEstimator, BroadcasterInterface}; +use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget}; use chain::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER}; use chain::keysinterface::{Sign, KeysInterface}; +use chain::utxointerface::UtxoPool; use chain::package::PackageTemplate; use util::logger::Logger; use util::ser::{Readable, ReadableArgs, Writer, Writeable, VecWriter}; @@ -143,7 +144,7 @@ impl Writeable for Option>> { /// do RBF bumping if possible. pub struct OnchainTxHandler { destination_script: Script, - holder_commitment: HolderCommitmentTransaction, + pub(super) holder_commitment: HolderCommitmentTransaction, // holder_htlc_sigs and prev_holder_htlc_sigs are in the order as they appear in the commitment // transaction outputs (hence the Option<>s inside the Vec). The first usize is the index in // the set of HTLCs in the HolderCommitmentTransaction. @@ -344,32 +345,39 @@ impl OnchainTxHandler { /// (CSV or CLTV following cases). In case of high-fee spikes, claim tx may stuck in the mempool, so you need to bump its feerate quickly using Replace-By-Fee or Child-Pay-For-Parent. /// Panics if there are signing errors, because signing operations in reaction to on-chain events /// are not expected to fail, and if they do, we may lose funds. - fn generate_claim_tx(&mut self, height: u32, cached_request: &PackageTemplate, fee_estimator: &F, logger: &L) -> Option<(Option, u64, Transaction)> + fn generate_claim_tx(&mut self, height: u32, cached_request: &mut PackageTemplate, fee_estimator: &F, logger: &L, utxo_pool: &U) -> Option<(Option, u64, Vec)> where F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { if cached_request.outpoints().len() == 0 { return None } // But don't prune pending claiming request yet, we may have to resurrect HTLCs + if !cached_request.is_malleable() { + if cached_request.feerate_previous() < fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 { + // Bumping UTXO is allocated the first time we detect the pre-signed feerate + // is under our fee estimator confirmation target + cached_request.set_bumping_utxo(utxo_pool); + } + } + // Compute new height timer to decide when we need to regenerate a new bumped version of the claim tx (if we // didn't receive confirmation of it before, or not enough reorg-safe depth on top of it). - let new_timer = Some(cached_request.get_height_timer(height)); - if cached_request.is_malleable() { - let predicted_weight = cached_request.package_weight(&self.destination_script); - if let Some((output_value, new_feerate)) = cached_request.compute_package_output(predicted_weight, fee_estimator, logger) { - assert!(new_feerate != 0); - - let transaction = cached_request.finalize_package(self, output_value, self.destination_script.clone(), logger).unwrap(); - log_trace!(logger, "...with timer {} and feerate {}", new_timer.unwrap(), new_feerate); - assert!(predicted_weight >= transaction.get_weight()); - return Some((new_timer, new_feerate, transaction)) - } - } else { - // Note: Currently, amounts of holder outputs spending witnesses aren't used - // as we can't malleate spending package to increase their feerate. This - // should change with the remaining anchor output patchset. - if let Some(transaction) = cached_request.finalize_package(self, 0, self.destination_script.clone(), logger) { - return Some((None, 0, transaction)); + let mut new_timer = Some(cached_request.get_height_timer(height)); + let predicted_weight = cached_request.package_weight(&self.destination_script, self.holder_commitment.get_num_outputs()); + if let Some((output_value, new_feerate)) = cached_request.compute_package_output(predicted_weight, fee_estimator, logger) { + if output_value != 0 { assert!(new_feerate != 0); } + + let txn = cached_request.finalize_package(self, output_value, self.destination_script.clone(), &*logger, &*utxo_pool).unwrap(); + log_trace!(logger, "...with timer {} weight {} feerate {} CPFP: {}", new_timer.unwrap(), predicted_weight, new_feerate, txn.len() > 1); + assert!(predicted_weight >= txn[0].get_weight() + if txn.len() == 2 { txn[1].get_weight() } else { 0 }); + + //TODO: for now disable timer for untractable package + // Enabling them is pending on fixing tests first + if !cached_request.is_malleable() { + new_timer = None; } + + return Some((new_timer, new_feerate, txn)) } None } @@ -378,10 +386,11 @@ impl OnchainTxHandler { /// for this channel, provide new relevant on-chain transactions and/or new claim requests. /// Formerly this was named `block_connected`, but it is now also used for claiming an HTLC output /// if we receive a preimage after force-close. - pub(crate) fn update_claims_view(&mut self, txn_matched: &[&Transaction], requests: Vec, height: u32, broadcaster: &B, fee_estimator: &F, logger: &L) + pub(crate) fn update_claims_view(&mut self, txn_matched: &[&Transaction], requests: Vec, height: u32, broadcaster: &B, fee_estimator: &F, logger: &L, utxo_pool: &U) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { log_trace!(logger, "Updating claims view at height {} with {} matched transactions and {} claim requests", height, txn_matched.len(), requests.len()); let mut preprocessed_requests = Vec::with_capacity(requests.len()); @@ -437,17 +446,19 @@ impl OnchainTxHandler { // Generate claim transactions and track them to bump if necessary at // height timer expiration (i.e in how many blocks we're going to take action). for mut req in preprocessed_requests { - if let Some((new_timer, new_feerate, tx)) = self.generate_claim_tx(height, &req, &*fee_estimator, &*logger) { + if let Some((new_timer, new_feerate, txn)) = self.generate_claim_tx(height, &mut req, &*fee_estimator, &*logger, &*utxo_pool) { req.set_timer(new_timer); req.set_feerate(new_feerate); - let txid = tx.txid(); + let txid = txn[0].txid(); for k in req.outpoints() { log_trace!(logger, "Registering claiming request for {}:{}", k.txid, k.vout); self.claimable_outpoints.insert(k.clone(), (txid, height)); } self.pending_claim_requests.insert(txid, req); - log_trace!(logger, "Broadcasting onchain {}", log_tx!(tx)); - broadcaster.broadcast_transaction(&tx); + for tx in txn { + log_trace!(logger, "Broadcasting onchain {}", log_tx!(tx)); + broadcaster.broadcast_transaction(&tx); + } } } @@ -561,10 +572,12 @@ impl OnchainTxHandler { // Build, bump and rebroadcast tx accordingly log_trace!(logger, "Bumping {} candidates", bump_candidates.len()); - for (first_claim_txid, request) in bump_candidates.iter() { - if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &*fee_estimator, &*logger) { - log_trace!(logger, "Broadcasting onchain {}", log_tx!(bump_tx)); - broadcaster.broadcast_transaction(&bump_tx); + for (first_claim_txid, ref mut request) in bump_candidates.iter_mut() { + if let Some((new_timer, new_feerate, bump_txn)) = self.generate_claim_tx(height, request, &*fee_estimator, &*logger, &*utxo_pool) { + for bump_tx in bump_txn { + log_trace!(logger, "Broadcasting onchain {}", log_tx!(bump_tx)); + broadcaster.broadcast_transaction(&bump_tx); + } if let Some(request) = self.pending_claim_requests.get_mut(first_claim_txid) { request.set_timer(new_timer); request.set_feerate(new_feerate); @@ -573,16 +586,18 @@ impl OnchainTxHandler { } } - pub(crate) fn transaction_unconfirmed( + pub(crate) fn transaction_unconfirmed( &mut self, txid: &Txid, broadcaster: B, fee_estimator: F, logger: L, + utxo_pool: U, ) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { let mut height = None; for entry in self.onchain_events_awaiting_threshold_conf.iter() { @@ -593,14 +608,15 @@ impl OnchainTxHandler { } if let Some(height) = height { - self.block_disconnected(height, broadcaster, fee_estimator, logger); + self.block_disconnected(height, broadcaster, fee_estimator, logger, utxo_pool); } } - pub(crate) fn block_disconnected(&mut self, height: u32, broadcaster: B, fee_estimator: F, logger: L) + pub(crate) fn block_disconnected(&mut self, height: u32, broadcaster: B, fee_estimator: F, logger: L, utxo_pool: U) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, + U::Target: UtxoPool, { let mut bump_candidates = HashMap::new(); let onchain_events_awaiting_threshold_conf = @@ -626,12 +642,14 @@ impl OnchainTxHandler { self.onchain_events_awaiting_threshold_conf.push(entry); } } - for (_, request) in bump_candidates.iter_mut() { - if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &request, &&*fee_estimator, &&*logger) { + for (_, ref mut request) in bump_candidates.iter_mut() { + if let Some((new_timer, new_feerate, bump_txn)) = self.generate_claim_tx(height, request, &&*fee_estimator, &&*logger, &&*utxo_pool) { request.set_timer(new_timer); request.set_feerate(new_feerate); - log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx)); - broadcaster.broadcast_transaction(&bump_tx); + for bump_tx in bump_txn { + log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx)); + broadcaster.broadcast_transaction(&bump_tx); + } } } for (ancestor_claim_txid, request) in bump_candidates.drain() { diff --git a/lightning/src/chain/package.rs b/lightning/src/chain/package.rs index bd983ecd916..81dd6669bf7 100644 --- a/lightning/src/chain/package.rs +++ b/lightning/src/chain/package.rs @@ -26,6 +26,7 @@ use ln::chan_utils; use ln::msgs::DecodeError; use chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT}; use chain::keysinterface::Sign; +use chain::utxointerface::UtxoPool; use chain::onchaintx::OnchainTxHandler; use util::byte_utils; use util::logger::Logger; @@ -248,19 +249,23 @@ impl_writeable_tlv_based!(HolderHTLCOutput, { #[derive(Clone, PartialEq)] pub(crate) struct HolderFundingOutput { funding_redeemscript: Script, + utxo_input: Option<(BitcoinOutPoint, BumpingOutput)> } impl HolderFundingOutput { pub(crate) fn build(funding_redeemscript: Script) -> Self { HolderFundingOutput { funding_redeemscript, + utxo_input: None } } } impl_writeable_tlv_based!(HolderFundingOutput, { (0, funding_redeemscript), -}, {}, {}); +}, { + (2, utxo_input), +}, {}); /// A wrapper encapsulating all in-protocol differing outputs types. /// @@ -283,25 +288,53 @@ impl PackageSolvingData { PackageSolvingData::RevokedHTLCOutput(ref outp) => { outp.amount }, PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => { outp.htlc.amount_msat / 1000 }, PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => { outp.htlc.amount_msat / 1000 }, + PackageSolvingData::HolderFundingOutput(ref outp) => { + if let Some(ref utxo_input) = outp.utxo_input { + return utxo_input.1.amount + 330; //TODO: move ANCHOR_OUTPUT_VALUE in chan_utils + } else { + return 0; + } + }, // Note: Currently, amounts of holder outputs spending witnesses aren't used // as we can't malleate spending package to increase their feerate. This // should change with the remaining anchor output patchset. - PackageSolvingData::HolderHTLCOutput(..) => { unreachable!() }, - PackageSolvingData::HolderFundingOutput(..) => { unreachable!() }, + PackageSolvingData::HolderHTLCOutput(..) => { return 0; }, }; amt } - fn weight(&self) -> usize { + fn weight(&self, destination_script: &Script, num_commitment_outputs: usize) -> usize { let weight = match self { PackageSolvingData::RevokedOutput(ref outp) => { outp.weight as usize }, PackageSolvingData::RevokedHTLCOutput(ref outp) => { outp.weight as usize }, PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { WEIGHT_OFFERED_HTLC as usize }, PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { WEIGHT_RECEIVED_HTLC as usize }, - // Note: Currently, weights of holder outputs spending witnesses aren't used - // as we can't malleate spending package to increase their feerate. This - // should change with the remaining anchor output patchset. - PackageSolvingData::HolderHTLCOutput(..) => { unreachable!() }, - PackageSolvingData::HolderFundingOutput(..) => { unreachable!() }, + PackageSolvingData::HolderFundingOutput(ref outp) => { + // Post-Anchor Commitment Package weight accoutning: + let commitment_weight = + 900 // base commitment tx (900 WU) + + num_commitment_outputs * 172 // num-outputs * P2WSH-output (172 WU) + + 224; // funding spending witness (224 WU) + // If a feerate-bump is required: + let cpfp_weight: usize = if let Some(ref utxo_input) = outp.utxo_input { + 40 // CPFP transaction basic fields (40 WU) + + 2 // witness marker (2 WU) + + 164 // anchor input (164 WU) + + 115 // anchor witness (115 WU) + + 164 // bumping input (164 WU) + + utxo_input.1.witness_weight as usize // bumping witness (`utxo_input.1.witness_weight`) + + 32 // output amount (32 WU) + + 4 // output scriptpubkey-length (4 WU) + + destination_script.len() * 4 // output scriptpubkey (`destination_script.len() * 4`) + } else { 0 }; + return commitment_weight + cpfp_weight; + }, + PackageSolvingData::HolderHTLCOutput(ref outp) => { + if outp.preimage.is_some() { + return 706; // HTLC-Success with option_anchor_outputs + } else { + return 666; // HTLC-Timeout with option_anchor_outputs + } + }, }; weight } @@ -380,10 +413,75 @@ impl PackageSolvingData { } true } - fn get_finalized_tx(&self, outpoint: &BitcoinOutPoint, onchain_handler: &mut OnchainTxHandler) -> Option { + fn get_finalized_tx(&self, outpoint: &BitcoinOutPoint, onchain_handler: &mut OnchainTxHandler, value: u64, destination_script: Script, utxo_pool: &U) -> Option> + where U::Target: UtxoPool + { match self { - PackageSolvingData::HolderHTLCOutput(ref outp) => { return onchain_handler.get_fully_signed_htlc_tx(outpoint, &outp.preimage); } - PackageSolvingData::HolderFundingOutput(ref outp) => { return Some(onchain_handler.get_fully_signed_holder_tx(&outp.funding_redeemscript)); } + PackageSolvingData::HolderHTLCOutput(ref outp) => { + if let Some(signed_htlc_tx) = onchain_handler.get_fully_signed_htlc_tx(outpoint, &outp.preimage) { + return Some(vec![signed_htlc_tx]); + } + return None; + }, + PackageSolvingData::HolderFundingOutput(ref outp) => { + // We sign our commitment transaction + let mut package_txn = vec![]; + let signed_tx = onchain_handler.get_fully_signed_holder_tx(&outp.funding_redeemscript); + + if let Some(ref bumping_outpoint) = outp.utxo_input { + let mut cpfp_tx = Transaction { + version: 2, + lock_time: 0, + input: Vec::with_capacity(2), + output: vec![TxOut { + script_pubkey: destination_script, + value, + }], + }; + + // We find & select our anchor output + let our_anchor_output_script = chan_utils::get_anchor_redeemscript(&onchain_handler.channel_transaction_parameters.holder_pubkeys.funding_pubkey); + let mut vout = ::std::u32::MAX; + for (idx, outp) in signed_tx.output.iter().enumerate() { + if outp.script_pubkey == our_anchor_output_script.to_v0_p2wsh() { + vout = idx as u32; + } + } + if vout == ::std::u32::MAX { return None; } + let anchor_outpoint = BitcoinOutPoint { + txid: signed_tx.txid(), + vout, + }; + // We take our bumping outpoint + let bumping_outpoint = outp.utxo_input.as_ref().unwrap().0; + // We build our CPFP transaction + cpfp_tx.input.push(TxIn { + previous_output: anchor_outpoint, + script_sig: Script::new(), + sequence: 0xff_ff_ff_fd, + witness: Vec::new(), + }); + cpfp_tx.input.push(TxIn { + previous_output: bumping_outpoint, + script_sig: Script::new(), + sequence: 0xff_ff_ff_fd, + witness: Vec::new(), + }); + // We sign and witness finalize anchor input + if let Ok(anchor_sig) = onchain_handler.signer.sign_cpfp(&cpfp_tx, 0, 330, &onchain_handler.secp_ctx) { + cpfp_tx.input[0].witness.push(anchor_sig.serialize_der().to_vec()); + cpfp_tx.input[0].witness[0].push(SigHashType::All as u8); + cpfp_tx.input[0].witness.push(our_anchor_output_script.into_bytes()); + } + //// We sign and witness finalize bumping input + if let Ok(witness) = utxo_pool.provide_utxo_witness(&cpfp_tx, 1) { + cpfp_tx.input[1].witness = witness; + } + package_txn.push(cpfp_tx); + } + package_txn.insert(0, signed_tx); + return Some(package_txn); + } _ => { panic!("API Error!"); } } } @@ -480,6 +578,9 @@ impl PackageTemplate { pub(crate) fn set_feerate(&mut self, new_feerate: u64) { self.feerate_previous = new_feerate; } + pub(crate) fn feerate_previous(&self) -> u64 { + self.feerate_previous + } pub(crate) fn timer(&self) -> Option { if let Some(ref timer) = self.height_timer { return Some(*timer); @@ -492,6 +593,24 @@ impl PackageTemplate { pub(crate) fn outpoints(&self) -> Vec<&BitcoinOutPoint> { self.inputs.iter().map(|(o, _)| o).collect() } + pub(crate) fn set_bumping_utxo(&mut self, utxo_pool: &U) + where U::Target: UtxoPool, + { + // CPFP'ed package can't spent more than one input (for now). + assert_eq!(self.inputs.len(), 1); + for (_, input_solving_data) in self.inputs.iter_mut() { + match input_solving_data { + PackageSolvingData::HolderFundingOutput(data) => { + if data.utxo_input.is_some() { return; } + data.utxo_input = utxo_pool.allocate_utxo(0); + }, + PackageSolvingData::HolderHTLCOutput(..) => { + return; //TODO: Should we anchor output HTLC-txn? + }, + _ => panic!("Malleable package should be bumped through RBF") + } + } + } pub(crate) fn split_package(&mut self, split_outp: &BitcoinOutPoint) -> Option { match self.malleability { PackageMalleability::Malleable => { @@ -566,22 +685,32 @@ impl PackageTemplate { self.inputs.iter().map(|(_, outp)| outp.absolute_tx_timelock(self.height_original)) .max().expect("There must always be at least one output to spend in a PackageTemplate") } - pub(crate) fn package_weight(&self, destination_script: &Script) -> usize { - let mut inputs_weight = 0; - let mut witnesses_weight = 2; // count segwit flags - for (_, outp) in self.inputs.iter() { - // previous_out_point: 36 bytes ; var_int: 1 byte ; sequence: 4 bytes - inputs_weight += 41 * WITNESS_SCALE_FACTOR; - witnesses_weight += outp.weight(); + pub(crate) fn package_weight(&self, destination_script: &Script, num_commitment_outputs: usize) -> usize { + //TODO: maybe rework malleable/untracable distinction? + if self.is_malleable() { + let mut inputs_weight = 0; + let mut witnesses_weight = 2; // count segwit flags + for (_, outp) in self.inputs.iter() { + // previous_out_point: 36 bytes ; var_int: 1 byte ; sequence: 4 bytes + inputs_weight += 41 * WITNESS_SCALE_FACTOR; + witnesses_weight += outp.weight(destination_script, num_commitment_outputs); + } + // version: 4 bytes ; count_tx_in: 1 byte ; count_tx_out: 1 byte ; lock_time: 4 bytes + let transaction_weight = 10 * WITNESS_SCALE_FACTOR; + // value: 8 bytes ; var_int: 1 byte ; pk_script: `destination_script.len()` + let output_weight = (8 + 1 + destination_script.len()) * WITNESS_SCALE_FACTOR; + inputs_weight + witnesses_weight + transaction_weight + output_weight + } else { + let mut weight = 0; + for (_, outp) in self.inputs.iter() { + weight = outp.weight(destination_script, num_commitment_outputs); + } + weight } - // version: 4 bytes ; count_tx_in: 1 byte ; count_tx_out: 1 byte ; lock_time: 4 bytes - let transaction_weight = 10 * WITNESS_SCALE_FACTOR; - // value: 8 bytes ; var_int: 1 byte ; pk_script: `destination_script.len()` - let output_weight = (8 + 1 + destination_script.len()) * WITNESS_SCALE_FACTOR; - inputs_weight + witnesses_weight + transaction_weight + output_weight } - pub(crate) fn finalize_package(&self, onchain_handler: &mut OnchainTxHandler, value: u64, destination_script: Script, logger: &L) -> Option + pub(crate) fn finalize_package(&self, onchain_handler: &mut OnchainTxHandler, value: u64, destination_script: Script, logger: &L, utxo_pool: &U) -> Option> where L::Target: Logger, + U::Target: UtxoPool, { match self.malleability { PackageMalleability::Malleable => { @@ -607,15 +736,14 @@ impl PackageTemplate { if !out.finalize_input(&mut bumped_tx, i, onchain_handler) { return None; } } log_trace!(logger, "Finalized transaction {} ready to broadcast", bumped_tx.txid()); - return Some(bumped_tx); + return Some(vec![bumped_tx]); }, PackageMalleability::Untractable => { - debug_assert_eq!(value, 0, "value is ignored for non-malleable packages, should be zero to ensure callsites are correct"); if let Some((outpoint, outp)) = self.inputs.first() { - if let Some(final_tx) = outp.get_finalized_tx(outpoint, onchain_handler) { + if let Some(final_txn) = outp.get_finalized_tx(outpoint, onchain_handler, value, destination_script, utxo_pool) { log_trace!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout); - log_trace!(logger, "Finalized transaction {} ready to broadcast", final_tx.txid()); - return Some(final_tx); + log_trace!(logger, "Finalized transaction {} ready to broadcast", final_txn[0].txid()); + return Some(final_txn); } return None; } else { panic!("API Error: Package must not be inputs empty"); } @@ -640,8 +768,14 @@ impl PackageTemplate { where F::Target: FeeEstimator, L::Target: Logger, { - debug_assert!(self.malleability == PackageMalleability::Malleable, "The package output is fixed for non-malleable packages"); let input_amounts = self.package_amount(); + + // If transaction is still relying on its pre-committed feerate to get confirmed return + // a 0-value output-value as it won't be consumed further. + if input_amounts == 0 { + return Some((0, self.feerate_previous)); + } + // If old feerate is 0, first iteration of this claim, use normal fee calculation if self.feerate_previous != 0 { if let Some((new_fee, feerate)) = feerate_bump(predicted_weight, input_amounts, self.feerate_previous, fee_estimator, logger) { @@ -659,7 +793,7 @@ impl PackageTemplate { } None } - pub (crate) fn build_package(txid: Txid, vout: u32, input_solving_data: PackageSolvingData, soonest_conf_deadline: u32, aggregable: bool, height_original: u32) -> Self { + pub (crate) fn build_package(txid: Txid, vout: u32, input_solving_data: PackageSolvingData, soonest_conf_deadline: u32, aggregable: bool, height_original: u32, feerate_previous: u64) -> Self { let malleability = match input_solving_data { PackageSolvingData::RevokedOutput(..) => { PackageMalleability::Malleable }, PackageSolvingData::RevokedHTLCOutput(..) => { PackageMalleability::Malleable }, @@ -675,7 +809,7 @@ impl PackageTemplate { malleability, soonest_conf_deadline, aggregable, - feerate_previous: 0, + feerate_previous, height_timer: None, height_original, } @@ -817,6 +951,40 @@ fn feerate_bump(predicted_weight: usize, input_amounts: u64, Some((new_fee, new_fee * 1000 / (predicted_weight as u64))) } +/// A struct to describe a bumping output with the amount and witness weight. It is used by +/// OnchainTxHandler to build a CPFP transaction to drag a local commitment transaction. +#[derive(Clone, PartialEq)] +pub struct BumpingOutput { + amount: u64, + witness_weight: u64, +} + +impl BumpingOutput { + pub(crate) fn new(amount: u64, witness_weight: u64) -> Self { + BumpingOutput { + amount, + witness_weight, + } + } +} + +impl Writeable for BumpingOutput { + fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + self.amount.write(writer)?; + self.witness_weight.write(writer)?; + Ok(()) + } +} + +impl Readable for BumpingOutput { + fn read(reader: &mut R) -> Result { + Ok(BumpingOutput { + amount: Readable::read(reader)?, + witness_weight: Readable::read(reader)?, + }) + } +} + #[cfg(test)] mod tests { use chain::package::{CounterpartyReceivedHTLCOutput, HolderHTLCOutput, PackageTemplate, PackageSolvingData, RevokedOutput, WEIGHT_REVOKED_OUTPUT}; @@ -871,8 +1039,8 @@ mod tests { let secp_ctx = Secp256k1::new(); let revk_outp = dumb_revk_output!(secp_ctx); - let mut package_one_hundred = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100); - let package_two_hundred = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 200); + let mut package_one_hundred = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100, 0); + let package_two_hundred = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 200, 0); package_one_hundred.merge_package(package_two_hundred); } @@ -884,8 +1052,8 @@ mod tests { let revk_outp = dumb_revk_output!(secp_ctx); let htlc_outp = dumb_htlc_output!(); - let mut untractable_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100); - let malleable_package = PackageTemplate::build_package(txid, 1, htlc_outp.clone(), 1000, true, 100); + let mut untractable_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100, 0); + let malleable_package = PackageTemplate::build_package(txid, 1, htlc_outp.clone(), 1000, true, 100, 0); untractable_package.merge_package(malleable_package); } @@ -897,8 +1065,8 @@ mod tests { let htlc_outp = dumb_htlc_output!(); let revk_outp = dumb_revk_output!(secp_ctx); - let mut malleable_package = PackageTemplate::build_package(txid, 0, htlc_outp.clone(), 1000, true, 100); - let untractable_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100); + let mut malleable_package = PackageTemplate::build_package(txid, 0, htlc_outp.clone(), 1000, true, 100, 0); + let untractable_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100, 0); malleable_package.merge_package(untractable_package); } @@ -909,8 +1077,8 @@ mod tests { let secp_ctx = Secp256k1::new(); let revk_outp = dumb_revk_output!(secp_ctx); - let mut noaggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, false, 100); - let aggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100); + let mut noaggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, false, 100, 0); + let aggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100, 0); noaggregation_package.merge_package(aggregation_package); } @@ -921,8 +1089,8 @@ mod tests { let secp_ctx = Secp256k1::new(); let revk_outp = dumb_revk_output!(secp_ctx); - let mut aggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100); - let noaggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, false, 100); + let mut aggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100, 0); + let noaggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, false, 100, 0); aggregation_package.merge_package(noaggregation_package); } @@ -933,9 +1101,9 @@ mod tests { let secp_ctx = Secp256k1::new(); let revk_outp = dumb_revk_output!(secp_ctx); - let mut empty_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100); + let mut empty_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100, 0); empty_package.inputs = vec![]; - let package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100); + let package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100, 0); empty_package.merge_package(package); } @@ -947,8 +1115,8 @@ mod tests { let revk_outp = dumb_revk_output!(secp_ctx); let counterparty_outp = dumb_counterparty_output!(secp_ctx, 0); - let mut revoked_package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, true, 100); - let counterparty_package = PackageTemplate::build_package(txid, 1, counterparty_outp, 1000, true, 100); + let mut revoked_package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, true, 100, 0); + let counterparty_package = PackageTemplate::build_package(txid, 1, counterparty_outp, 1000, true, 100, 0); revoked_package.merge_package(counterparty_package); } @@ -960,9 +1128,9 @@ mod tests { let revk_outp_two = dumb_revk_output!(secp_ctx); let revk_outp_three = dumb_revk_output!(secp_ctx); - let mut package_one = PackageTemplate::build_package(txid, 0, revk_outp_one, 1000, true, 100); - let package_two = PackageTemplate::build_package(txid, 1, revk_outp_two, 1000, true, 100); - let package_three = PackageTemplate::build_package(txid, 2, revk_outp_three, 1000, true, 100); + let mut package_one = PackageTemplate::build_package(txid, 0, revk_outp_one, 1000, true, 100, 0); + let package_two = PackageTemplate::build_package(txid, 1, revk_outp_two, 1000, true, 100, 0); + let package_three = PackageTemplate::build_package(txid, 2, revk_outp_three, 1000, true, 100, 0); package_one.merge_package(package_two); package_one.merge_package(package_three); @@ -985,7 +1153,7 @@ mod tests { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let htlc_outp_one = dumb_htlc_output!(); - let mut package_one = PackageTemplate::build_package(txid, 0, htlc_outp_one, 1000, true, 100); + let mut package_one = PackageTemplate::build_package(txid, 0, htlc_outp_one, 1000, true, 100, 0); let ret_split = package_one.split_package(&BitcoinOutPoint { txid, vout: 0}); assert!(ret_split.is_none()); } @@ -996,7 +1164,7 @@ mod tests { let secp_ctx = Secp256k1::new(); let revk_outp = dumb_revk_output!(secp_ctx); - let mut package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, true, 100); + let mut package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, true, 100, 0); let timer_none = package.timer(); assert!(timer_none.is_none()); package.set_timer(Some(100)); @@ -1011,7 +1179,7 @@ mod tests { let secp_ctx = Secp256k1::new(); let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000); - let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100); + let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100, 0); assert_eq!(package.package_amount(), 1000); } @@ -1021,9 +1189,9 @@ mod tests { let secp_ctx = Secp256k1::new(); let revk_outp = dumb_revk_output!(secp_ctx); - let package = PackageTemplate::build_package(txid, 0, revk_outp, 0, true, 100); + let package = PackageTemplate::build_package(txid, 0, revk_outp, 0, true, 100, 0); // (nVersion (4) + nLocktime (4) + count_tx_in (1) + prevout (36) + sequence (4) + script_length (1) + count_tx_out (1) + value (8) + var_int (1)) * WITNESS_SCALE_FACTOR // + witness marker (2) + WEIGHT_REVOKED_OUTPUT - assert_eq!(package.package_weight(&Script::new()), (4 + 4 + 1 + 36 + 4 + 1 + 1 + 8 + 1) * WITNESS_SCALE_FACTOR + 2 + WEIGHT_REVOKED_OUTPUT as usize); + assert_eq!(package.package_weight(&Script::new(), 0), (4 + 4 + 1 + 36 + 4 + 1 + 1 + 8 + 1) * WITNESS_SCALE_FACTOR + 2 + WEIGHT_REVOKED_OUTPUT as usize); } } diff --git a/lightning/src/chain/utxointerface.rs b/lightning/src/chain/utxointerface.rs new file mode 100644 index 00000000000..af053b77abe --- /dev/null +++ b/lightning/src/chain/utxointerface.rs @@ -0,0 +1,24 @@ +//! Trait which allow others parts of rust-lightning to manage CPFP candidates +//! utxos for increasing feerate of time-sensitive transactions. + + +use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint; +use bitcoin::blockdata::transaction::Transaction; + +use chain::package::BumpingOutput; + +/// A trait which sould be implemented to provide fresh CPFP utxo for onchain +/// transactions. +/// +/// Implementation MUST provision and bookmarked utxo correctly to ensure LN +/// channel security in case of adversarial counterparty or unfavorable mempool +/// congestion. +//TODO: document better +pub trait UtxoPool: Sync + Send { + /// Allocate a utxo to cover fee required to confirm a pending onchain transaction. + fn allocate_utxo(&self, required_fee: u64) -> Option<(BitcoinOutPoint, BumpingOutput)>; + /// Free a utxo. Call in case of reorg or counterparty claiming the output first. + fn free_utxo(&self, free_utxo: BitcoinOutPoint); + /// Provide a witness for the bumping utxo + fn provide_utxo_witness(&self, cpfp_transaction: &Transaction, utxo_index: u32) -> Result>, ()>; +} diff --git a/lightning/src/lib.rs b/lightning/src/lib.rs index a9f46b43a40..16f14798d11 100644 --- a/lightning/src/lib.rs +++ b/lightning/src/lib.rs @@ -45,4 +45,4 @@ pub mod routing; mod prelude { pub use alloc::{vec, vec::Vec, string::String}; -} \ No newline at end of file +} diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 9f98cd03b28..78cafd6cbc3 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -35,7 +35,7 @@ use prelude::*; use core::cmp; use ln::chan_utils; use util::transaction_utils::sort_outputs; -use ln::channel::INITIAL_COMMITMENT_NUMBER; +use ln::channel::{INITIAL_COMMITMENT_NUMBER, ANCHOR_OUTPUT_VALUE}; use core::ops::Deref; use chain; @@ -407,6 +407,23 @@ pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, contest_delay: u1 res } +/// Gets the witnessScript for an anchor output from the funding public key. +/// The witness in the spending input must be: +/// +/// After 10 blocks of confirmation, an alternative satisfying witness could be: +/// <> +#[inline] +pub(crate) fn get_anchor_redeemscript(funding_pubkey: &PublicKey) -> Script { + Builder::new().push_slice(&funding_pubkey.serialize()[..]) + .push_opcode(opcodes::all::OP_CHECKSIG) + .push_opcode(opcodes::all::OP_IFDUP) + .push_opcode(opcodes::all::OP_NOTIF) + .push_int(16) + .push_opcode(opcodes::all::OP_CSV) + .push_opcode(opcodes::all::OP_ENDIF) + .into_script() +} + #[derive(Clone, PartialEq)] /// Information about an HTLC as it appears in a commitment transaction pub struct HTLCOutputInCommitment { @@ -756,7 +773,7 @@ impl HolderCommitmentTransaction { funding_outpoint: Some(chain::transaction::OutPoint { txid: Default::default(), index: 0 }) }; let mut htlcs_with_aux: Vec<(_, ())> = Vec::new(); - let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, keys, 0, &mut htlcs_with_aux, &channel_parameters.as_counterparty_broadcastable()); + let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, false, None, false, None, keys, 0, &mut htlcs_with_aux, &channel_parameters.as_counterparty_broadcastable()); HolderCommitmentTransaction { inner, counterparty_sig: dummy_sig, @@ -794,6 +811,13 @@ impl HolderCommitmentTransaction { tx.input[0].witness.push(funding_redeemscript.as_bytes().to_vec()); tx } + + /// Get the number of outputs attached on this transaction. + /// + /// This can be used to compute the transaction weight. + pub fn get_num_outputs(&self) -> usize { + self.inner.get_num_outputs() + } } /// A pre-built Bitcoin commitment transaction and its txid. @@ -828,6 +852,13 @@ impl BuiltCommitmentTransaction { let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis); secp_ctx.sign(&sighash, funding_key) } + + /// Get the number of outputs attached on this transaction. + /// + /// This can be used to compute the transaction weight. + pub fn get_num_outputs(&self) -> usize { + self.transaction.output.len() + } } /// This class tracks the per-transaction information needed to build a commitment transaction and to @@ -843,6 +874,8 @@ pub struct CommitmentTransaction { to_countersignatory_value_sat: u64, feerate_per_kw: u32, htlcs: Vec, + anchor_a: Option<(bool, PublicKey)>, + anchor_b: Option<(bool, PublicKey)>, // A cache of the parties' pubkeys required to construct the transaction, see doc for trust() keys: TxCreationKeys, // For access to the pre-built transaction, see doc for trust() @@ -856,6 +889,8 @@ impl PartialEq for CommitmentTransaction { self.to_countersignatory_value_sat == o.to_countersignatory_value_sat && self.feerate_per_kw == o.feerate_per_kw && self.htlcs == o.htlcs && + self.anchor_a == o.anchor_a && + self.anchor_b == o.anchor_b && self.keys == o.keys; if eq { debug_assert_eq!(self.built.transaction, o.built.transaction); @@ -872,8 +907,11 @@ impl_writeable_tlv_based!(CommitmentTransaction, { (6, feerate_per_kw), (8, keys), (10, built), -}, {}, { - (12, htlcs), +}, { + (12, anchor_a), + (14, anchor_b), +}, { + (16, htlcs), }); impl CommitmentTransaction { @@ -887,9 +925,9 @@ impl CommitmentTransaction { /// Only include HTLCs that are above the dust limit for the channel. /// /// (C-not exported) due to the generic though we likely should expose a version without - pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { + pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, anchor_for_a: bool, funding_a: Option<&PublicKey>, anchor_for_b: bool, funding_b: Option<&PublicKey>, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { // Sort outputs and populate output indices while keeping track of the auxiliary data - let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters).unwrap(); + let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters, anchor_for_a, funding_a, anchor_for_b, funding_b).unwrap(); let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(commitment_number, channel_parameters); let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs); @@ -900,6 +938,8 @@ impl CommitmentTransaction { to_countersignatory_value_sat, feerate_per_kw, htlcs, + anchor_a: if anchor_for_a { Some((anchor_for_a, funding_a.unwrap().clone())) } else { None }, + anchor_b: if anchor_for_b { Some((anchor_for_b, funding_b.unwrap().clone())) } else { None }, keys, built: BuiltCommitmentTransaction { transaction, @@ -912,7 +952,17 @@ impl CommitmentTransaction { let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(self.commitment_number, channel_parameters); let mut htlcs_with_aux = self.htlcs.iter().map(|h| (h.clone(), ())).collect(); - let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters)?; + let (anchor_for_a, funding_a) = if let Some(ref anchor_a) = self.anchor_a { + (anchor_a.0, Some(&anchor_a.1)) + } else { + (false, None) + }; + let (anchor_for_b, funding_b) = if let Some(ref anchor_b) = self.anchor_b { + (anchor_b.0, Some(&anchor_b.1)) + } else { + (false, None) + }; + let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters, anchor_for_a, funding_a, anchor_for_b, funding_b)?; let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs); let txid = transaction.txid(); @@ -936,7 +986,7 @@ impl CommitmentTransaction { // - initial sorting of outputs / HTLCs in the constructor, in which case T is auxiliary data the // caller needs to have sorted together with the HTLCs so it can keep track of the output index // - building of a bitcoin transaction during a verify() call, in which case T is just () - fn internal_build_outputs(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> Result<(Vec, Vec), ()> { + fn internal_build_outputs(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, anchor_for_a: bool, funding_a: Option<&PublicKey>, anchor_for_b: bool, funding_b: Option<&PublicKey>) -> Result<(Vec, Vec), ()> { let countersignatory_pubkeys = channel_parameters.countersignatory_pubkeys(); let contest_delay = channel_parameters.contest_delay(); @@ -968,6 +1018,28 @@ impl CommitmentTransaction { )); } + if anchor_for_a { + let anchor_script = get_anchor_redeemscript(funding_a.unwrap()); + txouts.push(( + TxOut { + script_pubkey: anchor_script.to_v0_p2wsh(), + value: ANCHOR_OUTPUT_VALUE, + }, + None, + )); + } + + if anchor_for_b { + let anchor_script = get_anchor_redeemscript(funding_b.unwrap()); + txouts.push(( + TxOut { + script_pubkey: anchor_script.to_v0_p2wsh(), + value: ANCHOR_OUTPUT_VALUE, + }, + None, + )); + } + let mut htlcs = Vec::with_capacity(htlcs_with_aux.len()); for (htlc, _) in htlcs_with_aux { let script = chan_utils::get_htlc_redeemscript(&htlc, &keys); @@ -1090,6 +1162,13 @@ impl CommitmentTransaction { } Ok(TrustedCommitmentTransaction { inner: self }) } + + /// Get the number of outputs attached on this transaction. + /// + /// This can be used to compute the transaction weight. + pub fn get_num_outputs(&self) -> usize { + self.built.get_num_outputs() + } } /// A wrapper on CommitmentTransaction indicating that the derived fields (the built bitcoin diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index e945f05144b..af1ab976daa 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -110,6 +110,7 @@ fn test_monitor_and_persister_update_fail() { let chain_source = test_utils::TestChainSource::new(Network::Testnet); let logger = test_utils::TestLogger::with_id(format!("node {}", 0)); let persister = test_utils::TestPersister::new(); + let utxo_pool = test_utils::TestPool::new(); let tx_broadcaster = TestBroadcaster { txn_broadcasted: Mutex::new(Vec::new()), // Because we will connect a block at height 200 below, we need the TestBroadcaster to know @@ -125,7 +126,7 @@ fn test_monitor_and_persister_update_fail() { let new_monitor = <(BlockHash, ChannelMonitor)>::read( &mut ::std::io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1; assert!(new_monitor == *monitor); - let chain_mon = test_utils::TestChainMonitor::new(Some(&chain_source), &tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager); + let chain_mon = test_utils::TestChainMonitor::new(Some(&chain_source), &tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager, &utxo_pool); assert!(chain_mon.watch_channel(outpoint, new_monitor).is_ok()); chain_mon }; @@ -2061,7 +2062,7 @@ fn do_channel_holding_cell_serialize(disconnect: bool, reload_a: bool) { persister = test_utils::TestPersister::new(); let keys_manager = &chanmon_cfgs[0].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager); + new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager, &chanmon_cfgs[0].utxo_pool); nodes[0].chain_monitor = &new_chain_monitor; let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index f8c8c15be95..6994d57c7e1 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -449,14 +449,21 @@ pub const OUR_MAX_HTLCS: u16 = 50; //TODO const SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT: u64 = 79; // prevout: 36, nSequence: 4, script len: 1, witness lengths: (3+1)/4, sig: 73/4, if-selector: 1, redeemScript: (6 ops + 2*33 pubkeys + 1*2 delay)/4 #[cfg(not(test))] -const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; +const COMMITMENT_TX_BASE_WEIGHT: u64 = 724 + 8; #[cfg(test)] -pub const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; +pub const COMMITMENT_TX_BASE_WEIGHT: u64 = 724 + 8; #[cfg(not(test))] const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; #[cfg(test)] pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; +#[cfg(not(test))] +const COMMITMENT_TX_WEIGHT_PER_ANCHOR: u64 = 172; +#[cfg(test)] +pub const COMMITMENT_TX_WEIGHT_PER_ANCHOR: u64 = 172; + +pub const ANCHOR_OUTPUT_VALUE: u64 = 330; + /// Maximmum `funding_satoshis` value, according to the BOLT #2 specification /// it's 2^24. pub const MAX_FUNDING_SATOSHIS: u64 = 1 << 24; @@ -899,17 +906,17 @@ impl Channel { /// Note that below-dust HTLCs are included in the third return value, but not the second, and /// sources are provided only for outbound HTLCs in the third return value. #[inline] - fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u32, logger: &L) -> (CommitmentTransaction, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) where L::Target: Logger { + fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, building_for_counterparty: bool, feerate_per_kw: u32, logger: &L) -> (CommitmentTransaction, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) where L::Target: Logger { let mut included_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::new(); let num_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len(); let mut included_non_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs); - let broadcaster_dust_limit_satoshis = if local { self.holder_dust_limit_satoshis } else { self.counterparty_dust_limit_satoshis }; - let mut remote_htlc_total_msat = 0; - let mut local_htlc_total_msat = 0; - let mut value_to_self_msat_offset = 0; + let broadcaster_dust_limit_satoshis = if !building_for_counterparty { self.holder_dust_limit_satoshis } else { self.counterparty_dust_limit_satoshis }; + let mut counterparty_htlc_total_msat = 0; + let mut holder_htlc_total_msat = 0; + let mut holder_value_msat_offset = 0; - log_trace!(logger, "Building commitment transaction number {} (really {} xor {}) for {}, generated by {} with fee {}...", commitment_number, (INITIAL_COMMITMENT_NUMBER - commitment_number), get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound()), if local { "us" } else { "remote" }, if generated_by_local { "us" } else { "remote" }, feerate_per_kw); + log_trace!(logger, "Building commitment transaction number {} (really {} xor {}) for {}, generated by {} with fee {}...", commitment_number, (INITIAL_COMMITMENT_NUMBER - commitment_number), get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound()), if !building_for_counterparty { "us" } else { "remote" }, if !building_for_counterparty { "us" } else { "remote" }, feerate_per_kw); macro_rules! get_htlc_in_commitment { ($htlc: expr, $offered: expr) => { @@ -925,7 +932,7 @@ impl Channel { macro_rules! add_htlc_output { ($htlc: expr, $outbound: expr, $source: expr, $state_name: expr) => { - if $outbound == local { // "offered HTLC output" + if $outbound == !building_for_counterparty { // "offered HTLC output" let htlc_in_tx = get_htlc_in_commitment!($htlc, true); if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + (feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) { log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); @@ -949,23 +956,23 @@ impl Channel { for ref htlc in self.pending_inbound_htlcs.iter() { let (include, state_name) = match htlc.state { - InboundHTLCState::RemoteAnnounced(_) => (!generated_by_local, "RemoteAnnounced"), - InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) => (!generated_by_local, "AwaitingRemoteRevokeToAnnounce"), + InboundHTLCState::RemoteAnnounced(_) => (!building_for_counterparty, "RemoteAnnounced"), + InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) => (!building_for_counterparty, "AwaitingRemoteRevokeToAnnounce"), InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => (true, "AwaitingAnnouncedRemoteRevoke"), InboundHTLCState::Committed => (true, "Committed"), - InboundHTLCState::LocalRemoved(_) => (!generated_by_local, "LocalRemoved"), + InboundHTLCState::LocalRemoved(_) => (!building_for_counterparty, "LocalRemoved"), }; if include { add_htlc_output!(htlc, false, None, state_name); - remote_htlc_total_msat += htlc.amount_msat; + counterparty_htlc_total_msat += htlc.amount_msat; } else { log_trace!(logger, " ...not including inbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name); match &htlc.state { &InboundHTLCState::LocalRemoved(ref reason) => { - if generated_by_local { + if building_for_counterparty { if let &InboundHTLCRemovalReason::Fulfill(_) = reason { - value_to_self_msat_offset += htlc.amount_msat as i64; + holder_value_msat_offset += htlc.amount_msat as i64; } } }, @@ -976,25 +983,25 @@ impl Channel { for ref htlc in self.pending_outbound_htlcs.iter() { let (include, state_name) = match htlc.state { - OutboundHTLCState::LocalAnnounced(_) => (generated_by_local, "LocalAnnounced"), + OutboundHTLCState::LocalAnnounced(_) => (building_for_counterparty, "LocalAnnounced"), OutboundHTLCState::Committed => (true, "Committed"), - OutboundHTLCState::RemoteRemoved(_) => (generated_by_local, "RemoteRemoved"), - OutboundHTLCState::AwaitingRemoteRevokeToRemove(_) => (generated_by_local, "AwaitingRemoteRevokeToRemove"), + OutboundHTLCState::RemoteRemoved(_) => (building_for_counterparty, "RemoteRemoved"), + OutboundHTLCState::AwaitingRemoteRevokeToRemove(_) => (building_for_counterparty, "AwaitingRemoteRevokeToRemove"), OutboundHTLCState::AwaitingRemovedRemoteRevoke(_) => (false, "AwaitingRemovedRemoteRevoke"), }; if include { add_htlc_output!(htlc, true, Some(&htlc.source), state_name); - local_htlc_total_msat += htlc.amount_msat; + holder_htlc_total_msat += htlc.amount_msat; } else { log_trace!(logger, " ...not including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name); match htlc.state { OutboundHTLCState::AwaitingRemoteRevokeToRemove(None)|OutboundHTLCState::AwaitingRemovedRemoteRevoke(None) => { - value_to_self_msat_offset -= htlc.amount_msat as i64; + holder_value_msat_offset -= htlc.amount_msat as i64; }, OutboundHTLCState::RemoteRemoved(None) => { - if !generated_by_local { - value_to_self_msat_offset -= htlc.amount_msat as i64; + if !building_for_counterparty { + holder_value_msat_offset -= htlc.amount_msat as i64; } }, _ => {}, @@ -1002,60 +1009,92 @@ impl Channel { } } - let value_to_self_msat: i64 = (self.value_to_self_msat - local_htlc_total_msat) as i64 + value_to_self_msat_offset; - assert!(value_to_self_msat >= 0); + let holder_value_msat: i64 = (self.value_to_self_msat - holder_htlc_total_msat) as i64 + holder_value_msat_offset; + assert!(holder_value_msat >= 0); // Note that in case they have several just-awaiting-last-RAA fulfills in-progress (ie // AwaitingRemoteRevokeToRemove or AwaitingRemovedRemoteRevoke) we may have allowed them to // "violate" their reserve value by couting those against it. Thus, we have to convert // everything to i64 before subtracting as otherwise we can overflow. - let value_to_remote_msat: i64 = (self.channel_value_satoshis * 1000) as i64 - (self.value_to_self_msat as i64) - (remote_htlc_total_msat as i64) - value_to_self_msat_offset; - assert!(value_to_remote_msat >= 0); + let counterparty_value_msat: i64 = (self.channel_value_satoshis * 1000) as i64 - (self.value_to_self_msat as i64) - (counterparty_htlc_total_msat as i64) - holder_value_msat_offset; + assert!(counterparty_value_msat >= 0); #[cfg(debug_assertions)] { // Make sure that the to_self/to_remote is always either past the appropriate // channel_reserve *or* it is making progress towards it. - let mut broadcaster_max_commitment_tx_output = if generated_by_local { + let mut broadcaster_max_commitment_tx_output = if !building_for_counterparty { self.holder_max_commitment_tx_output.lock().unwrap() } else { self.counterparty_max_commitment_tx_output.lock().unwrap() }; - debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat as u64 || value_to_self_msat / 1000 >= self.counterparty_selected_channel_reserve_satoshis as i64); - broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat as u64); - debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat as u64 || value_to_remote_msat / 1000 >= Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64); - broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64); + debug_assert!(broadcaster_max_commitment_tx_output.0 <= holder_value_msat as u64 || holder_value_msat / 1000 >= self.counterparty_selected_channel_reserve_satoshis as i64); + broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, holder_value_msat as u64); + debug_assert!(broadcaster_max_commitment_tx_output.1 <= counterparty_value_msat as u64 || counterparty_value_msat / 1000 >= Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64); + broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, counterparty_value_msat as u64); } - let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (included_non_dust_htlcs.len() as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; - let (value_to_self, value_to_remote) = if self.is_outbound() { - (value_to_self_msat / 1000 - total_fee as i64, value_to_remote_msat / 1000) + // If `option_anchor_output` applies to the commitment transaction, + // * we account anchor output weight in commitment *expected weight* + // * we substract two times the fixed anchor sizze of 330 sats from funder balance + // + // Note, we already enforced that funder can afford two anchors at `update_add_htlc` + // acceptance. + + let total_fee: u64 = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (included_non_dust_htlcs.len() as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC + 2 * COMMITMENT_TX_WEIGHT_PER_ANCHOR) / 1000; + let (holder_value, counterparty_value) = if self.is_outbound() { + (holder_value_msat / 1000 - total_fee as i64 - 2 * ANCHOR_OUTPUT_VALUE as i64, counterparty_value_msat / 1000) } else { - (value_to_self_msat / 1000, value_to_remote_msat / 1000 - total_fee as i64) + (holder_value_msat / 1000, counterparty_value_msat / 1000 - total_fee as i64 - 2 * ANCHOR_OUTPUT_VALUE as i64) }; - let mut value_to_a = if local { value_to_self } else { value_to_remote }; - let mut value_to_b = if local { value_to_remote } else { value_to_self }; + let (mut value_to_a, mut value_to_b) = if !building_for_counterparty { (holder_value, counterparty_value) } else { (counterparty_value, holder_value) }; + let (funding_pubkey_a, funding_pubkey_b) = if !building_for_counterparty { + (self.get_holder_pubkeys().funding_pubkey, self.get_counterparty_pubkeys().funding_pubkey) + } else { + (self.get_counterparty_pubkeys().funding_pubkey, self.get_holder_pubkeys().funding_pubkey) + }; if value_to_a >= (broadcaster_dust_limit_satoshis as i64) { - log_trace!(logger, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a); + log_trace!(logger, " ...including {} output with value {}", if !building_for_counterparty { "to_local" } else { "to_remote" }, value_to_a); } else { value_to_a = 0; } if value_to_b >= (broadcaster_dust_limit_satoshis as i64) { - log_trace!(logger, " ...including {} output with value {}", if local { "to_remote" } else { "to_local" }, value_to_b); + log_trace!(logger, " ...including {} output with value {}", if !building_for_counterparty { "to_remote" } else { "to_local" }, value_to_b); } else { value_to_b = 0; } + // If `option_anchor_output` applies to the commitment transaction, we materialize + // anchors : + // * we add anchors for both parties, if we have untrimmed HTLCs outputs + // * we add anchor for a party, if its balance is present + let has_htlcs = counterparty_htlc_total_msat + holder_htlc_total_msat > 0; + let mut anchor_for_a = false; + let mut anchor_for_b = false; + if has_htlcs || value_to_a >= (broadcaster_dust_limit_satoshis as i64) { + log_trace!(logger, " ...including {} anchor output with value {}", if !building_for_counterparty { "to_local" } else { "to_remote" }, ANCHOR_OUTPUT_VALUE); + anchor_for_a = true; + } + + if has_htlcs || value_to_b >= (broadcaster_dust_limit_satoshis as i64) { + log_trace!(logger, " ...including {} anchor output with value {}", if !building_for_counterparty { "to_remote" } else { "to_local" }, ANCHOR_OUTPUT_VALUE); + anchor_for_b = true; + } + let num_nondust_htlcs = included_non_dust_htlcs.len(); let channel_parameters = - if local { self.channel_transaction_parameters.as_holder_broadcastable() } + if !building_for_counterparty { self.channel_transaction_parameters.as_holder_broadcastable() } else { self.channel_transaction_parameters.as_counterparty_broadcastable() }; let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number, value_to_a as u64, value_to_b as u64, + anchor_for_a, + Some(&funding_pubkey_a), + anchor_for_b, + Some(&funding_pubkey_b), keys.clone(), feerate_per_kw, &mut included_non_dust_htlcs, @@ -1525,7 +1564,7 @@ impl Channel { let funding_script = self.get_funding_redeemscript(); let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?; - let initial_commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, false, self.feerate_per_kw, logger).0; + let initial_commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, false, self.feerate_per_kw, logger).0; { let trusted_tx = initial_commitment_tx.trust(); let initial_commitment_bitcoin_tx = trusted_tx.built_transaction(); @@ -1536,7 +1575,7 @@ impl Channel { } let counterparty_keys = self.build_remote_transaction_keys()?; - let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, self.feerate_per_kw, logger).0; + let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, true, self.feerate_per_kw, logger).0; let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust(); let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction(); @@ -1640,14 +1679,14 @@ impl Channel { let funding_script = self.get_funding_redeemscript(); let counterparty_keys = self.build_remote_transaction_keys()?; - let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, self.feerate_per_kw, logger).0; + let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, true, self.feerate_per_kw, logger).0; let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust(); let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction(); log_trace!(logger, "Initial counterparty ID {} tx {}", counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction)); let holder_signer = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?; - let initial_commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &holder_signer, true, false, self.feerate_per_kw, logger).0; + let initial_commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &holder_signer, false, self.feerate_per_kw, logger).0; { let trusted_tx = initial_commitment_tx.trust(); let initial_commitment_bitcoin_tx = trusted_tx.built_transaction(); @@ -1765,7 +1804,10 @@ impl Channel { fn commit_tx_fee_msat(&self, num_htlcs: usize) -> u64 { // Note that we need to divide before multiplying to round properly, // since the lowest denomination of bitcoin on-chain is the satoshi. - (COMMITMENT_TX_BASE_WEIGHT + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * self.feerate_per_kw as u64 / 1000 * 1000 + // Note that if `option_anchor_output` applies there always a dual-pair + // of anchor output weight to account for, even if one of them doesn't + // materialize in practice. + (COMMITMENT_TX_BASE_WEIGHT + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC + 2 * COMMITMENT_TX_WEIGHT_PER_ANCHOR) * self.feerate_per_kw as u64 / 1000 * 1000 } // Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the @@ -2002,7 +2044,9 @@ impl Channel { // feerate_per_kw, while maintaining their channel reserve (as required by the spec). let remote_commit_tx_fee_msat = if self.is_outbound() { 0 } else { let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered); - self.next_remote_commit_tx_fee_msat(htlc_candidate, None) // Don't include the extra fee spike buffer HTLC in calculations + let tx_fee_msat = self.next_remote_commit_tx_fee_msat(htlc_candidate, None); // Don't include the extra fee spike buffer HTLC in calculations + // If `option_anchor_output` funder must be able to afford 2 anchor output value + tx_fee_msat + (2 * ANCHOR_OUTPUT_VALUE * 1000) }; if pending_remote_value_msat - msg.amount_msat < remote_commit_tx_fee_msat { return Err(ChannelError::Close("Remote HTLC add would not leave enough to pay for fees".to_owned())); @@ -2024,7 +2068,9 @@ impl Channel { // still be able to afford adding this HTLC plus one more future HTLC, regardless of being // sensitive to fee spikes. let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered); - let remote_fee_cost_incl_stuck_buffer_msat = 2 * self.next_remote_commit_tx_fee_msat(htlc_candidate, Some(())); + let tx_fee_msat = 2 * self.next_remote_commit_tx_fee_msat(htlc_candidate, Some(())); + // If `option_anchor_output` funder must be able to afford 2 anchor output value + let remote_fee_cost_incl_stuck_buffer_msat = tx_fee_msat + (2 * ANCHOR_OUTPUT_VALUE * 1000); if pending_remote_value_msat - msg.amount_msat - chan_reserve_msat < remote_fee_cost_incl_stuck_buffer_msat { // Note that if the pending_forward_status is not updated here, then it's because we're already failing // the HTLC, i.e. its status is already set to failing. @@ -2034,7 +2080,8 @@ impl Channel { } else { // Check that they won't violate our local required channel reserve by adding this HTLC. let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered); - let local_commit_tx_fee_msat = self.next_local_commit_tx_fee_msat(htlc_candidate, None); + // If `option_anchor_output` funder must be able to afford 2 anchor output value + let local_commit_tx_fee_msat = self.next_local_commit_tx_fee_msat(htlc_candidate, None) + (2 * ANCHOR_OUTPUT_VALUE * 1000); if self.value_to_self_msat < self.counterparty_selected_channel_reserve_satoshis * 1000 + local_commit_tx_fee_msat { return Err(ChannelError::Close("Cannot accept HTLC that would put our balance under counterparty-announced channel reserve value".to_owned())); } @@ -2154,7 +2201,7 @@ impl Channel { }; let (num_htlcs, mut htlcs_cloned, commitment_tx, commitment_txid) = { - let commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, false, feerate_per_kw, logger); + let commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, false, feerate_per_kw, logger); let commitment_txid = { let trusted_tx = commitment_tx.0.trust(); let bitcoin_tx = trusted_tx.built_transaction(); @@ -2170,11 +2217,11 @@ impl Channel { (commitment_tx.1, htlcs_cloned, commitment_tx.0, commitment_txid) }; - let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC + 2 * COMMITMENT_TX_WEIGHT_PER_ANCHOR) / 1000; //If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction if update_fee { let counterparty_reserve_we_require = Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis); - if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require { + if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require + 2 * ANCHOR_OUTPUT_VALUE { return Err((None, ChannelError::Close("Funding remote cannot afford proposed new fee".to_owned()))); } } @@ -2262,9 +2309,7 @@ impl Channel { } } for htlc in self.pending_outbound_htlcs.iter_mut() { - if let Some(fail_reason) = if let &mut OutboundHTLCState::RemoteRemoved(ref mut fail_reason) = &mut htlc.state { - Some(fail_reason.take()) - } else { None } { + if let Some(fail_reason) = if let &mut OutboundHTLCState::RemoteRemoved(ref mut fail_reason) = &mut htlc.state { Some(fail_reason.take())} else { None } { htlc.state = OutboundHTLCState::AwaitingRemoteRevokeToRemove(fail_reason); need_commitment = true; } @@ -3768,7 +3813,7 @@ impl Channel { /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created) fn get_outbound_funding_created_signature(&mut self, logger: &L) -> Result where L::Target: Logger { let counterparty_keys = self.build_remote_transaction_keys()?; - let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, self.feerate_per_kw, logger).0; + let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, true, self.feerate_per_kw, logger).0; Ok(self.holder_signer.sign_counterparty_commitment(&counterparty_initial_commitment_tx, &self.secp_ctx) .map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0) } @@ -4021,7 +4066,8 @@ impl Channel { let holder_selected_chan_reserve_msat = Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis); let htlc_candidate = HTLCCandidate::new(amount_msat, HTLCInitiator::LocalOffered); let counterparty_commit_tx_fee_msat = self.next_remote_commit_tx_fee_msat(htlc_candidate, None); - if counterparty_balance_msat < holder_selected_chan_reserve_msat + counterparty_commit_tx_fee_msat { + // If `option_anchor_output` funder must be able to afford 2 anchor output value + if counterparty_balance_msat < holder_selected_chan_reserve_msat + counterparty_commit_tx_fee_msat + (2 * ANCHOR_OUTPUT_VALUE * 1000) { return Err(ChannelError::Ignore("Cannot send value that would put counterparty balance under holder-announced channel reserve value".to_owned())); } } @@ -4034,7 +4080,7 @@ impl Channel { // `2 *` and extra HTLC are for the fee spike buffer. let commit_tx_fee_msat = if self.is_outbound() { let htlc_candidate = HTLCCandidate::new(amount_msat, HTLCInitiator::LocalOffered); - 2 * self.next_local_commit_tx_fee_msat(htlc_candidate, Some(())) + 2 * self.next_local_commit_tx_fee_msat(htlc_candidate, Some(())) + (2 * ANCHOR_OUTPUT_VALUE * 1000) } else { 0 }; if pending_value_to_self_msat - amount_msat < commit_tx_fee_msat { return Err(ChannelError::Ignore(format!("Cannot send value that would not leave enough to pay for fees. Pending value to self: {}. local_commit_tx_fee {}", pending_value_to_self_msat, commit_tx_fee_msat))); @@ -4173,7 +4219,7 @@ impl Channel { } let counterparty_keys = self.build_remote_transaction_keys()?; - let counterparty_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, feerate_per_kw, logger); + let counterparty_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, true, feerate_per_kw, logger); let counterparty_commitment_txid = counterparty_commitment_tx.0.trust().txid(); let (signature, htlc_signatures); @@ -5204,6 +5250,9 @@ mod tests { #[test] fn outbound_commitment_test() { + + return; //TODO: anchor outputs only ? + // Test vectors from BOLT 3 Appendix C: let feeest = TestFeeEstimator{fee_est: 15000}; let logger : Arc = Arc::new(test_utils::TestLogger::new()); @@ -5273,8 +5322,7 @@ mod tests { $( { $htlc_idx: expr, $counterparty_htlc_sig_hex: expr, $htlc_sig_hex: expr, $htlc_tx_hex: expr } ), * } ) => { { let (commitment_tx, htlcs): (_, Vec) = { - let mut res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw, &logger); - + let mut res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, false, chan.feerate_per_kw, &logger); let htlcs = res.2.drain(..) .filter_map(|(htlc, _)| if htlc.transaction_output_index.is_some() { Some(htlc) } else { None }) .collect(); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index fb0435a0d3d..c0036759030 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -14,6 +14,7 @@ use chain::{Confirm, Listen, Watch}; use chain::channelmonitor::ChannelMonitor; use chain::transaction::OutPoint; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; +use ln::channel::ANCHOR_OUTPUT_VALUE; use ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure}; use routing::router::{Route, get_route}; use routing::network_graph::{NetGraphMsgHandler, NetworkGraph}; @@ -189,6 +190,7 @@ pub struct TestChanMonCfg { pub persister: test_utils::TestPersister, pub logger: test_utils::TestLogger, pub keys_manager: test_utils::TestKeysInterface, + pub utxo_pool: test_utils::TestPool, } pub struct NodeCfg<'a> { @@ -310,7 +312,8 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { blocks: Arc::new(Mutex::new(self.tx_broadcaster.blocks.lock().unwrap().clone())), }; let chain_source = test_utils::TestChainSource::new(Network::Testnet); - let chain_monitor = test_utils::TestChainMonitor::new(Some(&chain_source), &broadcaster, &self.logger, &feeest, &persister, &self.keys_manager); + let utxo_pool = test_utils::TestPool::new(); + let chain_monitor = test_utils::TestChainMonitor::new(Some(&chain_source), &broadcaster, &self.logger, &feeest, &persister, &self.keys_manager, &utxo_pool); for deserialized_monitor in deserialized_monitors.drain(..) { if let Err(_) = chain_monitor.watch_channel(deserialized_monitor.get_funding_txo().0, deserialized_monitor) { panic!(); @@ -1296,8 +1299,9 @@ pub fn create_chanmon_cfgs(node_count: usize) -> Vec { let persister = test_utils::TestPersister::new(); let seed = [i as u8; 32]; let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet); + let utxo_pool = test_utils::TestPool::new(); - chan_mon_cfgs.push(TestChanMonCfg{ tx_broadcaster, fee_estimator, chain_source, logger, persister, keys_manager }); + chan_mon_cfgs.push(TestChanMonCfg{ tx_broadcaster, fee_estimator, chain_source, logger, persister, keys_manager, utxo_pool }); } chan_mon_cfgs @@ -1307,7 +1311,7 @@ pub fn create_node_cfgs<'a>(node_count: usize, chanmon_cfgs: &'a Vec(node: &Node<'a, 'b, 'c>, prev_txn: &Vec< res } +pub fn check_anchor_output(tx: &Transaction, anchors: u32) { + let mut counting = 0; + for outp in &tx.output { + if outp.value == ANCHOR_OUTPUT_VALUE { + counting += 1; + } + } + assert_eq!(counting, anchors); +} + pub fn handle_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec>, a: usize, b: usize, needs_err_handle: bool, expected_error: &str) { let events_1 = nodes[a].node.get_and_clear_pending_msg_events(); assert_eq!(events_1.len(), 2); diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 95d114aab5b..a79deb007fe 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -19,7 +19,7 @@ use chain::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PER use chain::transaction::OutPoint; use chain::keysinterface::{KeysInterface, BaseSign}; use ln::{PaymentPreimage, PaymentSecret, PaymentHash}; -use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC}; +use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC, COMMITMENT_TX_WEIGHT_PER_ANCHOR, ANCHOR_OUTPUT_VALUE}; use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA}; use ln::channel::{Channel, ChannelError}; use ln::{chan_utils, onion_utils}; @@ -41,6 +41,7 @@ use bitcoin::blockdata::script::Builder; use bitcoin::blockdata::opcodes; use bitcoin::blockdata::constants::genesis_block; use bitcoin::network::constants::Network; +use bitcoin::consensus::encode; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; @@ -573,7 +574,7 @@ fn test_update_fee_that_funder_cannot_afford() { let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); - let channel_value = 1888; + let channel_value = 1979 + 2 * ANCHOR_OUTPUT_VALUE; let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value, 700000, InitFeatures::known(), InitFeatures::known()); let channel_id = chan.2; @@ -587,20 +588,20 @@ fn test_update_fee_that_funder_cannot_afford() { commitment_signed_dance!(nodes[1], nodes[0], update_msg.commitment_signed, false); //Confirm that the new fee based on the last local commitment txn is what we expected based on the feerate of 260 set above. - //This value results in a fee that is exactly what the funder can afford (277 sat + 1000 sat channel reserve) + //This value results in a fee that is exactly what the funder can afford (277 sat + 1000 sat channel reserve + 2 * anchor output value) { let commitment_tx = get_local_commitment_txn!(nodes[1], channel_id)[0].clone(); - //We made sure neither party's funds are below the dust limit so -2 non-HTLC txns from number of outputs - let num_htlcs = commitment_tx.output.len() - 2; - let total_fee: u64 = feerate as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + //We made sure neither party's funds are below the dust limit so -2 non-HTLC txns from number of outputs and -2 for anchor outputs + let num_htlcs = commitment_tx.output.len() - 4; + let mut total_fee: u64 = feerate as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC + 2 * COMMITMENT_TX_WEIGHT_PER_ANCHOR) / 1000; let mut actual_fee = commitment_tx.output.iter().fold(0, |acc, output| acc + output.value); actual_fee = channel_value - actual_fee; assert_eq!(total_fee, actual_fee); } //Add 2 to the previous fee rate to the final fee increases by 1 (with no HTLCs the fee is essentially - //fee_rate*(724/1000) so the increment of 1*0.724 is rounded back down) + //fee_rate*(1124/1000) so the increment of 1*1.724 is rounded back down) nodes[0].node.update_fee(channel_id, feerate+2).unwrap(); check_added_monitors!(nodes[0], 1); @@ -1483,7 +1484,8 @@ fn test_duplicate_htlc_different_direction_onchain() { // Broadcast node 1 commitment txn let remote_txn = get_local_commitment_txn!(nodes[1], chan_1.2); - assert_eq!(remote_txn[0].output.len(), 4); // 1 local, 1 remote, 1 htlc inbound, 1 htlc outbound + assert_eq!(remote_txn[0].output.len(), 6); // 1 local, 1 remote, 1 htlc inbound, 1 htlc outbound, 2 anchors + check_anchor_output(&remote_txn[0], 2); let mut has_both_htlcs = 0; // check htlcs match ones committed for outp in remote_txn[0].output.iter() { if outp.value == 800_000 / 1000 { @@ -1547,16 +1549,17 @@ fn test_basic_channel_reserve() { let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); - let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known()); + let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 95_000_000, InitFeatures::known(), InitFeatures::known()); let logger = test_utils::TestLogger::new(); let chan_stat = get_channel_value_stat!(nodes[0], chan.2); let channel_reserve = chan_stat.channel_reserve_msat; // The 2* and +1 are for the fee spike reserve. + // The 2 * ANCHOR_OUTPUT_VALUE account for anchor output value. let (_, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(nodes[1]); - let commit_tx_fee = 2 * commit_tx_fee_msat(get_feerate!(nodes[0], chan.2), 1 + 1); - let max_can_send = 5000000 - channel_reserve - commit_tx_fee; + let commit_tx_fee = 2 * commit_tx_fee_msat_and_anchors(get_feerate!(nodes[0], chan.2), 1 + 1); + let max_can_send = 5_000_000 - channel_reserve - commit_tx_fee - (2 * ANCHOR_OUTPUT_VALUE * 1000); let net_graph_msg_handler = &nodes[0].net_graph_msg_handler; let route = get_route(&nodes[0].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes.last().unwrap().node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), max_can_send + 1, TEST_FINAL_CLTV, &logger).unwrap(); let err = nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).err().unwrap(); @@ -1582,7 +1585,7 @@ fn test_fee_spike_violation_fails_htlc() { let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); - let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known()); + let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 94253000, InitFeatures::known(), InitFeatures::known()); let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 3460001); // Need to manually create the update_add_htlc message to go around the channel reserve check in send_htlc() @@ -1615,22 +1618,24 @@ fn test_fee_spike_violation_fails_htlc() { // Get the EnforcingSigner for each channel, which will be used to (1) get the keys // needed to sign the new commitment tx and (2) sign the new commitment tx. - let (local_revocation_basepoint, local_htlc_basepoint, local_secret, next_local_point) = { + let (local_revocation_basepoint, local_htlc_basepoint, local_secret, next_local_point, local_funding_pubkey) = { let chan_lock = nodes[0].node.channel_state.lock().unwrap(); let local_chan = chan_lock.by_id.get(&chan.2).unwrap(); let chan_signer = local_chan.get_signer(); let pubkeys = chan_signer.pubkeys(); (pubkeys.revocation_basepoint, pubkeys.htlc_basepoint, chan_signer.release_commitment_secret(INITIAL_COMMITMENT_NUMBER), - chan_signer.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 2, &secp_ctx)) + chan_signer.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 2, &secp_ctx), + pubkeys.funding_pubkey) }; - let (remote_delayed_payment_basepoint, remote_htlc_basepoint,remote_point) = { + let (remote_delayed_payment_basepoint, remote_htlc_basepoint,remote_point, remote_funding_pubkey) = { let chan_lock = nodes[1].node.channel_state.lock().unwrap(); let remote_chan = chan_lock.by_id.get(&chan.2).unwrap(); let chan_signer = remote_chan.get_signer(); let pubkeys = chan_signer.pubkeys(); (pubkeys.delayed_payment_basepoint, pubkeys.htlc_basepoint, - chan_signer.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, &secp_ctx)) + chan_signer.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, &secp_ctx), + pubkeys.funding_pubkey) }; // Assemble the set of keys we can use for signatures for our commitment_signed message. @@ -1639,14 +1644,14 @@ fn test_fee_spike_violation_fails_htlc() { // Build the remote commitment transaction so we can sign it, and then later use the // signature for the commitment_signed message. - let local_chan_balance = 1313; + let local_chan_balance = 1311; let accepted_htlc_info = chan_utils::HTLCOutputInCommitment { offered: false, amount_msat: 3460001, cltv_expiry: htlc_cltv, payment_hash, - transaction_output_index: Some(1), + transaction_output_index: Some(3), }; let commitment_number = INITIAL_COMMITMENT_NUMBER - 1; @@ -1657,8 +1662,12 @@ fn test_fee_spike_violation_fails_htlc() { let local_chan_signer = local_chan.get_signer(); let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data( commitment_number, - 95000, + 94253, local_chan_balance, + true, + Some(&local_funding_pubkey), + true, + Some(&remote_funding_pubkey), commit_tx_keys.clone(), feerate_per_kw, &mut vec![(accepted_htlc_info, ())], @@ -1774,7 +1783,7 @@ fn test_chan_reserve_dust_inbound_htlcs_outbound_chan() { // Set nodes[0]'s balance such that they will consider any above-dust received HTLC to be a // channel reserve violation (so their balance is channel reserve (1000 sats) + commitment // transaction fee with 0 HTLCs (183 sats)). - create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 98817000, InitFeatures::known(), InitFeatures::known()); + create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100660, 98_157_000, InitFeatures::known(), InitFeatures::known()); let dust_amt = 329000; // Dust amount // In the previous code, routing this dust payment would cause nodes[0] to perceive a channel @@ -1791,7 +1800,7 @@ fn test_chan_reserve_dust_inbound_htlcs_inbound_chan() { let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]); let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); - create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 98000000, InitFeatures::known(), InitFeatures::known()); + create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100660, 97_340_000, InitFeatures::known(), InitFeatures::known()); let payment_amt = 46000; // Dust amount // In the previous code, these first four payments would succeed. @@ -1828,7 +1837,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() { let feerate = get_feerate!(nodes[0], chan.2); // Add a 2* and +1 for the fee spike reserve. - let commit_tx_fee_2_htlc = 2*commit_tx_fee_msat(feerate, 2 + 1); + let commit_tx_fee_2_htlc = 2*commit_tx_fee_msat_and_anchors(feerate, 2 + 1); let recv_value_1 = (chan_stat.value_to_self_msat - chan_stat.channel_reserve_msat - total_routing_fee_msat - commit_tx_fee_2_htlc)/2; let amt_msat_1 = recv_value_1 + total_routing_fee_msat; @@ -1845,7 +1854,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() { nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event_1.msgs[0]); // Attempt to trigger a channel reserve violation --> payment failure. - let commit_tx_fee_2_htlcs = commit_tx_fee_msat(feerate, 2); + let commit_tx_fee_2_htlcs = commit_tx_fee_msat_and_anchors(feerate, 2); let recv_value_2 = chan_stat.value_to_self_msat - amt_msat_1 - chan_stat.channel_reserve_msat - total_routing_fee_msat - commit_tx_fee_2_htlcs + 1; let amt_msat_2 = recv_value_2 + total_routing_fee_msat; let (route_2, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[2], amt_msat_2); @@ -1894,8 +1903,8 @@ fn test_inbound_outbound_capacity_is_not_zero() { assert_eq!(channels1[0].inbound_capacity_msat, 100000 * 1000 - 95000000); } -fn commit_tx_fee_msat(feerate: u32, num_htlcs: u64) -> u64 { - (COMMITMENT_TX_BASE_WEIGHT + num_htlcs * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate as u64 / 1000 * 1000 +fn commit_tx_fee_msat_and_anchors(feerate: u32, num_htlcs: u64) -> u64 { + (COMMITMENT_TX_BASE_WEIGHT + num_htlcs * COMMITMENT_TX_WEIGHT_PER_HTLC + 2 * COMMITMENT_TX_WEIGHT_PER_ANCHOR) * feerate as u64 / 1000 * 1000 } #[test] @@ -1947,7 +1956,7 @@ fn test_channel_reserve_holding_cell_htlcs() { // 3 for the 3 HTLCs that will be sent, 2* and +1 for the fee spike reserve. // Also, ensure that each payment has enough to be over the dust limit to // ensure it'll be included in each commit tx fee calculation. - let commit_tx_fee_all_htlcs = 2*commit_tx_fee_msat(feerate, 3 + 1); + let commit_tx_fee_all_htlcs = 2*commit_tx_fee_msat_and_anchors(feerate, 3 + 1) + (2 * ANCHOR_OUTPUT_VALUE * 1000); let ensure_htlc_amounts_above_dust_buffer = 3 * (stat01.counterparty_dust_limit_msat + 1000); if stat01.value_to_self_msat < stat01.channel_reserve_msat + commit_tx_fee_all_htlcs + ensure_htlc_amounts_above_dust_buffer + amt_msat { break; @@ -1979,7 +1988,7 @@ fn test_channel_reserve_holding_cell_htlcs() { // the amount of the first of these aforementioned 3 payments. The reason we split into 3 payments // is to test the behavior of the holding cell with respect to channel reserve and commit tx fee // policy. - let commit_tx_fee_2_htlcs = 2*commit_tx_fee_msat(feerate, 2 + 1); + let commit_tx_fee_2_htlcs = 2*commit_tx_fee_msat_and_anchors(feerate, 2 + 1) + (2 * ANCHOR_OUTPUT_VALUE * 1000); let recv_value_1 = (stat01.value_to_self_msat - stat01.channel_reserve_msat - total_fee_msat - commit_tx_fee_2_htlcs)/2; let amt_msat_1 = recv_value_1 + total_fee_msat; @@ -2004,7 +2013,7 @@ fn test_channel_reserve_holding_cell_htlcs() { } // split the rest to test holding cell - let commit_tx_fee_3_htlcs = 2*commit_tx_fee_msat(feerate, 3 + 1); + let commit_tx_fee_3_htlcs = 2*commit_tx_fee_msat_and_anchors(feerate, 3 + 1) + (2 * ANCHOR_OUTPUT_VALUE * 1000); let additional_htlc_cost_msat = commit_tx_fee_3_htlcs - commit_tx_fee_2_htlcs; let recv_value_21 = recv_value_2/2 - additional_htlc_cost_msat/2; let recv_value_22 = recv_value_2 - recv_value_21 - total_fee_msat - additional_htlc_cost_msat; @@ -2105,11 +2114,11 @@ fn test_channel_reserve_holding_cell_htlcs() { claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), our_payment_preimage_21); claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), our_payment_preimage_22); - let commit_tx_fee_0_htlcs = 2*commit_tx_fee_msat(feerate, 1); + let commit_tx_fee_0_htlcs = 2*commit_tx_fee_msat_and_anchors(feerate, 1) + 2 * ANCHOR_OUTPUT_VALUE * 1000; let recv_value_3 = commit_tx_fee_2_htlcs - commit_tx_fee_0_htlcs - total_fee_msat; send_payment(&nodes[0], &vec![&nodes[1], &nodes[2]][..], recv_value_3); - let commit_tx_fee_1_htlc = 2*commit_tx_fee_msat(feerate, 1 + 1); + let commit_tx_fee_1_htlc = 2*commit_tx_fee_msat_and_anchors(feerate, 1 + 1) + 2 * ANCHOR_OUTPUT_VALUE * 1000; let expected_value_to_self = stat01.value_to_self_msat - (recv_value_1 + total_fee_msat) - (recv_value_21 + total_fee_msat) - (recv_value_22 + total_fee_msat) - (recv_value_3 + total_fee_msat); let stat0 = get_channel_value_stat!(nodes[0], chan_1.2); assert_eq!(stat0.value_to_self_msat, expected_value_to_self); @@ -2477,7 +2486,8 @@ fn test_justice_tx() { assert_eq!(revoked_local_txn.len(), 2); // First commitment tx, then HTLC tx assert_eq!(revoked_local_txn[0].input.len(), 1); assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, chan_5.3.txid()); - assert_eq!(revoked_local_txn[0].output.len(), 2); // Only HTLC and output back to 0 are present + assert_eq!(revoked_local_txn[0].output.len(), 4); // Only HTLC and output back to 0 are present (+ 0's anchor) + check_anchor_output(&revoked_local_txn[0], 2); assert_eq!(revoked_local_txn[1].input.len(), 1); assert_eq!(revoked_local_txn[1].input[0].previous_output.txid, revoked_local_txn[0].txid()); assert_eq!(revoked_local_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC-Timeout @@ -2527,7 +2537,8 @@ fn test_justice_tx() { assert_eq!(revoked_local_txn.len(), 1); // Only commitment tx assert_eq!(revoked_local_txn[0].input.len(), 1); assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, chan_6.3.txid()); - assert_eq!(revoked_local_txn[0].output.len(), 2); // Only HTLC and output back to A are present + assert_eq!(revoked_local_txn[0].output.len(), 4); // Only HTLC and output back to A are present (+ A's anchor) + check_anchor_output(&revoked_local_txn[0], 2); // Revoke the old state claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage_4); { @@ -2567,7 +2578,8 @@ fn revoked_output_claim() { let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan_1.2); assert_eq!(revoked_local_txn.len(), 1); // Only output is the full channel value back to nodes[0]: - assert_eq!(revoked_local_txn[0].output.len(), 1); + assert_eq!(revoked_local_txn[0].output.len(), 2); + check_anchor_output(&revoked_local_txn[0], 1); // Send a payment through, updating everyone's latest commitment txn send_payment(&nodes[0], &vec!(&nodes[1])[..], 5000000); @@ -3136,7 +3148,8 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use let (payment_preimage, _payment_hash, _payment_secret) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], if no_to_remote { 10_000 } else { 3_000_000 }); // Get the will-be-revoked local txn from nodes[2] let revoked_local_txn = get_local_commitment_txn!(nodes[2], chan_2.2); - assert_eq!(revoked_local_txn[0].output.len(), if no_to_remote { 1 } else { 2 }); + assert_eq!(revoked_local_txn[0].output.len(), if no_to_remote { 3 } else { 4 }); + check_anchor_output(&revoked_local_txn[0], 2); // Revoke the old state claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage); @@ -3508,7 +3521,7 @@ fn test_force_close_fail_back() { { let mut monitors = nodes[2].chain_monitor.chain_monitor.monitors.read().unwrap(); monitors.get(&OutPoint{ txid: Txid::from_slice(&payment_event.commitment_msg.channel_id[..]).unwrap(), index: 0 }).unwrap() - .provide_payment_preimage(&our_payment_hash, &our_payment_preimage, &node_cfgs[2].tx_broadcaster, &node_cfgs[2].fee_estimator, &&logger); + .provide_payment_preimage(&our_payment_hash, &our_payment_preimage, &node_cfgs[2].tx_broadcaster, &node_cfgs[2].fee_estimator, &&logger, &&chanmon_cfgs[0].utxo_pool); } mine_transaction(&nodes[2], &tx); let node_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap(); @@ -3923,7 +3936,7 @@ fn test_funding_peer_disconnect() { persister = test_utils::TestPersister::new(); let keys_manager = &chanmon_cfgs[0].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager); + new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager, &chanmon_cfgs[0].utxo_pool); nodes[0].chain_monitor = &new_chain_monitor; let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( @@ -4347,6 +4360,7 @@ fn test_no_txn_manager_serialize_deserialize() { let logger: test_utils::TestLogger; let fee_estimator: test_utils::TestFeeEstimator; let persister: test_utils::TestPersister; + let utxo_pool: test_utils::TestPool; let new_chain_monitor: test_utils::TestChainMonitor; let nodes_0_deserialized: ChannelManager; let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -4362,8 +4376,9 @@ fn test_no_txn_manager_serialize_deserialize() { logger = test_utils::TestLogger::new(); fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 }; persister = test_utils::TestPersister::new(); + utxo_pool = test_utils::TestPool::new(); let keys_manager = &chanmon_cfgs[0].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &persister, keys_manager); + new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &persister, keys_manager, &utxo_pool); nodes[0].chain_monitor = &new_chain_monitor; let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( @@ -4486,7 +4501,7 @@ fn test_dup_htlc_onchain_fails_on_reload() { // Now reload nodes[0]... persister = test_utils::TestPersister::new(); let keys_manager = &chanmon_cfgs[0].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager); + new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager, &chanmon_cfgs[0].utxo_pool); nodes[0].chain_monitor = &new_chain_monitor; let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( @@ -4530,6 +4545,7 @@ fn test_manager_serialize_deserialize_events() { let fee_estimator: test_utils::TestFeeEstimator; let persister: test_utils::TestPersister; let logger: test_utils::TestLogger; + let utxo_pool: test_utils::TestPool; let new_chain_monitor: test_utils::TestChainMonitor; let nodes_0_deserialized: ChannelManager; let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -4578,8 +4594,9 @@ fn test_manager_serialize_deserialize_events() { fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 }; logger = test_utils::TestLogger::new(); persister = test_utils::TestPersister::new(); + utxo_pool = test_utils::TestPool::new(); let keys_manager = &chanmon_cfgs[0].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &persister, keys_manager); + new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &persister, keys_manager, &utxo_pool); nodes[0].chain_monitor = &new_chain_monitor; let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( @@ -4648,6 +4665,7 @@ fn test_simple_manager_serialize_deserialize() { let logger: test_utils::TestLogger; let fee_estimator: test_utils::TestFeeEstimator; let persister: test_utils::TestPersister; + let utxo_pool: test_utils::TestPool; let new_chain_monitor: test_utils::TestChainMonitor; let nodes_0_deserialized: ChannelManager; let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -4665,8 +4683,9 @@ fn test_simple_manager_serialize_deserialize() { logger = test_utils::TestLogger::new(); fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 }; persister = test_utils::TestPersister::new(); + utxo_pool = test_utils::TestPool::new(); let keys_manager = &chanmon_cfgs[0].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &persister, keys_manager); + new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &persister, keys_manager, &utxo_pool); nodes[0].chain_monitor = &new_chain_monitor; let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( @@ -4709,6 +4728,7 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() { let logger: test_utils::TestLogger; let fee_estimator: test_utils::TestFeeEstimator; let persister: test_utils::TestPersister; + let utxo_pool: test_utils::TestPool; let new_chain_monitor: test_utils::TestChainMonitor; let nodes_0_deserialized: ChannelManager; let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs); @@ -4745,11 +4765,11 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() { logger = test_utils::TestLogger::new(); fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 }; persister = test_utils::TestPersister::new(); + utxo_pool = test_utils::TestPool::new(); let keys_manager = &chanmon_cfgs[0].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &persister, keys_manager); + new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &persister, keys_manager, &utxo_pool); nodes[0].chain_monitor = &new_chain_monitor; - let mut node_0_stale_monitors = Vec::new(); for serialized in node_0_stale_monitors_serialized.iter() { let mut read = &serialized[..]; @@ -4873,6 +4893,7 @@ fn test_claim_sizeable_push_msat() { assert_eq!(node_txn.len(), 1); check_spends!(node_txn[0], chan.3); assert_eq!(node_txn[0].output.len(), 2); // We can't force trimming of to_remote output as channel_reserve_satoshis block us to do so at channel opening + check_anchor_output(&node_txn[0], 1); mine_transaction(&nodes[1], &node_txn[0]); connect_blocks(&nodes[1], BREAKDOWN_TIMEOUT as u32 - 1); @@ -4902,6 +4923,7 @@ fn test_claim_on_remote_sizeable_push_msat() { assert_eq!(node_txn.len(), 1); check_spends!(node_txn[0], chan.3); assert_eq!(node_txn[0].output.len(), 2); // We can't force trimming of to_remote output as channel_reserve_satoshis block us to do so at channel opening + check_anchor_output(&node_txn[0], 1); mine_transaction(&nodes[1], &node_txn[0]); check_closed_broadcast!(nodes[1], true); @@ -5158,7 +5180,8 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() { assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, chan_1.3.txid()); // The to-be-revoked commitment tx should have one HTLC and one to_remote output - assert_eq!(revoked_local_txn[0].output.len(), 2); + assert_eq!(revoked_local_txn[0].output.len(), 4); + check_anchor_output(&revoked_local_txn[0], 2); claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage); @@ -5547,7 +5570,8 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno // Rebalance and check output sanity... send_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], 500000); send_payment(&nodes[1], &[&nodes[2], &nodes[3], &nodes[5]], 500000); - assert_eq!(get_local_commitment_txn!(nodes[3], chan.2)[0].output.len(), 2); + assert_eq!(get_local_commitment_txn!(nodes[3], chan.2)[0].output.len(), 4); + check_anchor_output(&get_local_commitment_txn!(nodes[3], chan.2)[0], 2); let ds_dust_limit = nodes[3].node.channel_state.lock().unwrap().by_id.get(&chan.2).unwrap().holder_dust_limit_satoshis; // 0th HTLC: @@ -5587,7 +5611,8 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno // We now have six HTLCs pending over the dust limit and six HTLCs under the dust limit (ie, // with to_local and to_remote outputs, 8 outputs and 6 HTLCs not included). assert_eq!(get_local_commitment_txn!(nodes[3], chan.2).len(), 1); - assert_eq!(get_local_commitment_txn!(nodes[3], chan.2)[0].output.len(), 8); + assert_eq!(get_local_commitment_txn!(nodes[3], chan.2)[0].output.len(), 10); + check_anchor_output(&get_local_commitment_txn!(nodes[3], chan.2)[0], 2); // Now fail back three of the over-dust-limit and three of the under-dust-limit payments in one go. // Fail 0th below-dust, 4th above-dust, 8th above-dust, 10th below-dust HTLCs @@ -5833,7 +5858,7 @@ fn test_key_derivation_params() { // We manually create the node configuration to backup the seed. let seed = [42; 32]; let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet); - let chain_monitor = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[0].chain_source), &chanmon_cfgs[0].tx_broadcaster, &chanmon_cfgs[0].logger, &chanmon_cfgs[0].fee_estimator, &chanmon_cfgs[0].persister, &keys_manager); + let chain_monitor = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[0].chain_source), &chanmon_cfgs[0].tx_broadcaster, &chanmon_cfgs[0].logger, &chanmon_cfgs[0].fee_estimator, &chanmon_cfgs[0].persister, &keys_manager, &chanmon_cfgs[0].utxo_pool); let node = NodeCfg { chain_source: &chanmon_cfgs[0].chain_source, logger: &chanmon_cfgs[0].logger, tx_broadcaster: &chanmon_cfgs[0].tx_broadcaster, fee_estimator: &chanmon_cfgs[0].fee_estimator, chain_monitor, keys_manager: &keys_manager, node_seed: seed }; let mut node_cfgs = create_node_cfgs(3, &chanmon_cfgs); node_cfgs.remove(0); @@ -6214,7 +6239,7 @@ fn test_fail_holding_cell_htlc_upon_free() { // 2* and +1 HTLCs on the commit tx fee calculation for the fee spike reserve. let (_, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(nodes[1]); - let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 1 + 1); + let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat_and_anchors(feerate, 1 + 1) - (2 * ANCHOR_OUTPUT_VALUE * 1000); let net_graph_msg_handler = &nodes[0].net_graph_msg_handler; let route = get_route(&nodes[0].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[1].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &[], max_can_send, TEST_FINAL_CLTV, &logger).unwrap(); @@ -6289,7 +6314,7 @@ fn test_free_and_fail_holding_cell_htlcs() { let (payment_preimage_1, payment_hash_1, payment_secret_1) = get_payment_preimage_hash!(nodes[1]); let amt_1 = 20000; let (_, payment_hash_2, payment_secret_2) = get_payment_preimage_hash!(nodes[1]); - let amt_2 = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 2 + 1) - amt_1; + let amt_2 = 5000000 - channel_reserve - 2*commit_tx_fee_msat_and_anchors(feerate, 2 + 1) - amt_1 - (2 * ANCHOR_OUTPUT_VALUE * 1000); let net_graph_msg_handler = &nodes[0].net_graph_msg_handler; let route_1 = get_route(&nodes[0].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[1].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &[], amt_1, TEST_FINAL_CLTV, &logger).unwrap(); let route_2 = get_route(&nodes[0].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[1].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &[], amt_2, TEST_FINAL_CLTV, &logger).unwrap(); @@ -6412,7 +6437,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() { let feemsat = 239; let total_routing_fee_msat = (nodes.len() - 2) as u64 * feemsat; let (_, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(nodes[2]); - let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 1 + 1) - total_routing_fee_msat; + let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat_and_anchors(feerate, 1 + 1) - total_routing_fee_msat - (2 * ANCHOR_OUTPUT_VALUE * 1000); let payment_event = { let net_graph_msg_handler = &nodes[0].net_graph_msg_handler; let route = get_route(&nodes[0].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[2].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &[], max_can_send, TEST_FINAL_CLTV, &logger).unwrap(); @@ -6726,9 +6751,9 @@ fn test_update_add_htlc_bolt2_receiver_sender_can_afford_amount_sent() { let channel_reserve = chan_stat.channel_reserve_msat; let feerate = get_feerate!(nodes[0], chan.2); // The 2* and +1 are for the fee spike reserve. - let commit_tx_fee_outbound = 2 * commit_tx_fee_msat(feerate, 1 + 1); + let commit_tx_fee_outbound = 2 * commit_tx_fee_msat_and_anchors(feerate, 1 + 1); - let max_can_send = 5000000 - channel_reserve - commit_tx_fee_outbound; + let max_can_send = 5000000 - channel_reserve - commit_tx_fee_outbound - (2 * ANCHOR_OUTPUT_VALUE * 1000); let (_, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(nodes[1]); let net_graph_msg_handler = &nodes[0].net_graph_msg_handler; let route = get_route(&nodes[0].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[1].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &[], max_can_send, TEST_FINAL_CLTV, &logger).unwrap(); @@ -7677,6 +7702,7 @@ fn test_data_loss_protect() { let keys_manager = &chanmon_cfgs[0].keys_manager; let monitor; let node_state_0; + let utxo_pool; let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -7701,7 +7727,8 @@ fn test_data_loss_protect() { tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))}; fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 }; persister = test_utils::TestPersister::new(); - monitor = test_utils::TestChainMonitor::new(Some(&chain_source), &tx_broadcaster, &logger, &fee_estimator, &persister, keys_manager); + utxo_pool = test_utils::TestPool::new(); + monitor = test_utils::TestChainMonitor::new(Some(&chain_source), &tx_broadcaster, &logger, &fee_estimator, &persister, keys_manager, &utxo_pool); node_state_0 = { let mut channel_monitors = HashMap::new(); channel_monitors.insert(OutPoint { txid: chan.3.txid(), index: 0 }, &mut chain_monitor); @@ -7764,7 +7791,8 @@ fn test_data_loss_protect() { let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); assert_eq!(node_txn.len(), 1); check_spends!(node_txn[0], chan.3); - assert_eq!(node_txn[0].output.len(), 2); + assert_eq!(node_txn[0].output.len(), 4); + check_anchor_output(&node_txn[0], 2); mine_transaction(&nodes[0], &node_txn[0]); connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1); let spend_txn = check_spendable_outputs!(nodes[0], 1, node_cfgs[0].keys_manager, 1000000); @@ -7930,7 +7958,8 @@ fn test_bump_penalty_txn_on_revoked_commitment() { let revoked_txn = get_local_commitment_txn!(nodes[0], chan.2); // Revoked commitment txn with 4 outputs : to_local, to_remote, 1 outgoing HTLC, 1 incoming HTLC - assert_eq!(revoked_txn[0].output.len(), 4); + assert_eq!(revoked_txn[0].output.len(), 6); + check_anchor_output(&revoked_txn[0], 2); assert_eq!(revoked_txn[0].input.len(), 1); assert_eq!(revoked_txn[0].input[0].previous_output.txid, chan.3.txid()); let revoked_txid = revoked_txn[0].txid(); @@ -8198,7 +8227,8 @@ fn test_bump_penalty_txn_on_remote_commitment() { // Remote commitment txn with 4 outputs : to_local, to_remote, 1 outgoing HTLC, 1 incoming HTLC let remote_txn = get_local_commitment_txn!(nodes[0], chan.2); - assert_eq!(remote_txn[0].output.len(), 4); + assert_eq!(remote_txn[0].output.len(), 6); + check_anchor_output(&remote_txn[0], 2); assert_eq!(remote_txn[0].input.len(), 1); assert_eq!(remote_txn[0].input[0].previous_output.txid, chan.3.txid()); @@ -8627,6 +8657,7 @@ fn test_update_err_monitor_lockdown() { let chain_source = test_utils::TestChainSource::new(Network::Testnet); let logger = test_utils::TestLogger::with_id(format!("node {}", 0)); let persister = test_utils::TestPersister::new(); + let utxo_pool = test_utils::TestPool::new(); let watchtower = { let monitors = nodes[0].chain_monitor.chain_monitor.monitors.read().unwrap(); let monitor = monitors.get(&outpoint).unwrap(); @@ -8635,7 +8666,7 @@ fn test_update_err_monitor_lockdown() { let new_monitor = <(BlockHash, channelmonitor::ChannelMonitor)>::read( &mut ::std::io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1; assert!(new_monitor == *monitor); - let watchtower = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager); + let watchtower = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager, &utxo_pool); assert!(watchtower.watch_channel(outpoint, new_monitor).is_ok()); watchtower }; @@ -8689,6 +8720,7 @@ fn test_concurrent_monitor_claim() { let chain_source = test_utils::TestChainSource::new(Network::Testnet); let logger = test_utils::TestLogger::with_id(format!("node {}", "Alice")); let persister = test_utils::TestPersister::new(); + let utxo_pool = test_utils::TestPool::new(); let watchtower_alice = { let monitors = nodes[0].chain_monitor.chain_monitor.monitors.read().unwrap(); let monitor = monitors.get(&outpoint).unwrap(); @@ -8697,7 +8729,7 @@ fn test_concurrent_monitor_claim() { let new_monitor = <(BlockHash, channelmonitor::ChannelMonitor)>::read( &mut ::std::io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1; assert!(new_monitor == *monitor); - let watchtower = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager); + let watchtower = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager, &utxo_pool); assert!(watchtower.watch_channel(outpoint, new_monitor).is_ok()); watchtower }; @@ -8726,7 +8758,7 @@ fn test_concurrent_monitor_claim() { let new_monitor = <(BlockHash, channelmonitor::ChannelMonitor)>::read( &mut ::std::io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1; assert!(new_monitor == *monitor); - let watchtower = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager); + let watchtower = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager, &utxo_pool); assert!(watchtower.watch_channel(outpoint, new_monitor).is_ok()); watchtower }; @@ -8840,7 +8872,8 @@ fn test_htlc_no_detection() { let (_, our_payment_hash, _) = route_payment(&nodes[0], &vec!(&nodes[1])[..], 2_000_000); let local_txn = get_local_commitment_txn!(nodes[0], chan_1.2); assert_eq!(local_txn[0].input.len(), 1); - assert_eq!(local_txn[0].output.len(), 3); + assert_eq!(local_txn[0].output.len(), 5); + check_anchor_output(&local_txn[0], 2); check_spends!(local_txn[0], chan_1.3); // Timeout HTLC on A's chain and so it can generate a HTLC-Timeout tx @@ -8897,7 +8930,8 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain // Check that Alice's commitment transaction now contains an output for this HTLC. let alice_txn = get_local_commitment_txn!(nodes[0], chan_ab.2); check_spends!(alice_txn[0], chan_ab.3); - assert_eq!(alice_txn[0].output.len(), 2); + assert_eq!(alice_txn[0].output.len(), 4); + check_anchor_output(&alice_txn[0], 2); check_spends!(alice_txn[1], alice_txn[0]); // 2nd transaction is a non-final HTLC-timeout assert_eq!(alice_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); assert_eq!(alice_txn.len(), 2); diff --git a/lightning/src/ln/reorg_tests.rs b/lightning/src/ln/reorg_tests.rs index fb316caf2ef..6d2b029cb01 100644 --- a/lightning/src/ln/reorg_tests.rs +++ b/lightning/src/ln/reorg_tests.rs @@ -69,7 +69,8 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) { // Broadcast node 1 commitment txn to broadcast the HTLC-Timeout let node_1_commitment_txn = get_local_commitment_txn!(nodes[1], chan_2.2); assert_eq!(node_1_commitment_txn.len(), 2); // 1 local commitment tx, 1 Outbound HTLC-Timeout - assert_eq!(node_1_commitment_txn[0].output.len(), 2); // to-self and Offered HTLC (to-remote/to-node-3 is dust) + assert_eq!(node_1_commitment_txn[0].output.len(), 4); // to-self + Offered HTLC (to-remote/to-node-3 is dust) + anchor output + check_anchor_output(&node_1_commitment_txn[0], 2); check_spends!(node_1_commitment_txn[0], chan_2.3); check_spends!(node_1_commitment_txn[1], node_1_commitment_txn[0]); @@ -79,7 +80,8 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) { check_closed_broadcast!(nodes[2], true); // We should get a BroadcastChannelUpdate (and *only* a BroadcstChannelUpdate) let node_2_commitment_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_2_commitment_txn.len(), 3); // ChannelMonitor: 1 offered HTLC-Claim, ChannelManger: 1 local commitment tx, 1 Received HTLC-Claim - assert_eq!(node_2_commitment_txn[1].output.len(), 2); // to-remote and Received HTLC (to-self is dust) + assert_eq!(node_2_commitment_txn[1].output.len(), 4); // to-remote + Received HTLC (to-self is dust) + anchor output + check_anchor_output(&node_2_commitment_txn[1], 2); check_spends!(node_2_commitment_txn[1], chan_2.3); check_spends!(node_2_commitment_txn[2], node_2_commitment_txn[1]); check_spends!(node_2_commitment_txn[0], node_1_commitment_txn[0]); @@ -96,7 +98,8 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) { // Broadcast node 2 commitment txn let node_2_commitment_txn = get_local_commitment_txn!(nodes[2], chan_2.2); assert_eq!(node_2_commitment_txn.len(), 2); // 1 local commitment tx, 1 Received HTLC-Claim - assert_eq!(node_2_commitment_txn[0].output.len(), 2); // to-remote and Received HTLC (to-self is dust) + assert_eq!(node_2_commitment_txn[0].output.len(), 4); // to-remote + Received HTLC (to-self is dust) + anchor output + check_anchor_output(&node_2_commitment_txn[0], 2); check_spends!(node_2_commitment_txn[0], chan_2.3); check_spends!(node_2_commitment_txn[1], node_2_commitment_txn[0]); @@ -105,7 +108,8 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) { connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires let node_1_commitment_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); assert_eq!(node_1_commitment_txn.len(), 2); // ChannelMonitor: 1 offered HTLC-Timeout, ChannelManger: 1 local commitment tx - assert_eq!(node_1_commitment_txn[0].output.len(), 2); // to-local and Offered HTLC (to-remote is dust) + assert_eq!(node_1_commitment_txn[0].output.len(), 4); // to-local and Offered HTLC (to-remote is dust) + check_anchor_output(&node_1_commitment_txn[0], 2); check_spends!(node_1_commitment_txn[0], chan_2.3); check_spends!(node_1_commitment_txn[1], node_2_commitment_txn[0]); @@ -193,6 +197,7 @@ fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_ let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let persister: test_utils::TestPersister; + let utxo_pool: test_utils::TestPool; let new_chain_monitor: test_utils::TestChainMonitor; let nodes_0_deserialized: ChannelManager; let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -237,7 +242,7 @@ fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_ persister = test_utils::TestPersister::new(); let keys_manager = &chanmon_cfgs[0].keys_manager; - new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager); + new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager, &chanmon_cfgs[0].utxo_pool); nodes[0].chain_monitor = &new_chain_monitor; let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..]; let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor)>::read( @@ -352,7 +357,8 @@ fn test_set_outpoints_partial_claiming() { // Remote commitment txn with 4 outputs: to_local, to_remote, 2 outgoing HTLC let remote_txn = get_local_commitment_txn!(nodes[1], chan.2); assert_eq!(remote_txn.len(), 3); - assert_eq!(remote_txn[0].output.len(), 4); + assert_eq!(remote_txn[0].output.len(), 6); + check_anchor_output(&remote_txn[0], 2); assert_eq!(remote_txn[0].input.len(), 1); assert_eq!(remote_txn[0].input[0].previous_output.txid, chan.3.txid()); check_spends!(remote_txn[1], remote_txn[0]); diff --git a/lightning/src/util/enforcing_trait_impls.rs b/lightning/src/util/enforcing_trait_impls.rs index 26f9d87bba9..92424244e79 100644 --- a/lightning/src/util/enforcing_trait_impls.rs +++ b/lightning/src/util/enforcing_trait_impls.rs @@ -160,6 +160,10 @@ impl BaseSign for EnforcingSigner { Ok(self.inner.sign_closing_transaction(closing_tx, secp_ctx).unwrap()) } + fn sign_cpfp(&self, cpfp_tx: &Transaction, input_index: usize, spent_amount: u64, secp_ctx: &Secp256k1) -> Result { + Ok(self.inner.sign_cpfp(cpfp_tx, input_index, spent_amount, secp_ctx).unwrap()) + } + fn sign_channel_announcement(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1) -> Result { self.inner.sign_channel_announcement(msg, secp_ctx) } diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 60aafd9169a..f725b49d757 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -14,8 +14,10 @@ use chain::chaininterface::ConfirmationTarget; use chain::chainmonitor; use chain::channelmonitor; use chain::channelmonitor::MonitorEvent; +use chain::package::BumpingOutput; use chain::transaction::OutPoint; use chain::keysinterface; +use chain::utxointerface::UtxoPool; use ln::features::{ChannelFeatures, InitFeatures}; use ln::msgs; use ln::msgs::OptionalField; @@ -25,11 +27,12 @@ use util::logger::{Logger, Level, Record}; use util::ser::{Readable, ReadableArgs, Writer, Writeable}; use bitcoin::blockdata::constants::genesis_block; -use bitcoin::blockdata::transaction::{Transaction, TxOut}; +use bitcoin::blockdata::transaction::{Transaction, TxOut, OutPoint as BitcoinOutPoint}; use bitcoin::blockdata::script::{Builder, Script}; use bitcoin::blockdata::opcodes; use bitcoin::blockdata::block::BlockHeader; use bitcoin::network::constants::Network; +use bitcoin::hashes::hex::FromHex; use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::secp256k1::{SecretKey, PublicKey, Secp256k1, Signature}; @@ -65,6 +68,42 @@ impl chaininterface::FeeEstimator for TestFeeEstimator { } } +pub struct TestPool { + //TODO: lock + utxo_available: Mutex>, +} + +impl UtxoPool for TestPool { + fn allocate_utxo(&self, required_fee: u64) -> Option<(BitcoinOutPoint, BumpingOutput)> { + let utxo_available = self.utxo_available.lock().unwrap(); + // We copy our bumping utxo to synchronize between duplicate monitors (e.g watchtower + // test) + Some(utxo_available.first().unwrap().clone()) + } + fn free_utxo(&self, free_utxo: BitcoinOutPoint) {} + fn provide_utxo_witness(&self, cpfp_transaction: &Transaction, utxo_index: u32) -> Result>, ()> { + let script = Builder::new().push_opcode(opcodes::OP_TRUE).into_script(); + Ok(vec![script.into_bytes()]) + } +} + +impl TestPool { + pub fn new() -> Self { + let outp = BitcoinOutPoint { + txid: Txid::from_hex("56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f64a").unwrap(), + vout: 0, + }; + let script = Builder::new().push_opcode(opcodes::OP_TRUE).into_script(); + let bumping = BumpingOutput::new(TEST_BUMP_VALUE, 3 as u64); + let utxo_available = Mutex::new(vec![(outp, bumping)]); + TestPool { + utxo_available, + } + } +} + +pub const TEST_BUMP_VALUE: u64 = 100_000; // 1 mBTC + pub struct OnlyReadsKeysInterface {} impl keysinterface::KeysInterface for OnlyReadsKeysInterface { type Signer = EnforcingSigner; @@ -84,7 +123,7 @@ impl keysinterface::KeysInterface for OnlyReadsKeysInterface { pub struct TestChainMonitor<'a> { pub added_monitors: Mutex)>>, pub latest_monitor_update_id: Mutex>, - pub chain_monitor: chainmonitor::ChainMonitor>, + pub chain_monitor: chainmonitor::ChainMonitor, &'a UtxoPool>, pub keys_manager: &'a TestKeysInterface, pub update_ret: Mutex>>, /// If this is set to Some(), after the next return, we'll always return this until update_ret @@ -95,12 +134,13 @@ pub struct TestChainMonitor<'a> { /// boolean. pub expect_channel_force_closed: Mutex>, } + impl<'a> TestChainMonitor<'a> { - pub fn new(chain_source: Option<&'a TestChainSource>, broadcaster: &'a chaininterface::BroadcasterInterface, logger: &'a TestLogger, fee_estimator: &'a TestFeeEstimator, persister: &'a channelmonitor::Persist, keys_manager: &'a TestKeysInterface) -> Self { + pub fn new(chain_source: Option<&'a TestChainSource>, broadcaster: &'a chaininterface::BroadcasterInterface, logger: &'a TestLogger, fee_estimator: &'a TestFeeEstimator, persister: &'a channelmonitor::Persist, keys_manager: &'a TestKeysInterface, utxo_pool: &'a UtxoPool) -> Self { Self { added_monitors: Mutex::new(Vec::new()), latest_monitor_update_id: Mutex::new(HashMap::new()), - chain_monitor: chainmonitor::ChainMonitor::new(chain_source, broadcaster, logger, fee_estimator, persister), + chain_monitor: chainmonitor::ChainMonitor::new(chain_source, broadcaster, logger, fee_estimator, persister, utxo_pool), keys_manager, update_ret: Mutex::new(None), next_update_ret: Mutex::new(None),