Skip to content

Commit 301f91e

Browse files
authored
Merge pull request #284 from TheBlueMatt/2019-01-remote-htlc-timeout-broadcast
Check for timing-out HTLCs in remote unrevoked commitments
2 parents a604cb6 + f065a62 commit 301f91e

File tree

4 files changed

+533
-383
lines changed

4 files changed

+533
-383
lines changed

src/ln/chan_utils.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ pub struct HTLCOutputInCommitment {
147147
pub amount_msat: u64,
148148
pub cltv_expiry: u32,
149149
pub payment_hash: PaymentHash,
150-
pub transaction_output_index: u32,
150+
pub transaction_output_index: Option<u32>,
151151
}
152152

153153
#[inline]
@@ -222,12 +222,13 @@ pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, keys: &TxCreationKey
222222
get_htlc_redeemscript_with_explicit_keys(htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key)
223223
}
224224

225+
/// panics if htlc.transaction_output_index.is_none()!
225226
pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_self_delay: u16, htlc: &HTLCOutputInCommitment, a_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
226227
let mut txins: Vec<TxIn> = Vec::new();
227228
txins.push(TxIn {
228229
previous_output: OutPoint {
229230
txid: prev_hash.clone(),
230-
vout: htlc.transaction_output_index,
231+
vout: htlc.transaction_output_index.expect("Can't build an HTLC transaction for a dust output"),
231232
},
232233
script_sig: Script::new(),
233234
sequence: 0,

src/ln/channel.rs

Lines changed: 77 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,6 @@ struct OutboundHTLCOutput {
132132
fail_reason: Option<HTLCFailReason>,
133133
}
134134

135-
macro_rules! get_htlc_in_commitment {
136-
($htlc: expr, $offered: expr) => {
137-
HTLCOutputInCommitment {
138-
offered: $offered,
139-
amount_msat: $htlc.amount_msat,
140-
cltv_expiry: $htlc.cltv_expiry,
141-
payment_hash: $htlc.payment_hash,
142-
transaction_output_index: 0
143-
}
144-
}
145-
}
146-
147135
/// See AwaitingRemoteRevoke ChannelState for more info
148136
enum HTLCUpdateAwaitingACK {
149137
AddHTLC {
@@ -759,8 +747,12 @@ impl Channel {
759747
/// have not yet committed it. Such HTLCs will only be included in transactions which are being
760748
/// generated by the peer which proposed adding the HTLCs, and thus we need to understand both
761749
/// which peer generated this transaction and "to whom" this transaction flows.
750+
/// Returns (the transaction built, the number of HTLC outputs which were present in the
751+
/// transaction, the list of HTLCs which were not ignored when building the transaction).
752+
/// Note that below-dust HTLCs are included in the third return value, but not the second, and
753+
/// sources are provided only for outbound HTLCs in the third return value.
762754
#[inline]
763-
fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, Vec<HTLCOutputInCommitment>, Vec<(PaymentHash, &HTLCSource, Option<u32>)>) {
755+
fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) {
764756
let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (INITIAL_COMMITMENT_NUMBER - commitment_number);
765757

766758
let txins = {
@@ -775,38 +767,46 @@ impl Channel {
775767
};
776768

777769
let mut txouts: Vec<(TxOut, Option<(HTLCOutputInCommitment, Option<&HTLCSource>)>)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2);
778-
let mut unincluded_htlc_sources: Vec<(PaymentHash, &HTLCSource, Option<u32>)> = Vec::new();
770+
let mut included_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::new();
779771

780772
let dust_limit_satoshis = if local { self.our_dust_limit_satoshis } else { self.their_dust_limit_satoshis };
781773
let mut remote_htlc_total_msat = 0;
782774
let mut local_htlc_total_msat = 0;
783775
let mut value_to_self_msat_offset = 0;
784776

777+
macro_rules! get_htlc_in_commitment {
778+
($htlc: expr, $offered: expr) => {
779+
HTLCOutputInCommitment {
780+
offered: $offered,
781+
amount_msat: $htlc.amount_msat,
782+
cltv_expiry: $htlc.cltv_expiry,
783+
payment_hash: $htlc.payment_hash,
784+
transaction_output_index: None
785+
}
786+
}
787+
}
788+
785789
macro_rules! add_htlc_output {
786790
($htlc: expr, $outbound: expr, $source: expr) => {
787791
if $outbound == local { // "offered HTLC output"
792+
let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
788793
if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000) {
789-
let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
790794
txouts.push((TxOut {
791795
script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
792796
value: $htlc.amount_msat / 1000
793797
}, Some((htlc_in_tx, $source))));
794798
} else {
795-
if let Some(source) = $source {
796-
unincluded_htlc_sources.push(($htlc.payment_hash, source, None));
797-
}
799+
included_dust_htlcs.push((htlc_in_tx, $source));
798800
}
799801
} else {
802+
let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
800803
if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) {
801-
let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
802804
txouts.push((TxOut { // "received HTLC output"
803805
script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
804806
value: $htlc.amount_msat / 1000
805807
}, Some((htlc_in_tx, $source))));
806808
} else {
807-
if let Some(source) = $source {
808-
unincluded_htlc_sources.push(($htlc.payment_hash, source, None));
809-
}
809+
included_dust_htlcs.push((htlc_in_tx, $source));
810810
}
811811
}
812812
}
@@ -919,26 +919,23 @@ impl Channel {
919919
transaction_utils::sort_outputs(&mut txouts);
920920

921921
let mut outputs: Vec<TxOut> = Vec::with_capacity(txouts.len());
922-
let mut htlcs_included: Vec<HTLCOutputInCommitment> = Vec::with_capacity(txouts.len());
923-
let mut htlc_sources: Vec<(PaymentHash, &HTLCSource, Option<u32>)> = Vec::with_capacity(txouts.len() + unincluded_htlc_sources.len());
924-
for (idx, out) in txouts.drain(..).enumerate() {
922+
let mut htlcs_included: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(txouts.len() + included_dust_htlcs.len());
923+
for (idx, mut out) in txouts.drain(..).enumerate() {
925924
outputs.push(out.0);
926-
if let Some((mut htlc, source_option)) = out.1 {
927-
htlc.transaction_output_index = idx as u32;
928-
if let Some(source) = source_option {
929-
htlc_sources.push((htlc.payment_hash, source, Some(idx as u32)));
930-
}
931-
htlcs_included.push(htlc);
925+
if let Some((mut htlc, source_option)) = out.1.take() {
926+
htlc.transaction_output_index = Some(idx as u32);
927+
htlcs_included.push((htlc, source_option));
932928
}
933929
}
934-
htlc_sources.append(&mut unincluded_htlc_sources);
930+
let non_dust_htlc_count = htlcs_included.len();
931+
htlcs_included.append(&mut included_dust_htlcs);
935932

936933
(Transaction {
937934
version: 2,
938935
lock_time: ((0x20 as u32) << 8*3) | ((obscured_commitment_transaction_number & 0xffffffu64) as u32),
939936
input: txins,
940937
output: outputs,
941-
}, htlcs_included, htlc_sources)
938+
}, non_dust_htlc_count, htlcs_included)
942939
}
943940

944941
#[inline]
@@ -1451,9 +1448,9 @@ impl Channel {
14511448

14521449
// Now that we're past error-generating stuff, update our local state:
14531450

1454-
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());
1451+
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());
14551452
self.last_local_commitment_txn = vec![local_initial_commitment_tx.clone()];
1456-
self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx, local_keys, self.feerate_per_kw, Vec::new(), Vec::new());
1453+
self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx, local_keys, self.feerate_per_kw, Vec::new());
14571454
self.channel_state = ChannelState::FundingSent as u32;
14581455
self.channel_id = funding_txo.to_channel_id();
14591456
self.cur_remote_commitment_transaction_number -= 1;
@@ -1490,7 +1487,7 @@ impl Channel {
14901487
secp_check!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid funding_signed signature from peer");
14911488

14921489
self.sign_commitment_transaction(&mut local_initial_commitment_tx, &msg.signature);
1493-
self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx.clone(), local_keys, self.feerate_per_kw, Vec::new(), Vec::new());
1490+
self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx.clone(), local_keys, self.feerate_per_kw, Vec::new());
14941491
self.last_local_commitment_txn = vec![local_initial_commitment_tx];
14951492
self.channel_state = ChannelState::FundingSent as u32;
14961493
self.cur_local_commitment_transaction_number -= 1;
@@ -1693,7 +1690,7 @@ impl Channel {
16931690

16941691
let mut local_commitment_tx = {
16951692
let mut commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, feerate_per_kw);
1696-
let htlcs_cloned: Vec<_> = commitment_tx.2.drain(..).map(|htlc_source| (htlc_source.0, htlc_source.1.clone(), htlc_source.2)).collect();
1693+
let htlcs_cloned: Vec<_> = commitment_tx.2.drain(..).map(|htlc| (htlc.0, htlc.1.map(|h| h.clone()))).collect();
16971694
(commitment_tx.0, commitment_tx.1, htlcs_cloned)
16981695
};
16991696
let local_commitment_txid = local_commitment_tx.0.txid();
@@ -1702,36 +1699,40 @@ impl Channel {
17021699

17031700
//If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
17041701
if update_fee {
1705-
let num_htlcs = local_commitment_tx.1.len();
1702+
let num_htlcs = local_commitment_tx.1;
17061703
let total_fee: u64 = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
17071704

17081705
if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + self.their_channel_reserve_satoshis {
17091706
return Err(ChannelError::Close("Funding remote cannot afford proposed new fee"));
17101707
}
17111708
}
17121709

1713-
if msg.htlc_signatures.len() != local_commitment_tx.1.len() {
1710+
if msg.htlc_signatures.len() != local_commitment_tx.1 {
17141711
return Err(ChannelError::Close("Got wrong number of HTLC signatures from remote"));
17151712
}
17161713

1717-
let mut new_local_commitment_txn = Vec::with_capacity(local_commitment_tx.1.len() + 1);
1714+
let mut new_local_commitment_txn = Vec::with_capacity(local_commitment_tx.1 + 1);
17181715
self.sign_commitment_transaction(&mut local_commitment_tx.0, &msg.signature);
17191716
new_local_commitment_txn.push(local_commitment_tx.0.clone());
17201717

1721-
let mut htlcs_and_sigs = Vec::with_capacity(local_commitment_tx.1.len());
1722-
for (idx, htlc) in local_commitment_tx.1.drain(..).enumerate() {
1723-
let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, &htlc, true, &local_keys, feerate_per_kw);
1724-
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys);
1725-
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
1726-
secp_check!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx signature from peer");
1727-
let htlc_sig = if htlc.offered {
1728-
let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, &htlc, &local_keys)?;
1729-
new_local_commitment_txn.push(htlc_tx);
1730-
htlc_sig
1718+
let mut htlcs_and_sigs = Vec::with_capacity(local_commitment_tx.2.len());
1719+
for (idx, (htlc, source)) in local_commitment_tx.2.drain(..).enumerate() {
1720+
if let Some(_) = htlc.transaction_output_index {
1721+
let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, &htlc, true, &local_keys, feerate_per_kw);
1722+
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys);
1723+
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
1724+
secp_check!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx signature from peer");
1725+
let htlc_sig = if htlc.offered {
1726+
let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, &htlc, &local_keys)?;
1727+
new_local_commitment_txn.push(htlc_tx);
1728+
htlc_sig
1729+
} else {
1730+
self.create_htlc_tx_signature(&htlc_tx, &htlc, &local_keys)?.1
1731+
};
1732+
htlcs_and_sigs.push((htlc, Some((msg.htlc_signatures[idx], htlc_sig)), source));
17311733
} else {
1732-
self.create_htlc_tx_signature(&htlc_tx, &htlc, &local_keys)?.1
1733-
};
1734-
htlcs_and_sigs.push((htlc, msg.htlc_signatures[idx], htlc_sig));
1734+
htlcs_and_sigs.push((htlc, None, source));
1735+
}
17351736
}
17361737

