X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=66d083377b0e6c23b5f863adb1c2f2aa0b7f98a4;hb=2c0fcf21f227ad1a01e4a884dda72b9537c16fae;hp=cffb968bd9a31cc4e7b875dbd51bff457131258e;hpb=36429e8245959c6020fbd24ce11fd98d83b5c5e8;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index cffb968b..66d08337 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -44,19 +44,20 @@ use crate::chain::{BestBlock, WatchedOutput}; use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator}; use crate::chain::transaction::{OutPoint, TransactionData}; use crate::sign::{ChannelDerivationParameters, HTLCDescriptor, SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, ecdsa::WriteableEcdsaChannelSigner, SignerProvider, EntropySource}; -use crate::chain::onchaintx::{ClaimEvent, OnchainTxHandler}; +use crate::chain::onchaintx::{ClaimEvent, FeerateStrategy, OnchainTxHandler}; use crate::chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput}; use crate::chain::Filter; use crate::util::logger::{Logger, Record}; use crate::util::ser::{Readable, ReadableArgs, RequiredWrapper, MaybeReadable, UpgradableRequired, Writer, Writeable, U48}; use crate::util::byte_utils; -use crate::events::{Event, EventHandler}; +use crate::events::{ClosureReason, Event, EventHandler}; use crate::events::bump_transaction::{AnchorDescriptor, BumpTransactionEvent}; +#[allow(unused_imports)] use crate::prelude::*; + use core::{cmp, mem}; use crate::io::{self, Error}; -use core::convert::TryInto; use core::ops::Deref; use crate::sync::{Mutex, LockTestExt}; @@ -155,6 +156,17 @@ pub enum MonitorEvent { /// A monitor event containing an HTLCUpdate. HTLCEvent(HTLCUpdate), + /// Indicates we broadcasted the channel's latest commitment transaction and thus closed the + /// channel. Holds information about the channel and why it was closed. + HolderForceClosedWithInfo { + /// The reason the channel was closed. + reason: ClosureReason, + /// The funding outpoint of the channel. + outpoint: OutPoint, + /// The channel ID of the channel. + channel_id: ChannelId, + }, + /// Indicates we broadcasted the channel's latest commitment transaction and thus closed the /// channel. HolderForceClosed(OutPoint), @@ -184,6 +196,11 @@ impl_writeable_tlv_based_enum_upgradable!(MonitorEvent, (2, monitor_update_id, required), (4, channel_id, required), }, + (5, HolderForceClosedWithInfo) => { + (0, reason, upgradable_required), + (2, outpoint, required), + (4, channel_id, required), + }, ; (2, HTLCEvent), (4, HolderForceClosed), @@ -387,7 +404,7 @@ impl OnchainEventEntry { } fn has_reached_confirmation_threshold(&self, best_block: &BestBlock) -> bool { - best_block.height() >= self.confirmation_threshold() + best_block.height >= self.confirmation_threshold() } } @@ -918,6 +935,9 @@ pub(crate) struct ChannelMonitorImpl { /// Ordering of tuple data: (their_per_commitment_point, feerate_per_kw, to_broadcaster_sats, /// to_countersignatory_sats) initial_counterparty_commitment_info: Option<(PublicKey, u32, u64, u64)>, + + /// The first block height at which we had no remaining claimable balances. + balances_empty_height: Option, } /// Transaction outputs to watch for on-chain spends. @@ -1059,6 +1079,7 @@ impl Writeable for ChannelMonitorImpl true, MonitorEvent::HolderForceClosed(_) => true, + MonitorEvent::HolderForceClosedWithInfo { .. } => true, _ => false, }).count() as u64).to_be_bytes())?; for event in self.pending_monitor_events.iter() { @@ -1068,6 +1089,10 @@ impl Writeable for ChannelMonitorImpl 1u8.write(writer)?, + // `HolderForceClosedWithInfo` replaced `HolderForceClosed` in v0.0.122. To keep + // backwards compatibility, we write a `HolderForceClosed` event along with the + // `HolderForceClosedWithInfo` event. This is deduplicated in the reader. + MonitorEvent::HolderForceClosedWithInfo { .. } => 1u8.write(writer)?, _ => {}, // Covered in the TLV writes below } } @@ -1077,8 +1102,8 @@ impl Writeable for ChannelMonitorImpl Writeable for ChannelMonitorImpl true, + _ => false, + }) { + Some(MonitorEvent::HolderForceClosedWithInfo { outpoint, .. }) => { + let mut pending_monitor_events = self.pending_monitor_events.clone(); + pending_monitor_events.push(MonitorEvent::HolderForceClosed(*outpoint)); + pending_monitor_events + } + _ => self.pending_monitor_events.clone(), + }; + write_tlv_fields!(writer, { (1, self.funding_spend_confirmed, option), (3, self.htlcs_resolved_on_chain, required_vec), - (5, self.pending_monitor_events, required_vec), + (5, pending_monitor_events, required_vec), (7, self.funding_spend_seen, required), (9, self.counterparty_node_id, option), (11, self.confirmed_commitment_tx_counterparty_output, option), @@ -1110,6 +1148,7 @@ impl Writeable for ChannelMonitorImpl ChannelMonitor { best_block, counterparty_node_id: Some(counterparty_node_id), initial_counterparty_commitment_info: None, + balances_empty_height: None, }) } @@ -1416,8 +1456,8 @@ impl ChannelMonitor { /// Loads the funding txo and outputs to watch into the given `chain::Filter` by repeatedly /// calling `chain::Filter::register_output` and `chain::Filter::register_tx` until all outputs /// have been registered. - pub fn load_outputs_to_watch(&self, filter: &F, logger: &L) - where + pub fn load_outputs_to_watch(&self, filter: &F, logger: &L) + where F::Target: chain::Filter, L::Target: Logger, { let lock = self.inner.lock().unwrap(); @@ -1562,28 +1602,30 @@ impl ChannelMonitor { self.inner.lock().unwrap().counterparty_node_id } - /// Used by [`ChannelManager`] deserialization to broadcast the latest holder state if its copy - /// of the channel state was out-of-date. - /// - /// You may also use this to broadcast the latest local commitment transaction, either because + /// You may use this to broadcast the latest local commitment transaction, either because /// a monitor update failed or because we've fallen behind (i.e. we've received proof that our /// counterparty side knows a revocation secret we gave them that they shouldn't know). /// - /// Broadcasting these transactions in the second case is UNSAFE, as they allow counterparty + /// Broadcasting these transactions in this manner is UNSAFE, as they allow counterparty /// side to punish you. Nevertheless you may want to broadcast them if counterparty doesn't /// close channel with their commitment transaction after a substantial amount of time. Best /// may be to contact the other node operator out-of-band to coordinate other options available /// to you. - /// - /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager - pub fn get_latest_holder_commitment_txn(&self, logger: &L) -> Vec - where L::Target: Logger { + pub fn broadcast_latest_holder_commitment_txn( + &self, broadcaster: &B, fee_estimator: &F, logger: &L + ) + where + B::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger + { let mut inner = self.inner.lock().unwrap(); + let fee_estimator = LowerBoundedFeeEstimator::new(&**fee_estimator); let logger = WithChannelMonitor::from_impl(logger, &*inner); - inner.get_latest_holder_commitment_txn(&logger) + inner.queue_latest_holder_commitment_txn_for_broadcast(broadcaster, &fee_estimator, &logger); } - /// Unsafe test-only version of get_latest_holder_commitment_txn used by our test framework + /// Unsafe test-only version of `broadcast_latest_holder_commitment_txn` used by our test framework /// to bypass HolderCommitmentTransaction state update lockdown after signature and generate /// revoked commitment transaction. #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))] @@ -1763,7 +1805,26 @@ impl ChannelMonitor { let logger = WithChannelMonitor::from_impl(logger, &*inner); let current_height = inner.best_block.height; inner.onchain_tx_handler.rebroadcast_pending_claims( - current_height, &broadcaster, &fee_estimator, &logger, + current_height, FeerateStrategy::HighestOfPreviousOrNew, &broadcaster, &fee_estimator, &logger, + ); + } + + /// Triggers rebroadcasts of pending claims from a force-closed channel after a transaction + /// signature generation failure. + pub fn signer_unblocked( + &self, broadcaster: B, fee_estimator: F, logger: &L, + ) + where + B::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + { + let fee_estimator = LowerBoundedFeeEstimator::new(fee_estimator); + let mut inner = self.inner.lock().unwrap(); + let logger = WithChannelMonitor::from_impl(logger, &*inner); + let current_height = inner.best_block.height; + inner.onchain_tx_handler.rebroadcast_pending_claims( + current_height, FeerateStrategy::RetryPrevious, &broadcaster, &fee_estimator, &logger, ); } @@ -1800,6 +1861,52 @@ impl ChannelMonitor { spendable_outputs } + /// Checks if the monitor is fully resolved. Resolved monitor is one that has claimed all of + /// its outputs and balances (i.e. [`Self::get_claimable_balances`] returns an empty set). + /// + /// This function returns true only if [`Self::get_claimable_balances`] has been empty for at least + /// 2016 blocks as an additional protection against any bugs resulting in spuriously empty balance sets. + pub fn is_fully_resolved(&self, logger: &L) -> bool { + let mut is_all_funds_claimed = self.get_claimable_balances().is_empty(); + let current_height = self.current_best_block().height; + let mut inner = self.inner.lock().unwrap(); + + if is_all_funds_claimed { + if !inner.funding_spend_seen { + debug_assert!(false, "We should see funding spend by the time a monitor clears out"); + is_all_funds_claimed = false; + } + } + + match (inner.balances_empty_height, is_all_funds_claimed) { + (Some(balances_empty_height), true) => { + // Claimed all funds, check if reached the blocks threshold. + const BLOCKS_THRESHOLD: u32 = 4032; // ~four weeks + return current_height >= balances_empty_height + BLOCKS_THRESHOLD; + }, + (Some(_), false) => { + // previously assumed we claimed all funds, but we have new funds to claim. + // Should not happen in practice. + debug_assert!(false, "Thought we were done claiming funds, but claimable_balances now has entries"); + log_error!(logger, + "WARNING: LDK thought it was done claiming all the available funds in the ChannelMonitor for channel {}, but later decided it had more to claim. This is potentially an important bug in LDK, please report it at https://github.com/lightningdevkit/rust-lightning/issues/new", + inner.get_funding_txo().0); + inner.balances_empty_height = None; + false + }, + (None, true) => { + // Claimed all funds but `balances_empty_height` is None. It is set to the + // current block height. + inner.balances_empty_height = Some(current_height); + false + }, + (None, false) => { + // Have funds to claim. + false + }, + } + } + #[cfg(test)] pub fn get_counterparty_payment_script(&self) -> ScriptBuf { self.inner.lock().unwrap().counterparty_payment_script.clone() @@ -1809,6 +1916,12 @@ impl ChannelMonitor { pub fn set_counterparty_payment_script(&self, script: ScriptBuf) { self.inner.lock().unwrap().counterparty_payment_script = script; } + + #[cfg(test)] + pub fn do_signer_call ()>(&self, mut f: F) { + let inner = self.inner.lock().unwrap(); + f(&inner.onchain_tx_handler.signer); + } } impl ChannelMonitorImpl { @@ -2246,7 +2359,7 @@ impl ChannelMonitor { // before considering it "no longer pending" - this matches when we // provide the ChannelManager an HTLC failure event. Some(commitment_tx_output_idx) == htlc.transaction_output_index && - us.best_block.height() >= event.height + ANTI_REORG_DELAY - 1 + us.best_block.height >= event.height + ANTI_REORG_DELAY - 1 } else if let OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, .. } = event.event { // If the HTLC was fulfilled with a preimage, we consider the HTLC // immediately non-pending, matching when we provide ChannelManager @@ -2647,7 +2760,7 @@ impl ChannelMonitorImpl { macro_rules! claim_htlcs { ($commitment_number: expr, $txid: expr) => { let (htlc_claim_reqs, _) = self.get_counterparty_output_claim_info($commitment_number, $txid, None); - self.onchain_tx_handler.update_claims_view_from_requests(htlc_claim_reqs, self.best_block.height(), self.best_block.height(), broadcaster, fee_estimator, logger); + self.onchain_tx_handler.update_claims_view_from_requests(htlc_claim_reqs, self.best_block.height, self.best_block.height, broadcaster, fee_estimator, logger); } } if let Some(txid) = self.current_counterparty_commitment_txid { @@ -2694,13 +2807,13 @@ impl ChannelMonitorImpl { // Assume that the broadcasted commitment transaction confirmed in the current best // block. Even if not, its a reasonable metric for the bump criteria on the HTLC // transactions. - let (claim_reqs, _) = self.get_broadcasted_holder_claims(&holder_commitment_tx, self.best_block.height()); - self.onchain_tx_handler.update_claims_view_from_requests(claim_reqs, self.best_block.height(), self.best_block.height(), broadcaster, fee_estimator, logger); + let (claim_reqs, _) = self.get_broadcasted_holder_claims(&holder_commitment_tx, self.best_block.height); + self.onchain_tx_handler.update_claims_view_from_requests(claim_reqs, self.best_block.height, self.best_block.height, broadcaster, fee_estimator, logger); } } } - fn generate_claimable_outpoints_and_watch_outputs(&mut self) -> (Vec, Vec) { + fn generate_claimable_outpoints_and_watch_outputs(&mut self, reason: ClosureReason) -> (Vec, Vec) { let funding_outp = HolderFundingOutput::build( self.funding_redeemscript.clone(), self.channel_value_satoshis, @@ -2709,10 +2822,16 @@ impl ChannelMonitorImpl { let commitment_package = PackageTemplate::build_package( self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), - self.best_block.height(), self.best_block.height() + self.best_block.height, self.best_block.height ); let mut claimable_outpoints = vec![commitment_package]; - self.pending_monitor_events.push(MonitorEvent::HolderForceClosed(self.funding_info.0)); + let event = MonitorEvent::HolderForceClosedWithInfo { + reason, + outpoint: self.funding_info.0, + channel_id: self.channel_id, + }; + self.pending_monitor_events.push(event); + // Although we aren't signing the transaction directly here, the transaction will be signed // in the claim that is queued to OnchainTxHandler. We set holder_tx_signed here to reject // new channel updates. @@ -2726,7 +2845,7 @@ impl ChannelMonitorImpl { // assuming it gets confirmed in the next block. Sadly, we have code which considers // "not yet confirmed" things as discardable, so we cannot do that here. let (mut new_outpoints, _) = self.get_broadcasted_holder_claims( - &self.current_holder_commitment_tx, self.best_block.height() + &self.current_holder_commitment_tx, self.best_block.height ); let unsigned_commitment_tx = self.onchain_tx_handler.get_unsigned_holder_commitment_tx(); let new_outputs = self.get_broadcasted_holder_watch_outputs( @@ -2748,9 +2867,9 @@ impl ChannelMonitorImpl { F::Target: FeeEstimator, L::Target: Logger, { - let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs(); + let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs(ClosureReason::HolderForceClosed); self.onchain_tx_handler.update_claims_view_from_requests( - claimable_outpoints, self.best_block.height(), self.best_block.height(), broadcaster, + claimable_outpoints, self.best_block.height, self.best_block.height, broadcaster, fee_estimator, logger ); } @@ -2855,7 +2974,7 @@ impl ChannelMonitorImpl { } else if !self.holder_tx_signed { log_error!(logger, "WARNING: You have a potentially-unsafe holder commitment transaction available to broadcast"); log_error!(logger, " in channel monitor for channel {}!", &self.channel_id()); - log_error!(logger, " Read the docs for ChannelMonitor::get_latest_holder_commitment_txn and take manual action!"); + log_error!(logger, " Read the docs for ChannelMonitor::broadcast_latest_holder_commitment_txn to take manual action!"); } else { // If we generated a MonitorEvent::HolderForceClosed, the ChannelManager // will still give us a ChannelForceClosed event with !should_broadcast, but we @@ -2931,12 +3050,19 @@ impl ChannelMonitorImpl { ClaimEvent::BumpCommitment { package_target_feerate_sat_per_1000_weight, commitment_tx, anchor_output_idx, } => { + let channel_id = self.channel_id; + // unwrap safety: `ClaimEvent`s are only available for Anchor channels, + // introduced with v0.0.116. counterparty_node_id is guaranteed to be `Some` + // since v0.0.110. + let counterparty_node_id = self.counterparty_node_id.unwrap(); let commitment_txid = commitment_tx.txid(); debug_assert_eq!(self.current_holder_commitment_tx.txid, commitment_txid); let pending_htlcs = self.current_holder_commitment_tx.non_dust_htlcs(); let commitment_tx_fee_satoshis = self.channel_value_satoshis - commitment_tx.output.iter().fold(0u64, |sum, output| sum + output.value); ret.push(Event::BumpTransaction(BumpTransactionEvent::ChannelClose { + channel_id, + counterparty_node_id, claim_id, package_target_feerate_sat_per_1000_weight, commitment_tx, @@ -2958,6 +3084,11 @@ impl ChannelMonitorImpl { ClaimEvent::BumpHTLC { target_feerate_sat_per_1000_weight, htlcs, tx_lock_time, } => { + let channel_id = self.channel_id; + // unwrap safety: `ClaimEvent`s are only available for Anchor channels, + // introduced with v0.0.116. counterparty_node_id is guaranteed to be `Some` + // since v0.0.110. + let counterparty_node_id = self.counterparty_node_id.unwrap(); let mut htlc_descriptors = Vec::with_capacity(htlcs.len()); for htlc in htlcs { htlc_descriptors.push(HTLCDescriptor { @@ -2978,6 +3109,8 @@ impl ChannelMonitorImpl { }); } ret.push(Event::BumpTransaction(BumpTransactionEvent::HTLCResolution { + channel_id, + counterparty_node_id, claim_id, target_feerate_sat_per_1000_weight, htlc_descriptors, @@ -3488,45 +3621,6 @@ impl ChannelMonitorImpl { } } - fn get_latest_holder_commitment_txn( - &mut self, logger: &WithChannelMonitor, - ) -> Vec where L::Target: Logger { - log_debug!(logger, "Getting signed latest holder commitment transaction!"); - self.holder_tx_signed = true; - let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript); - let txid = commitment_tx.txid(); - let mut holder_transactions = vec![commitment_tx]; - // When anchor outputs are present, the HTLC transactions are only valid once the commitment - // transaction confirms. - if self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() { - return holder_transactions; - } - for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { - if let Some(vout) = htlc.0.transaction_output_index { - let preimage = if !htlc.0.offered { - if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else { - // We can't build an HTLC-Success transaction without the preimage - continue; - } - } else if htlc.0.cltv_expiry > self.best_block.height() + 1 { - // Don't broadcast HTLC-Timeout transactions immediately as they don't meet the - // current locktime requirements on-chain. We will broadcast them in - // `block_confirmed` when `should_broadcast_holder_commitment_txn` returns true. - // Note that we add + 1 as transactions are broadcastable when they can be - // confirmed in the next block. - continue; - } else { None }; - if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx( - &::bitcoin::OutPoint { txid, vout }, &preimage) { - holder_transactions.push(htlc_tx); - } - } - } - // We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do. - // The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation. - holder_transactions - } - #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] /// Note that this includes possibly-locktimed-in-the-future transactions! fn unsafe_get_latest_holder_commitment_txn( @@ -3549,9 +3643,12 @@ impl ChannelMonitorImpl { continue; } } else { None }; - if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx( - &::bitcoin::OutPoint { txid, vout }, &preimage) { - holder_transactions.push(htlc_tx); + if let Some(htlc_tx) = self.onchain_tx_handler.get_maybe_signed_htlc_tx( + &::bitcoin::OutPoint { txid, vout }, &preimage + ) { + if htlc_tx.is_fully_signed() { + holder_transactions.push(htlc_tx.0); + } } } } @@ -3588,11 +3685,11 @@ impl ChannelMonitorImpl { { let block_hash = header.block_hash(); - if height > self.best_block.height() { + if height > self.best_block.height { self.best_block = BestBlock::new(block_hash, height); log_trace!(logger, "Connecting new block {} at height {}", block_hash, height); self.block_confirmed(height, block_hash, vec![], vec![], vec![], &broadcaster, &fee_estimator, logger) - } else if block_hash != self.best_block.block_hash() { + } else if block_hash != self.best_block.block_hash { self.best_block = BestBlock::new(block_hash, height); log_trace!(logger, "Best block re-orged, replaced with new block {} at height {}", block_hash, height); self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.height <= height); @@ -3737,7 +3834,7 @@ impl ChannelMonitorImpl { } } - if height > self.best_block.height() { + if height > self.best_block.height { self.best_block = BestBlock::new(block_hash, height); } @@ -3769,11 +3866,11 @@ impl ChannelMonitorImpl { L::Target: Logger, { log_trace!(logger, "Processing {} matched transactions for block at height {}.", txn_matched.len(), conf_height); - debug_assert!(self.best_block.height() >= conf_height); + debug_assert!(self.best_block.height >= conf_height); let should_broadcast = self.should_broadcast_holder_commitment_txn(logger); if should_broadcast { - let (mut new_outpoints, mut new_outputs) = self.generate_claimable_outpoints_and_watch_outputs(); + let (mut new_outpoints, mut new_outputs) = self.generate_claimable_outpoints_and_watch_outputs(ClosureReason::HTLCsTimedOut); claimable_outpoints.append(&mut new_outpoints); watch_outputs.append(&mut new_outputs); } @@ -3860,8 +3957,8 @@ impl ChannelMonitorImpl { } } - self.onchain_tx_handler.update_claims_view_from_requests(claimable_outpoints, conf_height, self.best_block.height(), broadcaster, fee_estimator, logger); - self.onchain_tx_handler.update_claims_view_from_matched_txn(&txn_matched, conf_height, conf_hash, self.best_block.height(), broadcaster, fee_estimator, logger); + self.onchain_tx_handler.update_claims_view_from_requests(claimable_outpoints, conf_height, self.best_block.height, broadcaster, fee_estimator, logger); + self.onchain_tx_handler.update_claims_view_from_matched_txn(&txn_matched, conf_height, conf_hash, self.best_block.height, broadcaster, fee_estimator, logger); // Determine new outputs to watch by comparing against previously known outputs to watch, // updating the latter in the process. @@ -4012,7 +4109,7 @@ impl ChannelMonitorImpl { // to the source, and if we don't fail the channel we will have to ensure that the next // updates that peer sends us are update_fails, failing the channel if not. It's probably // easier to just fail the channel as this case should be rare enough anyway. - let height = self.best_block.height(); + let height = self.best_block.height; macro_rules! scan_commitment { ($htlcs: expr, $holder_tx: expr) => { for ref htlc in $htlcs { @@ -4284,6 +4381,7 @@ impl ChannelMonitorImpl { revocation_pubkey: broadcasted_holder_revokable_script.2, channel_keys_id: self.channel_keys_id, channel_value_satoshis: self.channel_value_satoshis, + channel_transaction_parameters: Some(self.onchain_tx_handler.channel_transaction_parameters.clone()), })); } } @@ -4586,6 +4684,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP let mut spendable_txids_confirmed = Some(Vec::new()); let mut counterparty_fulfilled_htlcs = Some(new_hash_map()); let mut initial_counterparty_commitment_info = None; + let mut balances_empty_height = None; let mut channel_id = None; read_tlv_fields!(reader, { (1, funding_spend_confirmed, option), @@ -4598,8 +4697,19 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP (15, counterparty_fulfilled_htlcs, option), (17, initial_counterparty_commitment_info, option), (19, channel_id, option), + (21, balances_empty_height, option), }); + // `HolderForceClosedWithInfo` replaced `HolderForceClosed` in v0.0.122. If we have both + // events, we can remove the `HolderForceClosed` event and just keep the `HolderForceClosedWithInfo`. + if let Some(ref mut pending_monitor_events) = pending_monitor_events { + if pending_monitor_events.iter().any(|e| matches!(e, MonitorEvent::HolderForceClosed(_))) && + pending_monitor_events.iter().any(|e| matches!(e, MonitorEvent::HolderForceClosedWithInfo { .. })) + { + pending_monitor_events.retain(|e| !matches!(e, MonitorEvent::HolderForceClosed(_))); + } + } + // Monitors for anchor outputs channels opened in v0.0.116 suffered from a bug in which the // wrong `counterparty_payment_script` was being tracked. Fix it now on deserialization to // give them a chance to recognize the spendable output. @@ -4611,7 +4721,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP chan_utils::get_to_countersignatory_with_anchors_redeemscript(&payment_point).to_v0_p2wsh(); } - Ok((best_block.block_hash(), ChannelMonitor::from_impl(ChannelMonitorImpl { + Ok((best_block.block_hash, ChannelMonitor::from_impl(ChannelMonitorImpl { latest_update_id, commitment_transaction_number_obscure_factor, @@ -4666,6 +4776,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP best_block, counterparty_node_id, initial_counterparty_commitment_info, + balances_empty_height, }))) } } @@ -4710,6 +4821,8 @@ mod tests { use crate::sync::{Arc, Mutex}; use crate::io; use crate::ln::features::ChannelTypeFeatures; + + #[allow(unused_imports)] use crate::prelude::*; use std::str::FromStr;