Skip to content

Commit 73e013c

Browse files
valentinewallaceAntoine Riard
and
Antoine Riard
committed
Claim HTLC output on-chain if preimage is recv'd after force-close
If we receive a preimage for an outgoing HTLC on a force-closed channel, we need to claim the HTLC output on-chain. Note that if no counterparty commitment transaction has been broadcasted, we currently default to broadcasting two preimage-output-claiming txs whenever we receive a preimage. This will be fixed in the next commit. Co-authored-by: Antoine Riard <[email protected]> Co-authored-by: Valentine Wallace <[email protected]>
1 parent a849b30 commit 73e013c

File tree

3 files changed

+268
-28
lines changed

3 files changed

+268
-28
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 68 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,6 +1168,38 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
11681168
L::Target: Logger,
11691169
{
11701170
self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone());
1171+
1172+
// If the channel is force closed, try to claim the output from this preimage.
1173+
// First check if a counterparty commitment transaction has been broadcasted:
1174+
macro_rules! claim_htlcs {
1175+
($commitment_number: expr, $txid: expr) => {
1176+
let htlc_claim_reqs = self.get_counterparty_htlc_output_claim_reqs($commitment_number, $txid, None);
1177+
self.onchain_tx_handler.update_claims_view(&Vec::new(), htlc_claim_reqs, None, broadcaster, fee_estimator, logger);
1178+
}
1179+
}
1180+
if let Some(txid) = self.current_counterparty_commitment_txid {
1181+
if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
1182+
claim_htlcs!(*commitment_number, txid);
1183+
return;
1184+
}
1185+
}
1186+
if let Some(txid) = self.prev_counterparty_commitment_txid {
1187+
if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
1188+
claim_htlcs!(*commitment_number, txid);
1189+
return;
1190+
}
1191+
}
1192+
1193+
// Then if a holder commitment transaction has been signed, broadcast transactions claiming
1194+
// the HTLC output from each of the holder commitment transactions.
1195+
if self.broadcasted_holder_revokable_script.is_some() {
1196+
let (claim_reqs, _, _) = self.broadcast_by_holder_state(None, &self.current_holder_commitment_tx);
1197+
self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, None, broadcaster, fee_estimator, logger);
1198+
if let Some(ref tx) = self.prev_holder_signed_commitment_tx {
1199+
let (claim_reqs, _, _) = self.broadcast_by_holder_state(None, &tx);
1200+
self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, None, broadcaster, fee_estimator, logger);
1201+
}
1202+
}
11711203
}
11721204

11731205
pub(crate) fn broadcast_latest_holder_commitment_txn<B: Deref, L: Deref>(&mut self, broadcaster: &B, logger: &L)
@@ -1467,39 +1499,49 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
14671499
check_htlc_fails!(txid, "previous", 'prev_loop);
14681500
}
14691501

