]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Track HTLCSource in ChannelMonitor
authorAntoine Riard <ariard@student.42.fr>
Fri, 30 Nov 2018 15:58:44 +0000 (10:58 -0500)
committerAntoine Riard <ariard@student.42.fr>
Fri, 30 Nov 2018 16:14:18 +0000 (11:14 -0500)
Insert it in current_local_signed_tx, prev_local_signed_tx,
remote_claimable_outpoints. For so get it provided by
Channel calls to provide_latest_{local,remote}_tx

src/ln/channel.rs
src/ln/channelmanager.rs
src/ln/channelmonitor.rs
src/ln/router.rs

index db1296a71f8ae1f63613d97ee3f758bb3af65fcd..f3b812d0001e857f4ef79db9d38db57e61c56949 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, Option<HTLCSource>)>) {
                let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (INITIAL_COMMITMENT_NUMBER - commitment_number);
 
                let txins = {
@@ -765,7 +765,7 @@ 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 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 +773,14 @@ 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 $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) {
@@ -788,7 +788,7 @@ 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))));
                                        }
                                }
                        }
@@ -804,7 +804,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 +830,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,12 +901,12 @@ 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_used: Vec<(HTLCOutputInCommitment, Option<HTLCSource>)> = Vec::with_capacity(txouts.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 out_htlc) = out.1 {
+                               out_htlc.0.transaction_output_index = idx as u32;
+                               htlcs_used.push((out_htlc.0, out_htlc.1));
                        }
                }
 
@@ -1692,7 +1692,7 @@ impl Channel {
                new_local_commitment_txn.push(local_commitment_tx.0.clone());
 
                let mut htlcs_and_sigs = Vec::with_capacity(local_commitment_tx.1.len());
-               for (idx, ref htlc) in local_commitment_tx.1.iter().enumerate() {
+               for (idx, &(ref htlc, ref htlc_source)) in local_commitment_tx.1.iter().enumerate() {
                        let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, htlc, true, &local_keys, feerate_per_kw);
                        let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys);
                        let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
@@ -1704,7 +1704,7 @@ impl Channel {
                        } else {
                                self.create_htlc_tx_signature(&htlc_tx, htlc, &local_keys)?.1
                        };
-                       htlcs_and_sigs.push(((*htlc).clone(), msg.htlc_signatures[idx], htlc_sig));
+                       htlcs_and_sigs.push(((*htlc).clone(), msg.htlc_signatures[idx], htlc_sig, (*htlc_source).clone()));
                }
 
                let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number - 1));
