Skip to content

Commit c156d15

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. Co-authored-by: Antoine Riard <[email protected]> Co-authored-by: Valentine Wallace <[email protected]>
1 parent 0075e63 commit c156d15

File tree

3 files changed

+248
-28
lines changed

3 files changed

+248
-28
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,18 @@ pub struct ChannelMonitorUpdate {
6464
pub(crate) updates: Vec<ChannelMonitorUpdateStep>,
6565
/// The sequence number of this update. Updates *must* be replayed in-order according to this
6666
/// sequence number (and updates may panic if they are not). The update_id values are strictly
67-
/// increasing and increase by one for each new update.
67+
/// increasing and increase by one for each new update, with one exception specified below.
6868
///
6969
/// This sequence number is also used to track up to which points updates which returned
7070
/// ChannelMonitorUpdateErr::TemporaryFailure have been applied to all copies of a given
7171
/// ChannelMonitor when ChannelManager::channel_monitor_updated is called.
72+
///
73+
/// The only instance where update_id values are not strictly increasing is the case where: (1)
74+
/// the channel has been force closed and (2) we receive a preimage from a forward link that
75+
/// allows us to spend an HTLC output on this channel's (the backward link's) broadcasted
76+
/// commitment transaction. In this case, we allow the `ChannelManager` to send a
77+
/// `ChannelMonitorUpdate` with an update_id of `std::u64::MAX`, with the update providing said
78+
/// payment preimage. No other update types are allowed after force-close.
7279
pub update_id: u64,
7380
}
7481

@@ -1150,6 +1157,46 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
11501157
L::Target: Logger,
11511158
{
11521159
self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone());
1160+
1161+
// If the channel is force closed, try to claim the output from this preimage.
1162+
// First check if a counterparty commitment transaction has been broadcasted:
1163+
macro_rules! claim_htlcs {
1164+
($commitment_number: expr, $txid: expr) => {
1165+
let (htlc_claim_reqs, set_script) = self.get_counterparty_htlc_output_claim_reqs($commitment_number, $txid, None);
1166+
if set_script {
1167+
self.counterparty_payment_script = {
1168+
// Note that the Network here is ignored as we immediately drop the address for the
1169+
// script_pubkey version
1170+
let payment_hash160 = WPubkeyHash::hash(&self.keys.pubkeys().payment_point.serialize());
1171+
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script()
1172+
};
1173+
}
1174+
self.onchain_tx_handler.update_claims_view(&Vec::new(), htlc_claim_reqs, None, broadcaster, fee_estimator, logger);
1175+
}
1176+
}
1177+
if let Some(txid) = self.current_counterparty_commitment_txid {
1178+
if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
1179+
claim_htlcs!(*commitment_number, txid);
1180+
return;
1181+
}
1182+
}
1183+
if let Some(txid) = self.prev_counterparty_commitment_txid {
1184+
if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
1185+
claim_htlcs!(*commitment_number, txid);
1186+
return;
1187+
}
1188+
}
1189+
1190+
// Then if a holder commitment transaction has been signed, broadcast transactions claiming
1191+
// the HTLC output from each of the holder commitment transactions.
1192+
if self.holder_tx_signed {
1193+
let (claim_reqs, _, _) = self.broadcast_by_holder_state(None, &self.current_holder_commitment_tx);
1194+
self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, None, broadcaster, fee_estimator, logger);
1195+
if let Some(ref tx) = self.prev_holder_signed_commitment_tx {
1196+
let (claim_reqs, _, _) = self.broadcast_by_holder_state(None, &tx);
1197+
self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, None, broadcaster, fee_estimator, logger);
1198+
}
1199+
}
11531200
}
11541201