1502+
let htlc_claim_reqs = self.get_counterparty_htlc_output_claim_reqs(commitment_number, commitment_txid, Some(tx));
1503+
for req in htlc_claim_reqs {
1504+
claimable_outpoints.push(req);
1505+
}
1506+
1507+
}
1508+
(claimable_outpoints, (commitment_txid, watch_outputs))
1509+
}
1510+
1511+
fn get_counterparty_htlc_output_claim_reqs(&self, commitment_number: u64, commitment_txid: Txid, tx: Option<&Transaction>) -> Vec<ClaimRequest> {
1512+
let mut claims = Vec::new();
1513+
if let Some(htlc_outputs) = self.counterparty_claimable_outpoints.get(&commitment_txid) {
14701514
if let Some(revocation_points) = self.their_cur_revocation_points {
14711515
let revocation_point_option =
14721516
if revocation_points.0 == commitment_number { Some(&revocation_points.1) }
1473-
else if let Some(point) = revocation_points.2.as_ref() {
1474-
if revocation_points.0 == commitment_number + 1 { Some(point) } else { None }
1475-
} else { None };
1517+
else if let Some(point) = revocation_points.2.as_ref() {
1518+
if revocation_points.0 == commitment_number + 1 { Some(point) } else { None }
1519+
} else { None };
14761520
if let Some(revocation_point) = revocation_point_option {
1477-
self.counterparty_payment_script = {
1478-
// Note that the Network here is ignored as we immediately drop the address for the
1479-
// script_pubkey version
1480-
let payment_hash160 = WPubkeyHash::hash(&self.keys.pubkeys().payment_point.serialize());
1481-
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script()
1482-
};
1483-
1484-
// Then, try to find htlc outputs
1485-
for (_, &(ref htlc, _)) in per_commitment_data.iter().enumerate() {
1521+
for (_, &(ref htlc, _)) in htlc_outputs.iter().enumerate() {
14861522
if let Some(transaction_output_index) = htlc.transaction_output_index {
1487-
if transaction_output_index as usize >= tx.output.len() ||
1488-
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 {
1489-
return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user
1523+
if let Some(transaction) = tx {
1524+
if transaction_output_index as usize >= transaction.output.len() ||
1525+
transaction.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 {
1526+
return claims; // Corrupted per_commitment_data, fuck this user
1527+
}
14901528
}
1491-
let preimage = if htlc.offered { if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) { Some(*p) } else { None } } else { None };
1529+
let preimage = if htlc.offered {
1530+
if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) {
1531+
Some(*p)
1532+
} else { None }
1533+
} else { None };
14921534
let aggregable = if !htlc.offered { false } else { true };
14931535
if preimage.is_some() || !htlc.offered {
14941536
let witness_data = InputMaterial::CounterpartyHTLC { per_commitment_point: *revocation_point, counterparty_delayed_payment_base_key: self.counterparty_tx_cache.counterparty_delayed_payment_base_key, counterparty_htlc_base_key: self.counterparty_tx_cache.counterparty_htlc_base_key, preimage, htlc: htlc.clone() };
1495-
claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data });
1537+
claims.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data });
14961538
}
14971539
}
14981540
}
14991541
}
15001542
}
15011543
}
1502-
(claimable_outpoints, (commitment_txid, watch_outputs))
1544+
claims
15031545
}
15041546

15051547
/// Attempts to claim a counterparty HTLC-Success/HTLC-Timeout's outputs using the revocation key
@@ -1529,7 +1571,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15291571
(claimable_outpoints, Some((htlc_txid, outputs)))
15301572
}
15311573

1532-
fn broadcast_by_holder_state(&self, commitment_tx: &Transaction, holder_tx: &HolderSignedTx) -> (Vec<ClaimRequest>, Vec<(u32, TxOut)>, Option<(Script, PublicKey, PublicKey)>) {
1574+
fn broadcast_by_holder_state(&self, commitment_tx: Option<&Transaction>, holder_tx: &HolderSignedTx) -> (Vec<ClaimRequest>, Vec<(u32, TxOut)>, Option<(Script, PublicKey, PublicKey)>) {
15331575
let mut claim_requests = Vec::with_capacity(holder_tx.htlc_outputs.len());
15341576
let mut watch_outputs = Vec::with_capacity(holder_tx.htlc_outputs.len());
15351577

@@ -1550,7 +1592,9 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15501592
} else { None },
15511593
amount: htlc.amount_msat,
15521594
}});
1553-
watch_outputs.push((transaction_output_index, commitment_tx.output[transaction_output_index as usize].clone()));
1595+
if let Some(commitment_tx) = commitment_tx {
1596+
watch_outputs.push((transaction_output_index, commitment_tx.output[transaction_output_index as usize].clone()));
1597+
}
15541598
}
15551599
}
15561600