@@ -3221,7 +3221,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, Option<HTLCSource>)>)), ChannelError> {
                let funding_script = self.get_funding_redeemscript();
 
                let mut feerate_per_kw = self.feerate_per_kw;
@@ -3239,7 +3239,7 @@ impl Channel {
 
                let mut htlc_sigs = Vec::new();
 
-               for ref htlc in remote_commitment_tx.1.iter() {
+               for &(ref htlc, _) in remote_commitment_tx.1.iter() {
                        let htlc_tx = self.build_htlc_transaction(&remote_commitment_txid, htlc, false, &remote_keys, feerate_per_kw);
                        let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys);
                        let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
@@ -3960,7 +3960,7 @@ mod tests {
                let htlc_basepoint = PublicKey::from_secret_key(&secp_ctx, &chan.local_keys.htlc_base_key);
                let keys = TxCreationKeys::new(&secp_ctx, &per_commitment_point, &delayed_payment_base, &htlc_basepoint, &chan.their_revocation_basepoint.unwrap(), &chan.their_payment_basepoint.unwrap(), &chan.their_htlc_basepoint.unwrap()).unwrap();
 
-               let mut unsigned_tx: (Transaction, Vec<HTLCOutputInCommitment>);
+               let mut unsigned_tx: (Transaction, Vec<(HTLCOutputInCommitment, Option<HTLCSource>)>);
 
                macro_rules! test_commitment {
                        ( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => {
@@ -3980,7 +3980,7 @@ mod tests {
                        ( $htlc_idx: expr, $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr ) => {
                                let remote_signature = Signature::from_der(&secp_ctx, &hex::decode($their_sig_hex).unwrap()[..]).unwrap();
 
-                               let ref htlc = unsigned_tx.1[$htlc_idx];
+                               let (ref htlc, _) = unsigned_tx.1[$htlc_idx];
                                let mut htlc_tx = chan.build_htlc_transaction(&unsigned_tx.0.txid(), &htlc, true, &keys, chan.feerate_per_kw);
                                let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
                                let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
index 678e3206af878ac8f7d455eabe26a7748da5f6ba..e8deecdcb296d3adf840a1588a971b8adaa56c8f 100644 (file)
@@ -90,15 +90,15 @@ mod channel_held_info {
        }
 
        /// Tracks the inbound corresponding to an outbound HTLC
-       #[derive(Clone)]
+       #[derive(Clone, PartialEq)]
        pub struct HTLCPreviousHopData {
-               pub(super) short_channel_id: u64,
-               pub(super) htlc_id: u64,
-               pub(super) incoming_packet_shared_secret: [u8; 32],
+               pub(crate) short_channel_id: u64,
+               pub(crate) htlc_id: u64,
+               pub(crate) incoming_packet_shared_secret: [u8; 32],
        }
 
        /// Tracks the inbound corresponding to an outbound HTLC
-       #[derive(Clone)]
+       #[derive(Clone, PartialEq)]
        pub enum HTLCSource {
                PreviousHopData(HTLCPreviousHopData),
                OutboundRoute {
@@ -131,7 +131,7 @@ mod channel_held_info {
                }
        }
 }
-pub(super) use self::channel_held_info::*;
+pub(crate) use self::channel_held_info::*;
 
 type ShutdownResult = (Vec<Transaction>, Vec<(HTLCSource, [u8; 32])>);
 
index 2a81a151c7a97c23e652a99af2bcd3a38324a1c4..92c95efc6d67b4e0b5672d65f3acbae5300dae75 100644 (file)
@@ -29,6 +29,8 @@ use secp256k1;
 use ln::msgs::DecodeError;
 use ln::chan_utils;
 use ln::chan_utils::HTLCOutputInCommitment;
+use ln::channelmanager::{HTLCSource, HTLCPreviousHopData};
+use ln::router::{Route, RouteHop};
 use chain::chaininterface::{ChainListener, ChainWatchInterface, BroadcasterInterface};
 use chain::transaction::OutPoint;
 use chain::keysinterface::SpendableOutputDescriptor;
@@ -258,7 +260,7 @@ struct LocalSignedTx {
        b_htlc_key: PublicKey,
        delayed_payment_key: PublicKey,
        feerate_per_kw: u64,
-       htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature)>,
+       htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature, Option<HTLCSource>)>,
 }
 
 const SERIALIZATION_VERSION: u8 = 1;
@@ -283,7 +285,7 @@ pub struct ChannelMonitor {
        their_to_self_delay: Option<u16>,
 
        old_secrets: [([u8; 32], u64); 49],
-       remote_claimable_outpoints: HashMap<Sha256dHash, Vec<HTLCOutputInCommitment>>,
+       remote_claimable_outpoints: HashMap<Sha256dHash, Vec<(HTLCOutputInCommitment, Option<HTLCSource>)>>,
        /// We cannot identify HTLC-Success or HTLC-Timeout transactions by themselves on the chain.
        /// Nor can we figure out their commitment numbers without the commitment transaction they are
        /// spending. Thus, in order to claim them via revocation key, we track all the remote
@@ -440,13 +442,13 @@ impl ChannelMonitor {
                        let remote_hash_commitment_number = &mut self.remote_hash_commitment_number;
 
                        self.payment_preimages.retain(|&k, _| {
-                               for &(ref htlc, _, _) in &local_signed_commitment_tx.htlc_outputs {
+                               for &(ref htlc, _, _, _) in &local_signed_commitment_tx.htlc_outputs {
                                        if k == htlc.payment_hash {
                                                return true
                                        }
                                }
                                if let Some(prev_local_commitment_tx) = prev_local_signed_commitment_tx {
-                                       for &(ref htlc, _, _) in prev_local_commitment_tx.htlc_outputs.iter() {
+                                       for &(ref htlc, _, _, _) in prev_local_commitment_tx.htlc_outputs.iter() {
                                                if k == htlc.payment_hash {
                                                        return true
                                                }
@@ -472,14 +474,21 @@ impl ChannelMonitor {
        /// 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(super) fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec<HTLCOutputInCommitment>, commitment_number: u64, their_revocation_point: PublicKey) {
+       pub(super) fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<HTLCSource>)>, commitment_number: u64, their_revocation_point: PublicKey) {
                // 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.
                // (only maybe, sadly we cant do the same for local info, as we need to be aware of
                // timeouts)
-               for htlc in &htlc_outputs {
+               for &(ref htlc, _) in &htlc_outputs {
                        self.remote_hash_commitment_number.insert(htlc.payment_hash, commitment_number);
                }
+               // We prune old claimable outpoints, useless to pass backward state when remote commitment
+               // tx get revoked, optimize for storage
+               for (_, htlc_data) in self.remote_claimable_outpoints.iter_mut() {
+                       for &mut(_, ref mut source) in htlc_data.iter_mut() {
+                               source.take();
+                       }
+               }
                self.remote_claimable_outpoints.insert(unsigned_commitment_tx.txid(), htlc_outputs);
                self.current_remote_commitment_number = commitment_number;
                //TODO: Merge this into the other per-remote-transaction output storage stuff
@@ -510,7 +519,7 @@ impl ChannelMonitor {
        /// Panics if set_their_to_self_delay has never been called.
        /// Also update Storage with latest local per_commitment_point to derive local_delayedkey in
        /// case of onchain HTLC tx
-       pub(super) fn provide_latest_local_commitment_tx_info(&mut self, signed_commitment_tx: Transaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64, htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature)>) {
+       pub(super) fn provide_latest_local_commitment_tx_info(&mut self, signed_commitment_tx: Transaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64, htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature, Option<HTLCSource>)>) {
                assert!(self.their_to_self_delay.is_some());
                self.prev_local_signed_commitment_tx = self.current_local_signed_commitment_tx.take();
                self.current_local_signed_commitment_tx = Some(LocalSignedTx {
@@ -842,12 +851,57 @@ impl ChannelMonitor {
                        }
                }
 
+               macro_rules! serialize_htlc_source {
+                       ($htlc_source: expr) => {
+                               if let &Some(ref source) = $htlc_source {
+                                       writer.write_all(&[1; 1])?;
+                                       match source {
+                                               &HTLCSource::PreviousHopData(ref source) => { serialize_htlc_previous_hop_data!(source); },
+                                               &HTLCSource::OutboundRoute { ref route, ref session_priv, ref first_hop_htlc_msat } => { serialize_htlc_outbound_route!(route, session_priv, *first_hop_htlc_msat); },
+                                       }
+                               } else {
+                                       writer.write_all(&[0; 1])?;
+                               }
+                       }
+               }
+
+               macro_rules! serialize_htlc_previous_hop_data {
+                       ($htlc_source: expr) => {
+                               writer.write_all(&[0; 1])?;
+                               writer.write_all(&byte_utils::be64_to_array($htlc_source.short_channel_id))?;
+                               writer.write_all(&byte_utils::be64_to_array($htlc_source.htlc_id))?;
+                               writer.write_all(&$htlc_source.incoming_packet_shared_secret[..])?;
+                       }
+               }
+
+               macro_rules! serialize_htlc_outbound_route {
+                       ($route: expr, $session_priv: expr, $first_hop_htlc_msat: expr) => {
+                               writer.write_all(&[1; 1])?;
+                               serialize_route!($route);
+                               writer.write_all(&$session_priv[..])?;
+                               writer.write_all(&byte_utils::be64_to_array($first_hop_htlc_msat))?;
+                       }
+               }
+
+               macro_rules! serialize_route {
+                       ($route: expr) => {
+                               writer.write_all(&byte_utils::be64_to_array($route.hops.len() as u64))?;
+                               for hop in &$route.hops {
+                                       writer.write_all(&hop.pubkey.serialize())?;
+                                       writer.write_all(&byte_utils::be64_to_array(hop.short_channel_id))?;
+                                       writer.write_all(&byte_utils::be64_to_array(hop.fee_msat))?;
+                                       writer.write_all(&byte_utils::be32_to_array(hop.cltv_expiry_delta))?;
+                               }
+                       }
+               }
+
                writer.write_all(&byte_utils::be64_to_array(self.remote_claimable_outpoints.len() as u64))?;
-               for (ref txid, ref htlc_outputs) in self.remote_claimable_outpoints.iter() {
+               for (ref txid, ref htlc_infos) in self.remote_claimable_outpoints.iter() {
                        writer.write_all(&txid[..])?;
-                       writer.write_all(&byte_utils::be64_to_array(htlc_outputs.len() as u64))?;
-                       for htlc_output in htlc_outputs.iter() {
+                       writer.write_all(&byte_utils::be64_to_array(htlc_infos.len() as u64))?;
+                       for &(ref htlc_output, ref htlc_source) in htlc_infos.iter() {
                                serialize_htlc_in_commitment!(htlc_output);
+                               serialize_htlc_source!(htlc_source);
                        }
                }
 
@@ -887,10 +941,11 @@ impl ChannelMonitor {
 
                                writer.write_all(&byte_utils::be64_to_array($local_tx.feerate_per_kw))?;
                                writer.write_all(&byte_utils::be64_to_array($local_tx.htlc_outputs.len() as u64))?;
-                               for &(ref htlc_output, ref their_sig, ref our_sig) in $local_tx.htlc_outputs.iter() {
+                               for &(ref htlc_output, ref their_sig, ref our_sig, ref htlc_source) in $local_tx.htlc_outputs.iter() {
                                        serialize_htlc_in_commitment!(htlc_output);
                                        writer.write_all(&their_sig.serialize_compact(&self.secp_ctx))?;
                                        writer.write_all(&our_sig.serialize_compact(&self.secp_ctx))?;
+                                       serialize_htlc_source!(htlc_source);
                                }
                        }
                }
@@ -1074,7 +1129,7 @@ impl ChannelMonitor {
                                                let (sig, redeemscript) = match self.key_storage {
                                                        Storage::Local { ref revocation_base_key, .. } => {
                                                                let redeemscript = if $htlc_idx.is_none() { revokeable_redeemscript.clone() } else {
-                                                                       let htlc = &per_commitment_option.unwrap()[$htlc_idx.unwrap()];
+                                                                       let htlc = &per_commitment_option.unwrap()[$htlc_idx.unwrap()].0;
                                                                        chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey)
                                                                };
                                                                let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]));
@@ -1100,7 +1155,7 @@ impl ChannelMonitor {
                        if let Some(per_commitment_data) = per_commitment_option {
                                inputs.reserve_exact(per_commitment_data.len());
 
-                               for (idx, htlc) in per_commitment_data.iter().enumerate() {
+                               for (idx, &(ref htlc, _)) in per_commitment_data.iter().enumerate() {
                                        let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
                                        if htlc.transaction_output_index as usize >= tx.output.len() ||
                                                        tx.output[htlc.transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
@@ -1229,7 +1284,7 @@ impl ChannelMonitor {
                                                        {
                                                                let (sig, redeemscript) = match self.key_storage {
                                                                        Storage::Local { ref htlc_base_key, .. } => {
-                                                                               let htlc = &per_commitment_option.unwrap()[$input.sequence as usize];
+                                                                               let htlc = &per_commitment_option.unwrap()[$input.sequence as usize].0;
                                                                                let redeemscript = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
                                                                                let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]));
                                                                                let htlc_key = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, revocation_point, &htlc_base_key));
@@ -1247,7 +1302,7 @@ impl ChannelMonitor {
                                                }
                                        }
 
-                                       for (idx, htlc) in per_commitment_data.iter().enumerate() {
+                                       for (idx, &(ref htlc, _)) in per_commitment_data.iter().enumerate() {
                                                if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
                                                        let input = TxIn {
                                                                previous_output: BitcoinOutPoint {
@@ -1435,7 +1490,7 @@ impl ChannelMonitor {
                        }
                }
 
-               for &(ref htlc, ref their_sig, ref our_sig) in local_tx.htlc_outputs.iter() {
+               for &(ref htlc, ref their_sig, ref our_sig, _) in local_tx.htlc_outputs.iter() {
                        if htlc.offered {
                                let mut htlc_timeout_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
 
@@ -1641,7 +1696,7 @@ impl ChannelMonitor {
 
        pub(super) fn would_broadcast_at_height(&self, height: u32) -> bool {
                if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {
-                       for &(ref htlc, _, _) in cur_local_tx.htlc_outputs.iter() {
+                       for &(ref htlc, _, _, _) in cur_local_tx.htlc_outputs.iter() {
                                // For inbound HTLCs which we know the preimage for, we have to ensure we hit the
                                // chain with enough room to claim the HTLC without our counterparty being able to
                                // time out the HTLC first.
@@ -1781,6 +1836,72 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
                        }
                }
 
+               macro_rules! read_htlc_source {
+                       () => {
+                               {
+                                       match <u8 as Readable<R>>::read(reader)? {
+                                               0 => None,
+                                               1 => {
+                                                       match <u8 as Readable<R>>::read(reader)? {
+                                                               0 => Some(HTLCSource::PreviousHopData(read_htlc_previous_hop_data!())),
+                                                               1 => Some(read_htlc_outbound_route!()),
+                                                               _ => return Err(DecodeError::InvalidValue),
+                                                       }
+                                               },
+                                               _ => return Err(DecodeError::InvalidValue),
+                                       }
+                               }
+                       }
+               }
+
+               macro_rules! read_htlc_previous_hop_data  {
+                       () => {
+                               {
+                                       let short_channel_id: u64 = Readable::read(reader)?;
+                                       let htlc_id: u64 = Readable::read(reader)?;
+                                       let incoming_packet_shared_secret: [u8; 32] = Readable::read(reader)?;
+
+                                       HTLCPreviousHopData {
+                                               short_channel_id, htlc_id, incoming_packet_shared_secret
+                                       }
+                               }
+                       }
+               }
+
+               macro_rules! read_htlc_outbound_route {
+                       () => {
+                               {
+                                       let route = read_route!();
+                                       let session_priv = Readable::read(reader)?;
+                                       let first_hop_htlc_msat = Readable::read(reader)?;
+
+                                       HTLCSource::OutboundRoute {
+                                               route, session_priv, first_hop_htlc_msat
+                                       }
+                               }
+                       }
+               }
+
+               macro_rules! read_route {
+                       () => {
+                               {
+                                       let route_len: u64 = Readable::read(reader)?;
+                                       let mut hops = Vec::with_capacity(cmp::min(route_len as usize, MAX_ALLOC_SIZE / 64));
+                                       for _ in 0..route_len {
+                                               let pubkey = Readable::read(reader)?;
+                                               let short_channel_id = Readable::read(reader)?;
+                                               let fee_msat = Readable::read(reader)?;
+                                               let cltv_expiry_delta = Readable::read(reader)?;
+
+                                               hops.push(RouteHop { pubkey, short_channel_id, fee_msat, cltv_expiry_delta });
+                                       }
+                                       Route {
+                                               hops
+                                       }
+                               }
+                       }
+               }
+
                let remote_claimable_outpoints_len: u64 = Readable::read(reader)?;
                let mut remote_claimable_outpoints = HashMap::with_capacity(cmp::min(remote_claimable_outpoints_len as usize, MAX_ALLOC_SIZE / 64));
                for _ in 0..remote_claimable_outpoints_len {
@@ -1788,7 +1909,9 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
                        let outputs_count: u64 = Readable::read(reader)?;
                        let mut outputs = Vec::with_capacity(cmp::min(outputs_count as usize, MAX_ALLOC_SIZE / 32));
                        for _ in 0..outputs_count {
-                               outputs.push(read_htlc_in_commitment!());
+                               let out = read_htlc_in_commitment!();
+                               let source = read_htlc_source!();
+                               outputs.push((out, source));
                        }
                        if let Some(_) = remote_claimable_outpoints.insert(txid, outputs) {
                                return Err(DecodeError::InvalidValue);
@@ -1845,7 +1968,10 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
                                        let htlc_outputs_len: u64 = Readable::read(reader)?;
                                        let mut htlc_outputs = Vec::with_capacity(cmp::min(htlc_outputs_len as usize, MAX_ALLOC_SIZE / 128));
                                        for _ in 0..htlc_outputs_len {
-                                               htlc_outputs.push((read_htlc_in_commitment!(), Readable::read(reader)?, Readable::read(reader)?));
+                                               let out = read_htlc_in_commitment!();
+                                               let sigs = (Readable::read(reader)?, Readable::read(reader)?);
+                                               let source = read_htlc_source!();
+                                               htlc_outputs.push((out, sigs.0, sigs.1, source));
                                        }
 
                                        LocalSignedTx {
@@ -1930,6 +2056,7 @@ mod tests {
        use hex;
        use ln::channelmonitor::ChannelMonitor;
        use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys};
+       use ln::channelmanager::{HTLCSource, HTLCPreviousHopData};
        use util::sha2::Sha256;
        use util::test_utils::TestLogger;
        use secp256k1::key::{SecretKey,PublicKey};
@@ -2314,6 +2441,7 @@ mod tests {
                        }
                }
                let dummy_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() };
+               let dummy_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id: 0, htlc_id: 0, incoming_packet_shared_secret: [0; 32]});
 
                let mut preimages = Vec::new();
                {
@@ -2334,13 +2462,13 @@ mod tests {
                                {
                                        let mut res = Vec::new();
                                        for (idx, preimage) in $preimages_slice.iter().enumerate() {
-                                               res.push(HTLCOutputInCommitment {
+                                               res.push((HTLCOutputInCommitment {
                                                        offered: true,
                                                        amount_msat: 0,
                                                        cltv_expiry: 0,
                                                        payment_hash: preimage.1.clone(),
                                                        transaction_output_index: idx as u32,
-                                               });
+                                               }, Some(dummy_source.clone())));
                                        }
                                        res
                                }
@@ -2350,7 +2478,7 @@ mod tests {
                        ($preimages_slice: expr) => {
                                {
                                        let mut inp = preimages_slice_to_htlc_outputs!($preimages_slice);
-                                       let res: Vec<_> = inp.drain(..).map(|e| { (e, dummy_sig.clone(), dummy_sig.clone()) }).collect();
+                                       let res: Vec<_> = inp.drain(..).map(|e| { (e.0, dummy_sig.clone(), dummy_sig.clone(), e.1) }).collect();
                                        res
                                }
                        }
index 3de73ccc059ae8159b09f856ca4508fbedf7a278..3920d44fc7abddc65c94edab16cc864e0e6f4747 100644 (file)
@@ -25,7 +25,7 @@ use std::collections::btree_map::Entry as BtreeEntry;
 use std;
 
 /// A hop in a route
-#[derive(Clone)]
+#[derive(Clone, PartialEq)]
 pub struct RouteHop {
        /// The node_id of the node at this hop.
        pub pubkey: PublicKey,
@@ -39,7 +39,7 @@ pub struct RouteHop {
 }
 
 /// A route from us through the network to a destination
-#[derive(Clone)]
+#[derive(Clone, PartialEq)]
 pub struct Route {
        /// The list of hops, NOT INCLUDING our own, where the last hop is the destination. Thus, this
        /// must always be at least length one. By protocol rules, this may not currently exceed 20 in