Skip to content

Commit 8271ebd

Browse files
Prevent redundant PaymentClaimeds for closed channels
Previously, if we had an inbound payment on a closed channel that we started claiming but did not end up removing from the commitment tx, we would generate a PaymentClaimed event for the payment on every restart until the channelmonitor was archived. The past few commits have laid the groundwork to get rid of this redundancy -- here we now generate an event completion action for when the PaymentClaimed is processed by the user, at which point a monitor update will be released that tells the channel monitor that the user has processed the PaymentClaimed event. The monitor tracks this internally such that the pending claim will no longer be returned to the ChannelManager when reconstructing the set of mid-claim inbound payments on startup, and thus no longer generate the redundant event.
1 parent f761051 commit 8271ebd

5 files changed

Lines changed: 91 additions & 17 deletions

File tree

lightning/src/chain/channelmonitor.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3270,6 +3270,20 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
32703270

32713271
pub(crate) fn get_stored_preimages(
32723272
&self,
3273+
) -> HashMap<PaymentHash, (PaymentPreimage, Vec<PaymentClaimDetails>)> {
3274+
let inner = self.inner.lock().unwrap();
3275+
inner
3276+
.payment_preimages
3277+
.iter()
3278+
.filter(|(hash, _)| !inner.inbound_payments_claimed.contains(*hash))
3279+
.map(|(hash, value)| (*hash, value.clone()))
3280+
.collect()
3281+
}
3282+
3283+
/// Used in tests to verify preimage propagation.
3284+
#[cfg(test)]
3285+
pub(crate) fn test_get_all_stored_preimages(
3286+
&self,
32733287
) -> HashMap<PaymentHash, (PaymentPreimage, Vec<PaymentClaimDetails>)> {
32743288
self.inner.lock().unwrap().payment_preimages.clone()
32753289
}
@@ -4304,6 +4318,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
43044318
self.htlcs_resolved_to_user.insert(*htlc);
43054319
},
43064320
ChannelMonitorUpdateStep::InboundPaymentClaimed { payment_hash } => {
4321+
log_trace!(logger, "Inbound payment {} claimed", payment_hash);
4322+
self.inbound_payments_claimed.insert(*payment_hash);
43074323
},
43084324
}
43094325
}

lightning/src/ln/chanmon_update_fail_tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4598,6 +4598,7 @@ fn test_claim_to_closed_channel_blocks_claimed_event() {
45984598
// available.
45994599
nodes[1].chain_monitor.complete_sole_pending_chan_update(&chan_a.2);
46004600
expect_payment_claimed!(nodes[1], payment_hash, 1_000_000);
4601+
check_added_monitors(&nodes[1], 1);
46014602
}
46024603

46034604
#[test]

lightning/src/ln/channelmanager.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10004,11 +10004,34 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1000410004
let action = if let Some((outpoint, counterparty_node_id, channel_id)) =
1000510005
durable_preimage_channel
1000610006
{
10007-
Some(EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
10008-
channel_funding_outpoint: Some(outpoint),
10009-
counterparty_node_id,
10010-
channel_id,
10011-
})
10007+
let per_peer_state = self.per_peer_state.read().unwrap();
10008+
let is_channel_closed = per_peer_state
10009+
.get(&counterparty_node_id)
10010+
.map(|peer_state_mutex| {
10011+
let peer_state = peer_state_mutex.lock().unwrap();
10012+
!peer_state.channel_by_id.contains_key(&channel_id)
10013+
})
10014+
.unwrap_or(true);
10015+
// For open channels, we use ReleaseRAAChannelMonitorUpdate to maintain the blocking
10016+
// behavior (RAA updates are blocked until the PaymentClaimed event is handled).
10017+
// For closed channels, we use InboundPaymentClaimedChannelMonitorUpdate to persist
10018+
// that the PaymentClaimed event has been handled, preventing regeneration on restart.
10019+
if is_channel_closed {
10020+
Some(EventCompletionAction::InboundPaymentClaimedChannelMonitorUpdate(
10021+
InboundPaymentClaimedUpdate {
10022+
channel_funding_outpoint: outpoint,
10023+
counterparty_node_id,
10024+
channel_id,
10025+
payment_hash,
10026+
},
10027+
))
10028+
} else {
10029+
Some(EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
10030+
channel_funding_outpoint: Some(outpoint),
10031+
counterparty_node_id,
10032+
channel_id,
10033+
})
10034+
}
1001210035
} else {
1001310036
None
1001410037
};
@@ -14840,7 +14863,23 @@ impl<
1484014863
update_step,
1484114864
);
1484214865
},
14843-
EventCompletionAction::InboundPaymentClaimedChannelMonitorUpdate(_) => {},
14866+
EventCompletionAction::InboundPaymentClaimedChannelMonitorUpdate(
14867+
InboundPaymentClaimedUpdate {
14868+
counterparty_node_id,
14869+
channel_funding_outpoint,
14870+
channel_id,
14871+
payment_hash,
14872+
},
14873+
) => {
14874+
let update_step =
14875+
ChannelMonitorUpdateStep::InboundPaymentClaimed { payment_hash };
14876+
self.handle_closed_channel_monitor_update_for_event(
14877+
counterparty_node_id,
14878+
channel_funding_outpoint,
14879+
channel_id,
14880+
update_step,
14881+
);
14882+
},
1484414883
}
1484514884
}
1484614885
}