11551202
pub(crate) fn broadcast_latest_holder_commitment_txn<B: Deref, L: Deref>(&mut self, broadcaster: &B, logger: &L)
@@ -1171,7 +1218,18 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
11711218
F::Target: FeeEstimator,
11721219
L::Target: Logger,
11731220
{
1174-
if self.latest_update_id + 1 != updates.update_id {
1221+
// ChannelMonitor updates may be applied after force close if we receive a
1222+
// preimage for a broadcasted commitment transaction HTLC output that we'd
1223+
// like to claim on-chain. If this is the case, we no longer have guaranteed
1224+
// access to the monitor's update ID, so we use a sentinel value instead.
1225+
if updates.update_id == std::u64::MAX {
1226+
match updates.updates[0] {
1227+
ChannelMonitorUpdateStep::PaymentPreimage { .. } => {},
1228+
_ => panic!("Attempted to apply post-force-close ChannelMonitorUpdate that wasn't providing a payment preimage"),
1229+
}
1230+
assert_eq!(updates.updates.len(), 1);
1231+
}
1232+
if updates.update_id != std::u64::MAX && self.latest_update_id + 1 != updates.update_id {
11751233
panic!("Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!");
11761234
}
11771235
for update in updates.updates.iter() {
@@ -1439,39 +1497,61 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
14391497
check_htlc_fails!(txid, "previous", 'prev_loop);
14401498
}
14411499

1500+
let (htlc_claim_reqs, set_script) = self.get_counterparty_htlc_output_claim_reqs(commitment_number, commitment_txid, Some(tx));
1501+
if set_script {
1502+
self.counterparty_payment_script = {
1503+
// Note that the Network here is ignored as we immediately drop the address for the
1504+
// script_pubkey version
1505+
let payment_hash160 = WPubkeyHash::hash(&self.keys.pubkeys().payment_point.serialize());
1506+
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script()
1507+
};
1508+
}
1509+
for req in htlc_claim_reqs {
1510+
claimable_outpoints.push(req);
1511+
}
1512+
1513+
}
1514+
(claimable_outpoints, (commitment_txid, watch_outputs))
1515+
}
1516+
1517+
fn get_counterparty_htlc_output_claim_reqs(&self, commitment_number: u64, commitment_txid: Txid, tx: Option<&Transaction>) -> (Vec<ClaimRequest>, bool) {
1518+
let mut claims = Vec::new();
1519+
let mut set_counterparty_payment_script = false;
1520+
if let Some(htlc_outputs) = self.counterparty_claimable_outpoints.get(&commitment_txid) {
14421521
if let Some(revocation_points) = self.their_cur_revocation_points {
14431522
let revocation_point_option =
14441523
if revocation_points.0 == commitment_number { Some(&revocation_points.1) }
1445-
else if let Some(point) = revocation_points.2.as_ref() {
1446-
if revocation_points.0 == commitment_number + 1 { Some(point) } else { None }
1447-
} else { None };
1524+
else if let Some(point) = revocation_points.2.as_ref() {
1525+
if revocation_points.0 == commitment_number + 1 { Some(point) } else { None }
1526+
} else { None };
14481527
if let Some(revocation_point) = revocation_point_option {
1449-
self.counterparty_payment_script = {
1450-
// Note that the Network here is ignored as we immediately drop the address for the
1451-
// script_pubkey version
1452-
let payment_hash160 = WPubkeyHash::hash(&self.keys.pubkeys().payment_point.serialize());
1453-
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script()
1454-
};
1528+
set_counterparty_payment_script = true;
14551529

14561530
// Then, try to find htlc outputs
1457-
for (_, &(ref htlc, _)) in per_commitment_data.iter().enumerate() {
1531+
for (_, &(ref htlc, _)) in htlc_outputs.iter().enumerate() {
14581532
if let Some(transaction_output_index) = htlc.transaction_output_index {
1459-
if transaction_output_index as usize >= tx.output.len() ||
1460-
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 {
1461-
return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user
1533+
if let Some(transaction) = tx {
1534+
if transaction_output_index as usize >= transaction.output.len() ||
1535+
transaction.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 {
1536+
return (claims, set_counterparty_payment_script) // Corrupted per_commitment_data, fuck this user
1537+
}
14621538
}
1463-
let preimage = if htlc.offered { if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) { Some(*p) } else { None } } else { None };
1539+
let preimage = if htlc.offered {
1540+
if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) {
1541+
Some(*p)
1542+
} else { None }
1543+
} else { None };
14641544
let aggregable = if !htlc.offered { false } else { true };
14651545
if preimage.is_some() || !htlc.offered {
14661546
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() };
1467-
claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data });
1547+
claims.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data });
14681548
}
14691549
}
14701550
}
14711551
}
14721552
}
14731553
}
1474-
(claimable_outpoints, (commitment_txid, watch_outputs))
1554+
(claims, set_counterparty_payment_script)
14751555
}
14761556

