Skip to content

Commit 543b098

Browse files
author
Antoine Riard
committed
Avoid claiming remote received HTLCs with preimage
In case of duplicate HTLCs with same hash going in opposite directions we may learn preimage of offered one, but we shouldn't claim received one to avoid invalidation of combined claim. The received HTLC is going to be claimed by a timeout tx at timelock expiration. Fix #337
1 parent 2afd531 commit 543b098

File tree

1 file changed

+40
-38
lines changed

1 file changed

+40
-38
lines changed

src/ln/channelmonitor.rs

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1643,46 +1643,48 @@ impl ChannelMonitor {
16431643
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); // Corrupted per_commitment_data, fuck this user
16441644
}
16451645
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
1646-
let input = TxIn {
1647-
previous_output: BitcoinOutPoint {
1648-
txid: commitment_txid,
1649-
vout: transaction_output_index,
1650-
},
1651-
script_sig: Script::new(),
1652-
sequence: idx as u32, // reset to 0xfffffffd in sign_input
1653-
witness: Vec::new(),
1654-
};
1655-
if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
1656-
inputs.push(input);
1657-
inputs_desc.push(if htlc.offered { InputDescriptors::OfferedHTLC } else { InputDescriptors::ReceivedHTLC });
1658-
inputs_info.push((payment_preimage, tx.output[transaction_output_index as usize].value, htlc.cltv_expiry));
1659-
total_value += tx.output[transaction_output_index as usize].value;
1660-
} else {
1661-
let mut single_htlc_tx = Transaction {
1662-
version: 2,
1663-
lock_time: 0,
1664-
input: vec![input],
1665-
output: vec!(TxOut {
1666-
script_pubkey: self.destination_script.clone(),
1667-
value: htlc.amount_msat / 1000,
1668-
}),
1646+
if htlc.offered {
1647+
let input = TxIn {
1648+
previous_output: BitcoinOutPoint {
1649+
txid: commitment_txid,
1650+
vout: transaction_output_index,
1651+
},
1652+
script_sig: Script::new(),
1653+
sequence: idx as u32, // reset to 0xfffffffd in sign_input
1654+
witness: Vec::new(),
16691655
};
1670-
let predicted_weight = single_htlc_tx.get_weight() + Self::get_witnesses_weight(&[if htlc.offered { InputDescriptors::OfferedHTLC } else { InputDescriptors::ReceivedHTLC }]);
1671-
let height_timer = Self::get_height_timer(height, htlc.cltv_expiry);
1672-
let mut used_feerate;
1673-
if subtract_high_prio_fee!(self, fee_estimator, single_htlc_tx.output[0].value, predicted_weight, tx.txid(), used_feerate) {
1674-
let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
1675-
let (redeemscript, htlc_key) = sign_input!(sighash_parts, single_htlc_tx.input[0], htlc.amount_msat / 1000, payment_preimage.0.to_vec());
1676-
assert!(predicted_weight >= single_htlc_tx.get_weight());
1677-
spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
1678-
outpoint: BitcoinOutPoint { txid: single_htlc_tx.txid(), vout: 0 },
1679-
output: single_htlc_tx.output[0].clone(),
1680-
});
1681-
match self.our_claim_txn_waiting_first_conf.entry(single_htlc_tx.input[0].previous_output.clone()) {
1682-
hash_map::Entry::Occupied(_) => {},
1683-
hash_map::Entry::Vacant(entry) => { entry.insert((height_timer, TxMaterial::RemoteHTLC { script: redeemscript, key: htlc_key, preimage: Some(*payment_preimage), amount: htlc.amount_msat / 1000 }, used_feerate, htlc.cltv_expiry, height)); }
1656+
if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
1657+
inputs.push(input);
1658+
inputs_desc.push(if htlc.offered { InputDescriptors::OfferedHTLC } else { InputDescriptors::ReceivedHTLC });
1659+
inputs_info.push((payment_preimage, tx.output[transaction_output_index as usize].value, htlc.cltv_expiry));
1660+
total_value += tx.output[transaction_output_index as usize].value;
1661+
} else {
1662+
let mut single_htlc_tx = Transaction {
1663+
version: 2,
1664+
lock_time: 0,
1665+
input: vec![input],
1666+
output: vec!(TxOut {
1667+
script_pubkey: self.destination_script.clone(),
1668+
value: htlc.amount_msat / 1000,
1669+
}),
1670+
};
1671+
let predicted_weight = single_htlc_tx.get_weight() + Self::get_witnesses_weight(&[if htlc.offered { InputDescriptors::OfferedHTLC } else { InputDescriptors::ReceivedHTLC }]);
1672+
let height_timer = Self::get_height_timer(height, htlc.cltv_expiry);
1673+
let mut used_feerate;
1674+
if subtract_high_prio_fee!(self, fee_estimator, single_htlc_tx.output[0].value, predicted_weight, tx.txid(), used_feerate) {
1675+
let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
1676+
let (redeemscript, htlc_key) = sign_input!(sighash_parts, single_htlc_tx.input[0], htlc.amount_msat / 1000, payment_preimage.0.to_vec());
1677+
assert!(predicted_weight >= single_htlc_tx.get_weight());
1678+
spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
1679+
outpoint: BitcoinOutPoint { txid: single_htlc_tx.txid(), vout: 0 },
1680+
output: single_htlc_tx.output[0].clone(),
1681+
});
1682+
match self.our_claim_txn_waiting_first_conf.entry(single_htlc_tx.input[0].previous_output.clone()) {
1683+
hash_map::Entry::Occupied(_) => {},
1684+
hash_map::Entry::Vacant(entry) => { entry.insert((height_timer, TxMaterial::RemoteHTLC { script: redeemscript, key: htlc_key, preimage: Some(*payment_preimage), amount: htlc.amount_msat / 1000 }, used_feerate, htlc.cltv_expiry, height)); }
1685+
}
1686+
txn_to_broadcast.push(single_htlc_tx);
16841687
}
1685-
txn_to_broadcast.push(single_htlc_tx);
16861688
}
16871689
}
16881690
}

0 commit comments

Comments
 (0)