17371738
let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number - 1));
@@ -1758,7 +1759,7 @@ impl Channel {
17581759
self.monitor_pending_order = None;
17591760
}
17601761

1761-
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);
1762+
self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs);
17621763

17631764
for htlc in self.pending_inbound_htlcs.iter_mut() {
17641765
let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state {
@@ -3028,7 +3029,7 @@ impl Channel {
30283029
let temporary_channel_id = self.channel_id;
30293030

30303031
// Now that we're past error-generating stuff, update our local state:
3031-
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());
3032+
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());
30323033
self.channel_state = ChannelState::FundingCreated as u32;
30333034
self.channel_id = funding_txo.to_channel_id();
30343035
self.cur_remote_commitment_transaction_number -= 1;
@@ -3260,23 +3261,23 @@ impl Channel {
32603261
}
32613262
}
32623263

3263-
let (res, remote_commitment_tx, htlcs, htlc_sources) = match self.send_commitment_no_state_update() {
3264-
Ok((res, (remote_commitment_tx, htlcs, mut htlc_sources))) => {
3264+
let (res, remote_commitment_tx, htlcs) = match self.send_commitment_no_state_update() {
3265+
Ok((res, (remote_commitment_tx, mut htlcs))) => {
32653266
// Update state now that we've passed all the can-fail calls...
3266-
let htlc_sources_no_ref = htlc_sources.drain(..).map(|htlc_source| (htlc_source.0, htlc_source.1.clone(), htlc_source.2)).collect();
3267-
(res, remote_commitment_tx, htlcs, htlc_sources_no_ref)
3267+
let htlcs_no_ref = htlcs.drain(..).map(|(htlc, htlc_source)| (htlc, htlc_source.map(|source_ref| Box::new(source_ref.clone())))).collect();
3268+
(res, remote_commitment_tx, htlcs_no_ref)
32683269
},
32693270
Err(e) => return Err(e),
32703271
};
32713272

3272-
self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_commitment_tx, htlcs, htlc_sources, self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
3273+
self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_commitment_tx, htlcs, self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
32733274
self.channel_state |= ChannelState::AwaitingRemoteRevoke as u32;
32743275
Ok((res, self.channel_monitor.clone()))
32753276
}
32763277

32773278
/// Only fails in case of bad keys. Used for channel_reestablish commitment_signed generation
32783279
/// when we shouldn't change HTLC/channel state.
3279-
fn send_commitment_no_state_update(&self) -> Result<(msgs::CommitmentSigned, (Transaction, Vec<HTLCOutputInCommitment>, Vec<(PaymentHash, &HTLCSource, Option<u32>)>)), ChannelError> {
3280+
fn send_commitment_no_state_update(&self) -> Result<(msgs::CommitmentSigned, (Transaction, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>)), ChannelError> {
32803281
let funding_script = self.get_funding_redeemscript();
32813282

32823283
let mut feerate_per_kw = self.feerate_per_kw;
@@ -3292,21 +3293,22 @@ impl Channel {
32923293
let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_commitment_tx.0).sighash_all(&remote_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
32933294
let our_sig = self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key);
32943295

3295-
let mut htlc_sigs = Vec::new();
3296-
3297-
for ref htlc in remote_commitment_tx.1.iter() {
3298-
let htlc_tx = self.build_htlc_transaction(&remote_commitment_txid, htlc, false, &remote_keys, feerate_per_kw);
3299-
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys);
3300-
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
3301-
let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &remote_keys.per_commitment_point, &self.local_keys.htlc_base_key), "Derived invalid key, peer is maliciously selecting parameters");
3302-
htlc_sigs.push(self.secp_ctx.sign(&htlc_sighash, &our_htlc_key));
3296+
let mut htlc_sigs = Vec::with_capacity(remote_commitment_tx.1);
3297+
for &(ref htlc, _) in remote_commitment_tx.2.iter() {
3298+
if let Some(_) = htlc.transaction_output_index {
3299+
let htlc_tx = self.build_htlc_transaction(&remote_commitment_txid, htlc, false, &remote_keys, feerate_per_kw);
3300+
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys);
3301+
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
3302+
let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &remote_keys.per_commitment_point, &self.local_keys.htlc_base_key), "Derived invalid key, peer is maliciously selecting parameters");
3303+
htlc_sigs.push(self.secp_ctx.sign(&htlc_sighash, &our_htlc_key));
3304+
}
33033305
}
33043306

33053307
Ok((msgs::CommitmentSigned {
33063308
channel_id: self.channel_id,
33073309
signature: our_sig,
33083310
htlc_signatures: htlc_sigs,
3309-
}, remote_commitment_tx))
3311+
}, (remote_commitment_tx.0, remote_commitment_tx.2)))
33103312
}
33113313

33123314
/// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction
@@ -4020,8 +4022,11 @@ mod tests {
40204022
macro_rules! test_commitment {
40214023
( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => {
40224024
unsigned_tx = {
4023-
let res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw);
4024-
(res.0, res.1)
4025+
let mut res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw);
4026+
let htlcs = res.2.drain(..)
4027+
.filter_map(|(htlc, _)| if htlc.transaction_output_index.is_some() { Some(htlc) } else { None })
4028+
.collect();
4029+
(res.0, htlcs)
40254030
};
40264031
let their_signature = Signature::from_der(&secp_ctx, &hex::decode($their_sig_hex).unwrap()[..]).unwrap();
40274032
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();

0 commit comments

Comments
 (0)