X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=0e87f3569e605d0c25736a9d203bc1fe6170655f;hb=07d991c82fadf10f59ae01b2b5aef6bc8797fd9a;hp=cdbec81abf52d04843e972889c60f717af445a3c;hpb=d70124cec4e7dede1c8918536c19a22cbc9e7279;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index cdbec81a..0e87f356 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -20,6 +20,7 @@ //! security-domain-separated system design, you should consider having multiple paths for //! ChannelMonitors to get out of the HSM and onto monitoring devices. +use bitcoin::amount::Amount; use bitcoin::blockdata::block::Header; use bitcoin::blockdata::transaction::{OutPoint as BitcoinOutPoint, TxOut, Transaction}; use bitcoin::blockdata::script::{Script, ScriptBuf}; @@ -28,13 +29,13 @@ use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hash_types::{Txid, BlockHash}; +use bitcoin::ecdsa::Signature as BitcoinSignature; use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature}; use bitcoin::secp256k1::{SecretKey, PublicKey}; use bitcoin::secp256k1; -use bitcoin::sighash::EcdsaSighashType; use crate::ln::channel::INITIAL_COMMITMENT_NUMBER; -use crate::ln::{PaymentHash, PaymentPreimage, ChannelId}; +use crate::ln::types::{PaymentHash, PaymentPreimage, ChannelId}; use crate::ln::msgs::DecodeError; use crate::ln::channel_keys::{DelayedPaymentKey, DelayedPaymentBasepoint, HtlcBasepoint, HtlcKey, RevocationKey, RevocationBasepoint}; use crate::ln::chan_utils::{self,CommitmentTransaction, CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCClaim, ChannelTransactionParameters, HolderCommitmentTransaction, TxCreationKeys}; @@ -43,20 +44,21 @@ use crate::chain; 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::sign::{ChannelDerivationParameters, HTLCDescriptor, SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, ecdsa::EcdsaChannelSigner, SignerProvider, EntropySource}; +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 +157,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 +197,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,14 +405,14 @@ impl OnchainEventEntry { } fn has_reached_confirmation_threshold(&self, best_block: &BestBlock) -> bool { - best_block.height() >= self.confirmation_threshold() + best_block.height >= self.confirmation_threshold() } } /// The (output index, sats value) for the counterparty's output in a commitment transaction. /// /// This was added as an `Option` in 0.0.110. -type CommitmentTxCounterpartyOutputInfo = Option<(u32, u64)>; +type CommitmentTxCounterpartyOutputInfo = Option<(u32, Amount)>; /// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it /// once they mature to enough confirmations (ANTI_REORG_DELAY) @@ -757,14 +775,14 @@ impl Readable for IrrevocablyResolvedHTLC { /// the "reorg path" (ie disconnecting blocks until you find a common ancestor from both the /// returned block hash and the the current chain and then reconnecting blocks to get to the /// best chain) upon deserializing the object! -pub struct ChannelMonitor { +pub struct ChannelMonitor { #[cfg(test)] pub(crate) inner: Mutex>, #[cfg(not(test))] pub(super) inner: Mutex>, } -impl Clone for ChannelMonitor where Signer: Clone { +impl Clone for ChannelMonitor where Signer: Clone { fn clone(&self) -> Self { let inner = self.inner.lock().unwrap().clone(); ChannelMonitor::from_impl(inner) @@ -772,7 +790,7 @@ impl Clone for ChannelMonitor where } #[derive(Clone, PartialEq)] -pub(crate) struct ChannelMonitorImpl { +pub(crate) struct ChannelMonitorImpl { latest_update_id: u64, commitment_transaction_number_obscure_factor: u64, @@ -918,12 +936,15 @@ 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. pub type TransactionOutputs = (Txid, Vec<(u32, TxOut)>); -impl PartialEq for ChannelMonitor where Signer: PartialEq { +impl PartialEq for ChannelMonitor where Signer: PartialEq { fn eq(&self, other: &Self) -> bool { // We need some kind of total lockorder. Absent a better idea, we sort by position in // memory and take locks in that order (assuming that we can't move within memory while a @@ -935,7 +956,7 @@ impl PartialEq for ChannelMonitor w } } -impl Writeable for ChannelMonitor { +impl Writeable for ChannelMonitor { fn write(&self, writer: &mut W) -> Result<(), Error> { self.inner.lock().unwrap().write(writer) } @@ -945,7 +966,7 @@ impl Writeable for ChannelMonitor { const SERIALIZATION_VERSION: u8 = 1; const MIN_SERIALIZATION_VERSION: u8 = 1; -impl Writeable for ChannelMonitorImpl { +impl Writeable for ChannelMonitorImpl { fn write(&self, writer: &mut W) -> Result<(), Error> { write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION); @@ -1059,6 +1080,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 +1090,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 +1103,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 +1149,7 @@ impl Writeable for ChannelMonitorImpl where L::Target: Logger { logger: &'a L, peer_id: Option, channel_id: Option, + payment_hash: Option, } impl<'a, L: Deref> Logger for WithChannelMonitor<'a, L> where L::Target: Logger { fn log(&self, mut record: Record) { record.peer_id = self.peer_id; record.channel_id = self.channel_id; + record.payment_hash = self.payment_hash; self.logger.log(record) } } impl<'a, L: Deref> WithChannelMonitor<'a, L> where L::Target: Logger { - pub(crate) fn from(logger: &'a L, monitor: &ChannelMonitor) -> Self { - Self::from_impl(logger, &*monitor.inner.lock().unwrap()) + pub(crate) fn from(logger: &'a L, monitor: &ChannelMonitor, payment_hash: Option) -> Self { + Self::from_impl(logger, &*monitor.inner.lock().unwrap(), payment_hash) } - pub(crate) fn from_impl(logger: &'a L, monitor_impl: &ChannelMonitorImpl) -> Self { + pub(crate) fn from_impl(logger: &'a L, monitor_impl: &ChannelMonitorImpl, payment_hash: Option) -> Self { let peer_id = monitor_impl.counterparty_node_id; let channel_id = Some(monitor_impl.channel_id()); WithChannelMonitor { - logger, peer_id, channel_id, + logger, peer_id, channel_id, payment_hash, } } } -impl ChannelMonitor { +impl ChannelMonitor { /// For lockorder enforcement purposes, we need to have a single site which constructs the /// `inner` mutex, otherwise cases where we lock two monitors at the same time (eg in our /// PartialEq implementation) we may decide a lockorder violation has occurred. @@ -1293,6 +1335,7 @@ impl ChannelMonitor { best_block, counterparty_node_id: Some(counterparty_node_id), initial_counterparty_commitment_info: None, + balances_empty_height: None, }) } @@ -1316,7 +1359,7 @@ impl ChannelMonitor { where L::Target: Logger { let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); inner.provide_initial_counterparty_commitment_tx(txid, htlc_outputs, commitment_number, their_cur_per_commitment_point, feerate_per_kw, to_broadcaster_value_sat, to_countersignatory_value_sat, &logger); @@ -1336,7 +1379,7 @@ impl ChannelMonitor { logger: &L, ) where L::Target: Logger { let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); inner.provide_latest_counterparty_commitment_tx( txid, htlc_outputs, commitment_number, their_per_commitment_point, &logger) } @@ -1364,7 +1407,7 @@ impl ChannelMonitor { L::Target: Logger, { let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, Some(*payment_hash)); inner.provide_payment_preimage( payment_hash, payment_preimage, broadcaster, fee_estimator, &logger) } @@ -1386,7 +1429,7 @@ impl ChannelMonitor { L::Target: Logger, { let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); inner.update_monitor(updates, broadcaster, fee_estimator, &logger) } @@ -1421,7 +1464,7 @@ impl ChannelMonitor { F::Target: chain::Filter, L::Target: Logger, { let lock = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*lock); + let logger = WithChannelMonitor::from_impl(logger, &*lock, None); log_trace!(&logger, "Registering funding outpoint {}", &lock.get_funding_txo().0); filter.register_tx(&lock.get_funding_txo().0.txid, &lock.get_funding_txo().1); for (txid, outputs) in lock.get_outputs_to_watch().iter() { @@ -1562,35 +1605,37 @@ 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 logger = WithChannelMonitor::from_impl(logger, &*inner); - inner.get_latest_holder_commitment_txn(&logger) + let fee_estimator = LowerBoundedFeeEstimator::new(&**fee_estimator); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); + 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"))] pub fn unsafe_get_latest_holder_commitment_txn(&self, logger: &L) -> Vec where L::Target: Logger { let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); inner.unsafe_get_latest_holder_commitment_txn(&logger) } @@ -1620,7 +1665,7 @@ impl ChannelMonitor { L::Target: Logger, { let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); inner.block_connected( header, txdata, height, broadcaster, fee_estimator, &logger) } @@ -1640,7 +1685,7 @@ impl ChannelMonitor { L::Target: Logger, { let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); inner.block_disconnected( header, height, broadcaster, fee_estimator, &logger) } @@ -1668,7 +1713,7 @@ impl ChannelMonitor { { let bounded_fee_estimator = LowerBoundedFeeEstimator::new(fee_estimator); let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); inner.transactions_confirmed( header, txdata, height, broadcaster, &bounded_fee_estimator, &logger) } @@ -1692,7 +1737,7 @@ impl ChannelMonitor { { let bounded_fee_estimator = LowerBoundedFeeEstimator::new(fee_estimator); let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); inner.transaction_unconfirmed( txid, broadcaster, &bounded_fee_estimator, &logger ); @@ -1720,7 +1765,7 @@ impl ChannelMonitor { { let bounded_fee_estimator = LowerBoundedFeeEstimator::new(fee_estimator); let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); inner.best_block_updated( header, height, broadcaster, &bounded_fee_estimator, &logger ) @@ -1760,10 +1805,35 @@ impl ChannelMonitor { { let fee_estimator = LowerBoundedFeeEstimator::new(fee_estimator); let mut inner = self.inner.lock().unwrap(); - let logger = WithChannelMonitor::from_impl(logger, &*inner); + let logger = WithChannelMonitor::from_impl(logger, &*inner, None); 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, + ); + } + + /// Returns true if the monitor has pending claim requests that are not fully confirmed yet. + pub fn has_pending_claims(&self) -> bool + { + self.inner.lock().unwrap().onchain_tx_handler.has_pending_claims() + } + + /// 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, None); + let current_height = inner.best_block.height; + inner.onchain_tx_handler.rebroadcast_pending_claims( + current_height, FeerateStrategy::RetryPrevious, &broadcaster, &fee_estimator, &logger, ); } @@ -1800,6 +1870,55 @@ 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 + /// 4032 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; + } + } + + const BLOCKS_THRESHOLD: u32 = 4032; // ~four weeks + match (inner.balances_empty_height, is_all_funds_claimed) { + (Some(balances_empty_height), true) => { + // Claimed all funds, check if reached the blocks threshold. + 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. + log_debug!(logger, + "ChannelMonitor funded at {} is now fully resolved. It will become archivable in {} blocks", + inner.get_funding_txo().0, BLOCKS_THRESHOLD); + 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,9 +1928,15 @@ impl ChannelMonitor { pub fn set_counterparty_payment_script(&self, script: ScriptBuf) { self.inner.lock().unwrap().counterparty_payment_script = script; } + + #[cfg(test)] + pub fn do_mut_signer_call ()>(&self, mut f: F) { + let mut inner = self.inner.lock().unwrap(); + f(&mut inner.onchain_tx_handler.signer); + } } -impl ChannelMonitorImpl { +impl ChannelMonitorImpl { /// Helper for get_claimable_balances which does the work for an individual HTLC, generating up /// to one `Balance` for the HTLC. fn get_htlc_balance(&self, htlc: &HTLCOutputInCommitment, holder_commitment: bool, @@ -1990,7 +2115,7 @@ impl ChannelMonitorImpl { } } -impl ChannelMonitor { +impl ChannelMonitor { /// Gets the balances in this channel which are either claimable by us if we were to /// force-close the channel now or which are claimable on-chain (possibly awaiting /// confirmation). @@ -2053,7 +2178,7 @@ impl ChannelMonitor { } else { None } }) { res.push(Balance::ClaimableAwaitingConfirmations { - amount_satoshis: value, + amount_satoshis: value.to_sat(), confirmation_height: conf_thresh, }); } else { @@ -2076,7 +2201,7 @@ impl ChannelMonitor { descriptor: SpendableOutputDescriptor::StaticOutput { output, .. } } = &event.event { res.push(Balance::ClaimableAwaitingConfirmations { - amount_satoshis: output.value, + amount_satoshis: output.value.to_sat(), confirmation_height: event.confirmation_threshold(), }); if let Some(confirmed_to_self_idx) = confirmed_counterparty_output.map(|(idx, _)| idx) { @@ -2095,7 +2220,7 @@ impl ChannelMonitor { .is_output_spend_pending(&BitcoinOutPoint::new(txid, confirmed_to_self_idx)); if output_spendable { res.push(Balance::CounterpartyRevokedOutputClaimable { - amount_satoshis: amt, + amount_satoshis: amt.to_sat(), }); } } else { @@ -2246,7 +2371,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 @@ -2312,8 +2437,8 @@ macro_rules! fail_unbroadcast_htlcs { debug_assert_eq!($commitment_tx_confirmed.txid(), $commitment_txid_confirmed); macro_rules! check_htlc_fails { - ($txid: expr, $commitment_tx: expr) => { - if let Some(ref latest_outpoints) = $self.counterparty_claimable_outpoints.get($txid) { + ($txid: expr, $commitment_tx: expr, $per_commitment_outpoints: expr) => { + if let Some(ref latest_outpoints) = $per_commitment_outpoints { for &(ref htlc, ref source_option) in latest_outpoints.iter() { if let &Some(ref source) = source_option { // Check if the HTLC is present in the commitment transaction that was @@ -2373,10 +2498,10 @@ macro_rules! fail_unbroadcast_htlcs { } } if let Some(ref txid) = $self.current_counterparty_commitment_txid { - check_htlc_fails!(txid, "current"); + check_htlc_fails!(txid, "current", $self.counterparty_claimable_outpoints.get(txid)); } if let Some(ref txid) = $self.prev_counterparty_commitment_txid { - check_htlc_fails!(txid, "previous"); + check_htlc_fails!(txid, "previous", $self.counterparty_claimable_outpoints.get(txid)); } } } } @@ -2402,7 +2527,7 @@ pub fn deliberately_bogus_accepted_htlc_witness() -> Vec> { vec![Vec::new(), Vec::new(), Vec::new(), Vec::new(), deliberately_bogus_accepted_htlc_witness_program().into()].into() } -impl ChannelMonitorImpl { +impl ChannelMonitorImpl { /// Inserts a revocation secret into this channel monitor. Prunes old preimages if neither /// needed by holder commitment transactions HTCLs nor by counterparty ones. Unless we haven't already seen /// counterparty commitment transaction's secret, they are de facto pruned (we can use revocation key). @@ -2645,15 +2770,15 @@ impl ChannelMonitorImpl { // If the channel is force closed, try to claim the output from this preimage. // First check if a counterparty commitment transaction has been broadcasted: 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); + ($commitment_number: expr, $txid: expr, $htlcs: expr) => { + let (htlc_claim_reqs, _) = self.get_counterparty_output_claim_info($commitment_number, $txid, None, $htlcs); + 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 { if txid == confirmed_spend_txid { if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) { - claim_htlcs!(*commitment_number, txid); + claim_htlcs!(*commitment_number, txid, self.counterparty_claimable_outpoints.get(&txid)); } else { debug_assert!(false); log_error!(logger, "Detected counterparty commitment tx on-chain without tracking commitment number"); @@ -2664,7 +2789,7 @@ impl ChannelMonitorImpl { if let Some(txid) = self.prev_counterparty_commitment_txid { if txid == confirmed_spend_txid { if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) { - claim_htlcs!(*commitment_number, txid); + claim_htlcs!(*commitment_number, txid, self.counterparty_claimable_outpoints.get(&txid)); } else { debug_assert!(false); log_error!(logger, "Detected counterparty commitment tx on-chain without tracking commitment number"); @@ -2694,13 +2819,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 +2834,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 +2857,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 +2879,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 { broadcasted_latest_txn: Some(true) }); 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 +2986,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 @@ -2940,7 +3071,7 @@ impl ChannelMonitorImpl { 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); + commitment_tx.output.iter().fold(0u64, |sum, output| sum + output.value.to_sat()); ret.push(Event::BumpTransaction(BumpTransactionEvent::ChannelClose { channel_id, counterparty_node_id, @@ -2980,9 +3111,7 @@ impl ChannelMonitorImpl { }, commitment_txid: htlc.commitment_txid, per_commitment_number: htlc.per_commitment_number, - per_commitment_point: self.onchain_tx_handler.signer.get_per_commitment_point( - htlc.per_commitment_number, &self.onchain_tx_handler.secp_ctx, - ), + per_commitment_point: htlc.per_commitment_point, feerate_per_kw: 0, htlc: htlc.htlc, preimage: htlc.preimage, @@ -3080,7 +3209,7 @@ impl ChannelMonitorImpl { let sig = self.onchain_tx_handler.signer.sign_justice_revoked_output( &justice_tx, input_idx, value, &per_commitment_key, &self.onchain_tx_handler.secp_ctx)?; - justice_tx.input[input_idx].witness.push_bitcoin_signature(&sig.serialize_der(), EcdsaSighashType::All); + justice_tx.input[input_idx].witness.push_ecdsa_signature(&BitcoinSignature::sighash_all(sig)); justice_tx.input[input_idx].witness.push(&[1u8]); justice_tx.input[input_idx].witness.push(revokeable_redeemscript.as_bytes()); Ok(justice_tx) @@ -3108,16 +3237,14 @@ impl ChannelMonitorImpl { /// height > height + CLTV_SHARED_CLAIM_BUFFER. In any case, will install monitoring for /// HTLC-Success/HTLC-Timeout transactions. /// - /// Returns packages to claim the revoked output(s), as well as additional outputs to watch and - /// general information about the output that is to the counterparty in the commitment - /// transaction. + /// Returns packages to claim the revoked output(s) and general information about the output that + /// is to the counterparty in the commitment transaction. fn check_spend_counterparty_transaction(&mut self, tx: &Transaction, height: u32, block_hash: &BlockHash, logger: &L) - -> (Vec, TransactionOutputs, CommitmentTxCounterpartyOutputInfo) + -> (Vec, CommitmentTxCounterpartyOutputInfo) where L::Target: Logger { // Most secp and related errors trying to create keys means we have no hope of constructing // a spend transaction...so we return no transactions to broadcast let mut claimable_outpoints = Vec::new(); - let mut watch_outputs = Vec::new(); let mut to_counterparty_output_info = None; let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers! @@ -3127,7 +3254,7 @@ impl ChannelMonitorImpl { ( $thing : expr ) => { match $thing { Ok(a) => a, - Err(_) => return (claimable_outpoints, (commitment_txid, watch_outputs), to_counterparty_output_info) + Err(_) => return (claimable_outpoints, to_counterparty_output_info) } }; } @@ -3141,7 +3268,7 @@ impl ChannelMonitorImpl { let delayed_key = DelayedPaymentKey::from_basepoint(&self.onchain_tx_handler.secp_ctx, &self.counterparty_commitment_params.counterparty_delayed_payment_base_key, &PublicKey::from_secret_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_key)); let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.counterparty_commitment_params.on_counterparty_tx_csv, &delayed_key); - let revokeable_p2wsh = revokeable_redeemscript.to_v0_p2wsh(); + let revokeable_p2wsh = revokeable_redeemscript.to_p2wsh(); // First, process non-htlc outputs (to_holder & to_counterparty) for (idx, outp) in tx.output.iter().enumerate() { @@ -3155,14 +3282,13 @@ impl ChannelMonitorImpl { } // Then, try to find revoked htlc outputs - if let Some(ref per_commitment_data) = per_commitment_option { - for (_, &(ref htlc, _)) in per_commitment_data.iter().enumerate() { + if let Some(per_commitment_claimable_data) = per_commitment_option { + for (htlc, _) in per_commitment_claimable_data { if let Some(transaction_output_index) = htlc.transaction_output_index { if transaction_output_index as usize >= tx.output.len() || - tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 { + tx.output[transaction_output_index as usize].value != htlc.to_bitcoin_amount() { // per_commitment_data is corrupt or our commitment signing key leaked! - return (claimable_outpoints, (commitment_txid, watch_outputs), - to_counterparty_output_info); + return (claimable_outpoints, to_counterparty_output_info); } let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone(), &self.onchain_tx_handler.channel_transaction_parameters.channel_type_features); let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, height); @@ -3175,14 +3301,11 @@ impl ChannelMonitorImpl { if !claimable_outpoints.is_empty() || per_commitment_option.is_some() { // ie we're confident this is actually ours // We're definitely a counterparty commitment transaction! log_error!(logger, "Got broadcast of revoked counterparty commitment transaction, going to generate general spend tx with {} inputs", claimable_outpoints.len()); - for (idx, outp) in tx.output.iter().enumerate() { - watch_outputs.push((idx as u32, outp.clone())); - } self.counterparty_commitment_txn_on_chain.insert(commitment_txid, commitment_number); - if let Some(per_commitment_data) = per_commitment_option { + if let Some(per_commitment_claimable_data) = per_commitment_option { fail_unbroadcast_htlcs!(self, "revoked_counterparty", commitment_txid, tx, height, - block_hash, per_commitment_data.iter().map(|(htlc, htlc_source)| + block_hash, per_commitment_claimable_data.iter().map(|(htlc, htlc_source)| (htlc, htlc_source.as_ref().map(|htlc_source| htlc_source.as_ref())) ), logger); } else { @@ -3195,7 +3318,7 @@ impl ChannelMonitorImpl { block_hash, [].iter().map(|reference| *reference), logger); } } - } else if let Some(per_commitment_data) = per_commitment_option { + } else if let Some(per_commitment_claimable_data) = per_commitment_option { // While this isn't useful yet, there is a potential race where if a counterparty // revokes a state at the same time as the commitment transaction for that state is // confirmed, and the watchtower receives the block before the user, the user could @@ -3203,35 +3326,31 @@ impl ChannelMonitorImpl { // already processed the block, resulting in the counterparty_commitment_txn_on_chain entry // not being generated by the above conditional. Thus, to be safe, we go ahead and // insert it here. - for (idx, outp) in tx.output.iter().enumerate() { - watch_outputs.push((idx as u32, outp.clone())); - } self.counterparty_commitment_txn_on_chain.insert(commitment_txid, commitment_number); log_info!(logger, "Got broadcast of non-revoked counterparty commitment transaction {}", commitment_txid); fail_unbroadcast_htlcs!(self, "counterparty", commitment_txid, tx, height, block_hash, - per_commitment_data.iter().map(|(htlc, htlc_source)| + per_commitment_claimable_data.iter().map(|(htlc, htlc_source)| (htlc, htlc_source.as_ref().map(|htlc_source| htlc_source.as_ref())) ), logger); - let (htlc_claim_reqs, counterparty_output_info) = - self.get_counterparty_output_claim_info(commitment_number, commitment_txid, Some(tx)); + self.get_counterparty_output_claim_info(commitment_number, commitment_txid, Some(tx), per_commitment_option); to_counterparty_output_info = counterparty_output_info; for req in htlc_claim_reqs { claimable_outpoints.push(req); } } - (claimable_outpoints, (commitment_txid, watch_outputs), to_counterparty_output_info) + (claimable_outpoints, to_counterparty_output_info) } /// Returns the HTLC claim package templates and the counterparty output info - fn get_counterparty_output_claim_info(&self, commitment_number: u64, commitment_txid: Txid, tx: Option<&Transaction>) + fn get_counterparty_output_claim_info(&self, commitment_number: u64, commitment_txid: Txid, tx: Option<&Transaction>, per_commitment_option: Option<&Vec<(HTLCOutputInCommitment, Option>)>>) -> (Vec, CommitmentTxCounterpartyOutputInfo) { let mut claimable_outpoints = Vec::new(); let mut to_counterparty_output_info: CommitmentTxCounterpartyOutputInfo = None; - let htlc_outputs = match self.counterparty_claimable_outpoints.get(&commitment_txid) { + let per_commitment_claimable_data = match per_commitment_option { Some(outputs) => outputs, None => return (claimable_outpoints, to_counterparty_output_info), }; @@ -3261,7 +3380,7 @@ impl ChannelMonitorImpl { let revokeable_p2wsh = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.counterparty_commitment_params.on_counterparty_tx_csv, - &delayed_key).to_v0_p2wsh(); + &delayed_key).to_p2wsh(); for (idx, outp) in transaction.output.iter().enumerate() { if outp.script_pubkey == revokeable_p2wsh { to_counterparty_output_info = @@ -3270,11 +3389,11 @@ impl ChannelMonitorImpl { } } - for (_, &(ref htlc, _)) in htlc_outputs.iter().enumerate() { + for &(ref htlc, _) in per_commitment_claimable_data.iter() { if let Some(transaction_output_index) = htlc.transaction_output_index { if let Some(transaction) = tx { if transaction_output_index as usize >= transaction.output.len() || - transaction.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 { + transaction.output[transaction_output_index as usize].value != htlc.to_bitcoin_amount() { // per_commitment_data is corrupt or our commitment signing key leaked! return (claimable_outpoints, to_counterparty_output_info); } @@ -3357,7 +3476,7 @@ impl ChannelMonitorImpl { let mut claim_requests = Vec::with_capacity(holder_tx.htlc_outputs.len()); let redeemscript = chan_utils::get_revokeable_redeemscript(&holder_tx.revocation_key, self.on_holder_tx_csv, &holder_tx.delayed_payment_key); - let broadcasted_holder_revokable_script = Some((redeemscript.to_v0_p2wsh(), holder_tx.per_commitment_point.clone(), holder_tx.revocation_key.clone())); + let broadcasted_holder_revokable_script = Some((redeemscript.to_p2wsh(), holder_tx.per_commitment_point.clone(), holder_tx.revocation_key.clone())); for &(ref htlc, _, _) in holder_tx.htlc_outputs.iter() { if let Some(transaction_output_index) = htlc.transaction_output_index { @@ -3460,6 +3579,8 @@ impl ChannelMonitorImpl { if counterparty_commitment_txid == confirmed_commitment_txid { continue; } + // If we have generated claims for counterparty_commitment_txid earlier, we can rely on always + // having claim related htlcs for counterparty_commitment_txid in counterparty_claimable_outpoints. for (htlc, _) in self.counterparty_claimable_outpoints.get(counterparty_commitment_txid).unwrap_or(&vec![]) { log_trace!(logger, "Canceling claims for previously confirmed counterparty commitment {}", counterparty_commitment_txid); @@ -3502,45 +3623,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( @@ -3563,9 +3645,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); + } } } } @@ -3602,11 +3687,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); @@ -3631,11 +3716,11 @@ impl ChannelMonitorImpl { { let txn_matched = self.filter_block(txdata); for tx in &txn_matched { - let mut output_val = 0; + let mut output_val = Amount::ZERO; for out in tx.output.iter() { - if out.value > 21_000_000_0000_0000 { panic!("Value-overflowing transaction provided to block connected"); } + if out.value > Amount::MAX_MONEY { panic!("Value-overflowing transaction provided to block connected"); } output_val += out.value; - if output_val > 21_000_000_0000_0000 { panic!("Value-overflowing transaction provided to block connected"); } + if output_val > Amount::MAX_MONEY { panic!("Value-overflowing transaction provided to block connected"); } } } @@ -3688,24 +3773,25 @@ impl ChannelMonitorImpl { self.funding_spend_seen = true; let mut commitment_tx_to_counterparty_output = None; if (tx.input[0].sequence.0 >> 8*3) as u8 == 0x80 && (tx.lock_time.to_consensus_u32() >> 8*3) as u8 == 0x20 { - let (mut new_outpoints, new_outputs, counterparty_output_idx_sats) = - self.check_spend_counterparty_transaction(&tx, height, &block_hash, &logger); - commitment_tx_to_counterparty_output = counterparty_output_idx_sats; - if !new_outputs.1.is_empty() { - watch_outputs.push(new_outputs); - } - claimable_outpoints.append(&mut new_outpoints); - if new_outpoints.is_empty() { - if let Some((mut new_outpoints, new_outputs)) = self.check_spend_holder_transaction(&tx, height, &block_hash, &logger) { - #[cfg(not(fuzzing))] - debug_assert!(commitment_tx_to_counterparty_output.is_none(), - "A commitment transaction matched as both a counterparty and local commitment tx?"); - if !new_outputs.1.is_empty() { - watch_outputs.push(new_outputs); - } - claimable_outpoints.append(&mut new_outpoints); - balance_spendable_csv = Some(self.on_holder_tx_csv); + if let Some((mut new_outpoints, new_outputs)) = self.check_spend_holder_transaction(&tx, height, &block_hash, &logger) { + if !new_outputs.1.is_empty() { + watch_outputs.push(new_outputs); + } + + claimable_outpoints.append(&mut new_outpoints); + balance_spendable_csv = Some(self.on_holder_tx_csv); + } else { + let mut new_watch_outputs = Vec::new(); + for (idx, outp) in tx.output.iter().enumerate() { + new_watch_outputs.push((idx as u32, outp.clone())); } + watch_outputs.push((txid, new_watch_outputs)); + + let (mut new_outpoints, counterparty_output_idx_sats) = + self.check_spend_counterparty_transaction(&tx, height, &block_hash, &logger); + commitment_tx_to_counterparty_output = counterparty_output_idx_sats; + + claimable_outpoints.append(&mut new_outpoints); } } self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry { @@ -3751,7 +3837,7 @@ impl ChannelMonitorImpl { } } - if height > self.best_block.height() { + if height > self.best_block.height { self.best_block = BestBlock::new(block_hash, height); } @@ -3783,11 +3869,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); } @@ -3874,8 +3960,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. @@ -3981,7 +4067,7 @@ impl ChannelMonitorImpl { // If the expected script is a known type, check that the witness // appears to be spending the correct type (ie that the match would // actually succeed in BIP 158/159-style filters). - if _script_pubkey.is_v0_p2wsh() { + if _script_pubkey.is_p2wsh() { if input.witness.last().unwrap().to_vec() == deliberately_bogus_accepted_htlc_witness_program() { // In at least one test we use a deliberately bogus witness // script which hit an old panic. Thus, we check for that here @@ -3990,7 +4076,7 @@ impl ChannelMonitorImpl { } assert_eq!(&bitcoin::Address::p2wsh(&ScriptBuf::from(input.witness.last().unwrap().to_vec()), bitcoin::Network::Bitcoin).script_pubkey(), _script_pubkey); - } else if _script_pubkey.is_v0_p2wpkh() { + } else if _script_pubkey.is_p2wpkh() { assert_eq!(&bitcoin::Address::p2wpkh(&bitcoin::PublicKey::from_slice(&input.witness.last().unwrap()).unwrap(), bitcoin::Network::Bitcoin).unwrap().script_pubkey(), _script_pubkey); } else { panic!(); } } @@ -4026,7 +4112,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 { @@ -4131,9 +4217,8 @@ impl ChannelMonitorImpl { } macro_rules! check_htlc_valid_counterparty { - ($counterparty_txid: expr, $htlc_output: expr) => { - if let Some(txid) = $counterparty_txid { - for &(ref pending_htlc, ref pending_source) in self.counterparty_claimable_outpoints.get(&txid).unwrap() { + ($htlc_output: expr, $per_commitment_data: expr) => { + for &(ref pending_htlc, ref pending_source) in $per_commitment_data { if pending_htlc.payment_hash == $htlc_output.payment_hash && pending_htlc.amount_msat == $htlc_output.amount_msat { if let &Some(ref source) = pending_source { log_claim!("revoked counterparty commitment tx", false, pending_htlc, true); @@ -4142,7 +4227,6 @@ impl ChannelMonitorImpl { } } } - } } } @@ -4159,9 +4243,13 @@ impl ChannelMonitorImpl { // resolve the source HTLC with the original sender. payment_data = Some(((*source).clone(), htlc_output.payment_hash, htlc_output.amount_msat)); } else if !$holder_tx { - check_htlc_valid_counterparty!(self.current_counterparty_commitment_txid, htlc_output); + if let Some(current_counterparty_commitment_txid) = &self.current_counterparty_commitment_txid { + check_htlc_valid_counterparty!(htlc_output, self.counterparty_claimable_outpoints.get(current_counterparty_commitment_txid).unwrap()); + } if payment_data.is_none() { - check_htlc_valid_counterparty!(self.prev_counterparty_commitment_txid, htlc_output); + if let Some(prev_counterparty_commitment_txid) = &self.prev_counterparty_commitment_txid { + check_htlc_valid_counterparty!(htlc_output, self.counterparty_claimable_outpoints.get(prev_counterparty_commitment_txid).unwrap()); + } } } if payment_data.is_none() { @@ -4199,7 +4287,7 @@ impl ChannelMonitorImpl { } } if let Some(ref htlc_outputs) = self.counterparty_claimable_outpoints.get(&input.previous_output.txid) { - scan_commitment!(htlc_outputs.iter().map(|&(ref a, ref b)| (a, (b.as_ref().clone()).map(|boxed| &**boxed))), + scan_commitment!(htlc_outputs.iter().map(|&(ref a, ref b)| (a, b.as_ref().map(|boxed| &**boxed))), "counterparty commitment tx", false); } @@ -4298,6 +4386,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()), })); } } @@ -4340,7 +4429,7 @@ impl ChannelMonitorImpl { } } -impl chain::Listen for (ChannelMonitor, T, F, L) +impl chain::Listen for (ChannelMonitor, T, F, L) where T::Target: BroadcasterInterface, F::Target: FeeEstimator, @@ -4355,7 +4444,7 @@ where } } -impl chain::Confirm for (M, T, F, L) +impl chain::Confirm for (M, T, F, L) where M: Deref>, T::Target: BroadcasterInterface, @@ -4600,6 +4689,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), @@ -4612,20 +4702,31 @@ 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. if onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() && - counterparty_payment_script.is_v0_p2wpkh() + counterparty_payment_script.is_p2wpkh() { let payment_point = onchain_tx_handler.channel_transaction_parameters.holder_pubkeys.payment_point; counterparty_payment_script = - chan_utils::get_to_countersignatory_with_anchors_redeemscript(&payment_point).to_v0_p2wsh(); + chan_utils::get_to_countersignatory_with_anchors_redeemscript(&payment_point).to_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, @@ -4680,16 +4781,18 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP best_block, counterparty_node_id, initial_counterparty_commitment_info, + balances_empty_height, }))) } } #[cfg(test)] mod tests { + use bitcoin::amount::Amount; use bitcoin::blockdata::locktime::absolute::LockTime; use bitcoin::blockdata::script::{ScriptBuf, Builder}; use bitcoin::blockdata::opcodes; - use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut}; + use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, Version}; use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint; use bitcoin::sighash; use bitcoin::sighash::EcdsaSighashType; @@ -4697,7 +4800,7 @@ mod tests { use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::hex::FromHex; use bitcoin::hash_types::{BlockHash, Txid}; - use bitcoin::network::constants::Network; + use bitcoin::network::Network; use bitcoin::secp256k1::{SecretKey,PublicKey}; use bitcoin::secp256k1::Secp256k1; use bitcoin::{Sequence, Witness}; @@ -4711,7 +4814,7 @@ mod tests { use crate::chain::package::{weight_offered_htlc, weight_received_htlc, weight_revoked_offered_htlc, weight_revoked_received_htlc, WEIGHT_REVOKED_OUTPUT}; use crate::chain::transaction::OutPoint; use crate::sign::InMemorySigner; - use crate::ln::{PaymentPreimage, PaymentHash, ChannelId}; + use crate::ln::types::{PaymentPreimage, PaymentHash, ChannelId}; use crate::ln::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcBasepoint, RevocationBasepoint, RevocationKey}; use crate::ln::chan_utils::{self,HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters}; use crate::ln::channelmanager::{PaymentSendFailure, PaymentId, RecipientOnionFields}; @@ -4724,6 +4827,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; @@ -4855,7 +4960,7 @@ mod tests { } } let dummy_sig = crate::crypto::utils::sign(&secp_ctx, - &bitcoin::secp256k1::Message::from_slice(&[42; 32]).unwrap(), + &bitcoin::secp256k1::Message::from_digest([42; 32]), &SecretKey::from_slice(&[42; 32]).unwrap()); macro_rules! test_preimages_exist { @@ -4987,7 +5092,7 @@ mod tests { transaction_output_index: Some($idx as u32), }; let redeem_script = if *$weight == WEIGHT_REVOKED_OUTPUT { chan_utils::get_revokeable_redeemscript(&RevocationKey::from_basepoint(&secp_ctx, &RevocationBasepoint::from(pubkey), &pubkey), 256, &DelayedPaymentKey::from_basepoint(&secp_ctx, &DelayedPaymentBasepoint::from(pubkey), &pubkey)) } else { chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, $opt_anchors, &HtlcKey::from_basepoint(&secp_ctx, &HtlcBasepoint::from(pubkey), &pubkey), &HtlcKey::from_basepoint(&secp_ctx, &HtlcBasepoint::from(pubkey), &pubkey), &RevocationKey::from_basepoint(&secp_ctx, &RevocationBasepoint::from(pubkey), &pubkey)) }; - let sighash = hash_to_message!(&$sighash_parts.segwit_signature_hash($idx, &redeem_script, $amount, EcdsaSighashType::All).unwrap()[..]); + let sighash = hash_to_message!(&$sighash_parts.p2wsh_signature_hash($idx, &redeem_script, $amount, EcdsaSighashType::All).unwrap()[..]); let sig = secp_ctx.sign_ecdsa(&sighash, &privkey); let mut ser_sig = sig.serialize_der().to_vec(); ser_sig.push(EcdsaSighashType::All as u8); @@ -5016,7 +5121,7 @@ mod tests { // Justice tx with 1 to_holder, 2 revoked offered HTLCs, 1 revoked received HTLCs for channel_type_features in [ChannelTypeFeatures::only_static_remote_key(), ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies()].iter() { - let mut claim_tx = Transaction { version: 0, lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() }; + let mut claim_tx = Transaction { version: Version(0), lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() }; let mut sum_actual_sigs = 0; for i in 0..4 { claim_tx.input.push(TxIn { @@ -5031,7 +5136,7 @@ mod tests { } claim_tx.output.push(TxOut { script_pubkey: script_pubkey.clone(), - value: 0, + value: Amount::ZERO, }); let base_weight = claim_tx.weight().to_wu(); let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT, weight_revoked_offered_htlc(channel_type_features), weight_revoked_offered_htlc(channel_type_features), weight_revoked_received_htlc(channel_type_features)]; @@ -5039,7 +5144,7 @@ mod tests { { let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx); for (idx, inp) in inputs_weight.iter().enumerate() { - sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, channel_type_features); + sign_input!(sighash_parts, idx, Amount::ZERO, inp, sum_actual_sigs, channel_type_features); inputs_total_weight += inp; } } @@ -5048,7 +5153,7 @@ mod tests { // Claim tx with 1 offered HTLCs, 3 received HTLCs for channel_type_features in [ChannelTypeFeatures::only_static_remote_key(), ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies()].iter() { - let mut claim_tx = Transaction { version: 0, lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() }; + let mut claim_tx = Transaction { version: Version(0), lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() }; let mut sum_actual_sigs = 0; for i in 0..4 { claim_tx.input.push(TxIn { @@ -5063,7 +5168,7 @@ mod tests { } claim_tx.output.push(TxOut { script_pubkey: script_pubkey.clone(), - value: 0, + value: Amount::ZERO, }); let base_weight = claim_tx.weight().to_wu(); let inputs_weight = vec![weight_offered_htlc(channel_type_features), weight_received_htlc(channel_type_features), weight_received_htlc(channel_type_features), weight_received_htlc(channel_type_features)]; @@ -5071,7 +5176,7 @@ mod tests { { let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx); for (idx, inp) in inputs_weight.iter().enumerate() { - sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, channel_type_features); + sign_input!(sighash_parts, idx, Amount::ZERO, inp, sum_actual_sigs, channel_type_features); inputs_total_weight += inp; } } @@ -5080,7 +5185,7 @@ mod tests { // Justice tx with 1 revoked HTLC-Success tx output for channel_type_features in [ChannelTypeFeatures::only_static_remote_key(), ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies()].iter() { - let mut claim_tx = Transaction { version: 0, lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() }; + let mut claim_tx = Transaction { version: Version(0), lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() }; let mut sum_actual_sigs = 0; claim_tx.input.push(TxIn { previous_output: BitcoinOutPoint { @@ -5093,7 +5198,7 @@ mod tests { }); claim_tx.output.push(TxOut { script_pubkey: script_pubkey.clone(), - value: 0, + value: Amount::ZERO, }); let base_weight = claim_tx.weight().to_wu(); let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT]; @@ -5101,7 +5206,7 @@ mod tests { { let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx); for (idx, inp) in inputs_weight.iter().enumerate() { - sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, channel_type_features); + sign_input!(sighash_parts, idx, Amount::ZERO, inp, sum_actual_sigs, channel_type_features); inputs_total_weight += inp; } } @@ -5158,7 +5263,8 @@ mod tests { best_block, dummy_key, channel_id); let chan_id = monitor.inner.lock().unwrap().channel_id(); - let context_logger = WithChannelMonitor::from(&logger, &monitor); + let payment_hash = PaymentHash([1; 32]); + let context_logger = WithChannelMonitor::from(&logger, &monitor, Some(payment_hash)); log_error!(context_logger, "This is an error"); log_warn!(context_logger, "This is an error"); log_debug!(context_logger, "This is an error");