From 6e1ccc7c0f5ec445f6e45201255cbd417182ad1c Mon Sep 17 00:00:00 2001 From: Antoine Riard Date: Fri, 30 Nov 2018 10:58:44 -0500 Subject: [PATCH] Track HTLCSource in ChannelMonitor 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 | 34 ++++---- src/ln/channelmanager.rs | 12 +-- src/ln/channelmonitor.rs | 172 ++++++++++++++++++++++++++++++++++----- src/ln/router.rs | 4 +- 4 files changed, 175 insertions(+), 47 deletions(-) diff --git a/src/ln/channel.rs b/src/ln/channel.rs index db1296a71..f3b812d00 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -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) { + fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, Vec<(HTLCOutputInCommitment, Option)>) { 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)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2); + let mut txouts: Vec<(TxOut, Option<(HTLCOutputInCommitment, Option)>)> = 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 = Vec::with_capacity(txouts.len()); - let mut htlcs_used: Vec = Vec::with_capacity(txouts.len()); + let mut htlcs_used: Vec<(HTLCOutputInCommitment, Option)> = 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)), ChannelError> { + fn send_commitment_no_state_update(&self) -> Result<(msgs::CommitmentSigned, (Transaction, Vec<(HTLCOutputInCommitment, Option)>)), 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); + let mut unsigned_tx: (Transaction, Vec<(HTLCOutputInCommitment, Option)>); 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(); diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index 678e3206a..e8deecdcb 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -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, Vec<(HTLCSource, [u8; 32])>); diff --git a/src/ln/channelmonitor.rs b/src/ln/channelmonitor.rs index 2a81a151c..92c95efc6 100644 --- a/src/ln/channelmonitor.rs +++ b/src/ln/channelmonitor.rs @@ -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)>, } const SERIALIZATION_VERSION: u8 = 1; @@ -283,7 +285,7 @@ pub struct ChannelMonitor { their_to_self_delay: Option, old_secrets: [([u8; 32], u64); 49], - remote_claimable_outpoints: HashMap>, + remote_claimable_outpoints: HashMap)>>, /// 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, 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)>, 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)>) { 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 ReadableArgs> for (Sha256dHash, ChannelM } } + macro_rules! read_htlc_source { + () => { + { + match >::read(reader)? { + 0 => None, + 1 => { + match >::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 ReadableArgs> 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 ReadableArgs> 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 } } diff --git a/src/ln/router.rs b/src/ln/router.rs index 3de73ccc0..3920d44fc 100644 --- a/src/ln/router.rs +++ b/src/ln/router.rs @@ -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 -- 2.39.5