Track HTLCSource in ChannelMonitor
[rust-lightning] / src / ln / channel.rs
index cbcec942d80661dafb83e13f98826dfc2cceb2d1..de6588e7a8ba96c0f47210e1ecfd1a0603535c9a 100644 (file)
@@ -751,7 +751,7 @@ impl Channel {
        /// generated by the peer which proposed adding the HTLCs, and thus we need to understand both
        /// which peer generated this transaction and "to whom" this transaction flows.
        #[inline]
-       fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, Vec<HTLCOutputInCommitment>) {
+       fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, Vec<HTLCOutputInCommitment>, Vec<([u8; 32], HTLCSource, Option<u32>)>) {
                let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (INITIAL_COMMITMENT_NUMBER - commitment_number);
 
                let txins = {
@@ -765,7 +765,8 @@ impl Channel {
                        ins
                };
 
-               let mut txouts: Vec<(TxOut, Option<HTLCOutputInCommitment>)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2);
+               let mut txouts: Vec<(TxOut, Option<(HTLCOutputInCommitment, Option<HTLCSource>)>)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2);
+               let mut unincluded_htlc_sources: Vec<([u8; 32], HTLCSource, Option<u32>)> = Vec::new();
 
                let dust_limit_satoshis = if local { self.our_dust_limit_satoshis } else { self.their_dust_limit_satoshis };
                let mut remote_htlc_total_msat = 0;
@@ -773,14 +774,18 @@ impl Channel {
                let mut value_to_self_msat_offset = 0;
 
                macro_rules! add_htlc_output {
-                       ($htlc: expr, $outbound: expr) => {
+                       ($htlc: expr, $outbound: expr, $source: expr) => {
                                if $outbound == local { // "offered HTLC output"
                                        if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000) {
                                                let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
                                                txouts.push((TxOut {
                                                        script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
                                                        value: $htlc.amount_msat / 1000
-                                               }, Some(htlc_in_tx)));
+                                               }, Some((htlc_in_tx, $source))));
+                                       } else {
+                                               if let Some(source) = $source {
+                                                       unincluded_htlc_sources.push(($htlc.payment_hash, source, None));
+                                               }
                                        }
                                } else {
                                        if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) {
@@ -788,7 +793,11 @@ impl Channel {
                                                txouts.push((TxOut { // "received HTLC output"
                                                        script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
                                                        value: $htlc.amount_msat / 1000
-                                               }, Some(htlc_in_tx)));
+                                               }, Some((htlc_in_tx, $source))));
+                                       } else {
+                                               if let Some(source) = $source {
+                                                       unincluded_htlc_sources.push(($htlc.payment_hash, source, None));
+                                               }
                                        }
                                }
                        }
