use bitcoin::blockdata::block::BlockHeader;
use bitcoin::blockdata::transaction::{OutPoint as BitcoinOutPoint, TxOut, Transaction};
-use bitcoin::blockdata::script::{Script, Builder};
-use bitcoin::blockdata::opcodes;
+use bitcoin::blockdata::script::Script;
use bitcoin::hashes::Hash;
use bitcoin::hashes::sha256::Hash as Sha256;
-use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
+use bitcoin::hash_types::{Txid, BlockHash};
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
use bitcoin::secp256k1::{SecretKey, PublicKey};
-use bitcoin::secp256k1;
+use bitcoin::{secp256k1, EcdsaSighashType};
+use crate::ln::channel::INITIAL_COMMITMENT_NUMBER;
use crate::ln::{PaymentHash, PaymentPreimage};
use crate::ln::msgs::DecodeError;
use crate::ln::chan_utils;
-use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCClaim, ChannelTransactionParameters, HolderCommitmentTransaction};
+use crate::ln::chan_utils::{CommitmentTransaction, CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCClaim, ChannelTransactionParameters, HolderCommitmentTransaction, TxCreationKeys};
use crate::ln::channelmanager::{HTLCSource, SentHTLCId};
use crate::chain;
use crate::chain::{BestBlock, WatchedOutput};
/// much smaller than a full [`ChannelMonitor`]. However, for large single commitment transaction
/// updates (e.g. ones during which there are hundreds of HTLCs pending on the commitment
/// transaction), a single update may reach upwards of 1 MiB in serialized size.
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
#[must_use]
pub struct ChannelMonitorUpdate {
pub(crate) updates: Vec<ChannelMonitorUpdateStep>,
HTLCEvent(HTLCUpdate),
/// A monitor event that the Channel's commitment transaction was confirmed.
- CommitmentTxConfirmed(OutPoint),
+ HolderForceClosed(OutPoint),
/// Indicates a [`ChannelMonitor`] update has completed. See
/// [`ChannelMonitorUpdateStatus::InProgress`] for more information on how this is used.
/// same [`ChannelMonitor`] have been applied and persisted.
monitor_update_id: u64,
},
-
- /// Indicates a [`ChannelMonitor`] update has failed. See
- /// [`ChannelMonitorUpdateStatus::PermanentFailure`] for more information on how this is used.
- ///
- /// [`ChannelMonitorUpdateStatus::PermanentFailure`]: super::ChannelMonitorUpdateStatus::PermanentFailure
- UpdateFailed(OutPoint),
}
impl_writeable_tlv_based_enum_upgradable!(MonitorEvent,
- // Note that Completed and UpdateFailed are currently never serialized to disk as they are
- // generated only in ChainMonitor
+ // Note that Completed is currently never serialized to disk as it is generated only in
+ // ChainMonitor.
(0, Completed) => {
(0, funding_txo, required),
(2, monitor_update_id, required),
},
;
(2, HTLCEvent),
- (4, CommitmentTxConfirmed),
- (6, UpdateFailed),
+ (4, HolderForceClosed),
+ // 6 was `UpdateFailed` until LDK 0.0.117
);
/// Simple structure sent back by `chain::Watch` when an HTLC from a forward channel is detected on
);
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum ChannelMonitorUpdateStep {
LatestHolderCommitmentTXInfo {
commitment_tx: HolderCommitmentTransaction,
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
commitment_number: u64,
their_per_commitment_point: PublicKey,
+ feerate_per_kw: Option<u32>,
+ to_broadcaster_value_sat: Option<u64>,
+ to_countersignatory_value_sat: Option<u64>,
},
PaymentPreimage {
payment_preimage: PaymentPreimage,
},
(1, LatestCounterpartyCommitmentTXInfo) => {
(0, commitment_txid, required),
+ (1, feerate_per_kw, option),
(2, commitment_number, required),
+ (3, to_broadcaster_value_sat, option),
(4, their_per_commitment_point, required),
+ (5, to_countersignatory_value_sat, option),
(6, htlc_outputs, required_vec),
},
(2, PaymentPreimage) => {
/// The node_id of our counterparty
counterparty_node_id: Option<PublicKey>,
+
+ /// Initial counterparty commmitment data needed to recreate the commitment tx
+ /// in the persistence pipeline for third-party watchtowers. This will only be present on
+ /// monitors created after 0.0.117.
+ ///
+ /// 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)>,
}
/// Transaction outputs to watch for on-chain spends.
writer.write_all(&(self.pending_monitor_events.iter().filter(|ev| match ev {
MonitorEvent::HTLCEvent(_) => true,
- MonitorEvent::CommitmentTxConfirmed(_) => true,
+ MonitorEvent::HolderForceClosed(_) => true,
_ => false,
}).count() as u64).to_be_bytes())?;
for event in self.pending_monitor_events.iter() {
0u8.write(writer)?;
upd.write(writer)?;
},
- MonitorEvent::CommitmentTxConfirmed(_) => 1u8.write(writer)?,
+ MonitorEvent::HolderForceClosed(_) => 1u8.write(writer)?,
_ => {}, // Covered in the TLV writes below
}
}
(11, self.confirmed_commitment_tx_counterparty_output, option),
(13, self.spendable_txids_confirmed, required_vec),
(15, self.counterparty_fulfilled_htlcs, required),
+ (17, self.initial_counterparty_commitment_info, option),
});
Ok(())
best_block: BestBlock, counterparty_node_id: PublicKey) -> ChannelMonitor<Signer> {
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
- let payment_key_hash = WPubkeyHash::hash(&keys.pubkeys().payment_point.serialize());
- let counterparty_payment_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_key_hash[..]).into_script();
+ let counterparty_payment_script = chan_utils::get_counterparty_payment_script(
+ &channel_parameters.channel_type_features, &keys.pubkeys().payment_point
+ );
let counterparty_channel_parameters = channel_parameters.counterparty_parameters.as_ref().unwrap();
let counterparty_delayed_payment_base_key = counterparty_channel_parameters.pubkeys.delayed_payment_basepoint;
best_block,
counterparty_node_id: Some(counterparty_node_id),
+ initial_counterparty_commitment_info: None,
})
}
self.inner.lock().unwrap().provide_secret(idx, secret)
}
+ /// A variant of `Self::provide_latest_counterparty_commitment_tx` used to provide
+ /// additional information to the monitor to store in order to recreate the initial
+ /// counterparty commitment transaction during persistence (mainly for use in third-party
+ /// watchtowers).
+ ///
+ /// This is used to provide the counterparty commitment information directly to the monitor
+ /// before the initial persistence of a new channel.
+ pub(crate) fn provide_initial_counterparty_commitment_tx<L: Deref>(
+ &self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
+ commitment_number: u64, their_cur_per_commitment_point: PublicKey, feerate_per_kw: u32,
+ to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, logger: &L,
+ )
+ where L::Target: Logger
+ {
+ self.inner.lock().unwrap().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);
+ }
+
/// Informs this monitor of the latest counterparty (ie non-broadcastable) commitment transaction.
/// The monitor watches for it to be broadcasted and then uses the HTLC information (and
/// possibly future revocation/preimage information) to claim outputs where possible.
/// We cache also the mapping hash:commitment number to lighten pruning of old preimages by watchtowers.
- pub(crate) fn provide_latest_counterparty_commitment_tx<L: Deref>(
+ #[cfg(test)]
+ fn provide_latest_counterparty_commitment_tx<L: Deref>(
&self,
txid: Txid,
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
ret
}
+ /// Gets the counterparty's initial commitment transaction. The returned commitment
+ /// transaction is unsigned. This is intended to be called during the initial persistence of
+ /// the monitor (inside an implementation of [`Persist::persist_new_channel`]), to allow for
+ /// watchtowers in the persistence pipeline to have enough data to form justice transactions.
+ ///
+ /// This is similar to [`Self::counterparty_commitment_txs_from_update`], except
+ /// that for the initial commitment transaction, we don't have a corresponding update.
+ ///
+ /// This will only return `Some` for channel monitors that have been created after upgrading
+ /// to LDK 0.0.117+.
+ ///
+ /// [`Persist::persist_new_channel`]: crate::chain::chainmonitor::Persist::persist_new_channel
+ pub fn initial_counterparty_commitment_tx(&self) -> Option<CommitmentTransaction> {
+ self.inner.lock().unwrap().initial_counterparty_commitment_tx()
+ }
+
+ /// Gets all of the counterparty commitment transactions provided by the given update. This
+ /// may be empty if the update doesn't include any new counterparty commitments. Returned
+ /// commitment transactions are unsigned.
+ ///
+ /// This is provided so that watchtower clients in the persistence pipeline are able to build
+ /// justice transactions for each counterparty commitment upon each update. It's intended to be
+ /// used within an implementation of [`Persist::update_persisted_channel`], which is provided
+ /// with a monitor and an update. Once revoked, signing a justice transaction can be done using
+ /// [`Self::sign_to_local_justice_tx`].
+ ///
+ /// It is expected that a watchtower client may use this method to retrieve the latest counterparty
+ /// commitment transaction(s), and then hold the necessary data until a later update in which
+ /// the monitor has been updated with the corresponding revocation data, at which point the
+ /// monitor can sign the justice transaction.
+ ///
+ /// This will only return a non-empty list for monitor updates that have been created after
+ /// upgrading to LDK 0.0.117+. Note that no restriction lies on the monitors themselves, which
+ /// may have been created prior to upgrading.
+ ///
+ /// [`Persist::update_persisted_channel`]: crate::chain::chainmonitor::Persist::update_persisted_channel
+ pub fn counterparty_commitment_txs_from_update(&self, update: &ChannelMonitorUpdate) -> Vec<CommitmentTransaction> {
+ self.inner.lock().unwrap().counterparty_commitment_txs_from_update(update)
+ }
+
+ /// Wrapper around [`EcdsaChannelSigner::sign_justice_revoked_output`] to make
+ /// signing the justice transaction easier for implementors of
+ /// [`chain::chainmonitor::Persist`]. On success this method returns the provided transaction
+ /// signing the input at `input_idx`. This method will only produce a valid signature for
+ /// a transaction spending the `to_local` output of a commitment transaction, i.e. this cannot
+ /// be used for revoked HTLC outputs.
+ ///
+ /// `Value` is the value of the output being spent by the input at `input_idx`, committed
+ /// in the BIP 143 signature.
+ ///
+ /// This method will only succeed if this monitor has received the revocation secret for the
+ /// provided `commitment_number`. If a commitment number is provided that does not correspond
+ /// to the commitment transaction being revoked, this will return a signed transaction, but
+ /// the signature will not be valid.
+ ///
+ /// [`EcdsaChannelSigner::sign_justice_revoked_output`]: crate::sign::EcdsaChannelSigner::sign_justice_revoked_output
+ /// [`Persist`]: crate::chain::chainmonitor::Persist
+ pub fn sign_to_local_justice_tx(&self, justice_tx: Transaction, input_idx: usize, value: u64, commitment_number: u64) -> Result<Transaction, ()> {
+ self.inner.lock().unwrap().sign_to_local_justice_tx(justice_tx, input_idx, value, commitment_number)
+ }
+
pub(crate) fn get_min_seen_secret(&self) -> u64 {
self.inner.lock().unwrap().get_min_seen_secret()
}
self.inner.lock().unwrap().counterparty_node_id
}
- /// Used by ChannelManager deserialization to broadcast the latest holder state if its copy of
- /// the Channel was out-of-date.
+ /// 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
- /// a monitor update failed with [`ChannelMonitorUpdateStatus::PermanentFailure`] 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).
+ /// 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
/// 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. In any-case, the choice is up to you.
+ /// to you.
///
- /// [`ChannelMonitorUpdateStatus::PermanentFailure`]: super::ChannelMonitorUpdateStatus::PermanentFailure
+ /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
pub fn get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Vec<Transaction>
where L::Target: Logger {
self.inner.lock().unwrap().get_latest_holder_commitment_txn(logger)
current_height, &broadcaster, &fee_estimator, &logger,
);
}
+
+ /// Returns the descriptors for relevant outputs (i.e., those that we can spend) within the
+ /// transaction if they exist and the transaction has at least [`ANTI_REORG_DELAY`]
+ /// confirmations. For [`SpendableOutputDescriptor::DelayedPaymentOutput`] descriptors to be
+ /// returned, the transaction must have at least `max(ANTI_REORG_DELAY, to_self_delay)`
+ /// confirmations.
+ ///
+ /// Descriptors returned by this method are primarily exposed via [`Event::SpendableOutputs`]
+ /// once they are no longer under reorg risk. This method serves as a way to retrieve these
+ /// descriptors at a later time, either for historical purposes, or to replay any
+ /// missed/unhandled descriptors. For the purpose of gathering historical records, if the
+ /// channel close has fully resolved (i.e., [`ChannelMonitor::get_claimable_balances`] returns
+ /// an empty set), you can retrieve all spendable outputs by providing all descendant spending
+ /// transactions starting from the channel's funding transaction and going down three levels.
+ ///
+ /// `tx` is a transaction we'll scan the outputs of. Any transaction can be provided. If any
+ /// outputs which can be spent by us are found, at least one descriptor is returned.
+ ///
+ /// `confirmation_height` must be the height of the block in which `tx` was included in.
+ pub fn get_spendable_outputs(&self, tx: &Transaction, confirmation_height: u32) -> Vec<SpendableOutputDescriptor> {
+ let inner = self.inner.lock().unwrap();
+ let current_height = inner.best_block.height;
+ let mut spendable_outputs = inner.get_spendable_outputs(tx);
+ spendable_outputs.retain(|descriptor| {
+ let mut conf_threshold = current_height.saturating_sub(ANTI_REORG_DELAY) + 1;
+ if let SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) = descriptor {
+ conf_threshold = cmp::min(conf_threshold,
+ current_height.saturating_sub(descriptor.to_self_delay as u32) + 1);
+ }
+ conf_threshold >= confirmation_height
+ });
+ spendable_outputs
+ }
+
+ #[cfg(test)]
+ pub fn get_counterparty_payment_script(&self) -> Script{
+ self.inner.lock().unwrap().counterparty_payment_script.clone()
+ }
+
+ #[cfg(test)]
+ pub fn set_counterparty_payment_script(&self, script: Script) {
+ self.inner.lock().unwrap().counterparty_payment_script = script;
+ }
}
impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
},
OnchainEvent::MaturingOutput {
descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor) }
- if descriptor.outpoint.index as u32 == htlc_commitment_tx_output_idx => {
+ if event.transaction.as_ref().map(|tx| tx.input.iter().enumerate()
+ .any(|(input_idx, inp)|
+ Some(inp.previous_output.txid) == confirmed_txid &&
+ inp.previous_output.vout == htlc_commitment_tx_output_idx &&
+ // A maturing output for an HTLC claim will always be at the same
+ // index as the HTLC input. This is true pre-anchors, as there's
+ // only 1 input and 1 output. This is also true post-anchors,
+ // because we have a SIGHASH_SINGLE|ANYONECANPAY signature from our
+ // channel counterparty.
+ descriptor.outpoint.index as usize == input_idx
+ ))
+ .unwrap_or(false)
+ => {
debug_assert!(holder_delayed_output_pending.is_none());
holder_delayed_output_pending = Some(event.confirmation_threshold());
},
/// confirmations on the claim transaction.
///
/// Note that for `ChannelMonitors` which track a channel which went on-chain with versions of
- /// LDK prior to 0.0.111, balances may not be fully captured if our counterparty broadcasted
- /// a revoked state.
+ /// LDK prior to 0.0.111, not all or excess balances may be included.
///
/// See [`Balance`] for additional details on the types of claimable balances which
/// may be returned here and their meanings.
#[cfg(test)]
pub fn deliberately_bogus_accepted_htlc_witness_program() -> Vec<u8> {
+ use bitcoin::blockdata::opcodes;
let mut ret = [opcodes::all::OP_NOP.to_u8(); 136];
ret[131] = opcodes::all::OP_DROP.to_u8();
ret[132] = opcodes::all::OP_DROP.to_u8();
Ok(())
}
+ pub(crate) fn provide_initial_counterparty_commitment_tx<L: Deref>(
+ &mut self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
+ commitment_number: u64, their_per_commitment_point: PublicKey, feerate_per_kw: u32,
+ to_broadcaster_value: u64, to_countersignatory_value: u64, logger: &L
+ )
+ where L::Target: Logger
+ {
+ self.initial_counterparty_commitment_info = Some((their_per_commitment_point.clone(),
+ feerate_per_kw, to_broadcaster_value, to_countersignatory_value));
+
+ #[cfg(debug_assertions)] {
+ let rebuilt_commitment_tx = self.initial_counterparty_commitment_tx().unwrap();
+ debug_assert_eq!(rebuilt_commitment_tx.trust().txid(), txid);
+ }
+
+ self.provide_latest_counterparty_commitment_tx(txid, htlc_outputs, commitment_number,
+ their_per_commitment_point, logger);
+ }
+
pub(crate) fn provide_latest_counterparty_commitment_tx<L: Deref>(&mut self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>, commitment_number: u64, their_per_commitment_point: PublicKey, logger: &L) where L::Target: Logger {
// TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction
// so that a remote monitor doesn't learn anything unless there is a malicious close.
{
self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone());
+ let confirmed_spend_txid = self.funding_spend_confirmed.or_else(|| {
+ self.onchain_events_awaiting_threshold_conf.iter().find_map(|event| match event.event {
+ OnchainEvent::FundingSpendConfirmation { .. } => Some(event.txid),
+ _ => None,
+ })
+ });
+ let confirmed_spend_txid = if let Some(txid) = confirmed_spend_txid {
+ txid
+ } else {
+ return;
+ };
+
// 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 {
}
}
if let Some(txid) = self.current_counterparty_commitment_txid {
- if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
- claim_htlcs!(*commitment_number, txid);
+ if txid == confirmed_spend_txid {
+ if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
+ claim_htlcs!(*commitment_number, txid);
+ } else {
+ debug_assert!(false);
+ log_error!(logger, "Detected counterparty commitment tx on-chain without tracking commitment number");
+ }
return;
}
}
if let Some(txid) = self.prev_counterparty_commitment_txid {
- if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
- claim_htlcs!(*commitment_number, txid);
+ if txid == confirmed_spend_txid {
+ if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
+ claim_htlcs!(*commitment_number, txid);
+ } else {
+ debug_assert!(false);
+ log_error!(logger, "Detected counterparty commitment tx on-chain without tracking commitment number");
+ }
return;
}
}
// *we* sign a holder commitment transaction, not when e.g. a watchtower broadcasts one of our
// holder commitment transactions.
if self.broadcasted_holder_revokable_script.is_some() {
- // 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(&self.current_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);
- if let Some(ref tx) = self.prev_holder_signed_commitment_tx {
- let (claim_reqs, _) = self.get_broadcasted_holder_claims(&tx, self.best_block.height());
+ let holder_commitment_tx = if self.current_holder_commitment_tx.txid == confirmed_spend_txid {
+ Some(&self.current_holder_commitment_tx)
+ } else if let Some(prev_holder_commitment_tx) = &self.prev_holder_signed_commitment_tx {
+ if prev_holder_commitment_tx.txid == confirmed_spend_txid {
+ Some(prev_holder_commitment_tx)
+ } else {
+ None
+ }
+ } else {
+ None
+ };
+ if let Some(holder_commitment_tx) = holder_commitment_tx {
+ // 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);
}
}
txs.push(tx);
}
broadcaster.broadcast_transactions(&txs);
- self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0));
+ self.pending_monitor_events.push(MonitorEvent::HolderForceClosed(self.funding_info.0));
}
pub fn update_monitor<B: Deref, F: Deref, L: Deref>(&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: F, logger: &L) -> Result<(), ()>
ret = Err(());
}
}
- ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_per_commitment_point } => {
+ ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_per_commitment_point, .. } => {
log_trace!(logger, "Updating ChannelMonitor with latest counterparty commitment transaction info");
self.provide_latest_counterparty_commitment_tx(*commitment_txid, htlc_outputs.clone(), *commitment_number, *their_per_commitment_point, logger)
},
ChannelMonitorUpdateStep::CommitmentSecret { idx, secret } => {
log_trace!(logger, "Updating ChannelMonitor with commitment secret");
if let Err(e) = self.provide_secret(*idx, *secret) {
+ debug_assert!(false, "Latest counterparty commitment secret was invalid");
log_error!(logger, "Providing latest counterparty commitment secret failed/was refused:");
log_error!(logger, " {}", e);
ret = Err(());
}
} 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 {}!", log_bytes!(self.funding_info.0.to_channel_id()));
+ log_error!(logger, " in channel monitor for channel {}!", &self.funding_info.0.to_channel_id());
log_error!(logger, " Read the docs for ChannelMonitor::get_latest_holder_commitment_txn and take manual action!");
} else {
- // If we generated a MonitorEvent::CommitmentTxConfirmed, the ChannelManager
+ // If we generated a MonitorEvent::HolderForceClosed, the ChannelManager
// will still give us a ChannelForceClosed event with !should_broadcast, but we
// shouldn't print the scary warning above.
log_info!(logger, "Channel off-chain state closed after we broadcasted our latest commitment transaction.");
}
}
+ #[cfg(debug_assertions)] {
+ self.counterparty_commitment_txs_from_update(updates);
+ }
+
// If the updates succeeded and we were in an already closed channel state, then there's no
// need to refuse any updates we expect to receive afer seeing a confirmed commitment.
if ret.is_ok() && updates.update_id == CLOSED_CHANNEL_UPDATE_ID && self.latest_update_id == updates.update_id {
ret
}
+ pub(crate) fn initial_counterparty_commitment_tx(&mut self) -> Option<CommitmentTransaction> {
+ let (their_per_commitment_point, feerate_per_kw, to_broadcaster_value,
+ to_countersignatory_value) = self.initial_counterparty_commitment_info?;
+ let htlc_outputs = vec![];
+
+ let commitment_tx = self.build_counterparty_commitment_tx(INITIAL_COMMITMENT_NUMBER,
+ &their_per_commitment_point, to_broadcaster_value, to_countersignatory_value,
+ feerate_per_kw, htlc_outputs);
+ Some(commitment_tx)
+ }
+
+ fn build_counterparty_commitment_tx(
+ &self, commitment_number: u64, their_per_commitment_point: &PublicKey,
+ to_broadcaster_value: u64, to_countersignatory_value: u64, feerate_per_kw: u32,
+ mut nondust_htlcs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>
+ ) -> CommitmentTransaction {
+ let broadcaster_keys = &self.onchain_tx_handler.channel_transaction_parameters
+ .counterparty_parameters.as_ref().unwrap().pubkeys;
+ let countersignatory_keys =
+ &self.onchain_tx_handler.channel_transaction_parameters.holder_pubkeys;
+
+ let broadcaster_funding_key = broadcaster_keys.funding_pubkey;
+ let countersignatory_funding_key = countersignatory_keys.funding_pubkey;
+ let keys = TxCreationKeys::from_channel_static_keys(&their_per_commitment_point,
+ &broadcaster_keys, &countersignatory_keys, &self.onchain_tx_handler.secp_ctx);
+ let channel_parameters =
+ &self.onchain_tx_handler.channel_transaction_parameters.as_counterparty_broadcastable();
+
+ CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
+ to_broadcaster_value, to_countersignatory_value, broadcaster_funding_key,
+ countersignatory_funding_key, keys, feerate_per_kw, &mut nondust_htlcs,
+ channel_parameters)
+ }
+
+ pub(crate) fn counterparty_commitment_txs_from_update(&self, update: &ChannelMonitorUpdate) -> Vec<CommitmentTransaction> {
+ update.updates.iter().filter_map(|update| {
+ match update {
+ &ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid,
+ ref htlc_outputs, commitment_number, their_per_commitment_point,
+ feerate_per_kw: Some(feerate_per_kw),
+ to_broadcaster_value_sat: Some(to_broadcaster_value),
+ to_countersignatory_value_sat: Some(to_countersignatory_value) } => {
+
+ let nondust_htlcs = htlc_outputs.iter().filter_map(|(htlc, _)| {
+ htlc.transaction_output_index.map(|_| (htlc.clone(), None))
+ }).collect::<Vec<_>>();
+
+ let commitment_tx = self.build_counterparty_commitment_tx(commitment_number,
+ &their_per_commitment_point, to_broadcaster_value,
+ to_countersignatory_value, feerate_per_kw, nondust_htlcs);
+
+ debug_assert_eq!(commitment_tx.trust().txid(), commitment_txid);
+
+ Some(commitment_tx)
+ },
+ _ => None,
+ }
+ }).collect()
+ }
+
+ pub(crate) fn sign_to_local_justice_tx(
+ &self, mut justice_tx: Transaction, input_idx: usize, value: u64, commitment_number: u64
+ ) -> Result<Transaction, ()> {
+ let secret = self.get_secret(commitment_number).ok_or(())?;
+ let per_commitment_key = SecretKey::from_slice(&secret).map_err(|_| ())?;
+ let their_per_commitment_point = PublicKey::from_secret_key(
+ &self.onchain_tx_handler.secp_ctx, &per_commitment_key);
+
+ let revocation_pubkey = chan_utils::derive_public_revocation_key(
+ &self.onchain_tx_handler.secp_ctx, &their_per_commitment_point,
+ &self.holder_revocation_basepoint);
+ let delayed_key = chan_utils::derive_public_key(&self.onchain_tx_handler.secp_ctx,
+ &their_per_commitment_point,
+ &self.counterparty_commitment_params.counterparty_delayed_payment_base_key);
+ let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey,
+ self.counterparty_commitment_params.on_counterparty_tx_csv, &delayed_key);
+
+ 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(&[1u8]);
+ justice_tx.input[input_idx].witness.push(revokeable_redeemscript.as_bytes());
+ Ok(justice_tx)
+ }
+
/// Can only fail if idx is < get_min_seen_secret
fn get_secret(&self, idx: u64) -> Option<[u8; 32]> {
self.commitment_secrets.get_secret(idx)
if prevout.txid == self.funding_info.0.txid && prevout.vout == self.funding_info.0.index as u32 {
let mut balance_spendable_csv = None;
log_info!(logger, "Channel {} closed by funding output spend in txid {}.",
- log_bytes!(self.funding_info.0.to_channel_id()), txid);
+ &self.funding_info.0.to_channel_id(), txid);
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.0 >> 8*3) as u8 == 0x20 {
}
self.is_resolving_htlc_output(&tx, height, &block_hash, &logger);
- self.is_paying_spendable_output(&tx, height, &block_hash, &logger);
+ self.check_tx_and_push_spendable_outputs(&tx, height, &block_hash, &logger);
}
}
let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone(), self.channel_value_satoshis, self.onchain_tx_handler.channel_type_features().clone());
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());
claimable_outpoints.push(commitment_package);
- self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0));
- let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
+ self.pending_monitor_events.push(MonitorEvent::HolderForceClosed(self.funding_info.0));
+ // 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.
self.holder_tx_signed = true;
// We can't broadcast our HTLC transactions while the commitment transaction is
// unconfirmed. We'll delay doing so until we detect the confirmed commitment in
// 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());
- let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
+ let unsigned_commitment_tx = self.onchain_tx_handler.get_unsigned_holder_commitment_tx();
+ let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &unsigned_commitment_tx);
if !new_outputs.is_empty() {
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
}
OnchainEvent::MaturingOutput { descriptor } => {
log_debug!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
self.pending_events.push(Event::SpendableOutputs {
- outputs: vec![descriptor]
+ outputs: vec![descriptor],
+ channel_id: Some(self.funding_info.0.to_channel_id()),
});
self.spendable_txids_confirmed.push(entry.txid);
},
}
}
- /// Check if any transaction broadcasted is paying fund back to some address we can assume to own
- fn is_paying_spendable_output<L: Deref>(&mut self, tx: &Transaction, height: u32, block_hash: &BlockHash, logger: &L) where L::Target: Logger {
- let mut spendable_output = None;
- for (i, outp) in tx.output.iter().enumerate() { // There is max one spendable output for any channel tx, including ones generated by us
- if i > ::core::u16::MAX as usize {
- // While it is possible that an output exists on chain which is greater than the
- // 2^16th output in a given transaction, this is only possible if the output is not
- // in a lightning transaction and was instead placed there by some third party who
- // wishes to give us money for no reason.
- // Namely, any lightning transactions which we pre-sign will never have anywhere
- // near 2^16 outputs both because such transactions must have ~2^16 outputs who's
- // scripts are not longer than one byte in length and because they are inherently
- // non-standard due to their size.
- // Thus, it is completely safe to ignore such outputs, and while it may result in
- // us ignoring non-lightning fund to us, that is only possible if someone fills
- // nearly a full block with garbage just to hit this case.
- continue;
- }
+ fn get_spendable_outputs(&self, tx: &Transaction) -> Vec<SpendableOutputDescriptor> {
+ let mut spendable_outputs = Vec::new();
+ for (i, outp) in tx.output.iter().enumerate() {
if outp.script_pubkey == self.destination_script {
- spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
+ spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
output: outp.clone(),
});
- break;
}
if let Some(ref broadcasted_holder_revokable_script) = self.broadcasted_holder_revokable_script {
if broadcasted_holder_revokable_script.0 == outp.script_pubkey {
- spendable_output = Some(SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor {
+ spendable_outputs.push(SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor {
outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
per_commitment_point: broadcasted_holder_revokable_script.1,
to_self_delay: self.on_holder_tx_csv,
channel_keys_id: self.channel_keys_id,
channel_value_satoshis: self.channel_value_satoshis,
}));
- break;
}
}
if self.counterparty_payment_script == outp.script_pubkey {
- spendable_output = Some(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor {
+ spendable_outputs.push(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor {
outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
output: outp.clone(),
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()),
}));
- break;
}
if self.shutdown_script.as_ref() == Some(&outp.script_pubkey) {
- spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
+ spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
output: outp.clone(),
});
- break;
}
}
- if let Some(spendable_output) = spendable_output {
+ spendable_outputs
+ }
+
+ /// Checks if the confirmed transaction is paying funds back to some address we can assume to
+ /// own.
+ fn check_tx_and_push_spendable_outputs<L: Deref>(
+ &mut self, tx: &Transaction, height: u32, block_hash: &BlockHash, logger: &L,
+ ) where L::Target: Logger {
+ for spendable_output in self.get_spendable_outputs(tx) {
let entry = OnchainEventEntry {
txid: tx.txid(),
transaction: Some(tx.clone()),
1 => { None },
_ => return Err(DecodeError::InvalidValue),
};
- let counterparty_payment_script = Readable::read(reader)?;
+ let mut counterparty_payment_script: Script = Readable::read(reader)?;
let shutdown_script = {
let script = <Script as Readable>::read(reader)?;
if script.is_empty() { None } else { Some(script) }
for _ in 0..pending_monitor_events_len {
let ev = match <u8 as Readable>::read(reader)? {
0 => MonitorEvent::HTLCEvent(Readable::read(reader)?),
- 1 => MonitorEvent::CommitmentTxConfirmed(funding_info.0),
+ 1 => MonitorEvent::HolderForceClosed(funding_info.0),
_ => return Err(DecodeError::InvalidValue)
};
pending_monitor_events.as_mut().unwrap().push(ev);
let mut confirmed_commitment_tx_counterparty_output = None;
let mut spendable_txids_confirmed = Some(Vec::new());
let mut counterparty_fulfilled_htlcs = Some(HashMap::new());
+ let mut initial_counterparty_commitment_info = None;
read_tlv_fields!(reader, {
(1, funding_spend_confirmed, option),
(3, htlcs_resolved_on_chain, optional_vec),
(11, confirmed_commitment_tx_counterparty_output, option),
(13, spendable_txids_confirmed, optional_vec),
(15, counterparty_fulfilled_htlcs, option),
+ (17, initial_counterparty_commitment_info, option),
});
+ // 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()
+ {
+ 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();
+ }
+
Ok((best_block.block_hash(), ChannelMonitor::from_impl(ChannelMonitorImpl {
latest_update_id,
commitment_transaction_number_obscure_factor,
best_block,
counterparty_node_id,
+ initial_counterparty_commitment_info,
})))
}
}
use crate::chain::chaininterface::LowerBoundedFeeEstimator;
use super::ChannelMonitorUpdateStep;
- use crate::{check_added_monitors, check_closed_broadcast, check_closed_event, check_spends, get_local_commitment_txn, get_monitor, get_route_and_payment_hash, unwrap_send_err};
+ use crate::{check_added_monitors, check_spends, get_local_commitment_txn, get_monitor, get_route_and_payment_hash, unwrap_send_err};
use crate::chain::{BestBlock, Confirm};
use crate::chain::channelmonitor::ChannelMonitor;
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::events::ClosureReason;
use crate::ln::{PaymentPreimage, PaymentHash};
use crate::ln::chan_utils;
use crate::ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], 100_000);
unwrap_send_err!(nodes[1].node.send_payment_with_route(&route, payment_hash,
RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)
- ), true, APIError::ChannelUnavailable { ref err },
- assert!(err.contains("ChannelMonitor storage failure")));
- check_added_monitors!(nodes[1], 2); // After the failure we generate a close-channel monitor update
- check_closed_broadcast!(nodes[1], true);
- check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: "ChannelMonitor storage failure".to_string() },
- [nodes[0].node.get_our_node_id()], 100000);
+ ), false, APIError::MonitorUpdateInProgress, {});
+ check_added_monitors!(nodes[1], 1);
// Build a new ChannelMonitorUpdate which contains both the failing commitment tx update
// and provides the claim preimages for the two pending HTLCs. The first update generates
// an error, but the point of this test is to ensure the later updates are still applied.
let monitor_updates = nodes[1].chain_monitor.monitor_updates.lock().unwrap();
- let mut replay_update = monitor_updates.get(&channel.2).unwrap().iter().rev().skip(1).next().unwrap().clone();
+ let mut replay_update = monitor_updates.get(&channel.2).unwrap().iter().rev().next().unwrap().clone();
assert_eq!(replay_update.updates.len(), 1);
if let ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { .. } = replay_update.updates[0] {
} else { panic!(); }