@@ -1602,13 +1646,13 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
16021646
if self.current_holder_commitment_tx.txid == commitment_txid {
16031647
is_holder_tx = true;
16041648
log_trace!(logger, "Got latest holder commitment tx broadcast, searching for available HTLCs to claim");
1605-
let mut res = self.broadcast_by_holder_state(tx, &self.current_holder_commitment_tx);
1649+
let mut res = self.broadcast_by_holder_state(Some(tx), &self.current_holder_commitment_tx);
16061650
append_onchain_update!(res);
16071651
} else if let &Some(ref holder_tx) = &self.prev_holder_signed_commitment_tx {
16081652
if holder_tx.txid == commitment_txid {
16091653
is_holder_tx = true;
16101654
log_trace!(logger, "Got previous holder commitment tx broadcast, searching for available HTLCs to claim");
1611-
let mut res = self.broadcast_by_holder_state(tx, holder_tx);
1655+
let mut res = self.broadcast_by_holder_state(Some(tx), holder_tx);
16121656
append_onchain_update!(res);
16131657
}
16141658
}
@@ -1777,7 +1821,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
17771821
self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0));
17781822
if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript) {
17791823
self.holder_tx_signed = true;
1780-
let (mut new_outpoints, new_outputs, _) = self.broadcast_by_holder_state(&commitment_tx, &self.current_holder_commitment_tx);
1824+
let (mut new_outpoints, new_outputs, _) = self.broadcast_by_holder_state(Some(&commitment_tx), &self.current_holder_commitment_tx);
17811825
if !new_outputs.is_empty() {
17821826
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
17831827
}
@@ -1805,7 +1849,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
18051849
}
18061850
}
18071851

1808-
self.onchain_tx_handler.block_connected(&txn_matched, claimable_outpoints, height, &*broadcaster, &*fee_estimator, &*logger);
1852+
self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, Some(height), &&*broadcaster, &&*fee_estimator, &&*logger);
18091853
self.last_block_hash = block_hash;
18101854

18111855
// Determine new outputs to watch by comparing against previously known outputs to watch,