14771557
/// Attempts to claim a counterparty HTLC-Success/HTLC-Timeout's outputs using the revocation key
@@ -1501,7 +1581,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15011581
(claimable_outpoints, Some((htlc_txid, outputs)))
15021582
}
15031583

1504-
fn broadcast_by_holder_state(&self, commitment_tx: &Transaction, holder_tx: &HolderSignedTx) -> (Vec<ClaimRequest>, Vec<(u32, TxOut)>, Option<(Script, PublicKey, PublicKey)>) {
1584+
fn broadcast_by_holder_state(&self, commitment_tx: Option<&Transaction>, holder_tx: &HolderSignedTx) -> (Vec<ClaimRequest>, Vec<(u32, TxOut)>, Option<(Script, PublicKey, PublicKey)>) {
15051585
let mut claim_requests = Vec::with_capacity(holder_tx.htlc_outputs.len());
15061586
let mut watch_outputs = Vec::with_capacity(holder_tx.htlc_outputs.len());
15071587

@@ -1522,7 +1602,9 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15221602
} else { None },
15231603
amount: htlc.amount_msat,
15241604
}});
1525-
watch_outputs.push((transaction_output_index, commitment_tx.output[transaction_output_index as usize].clone()));
1605+
if let Some(commitment_tx) = commitment_tx {
1606+
watch_outputs.push((transaction_output_index, commitment_tx.output[transaction_output_index as usize].clone()));
1607+
}
15261608
}
15271609
}
15281610

@@ -1574,13 +1656,13 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15741656
if self.current_holder_commitment_tx.txid == commitment_txid {
15751657
is_holder_tx = true;
15761658
log_trace!(logger, "Got latest holder commitment tx broadcast, searching for available HTLCs to claim");
1577-
let mut res = self.broadcast_by_holder_state(tx, &self.current_holder_commitment_tx);
1659+
let mut res = self.broadcast_by_holder_state(Some(tx), &self.current_holder_commitment_tx);
15781660
append_onchain_update!(res);
15791661
} else if let &Some(ref holder_tx) = &self.prev_holder_signed_commitment_tx {
15801662
if holder_tx.txid == commitment_txid {
15811663
is_holder_tx = true;
15821664
log_trace!(logger, "Got previous holder commitment tx broadcast, searching for available HTLCs to claim");
1583-
let mut res = self.broadcast_by_holder_state(tx, holder_tx);
1665+
let mut res = self.broadcast_by_holder_state(Some(tx), holder_tx);
15841666
append_onchain_update!(res);
15851667
}
15861668
}
@@ -1749,7 +1831,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
17491831
self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0));
17501832
if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript) {
17511833
self.holder_tx_signed = true;
1752-
let (mut new_outpoints, new_outputs, _) = self.broadcast_by_holder_state(&commitment_tx, &self.current_holder_commitment_tx);
1834+
let (mut new_outpoints, new_outputs, _) = self.broadcast_by_holder_state(Some(&commitment_tx), &self.current_holder_commitment_tx);
17531835
if !new_outputs.is_empty() {
17541836
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
17551837
}
@@ -1777,7 +1859,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
17771859
}
17781860
}
17791861

1780-
self.onchain_tx_handler.block_connected(&txn_matched, claimable_outpoints, height, &*broadcaster, &*fee_estimator, &*logger);
1862+
self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, Some(height), &&*broadcaster, &&*fee_estimator, &&*logger);
17811863
self.last_block_hash = block_hash;
17821864

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