lightning/src/ln/monitor_tests.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ fn archive_fully_resolved_monitors() {
225225
nodes[1].node.claim_funds(payment_preimage);
226226
check_added_monitors(&nodes[1], 1);
227227
expect_payment_claimed!(nodes[1], payment_hash, 10_000_000);
228+
// Processing PaymentClaimed on a closed channel generates a monitor update to mark the claim as
229+
// resolved to the user.
230+
check_added_monitors(&nodes[1], 1);
228231
let htlc_claim_tx = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
229232
assert_eq!(htlc_claim_tx.len(), 1);
230233

@@ -3282,22 +3285,29 @@ fn test_update_replay_panics() {
32823285
nodes[1].node.claim_funds(payment_preimage_1);
32833286
check_added_monitors(&nodes[1], 1);
32843287
expect_payment_claimed!(nodes[1], payment_hash_1, 1_000_000);
3288+
// Processing PaymentClaimed on a closed channel generates a monitor update to mark the claim as
3289+
// resolved to the user.
3290+
check_added_monitors(&nodes[1], 1);
32853291

32863292
nodes[1].node.claim_funds(payment_preimage_2);
32873293
check_added_monitors(&nodes[1], 1);
32883294
expect_payment_claimed!(nodes[1], payment_hash_2, 1_000_000);
3295+
check_added_monitors(&nodes[1], 1);
32893296

32903297
let mut updates = nodes[1].chain_monitor.monitor_updates.lock().unwrap().get_mut(&chan.2).unwrap().split_off(0);
32913298

3292-
// Update `monitor` until there's just one normal updates, an FC update, and a post-FC claim
3293-
// update pending
3294-
for update in updates.drain(..updates.len() - 4) {
3299+
// Update `monitor` until there's just one normal updates, an FC update, a post-FC claim
3300+
// and InboundPaymentClaimed updates pending.
3301+
// Updates are: [normal, FC, preimage1, inbound_claimed1, preimage2, inbound_claimed2]
3302+
for update in updates.drain(..updates.len() - 6) {
32953303
monitor.update_monitor(&update, &nodes[1].tx_broadcaster, &nodes[1].fee_estimator, &nodes[1].logger).unwrap();
32963304
}
3297-
assert_eq!(updates.len(), 4);
3305+
assert_eq!(updates.len(), 6);
32983306
assert!(matches!(updates[1].updates[0], ChannelMonitorUpdateStep::ChannelForceClosed { .. }));
32993307
assert!(matches!(updates[2].updates[0], ChannelMonitorUpdateStep::PaymentPreimage { .. }));
3300-
assert!(matches!(updates[3].updates[0], ChannelMonitorUpdateStep::PaymentPreimage { .. }));
3308+
assert!(matches!(updates[3].updates[0], ChannelMonitorUpdateStep::InboundPaymentClaimed { .. }));
3309+
assert!(matches!(updates[4].updates[0], ChannelMonitorUpdateStep::PaymentPreimage { .. }));
3310+
assert!(matches!(updates[5].updates[0], ChannelMonitorUpdateStep::InboundPaymentClaimed { .. }));
33013311

33023312
// Ensure applying the force-close update skipping the last normal update fails
33033313
let poisoned_monitor = monitor.clone();
@@ -3384,11 +3394,13 @@ fn test_claim_event_never_handled() {
33843394
let chan_0_monitor_serialized = get_monitor!(nodes[1], chan.2).encode();
33853395
let mons = &[&chan_0_monitor_serialized[..]];
33863396
reload_node!(nodes[1], &init_node_ser, mons, persister, new_chain_mon, nodes_1_reload);
3397+
check_added_monitors(&nodes[1], 0);
33873398

33883399
expect_payment_claimed!(nodes[1], payment_hash_a, 1_000_000);
3389-
// The reload logic spuriously generates a redundant payment preimage-containing
3390-
// `ChannelMonitorUpdate`.
3391-
check_added_monitors(&nodes[1], 2);
3400+
// The reload logic spuriously generates 2 redundant payment preimage-containing
3401+
// `ChannelMonitorUpdate`s, plus we get a monitor update once the PaymentClaimed event is
3402+
// processed.
3403+
check_added_monitors(&nodes[1], 3);
33923404
}
33933405

33943406
fn do_test_lost_preimage_monitor_events(on_counterparty_tx: bool, p2a_anchor: bool) {
@@ -3863,6 +3875,7 @@ fn test_ladder_preimage_htlc_claims() {
38633875
check_closed_event(&nodes[1], 1, ClosureReason::CommitmentTxConfirmed, &[node_id_0], 1_000_000);
38643876

38653877
nodes[1].node.claim_funds(payment_preimage1);
3878+
check_added_monitors(&nodes[1], 1);
38663879
expect_payment_claimed!(&nodes[1], payment_hash1, 1_000_000);
38673880
check_added_monitors(&nodes[1], 1);
38683881

@@ -3884,6 +3897,7 @@ fn test_ladder_preimage_htlc_claims() {
38843897
check_added_monitors(&nodes[0], 1);
38853898

38863899
nodes[1].node.claim_funds(payment_preimage2);
3900+
check_added_monitors(&nodes[1], 1);
38873901
expect_payment_claimed!(&nodes[1], payment_hash2, 1_000_000);
38883902
check_added_monitors(&nodes[1], 1);
38893903

lightning/src/ln/reload_tests.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -853,16 +853,20 @@ fn do_test_partial_claim_before_restart(persist_both_monitors: bool, double_rest
853853
if persist_both_monitors {
854854
if let Event::ChannelClosed { reason: ClosureReason::OutdatedChannelManager, .. } = events[2] { } else { panic!(); }
855855
if let Event::PaymentClaimed { amount_msat: 15_000_000, .. } = events[3] { } else { panic!(); }
856-
check_added_monitors(&nodes[3], 4);
856+
// 4 monitors for preimage updates + 1 for InboundPaymentClaimed marking the payment as
857+
// claimed in the closed channel's monitor.
858+
check_added_monitors(&nodes[3], 5);
857859
} else {
858860
if let Event::PaymentClaimed { amount_msat: 15_000_000, .. } = events[2] { } else { panic!(); }
861+
// Only one channel closed; the durable_preimage_channel is the live one, so no extra
862+
// InboundPaymentClaimed update is generated.
859863
check_added_monitors(&nodes[3], 3);
860864
}
861865

862866
// Now that we've processed background events, the preimage should have been copied into the
863867
// non-persisted monitor:
864-
assert!(get_monitor!(nodes[3], chan_id_persisted).get_stored_preimages().contains_key(&payment_hash));
865-
assert!(get_monitor!(nodes[3], chan_id_not_persisted).get_stored_preimages().contains_key(&payment_hash));
868+
assert!(get_monitor!(nodes[3], chan_id_persisted).test_get_all_stored_preimages().contains_key(&payment_hash));
869+
assert!(get_monitor!(nodes[3], chan_id_not_persisted).test_get_all_stored_preimages().contains_key(&payment_hash));
866870

867871
// On restart, we should also get a duplicate PaymentClaimed event as we persisted the
868872
// ChannelManager prior to handling the original one.

0 commit comments

Comments
 (0)