lightning/src/ln/functional_tests.rs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8503,3 +8503,185 @@ fn test_htlc_no_detection() {
85038503
connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1, 201, true, header_201.block_hash());
85048504
expect_payment_failed!(nodes[0], our_payment_hash, true);
85058505
}
8506+
8507+
fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain_before_fulfill: bool) {
8508+
// If we route an HTLC, then learn the HTLC's preimage after the upstream channel has been
8509+
// force-closed, we must claim that HTLC on-chain. (Given an HTLC forwarded from Alice --> Bob -->
8510+
// Carol, Alice would be the upstream node, and Carol the downstream.)
8511+
//
8512+
// Steps of the test:
8513+
// 1) Alice sends a HTLC to Carol through Bob.
8514+
// 2) Carol doesn't settle the HTLC.
8515+
// 3) If broadcast_alice is true, Alice force-closes her channel with Bob. Else Bob force closes.
8516+
// Steps 4 and 5 may be reordered depending on go_onchain_before_fulfill.
8517+
// 4) Bob sees the Alice's commitment on his chain or vice versa. An offered output is present
8518+
// but can't be claimed as Bob doesn't have yet knowledge of the preimage.
8519+
// 5) Carol release the preimage to Bob off-chain.
8520+
// 6) Bob claims the offered output on the broadcasted commitment.
8521+
let chanmon_cfgs = create_chanmon_cfgs(3);
8522+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
8523+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
8524+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
8525+
8526+
// Create some initial channels
8527+
let chan_ab = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
8528+
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
8529+
8530+
// Steps (1) and (2):
8531+
// Send an HTLC Alice --> Bob --> Carol, but Carol doesn't settle the HTLC back.
8532+
let (payment_preimage, _payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), 3_000_000);
8533+
8534+
// Check that Alice's commitment transaction now contains an output for this HTLC.
8535+
let alice_txn = get_local_commitment_txn!(nodes[0], chan_ab.2);
8536+
check_spends!(alice_txn[0], chan_ab.3);
8537+
assert_eq!(alice_txn[0].output.len(), 2);
8538+
check_spends!(alice_txn[1], alice_txn[0]); // 2nd transaction is a non-final HTLC-timeout
8539+
assert_eq!(alice_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
8540+
assert_eq!(alice_txn.len(), 2);
8541+
8542+
// Steps (3) and (4):
8543+
// If `go_onchain_before_fufill`, broadcast the relevant commitment transaction and check that Bob
8544+
// responds by (1) broadcasting a channel update and (2) adding a new ChannelMonitor.
8545+
let mut force_closing_node = 0; // Alice force-closes
8546+
if !broadcast_alice { force_closing_node = 1; } // Bob force-closes
8547+
nodes[force_closing_node].node.force_close_channel(&chan_ab.2);
8548+
check_closed_broadcast!(nodes[force_closing_node], false);
8549+
check_added_monitors!(nodes[force_closing_node], 1);
8550+
if go_onchain_before_fulfill {
8551+
let txn_to_broadcast = match broadcast_alice {
8552+
true => alice_txn.clone(),
8553+
false => get_local_commitment_txn!(nodes[1], chan_ab.2)
8554+
};
8555+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
8556+
connect_block(&nodes[1], &Block { header, txdata: vec![txn_to_broadcast[0].clone()]}, 1);
8557+
let mut bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
8558+
if broadcast_alice {
8559+
check_closed_broadcast!(nodes[1], false);
8560+
check_added_monitors!(nodes[1], 1);
8561+
}
8562+
assert_eq!(bob_txn.len(), 1);
8563+
check_spends!(bob_txn[0], chan_ab.3);
8564+
}
8565+
8566+
// Step (5):
8567+
// Carol then claims the funds and sends an update_fulfill message to Bob, and they go through the
8568+
// process of removing the HTLC from their commitment transactions.
8569+
assert!(nodes[2].node.claim_funds(payment_preimage, &None, 3_000_000));
8570+
check_added_monitors!(nodes[2], 1);
8571+
let carol_updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
8572+
assert!(carol_updates.update_add_htlcs.is_empty());
8573+
assert!(carol_updates.update_fail_htlcs.is_empty());
8574+
assert!(carol_updates.update_fail_malformed_htlcs.is_empty());
8575+
assert!(carol_updates.update_fee.is_none());
8576+
assert_eq!(carol_updates.update_fulfill_htlcs.len(), 1);
8577+
8578+
nodes[1].node.handle_update_fulfill_htlc(&nodes[2].node.get_our_node_id(), &carol_updates.update_fulfill_htlcs[0]);
8579+
// If Alice broadcasted but Bob doesn't know yet, here he prepares to tell her about the preimage.
8580+
if !go_onchain_before_fulfill && broadcast_alice {
8581+
let events = nodes[1].node.get_and_clear_pending_msg_events();
8582+
assert_eq!(events.len(), 1);
8583+
match events[0] {
8584+
MessageSendEvent::UpdateHTLCs { .. } => {},
8585+
_ => panic!("Unexpected event"),
8586+
};
8587+
}
8588+
nodes[1].node.handle_commitment_signed(&nodes[2].node.get_our_node_id(), &carol_updates.commitment_signed);
8589+
// One monitor update for the preimage to update the Bob<->Alice channel, one monitor update
8590+
// Carol<->Bob's updated commitment transaction info.
8591+
check_added_monitors!(nodes[1], 2);
8592+
8593+
let events = nodes[1].node.get_and_clear_pending_msg_events();
8594+
assert_eq!(events.len(), 2);
8595+
let bob_revocation = match events[0] {
8596+
MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => {
8597+
assert_eq!(*node_id, nodes[2].node.get_our_node_id());
8598+
(*msg).clone()
8599+
},
8600+
_ => panic!("Unexpected event"),
8601+
};
8602+
let bob_updates = match events[1] {
8603+
MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => {
8604+
assert_eq!(*node_id, nodes[2].node.get_our_node_id());
8605+
(*updates).clone()
8606+
},
8607+
_ => panic!("Unexpected event"),
8608+
};
8609+
8610+
nodes[2].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bob_revocation);
8611+
check_added_monitors!(nodes[2], 1);
8612+
nodes[2].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &bob_updates.commitment_signed);
8613+
check_added_monitors!(nodes[2], 1);
8614+
8615+
let events = nodes[2].node.get_and_clear_pending_msg_events();
8616+
assert_eq!(events.len(), 1);
8617+
let carol_revocation = match events[0] {
8618+
MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => {
8619+
assert_eq!(*node_id, nodes[1].node.get_our_node_id());
8620+
(*msg).clone()
8621+
},
8622+
_ => panic!("Unexpected event"),
8623+
};
8624+
nodes[1].node.handle_revoke_and_ack(&nodes[2].node.get_our_node_id(), &carol_revocation);
8625+
check_added_monitors!(nodes[1], 1);
8626+
8627+
// If this test requires the force-closed channel to not be on-chain until after the fulfill,
8628+
// here's where we put said channel's commitment tx on-chain.
8629+
let mut txn_to_broadcast = alice_txn.clone();
8630+
if !broadcast_alice { txn_to_broadcast = get_local_commitment_txn!(nodes[1], chan_ab.2); }
8631+
if !go_onchain_before_fulfill {
8632+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
8633+
connect_block(&nodes[1], &Block { header, txdata: vec![txn_to_broadcast[0].clone()]}, 1);
8634+
// If Bob was the one to force-close, he will have already passed these checks earlier.
8635+
if broadcast_alice {
8636+
check_closed_broadcast!(nodes[1], false);
8637+
check_added_monitors!(nodes[1], 1);
8638+
}
8639+
let mut bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
8640+
if broadcast_alice {
8641+
// In `connect_block()`, the ChainMonitor and ChannelManager are separately notified about a
8642+
// new block being connected. The ChannelManager being notified triggers a monitor update,
8643+
// which triggers broadcasting our commitment tx and an HTLC-claiming tx. The ChainMonitor
8644+
// being notified triggers the HTLC-claiming tx redundantly, resulting in 3 total txs being
8645+
// broadcasted.
8646+
assert_eq!(bob_txn.len(), 3);
8647+
check_spends!(bob_txn[1], chan_ab.3);
8648+
} else {
8649+
assert_eq!(bob_txn.len(), 2);
8650+
check_spends!(bob_txn[0], chan_ab.3);
8651+
}
8652+
}
8653+
8654+
// Step (6):
8655+
// Finally, check that Bob broadcasted a preimage-claiming transaction for the HTLC output on the
8656+
// broadcasted commitment transaction.
8657+
{
8658+
let bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
8659+
if go_onchain_before_fulfill {
8660+
// Bob should now have an extra broadcasted tx, for the preimage-claiming transaction.
8661+
assert_eq!(bob_txn.len(), 2);
8662+
}
8663+
let script_weight = match broadcast_alice {
8664+
true => OFFERED_HTLC_SCRIPT_WEIGHT,
8665+
false => ACCEPTED_HTLC_SCRIPT_WEIGHT
8666+
};
8667+
// If Alice force-closed and Bob didn't receive her commitment transaction until after he
8668+
// received Carol's fulfill, he broadcasts the HTLC-output-claiming transaction first. Else if
8669+
// Bob force closed or if he found out about Alice's commitment tx before receiving Carol's
8670+
// fulfill, then he broadcasts the HTLC-output-claiming transaction second.
8671+
if broadcast_alice && !go_onchain_before_fulfill {
8672+
check_spends!(bob_txn[0], txn_to_broadcast[0]);
8673+
assert_eq!(bob_txn[0].input[0].witness.last().unwrap().len(), script_weight);
8674+
} else {
8675+
check_spends!(bob_txn[1], txn_to_broadcast[0]);
8676+
assert_eq!(bob_txn[1].input[0].witness.last().unwrap().len(), script_weight);
8677+
}
8678+
}
8679+
}
8680+
8681+
#[test]
8682+
fn test_onchain_htlc_settlement_after_close1() {
8683+
do_test_onchain_htlc_settlement_after_close(true, true);
8684+
do_test_onchain_htlc_settlement_after_close(false, true);
8685+
do_test_onchain_htlc_settlement_after_close(true, false);
8686+
do_test_onchain_htlc_settlement_after_close(false, false);
8687+
}

0 commit comments

Comments
 (0)