lightning/src/ln/functional_tests.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8503,3 +8503,126 @@ 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) {
8508+
// If we route an HTLC, then learn the HTLC's preimage after the upstream
8509+
// channel has been force-closed by our counterparty, we must claim that HTLC
8510+
// on-chain. (Given an HTLC forwarded from Alice --> Bob --> Carol, Alice
8511+
// would be the upstream node, and Carol the downstream.)
8512+
//
8513+
// Steps of the test:
8514+
// 1) Alice sends a HTLC to Carol through Bob.
8515+
// 2) Carol doesn't settle the HTLC.
8516+
// 3) If broadcast_alice is true, Alice force-closes her channel with Bob. Else Bob force closes.
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+
// Broadcast the relevant commitment transaction and check that Bob responds by (1) broadcasting
8544+
// a channel update and (2) adding a new ChannelMonitor.
8545+
let mut txn_to_broadcast = alice_txn;
8546+
if !broadcast_alice { txn_to_broadcast = get_local_commitment_txn!(nodes[1], chan_ab.2); }
8547+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
8548+
connect_block(&nodes[1], &Block { header, txdata: vec![txn_to_broadcast[0].clone()]}, 1);
8549+
check_closed_broadcast!(nodes[1], false);
8550+
check_added_monitors!(nodes[1], 1);
8551+
{
8552+
let mut bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); // ChannelManager : 1 (commitment tx)
8553+
assert_eq!(bob_txn.len(), 1);
8554+
check_spends!(bob_txn[0], chan_ab.3);
8555+
bob_txn.clear();
8556+
}
8557+
8558+
// Step (5):
8559+
// Carol then claims the funds and sends an update_fulfill message to Bob, and they go
8560+
// through the process of removing the HTLC from their commitment transactions.
8561+
assert!(nodes[2].node.claim_funds(payment_preimage, &None, 3_000_000));
8562+
check_added_monitors!(nodes[2], 1);
8563+
let carol_updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
8564+
assert!(carol_updates.update_add_htlcs.is_empty());
8565+
assert!(carol_updates.update_fail_htlcs.is_empty());
8566+
assert!(carol_updates.update_fail_malformed_htlcs.is_empty());
8567+
assert!(carol_updates.update_fee.is_none());
8568+
assert_eq!(carol_updates.update_fulfill_htlcs.len(), 1);
8569+
8570+
nodes[1].node.handle_update_fulfill_htlc(&nodes[2].node.get_our_node_id(), &carol_updates.update_fulfill_htlcs[0]);
8571+
nodes[1].node.handle_commitment_signed(&nodes[2].node.get_our_node_id(), &carol_updates.commitment_signed);
8572+
// One monitor update for the preimage, one monitor update for the new commitment tx info
8573+
check_added_monitors!(nodes[1], 2);
8574+
8575+
let events = nodes[1].node.get_and_clear_pending_msg_events();
8576+
assert_eq!(events.len(), 2);
8577+
let bob_revocation = match events[0] {
8578+
MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => {
8579+
assert_eq!(*node_id, nodes[2].node.get_our_node_id());
8580+
(*msg).clone()
8581+
},
8582+
_ => panic!("Unexpected event"),
8583+
};
8584+
let bob_updates = match events[1] {
8585+
MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => {
8586+
assert_eq!(*node_id, nodes[2].node.get_our_node_id());
8587+
(*updates).clone()
8588+
},
8589+
_ => panic!("Unexpected event"),
8590+
};
8591+
8592+
nodes[2].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bob_revocation);
8593+
check_added_monitors!(nodes[2], 1);
8594+
nodes[2].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &bob_updates.commitment_signed);
8595+
check_added_monitors!(nodes[2], 1);
8596+
8597+
let events = nodes[2].node.get_and_clear_pending_msg_events();
8598+
assert_eq!(events.len(), 1);
8599+
let carol_revocation = match events[0] {
8600+
MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => {
8601+
assert_eq!(*node_id, nodes[1].node.get_our_node_id());
8602+
(*msg).clone()
8603+
},
8604+
_ => panic!("Unexpected event"),
8605+
};
8606+
nodes[1].node.handle_revoke_and_ack(&nodes[2].node.get_our_node_id(), &carol_revocation);
8607+
check_added_monitors!(nodes[1], 1);
8608+
8609+
// Step (6):
8610+
// Finally, check that Bob broadcasted a preimage-claiming transaction for the HTLC
8611+
// output on the broadcasted commitment transaction.
8612+
{
8613+
let bob_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
8614+
assert_eq!(bob_txn.len(), 1);
8615+
check_spends!(bob_txn[0], txn_to_broadcast[0]);
8616+
let script_weight = match broadcast_alice {
8617+
true => OFFERED_HTLC_SCRIPT_WEIGHT,
8618+
false => ACCEPTED_HTLC_SCRIPT_WEIGHT
8619+
};
8620+
assert_eq!(bob_txn[0].input[0].witness.last().unwrap().len(), script_weight);
8621+
}
8622+
}
8623+
8624+
#[test]
8625+
fn test_onchain_htlc_settlement_after_close() {
8626+
do_test_onchain_htlc_settlement_after_close(true);
8627+
do_test_onchain_htlc_settlement_after_close(false);
8628+
}

0 commit comments

Comments
 (0)