Skip to content

Commit ed1f304

Browse files
authored
Merge pull request #3988 from TheBlueMatt/2025-08-durable-claims
Block RAA `ChannelMonitorUpdate`s on `PaymentClaimed` events
2 parents c8450bf + a80c855 commit ed1f304

File tree

7 files changed

+234
-135
lines changed

7 files changed

+234
-135
lines changed

lightning/src/events/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,11 @@ impl_writeable_tlv_based_enum_legacy!(PaymentPurpose,
233233
/// Information about an HTLC that is part of a payment that can be claimed.
234234
#[derive(Clone, Debug, PartialEq, Eq)]
235235
pub struct ClaimedHTLC {
236+
/// The counterparty of the channel.
237+
///
238+
/// This value will always be `None` for objects serialized with LDK versions prior to 0.2 and
239+
/// `Some` otherwise.
240+
pub counterparty_node_id: Option<PublicKey>,
236241
/// The `channel_id` of the channel over which the HTLC was received.
237242
pub channel_id: ChannelId,
238243
/// The `user_channel_id` of the channel over which the HTLC was received. This is the value
@@ -263,6 +268,7 @@ impl_writeable_tlv_based!(ClaimedHTLC, {
263268
(0, channel_id, required),
264269
(1, counterparty_skimmed_fee_msat, (default_value, 0u64)),
265270
(2, user_channel_id, required),
271+
(3, counterparty_node_id, option),
266272
(4, cltv_expiry, required),
267273
(6, value_msat, required),
268274
});

lightning/src/ln/async_signer_tests.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,7 @@ fn test_no_disconnect_while_async_commitment_signed_expecting_remote_revoke_and_
13951395
let (preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], payment_amount);
13961396
nodes[1].node.claim_funds(preimage);
13971397
check_added_monitors(&nodes[1], 1);
1398+
expect_payment_claimed!(nodes[1], payment_hash, payment_amount);
13981399

13991400
// We'll disable signing counterparty commitments on the payment sender.
14001401
nodes[0].disable_channel_signer_op(&node_b_id, &chan_id, SignerOp::SignCounterpartyCommitment);
@@ -1403,6 +1404,7 @@ fn test_no_disconnect_while_async_commitment_signed_expecting_remote_revoke_and_
14031404
// the `commitment_signed` is no longer pending.
14041405
let mut update = get_htlc_update_msgs!(&nodes[1], node_a_id);
14051406
nodes[0].node.handle_update_fulfill_htlc(node_b_id, update.update_fulfill_htlcs.remove(0));
1407+
expect_payment_sent(&nodes[0], preimage, None, false, false);
14061408
nodes[0].node.handle_commitment_signed_batch_test(node_b_id, &update.commitment_signed);
14071409
check_added_monitors(&nodes[0], 1);
14081410

@@ -1426,7 +1428,4 @@ fn test_no_disconnect_while_async_commitment_signed_expecting_remote_revoke_and_
14261428
};
14271429
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
14281430
assert!(nodes[1].node.get_and_clear_pending_msg_events().into_iter().any(has_disconnect_event));
1429-
1430-
expect_payment_sent(&nodes[0], preimage, None, false, false);
1431-
expect_payment_claimed!(nodes[1], payment_hash, payment_amount);
14321431
}

lightning/src/ln/chanmon_update_fail_tests.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4694,6 +4694,23 @@ fn test_single_channel_multiple_mpp() {
46944694
// `update_fulfill_htlc`/`commitment_signed` pair to pass to our counterparty.
46954695
do_a_write.send(()).unwrap();
46964696

4697+
let event_node: &'static TestChannelManager<'static, 'static> =
4698+
unsafe { std::mem::transmute(nodes[8].node as &TestChannelManager) };
4699+
let thrd_event = std::thread::spawn(move || {
4700+
let mut have_event = false;
4701+
while !have_event {
4702+
let mut events = event_node.get_and_clear_pending_events();
4703+
assert!(events.len() == 1 || events.len() == 0);
4704+
if events.len() == 1 {
4705+
if let Event::PaymentClaimed { .. } = events[0] {
4706+
} else {
4707+
panic!("Unexpected event {events:?}");
4708+
}
4709+
have_event = true;
4710+
}
4711+
}
4712+
});
4713+
46974714
// Then fetch the `update_fulfill_htlc`/`commitment_signed`. Note that the
46984715
// `get_and_clear_pending_msg_events` will immediately hang trying to take a peer lock which
46994716
// `claim_funds` is holding. Thus, we release a second write after a small sleep in the
@@ -4713,7 +4730,11 @@ fn test_single_channel_multiple_mpp() {
47134730
});
47144731
block_thrd2.store(false, Ordering::Release);
47154732
let mut first_updates = get_htlc_update_msgs(&nodes[8], &node_h_id);
4733+
4734+
// Thread 2 could unblock first, or it could get blocked waiting on us to process a
4735+
// `PaymentClaimed` event. Either way, wait until both have finished.
47164736
thrd2.join().unwrap();
4737+
thrd_event.join().unwrap();
47174738

47184739
// Disconnect node 6 from all its peers so it doesn't bother to fail the HTLCs back
47194740
nodes[7].node.peer_disconnected(node_b_id);
@@ -4760,8 +4781,6 @@ fn test_single_channel_multiple_mpp() {
47604781
thrd4.join().unwrap();
47614782
thrd.join().unwrap();
47624783

4763-
expect_payment_claimed!(nodes[8], payment_hash, 50_000_000);
4764-
47654784
// At the end, we should have 7 ChannelMonitorUpdates - 6 for HTLC claims, and one for the
47664785
// above `revoke_and_ack`.
47674786
check_added_monitors(&nodes[8], 7);

lightning/src/ln/channel.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6401,7 +6401,7 @@ where
64016401
Ok((closing_transaction, total_fee_satoshis))
64026402
}
64036403

6404-
fn funding_outpoint(&self) -> OutPoint {
6404+
pub fn funding_outpoint(&self) -> OutPoint {
64056405
self.funding.channel_transaction_parameters.funding_outpoint.unwrap()
64066406
}
64076407

0 commit comments

Comments
 (0)