@@ -804,7 +813,7 @@ impl Channel {
                        };
 
                        if include {
-                               add_htlc_output!(htlc, false);
+                               add_htlc_output!(htlc, false, None);
                                remote_htlc_total_msat += htlc.amount_msat;
                        } else {
                                match &htlc.state {
@@ -830,7 +839,7 @@ impl Channel {
                        };
 
                        if include {
-                               add_htlc_output!(htlc, true);
+                               add_htlc_output!(htlc, true, Some(htlc.source.clone()));
                                local_htlc_total_msat += htlc.amount_msat;
                        } else {
                                match htlc.state {
@@ -901,21 +910,26 @@ impl Channel {
                transaction_utils::sort_outputs(&mut txouts);
 
                let mut outputs: Vec<TxOut> = Vec::with_capacity(txouts.len());
-               let mut htlcs_used: Vec<HTLCOutputInCommitment> = Vec::with_capacity(txouts.len());
+               let mut htlcs_included: Vec<HTLCOutputInCommitment> = Vec::with_capacity(txouts.len());
+               let mut htlc_sources: Vec<([u8; 32], HTLCSource, Option<u32>)> = Vec::with_capacity(txouts.len() + unincluded_htlc_sources.len());
                for (idx, out) in txouts.drain(..).enumerate() {
                        outputs.push(out.0);
-                       if let Some(out_htlc) = out.1 {
-                               htlcs_used.push(out_htlc);
-                               htlcs_used.last_mut().unwrap().transaction_output_index = idx as u32;
+                       if let Some((mut htlc, source_option)) = out.1 {
+                               htlc.transaction_output_index = idx as u32;
+                               if let Some(source) = source_option {
+                                       htlc_sources.push((htlc.payment_hash, source, Some(idx as u32)));
+                               }
+                               htlcs_included.push(htlc);
                        }
                }
+               htlc_sources.append(&mut unincluded_htlc_sources);
 
                (Transaction {
                        version: 2,
                        lock_time: ((0x20 as u32) << 8*3) | ((obscured_commitment_transaction_number & 0xffffffu64) as u32),
                        input: txins,
                        output: outputs,
-               }, htlcs_used)
+               }, htlcs_included, htlc_sources)
        }
 
        #[inline]
@@ -1424,9 +1438,9 @@ impl Channel {
 
                // Now that we're past error-generating stuff, update our local state:
 
-               self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_initial_commitment_tx, Vec::new(), self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
+               self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_initial_commitment_tx, Vec::new(), Vec::new(), self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
                self.last_local_commitment_txn = vec![local_initial_commitment_tx.clone()];
-               self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx, local_keys, self.feerate_per_kw, Vec::new());
+               self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx, local_keys, self.feerate_per_kw, Vec::new(), Vec::new());
                self.channel_state = ChannelState::FundingSent as u32;
                self.channel_id = funding_txo.to_channel_id();
                self.cur_remote_commitment_transaction_number -= 1;
@@ -1463,7 +1477,7 @@ impl Channel {
                secp_check!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid funding_signed signature from peer");
 
                self.sign_commitment_transaction(&mut local_initial_commitment_tx, &msg.signature);
-               self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx.clone(), local_keys, self.feerate_per_kw, Vec::new());
+               self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx.clone(), local_keys, self.feerate_per_kw, Vec::new(), Vec::new());
                self.last_local_commitment_txn = vec![local_initial_commitment_tx];
                self.channel_state = ChannelState::FundingSent as u32;
                self.cur_local_commitment_transaction_number -= 1;
@@ -1731,7 +1745,7 @@ impl Channel {
                        self.monitor_pending_order = None;
                }
 
-               self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs);
+               self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs, local_commitment_tx.2);
 
                for htlc in self.pending_inbound_htlcs.iter_mut() {
                        let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state {
@@ -3001,7 +3015,7 @@ impl Channel {
                let temporary_channel_id = self.channel_id;
 
                // Now that we're past error-generating stuff, update our local state:
-               self.channel_monitor.provide_latest_remote_commitment_tx_info(&commitment_tx, Vec::new(), self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
+               self.channel_monitor.provide_latest_remote_commitment_tx_info(&commitment_tx, Vec::new(), Vec::new(), self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
                self.channel_state = ChannelState::FundingCreated as u32;
                self.channel_id = funding_txo.to_channel_id();
                self.cur_remote_commitment_transaction_number -= 1;
@@ -3229,7 +3243,7 @@ impl Channel {
                match self.send_commitment_no_state_update() {
                        Ok((res, remote_commitment_tx)) => {
                                // Update state now that we've passed all the can-fail calls...
-                               self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_commitment_tx.0, remote_commitment_tx.1, self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
+                               self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_commitment_tx.0, remote_commitment_tx.1, remote_commitment_tx.2, self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
                                self.channel_state |= ChannelState::AwaitingRemoteRevoke as u32;
                                Ok((res, self.channel_monitor.clone()))
                        },
@@ -3239,7 +3253,7 @@ impl Channel {
 
        /// Only fails in case of bad keys. Used for channel_reestablish commitment_signed generation
        /// when we shouldn't change HTLC/channel state.
-       fn send_commitment_no_state_update(&self) -> Result<(msgs::CommitmentSigned, (Transaction, Vec<HTLCOutputInCommitment>)), ChannelError> {
+       fn send_commitment_no_state_update(&self) -> Result<(msgs::CommitmentSigned, (Transaction, Vec<HTLCOutputInCommitment>, Vec<([u8; 32], HTLCSource, Option<u32>)>)), ChannelError> {
                let funding_script = self.get_funding_redeemscript();
 
                let mut feerate_per_kw = self.feerate_per_kw;
@@ -3982,7 +3996,10 @@ mod tests {
 
                macro_rules! test_commitment {
                        ( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => {
-                               unsigned_tx = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw);
+                               unsigned_tx = {
+                                       let res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw);
+                                       (res.0, res.1)
+                               };
                                let their_signature = Signature::from_der(&secp_ctx, &hex::decode($their_sig_hex).unwrap()[..]).unwrap();
                                let sighash = Message::from_slice(&bip143::SighashComponents::new(&unsigned_tx.0).sighash_all(&unsigned_tx.0.input[0], &chan.get_funding_redeemscript(), chan.channel_value_satoshis)[..]).unwrap();
                                secp_ctx.verify(&sighash, &their_signature, &chan.their_funding_pubkey.unwrap()).unwrap();