X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=47f5605edbb3cbeaa45ff3dfed8609baa6a422fa;hb=543674f1dac007586be8c94ae73af1ca82b5e095;hp=4d3b4d53ad75c0ce69959c0041a68f7b92eed3c5;hpb=0c250468d632ed6df93d8a9d34389a2cb61eac40;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 4d3b4d53..47f5605e 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -31,12 +31,13 @@ use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash}; 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}; @@ -502,6 +503,9 @@ pub(crate) enum ChannelMonitorUpdateStep { htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, commitment_number: u64, their_per_commitment_point: PublicKey, + feerate_per_kw: Option, + to_broadcaster_value_sat: Option, + to_countersignatory_value_sat: Option, }, PaymentPreimage { payment_preimage: PaymentPreimage, @@ -544,8 +548,11 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep, }, (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) => { @@ -882,6 +889,14 @@ pub(crate) struct ChannelMonitorImpl { /// The node_id of our counterparty counterparty_node_id: Option, + + /// 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. @@ -1072,6 +1087,7 @@ impl Writeable for ChannelMonitorImpl ChannelMonitor { best_block, counterparty_node_id: Some(counterparty_node_id), + initial_counterparty_commitment_info: None, }) } @@ -1230,11 +1247,31 @@ impl ChannelMonitor { 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( + &self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, + 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( + #[cfg(test)] + fn provide_latest_counterparty_commitment_tx( &self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, @@ -1370,6 +1407,67 @@ impl ChannelMonitor { 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 { + 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 { + 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 { + 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() } @@ -2226,6 +2324,25 @@ impl ChannelMonitorImpl { Ok(()) } + pub(crate) fn provide_initial_counterparty_commitment_tx( + &mut self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, + 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(&mut self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, 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. @@ -2471,7 +2588,7 @@ impl ChannelMonitorImpl { 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) }, @@ -2525,7 +2642,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 {}!", 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 @@ -2543,6 +2660,10 @@ impl ChannelMonitorImpl { } } + #[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 { @@ -2651,6 +2772,91 @@ impl ChannelMonitorImpl { ret } + pub(crate) fn initial_counterparty_commitment_tx(&mut self) -> Option { + 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>)> + ) -> 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 { + 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::>(); + + 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 { + 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) @@ -3183,7 +3389,7 @@ impl ChannelMonitorImpl { 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 { @@ -4113,6 +4319,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP 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), @@ -4122,6 +4329,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP (11, confirmed_commitment_tx_counterparty_output, option), (13, spendable_txids_confirmed, optional_vec), (15, counterparty_fulfilled_htlcs, option), + (17, initial_counterparty_commitment_info, option), }); Ok((best_block.block_hash(), ChannelMonitor::from_impl(ChannelMonitorImpl { @@ -4177,6 +4385,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP best_block, counterparty_node_id, + initial_counterparty_commitment_info, }))) } }