Skip to content

Commit c261d96

Browse files
Persistent monitor events for onchain outbound claims
Currently, the resolution of HTLCs (and decisions on when HTLCs can be forwarded) is the responsibility of Channel objects (a part of ChannelManager) until the channel is closed, and then the ChannelMonitor thereafter. This leads to some complexity around race conditions for HTLCs right around channel closure. Additionally, there is lots of complexity reconstructing the state of all HTLCs in the ChannelManager deserialization/loading logic. Instead, we want to do all resolution in ChannelMonitors (in response to ChannelMonitorUpdates) and pass them back to ChannelManager in the form of MonitorEvents (similar to how HTLCs are resolved after channels are closed). In order to have reliable resolution, we'll need to keep MonitorEvents around in the ChannelMonitor until the ChannelManager has finished processing them. This will simplify things - on restart instead of examining the set of HTLCs in monitors we can simply replay all the pending MonitorEvents. In recent work, we added support for keeping monitor events around until they are explicitly acked by the ChannelManager, but would always ack monitor events immediately, which preserved the previous behavior and didn't break any tests. Here we start acking monitor events for on-chain HTLC claims when the user processes the PaymentSent event, if the persistent_monitor_events feature is enabled. This allows us to stop issuing ReleasePaymentComplete monitor updates for onchain payment claims, because the purpose of that behavior is to ensure we won't keep repeatedly issuing PaymentSent events, and the monitor event and acking it on PaymentSent processing now serves that purpose instead.
1 parent cca3259 commit c261d96

7 files changed

Lines changed: 71 additions & 46 deletions

File tree

lightning/src/ln/chanmon_update_fail_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3954,7 +3954,7 @@ fn do_test_durable_preimages_on_closed_channel(
39543954

39553955
mine_transactions(&nodes[0], &[&as_closing_tx[0], bs_preimage_tx]);
39563956
check_closed_broadcast(&nodes[0], 1, false);
3957-
expect_payment_sent(&nodes[0], payment_preimage, None, true, true);
3957+
expect_payment_sent!(&nodes[0], payment_preimage);
39583958

39593959
if close_chans_before_reload && !hold_post_reload_mon_update {
39603960
// For close_chans_before_reload with hold=false, the deferred completions

lightning/src/ln/channelmanager.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10026,7 +10026,11 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1002610026
"We don't support claim_htlc claims during startup - monitors may not be available yet");
1002710027
debug_assert_eq!(next_channel_counterparty_node_id, path.hops[0].pubkey);
1002810028

10029-
let mut ev_completion_action = if from_onchain {
10029+
let mut ev_completion_action = if self.persistent_monitor_events {
10030+
monitor_event_id.map(|event_id| EventCompletionAction::AckMonitorEvent {
10031+
event_id: MonitorEventSource { channel_id: next_channel_id, event_id },
10032+
})
10033+
} else if from_onchain {
1003010034
let release = PaymentCompleteUpdate {
1003110035
counterparty_node_id: next_channel_counterparty_node_id,
1003210036
channel_funding_outpoint: next_channel_outpoint,
@@ -10035,17 +10039,11 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1003510039
};
1003610040
Some(EventCompletionAction::ReleasePaymentCompleteChannelMonitorUpdate(release))
1003710041
} else {
10038-
if self.persistent_monitor_events {
10039-
monitor_event_id.map(|event_id| EventCompletionAction::AckMonitorEvent {
10040-
event_id: MonitorEventSource { channel_id: next_channel_id, event_id },
10041-
})
10042-
} else {
10043-
Some(EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
10044-
channel_funding_outpoint: Some(next_channel_outpoint),
10045-
channel_id: next_channel_id,
10046-
counterparty_node_id: path.hops[0].pubkey,
10047-
})
10048-
}
10042+
Some(EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
10043+
channel_funding_outpoint: Some(next_channel_outpoint),
10044+
channel_id: next_channel_id,
10045+
counterparty_node_id: path.hops[0].pubkey,
10046+
})
1004910047
};
1005010048
let logger = WithContext::for_payment(
1005110049
&self.logger,
@@ -13651,7 +13649,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1365113649
Some(event_id),
1365213650
);
1365313651
}
13654-
if from_onchain | !we_are_sender {
13652+
if !we_are_sender {
1365513653
self.chain_monitor.ack_monitor_event(monitor_event_source);
1365613654
}
1365713655
} else {
@@ -19858,6 +19856,12 @@ impl<
1985819856
..
1985919857
} => {
1986019858
if let Some(preimage) = preimage_opt {
19859+
if persistent_monitor_events {
19860+
// If persistent_monitor_events is enabled, then the monitor will keep
19861+
// providing us with a monitor event for this claim until the ChannelManager
19862+
// explicitly marks it as resolved, no need to explicitly handle it here.
19863+
continue;
19864+
}
1986119865
let pending_events = Mutex::new(pending_events_read);
1986219866
let update = PaymentCompleteUpdate {
1986319867
counterparty_node_id: monitor.get_counterparty_node_id(),

lightning/src/ln/functional_tests.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1629,7 +1629,10 @@ pub fn test_htlc_on_chain_success() {
16291629
check_closed_broadcast(&nodes[0], 1, true);
16301630
check_added_monitors(&nodes[0], 1);
16311631
let events = nodes[0].node.get_and_clear_pending_events();
1632-
check_added_monitors(&nodes[0], 2);
1632+
check_added_monitors(
1633+
&nodes[0],
1634+
if nodes[0].node.test_persistent_monitor_events_enabled() { 0 } else { 2 },
1635+
);
16331636
assert_eq!(events.len(), 5);
16341637
let mut first_claimed = false;
16351638
for event in events {

lightning/src/ln/monitor_tests.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ fn archive_fully_resolved_monitors() {
274274

275275
// Finally, we process the pending `MonitorEvent` from nodes[0], allowing the `ChannelMonitor`
276276
// to be archived `ARCHIVAL_DELAY_BLOCKS` blocks later.
277-
expect_payment_sent(&nodes[0], payment_preimage, None, true, true);
277+
expect_payment_sent!(&nodes[0], payment_preimage);
278278
nodes[0].chain_monitor.chain_monitor.archive_fully_resolved_channel_monitors();
279279
assert_eq!(nodes[0].chain_monitor.chain_monitor.list_monitors().len(), 1);
280280
connect_blocks(&nodes[0], ARCHIVAL_DELAY_BLOCKS - 1);
@@ -747,9 +747,9 @@ fn do_test_claim_value_force_close(keyed_anchors: bool, p2a_anchor: bool, prev_c
747747
mine_transaction(&nodes[0], &b_broadcast_txn[0]);
748748
if prev_commitment_tx {
749749
expect_payment_path_successful!(nodes[0]);
750-
check_added_monitors(&nodes[0], 1);
750+
check_added_monitors(&nodes[0], if nodes[0].node.test_persistent_monitor_events_enabled() { 0 } else { 1 });
751751
} else {
752-
expect_payment_sent(&nodes[0], payment_preimage, None, true, true);
752+
expect_payment_sent!(&nodes[0], payment_preimage);
753753
}
754754
assert_eq!(sorted_vec(vec![sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]),
755755
sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(chan_id).unwrap().get_claimable_balances()));
@@ -1015,7 +1015,7 @@ fn do_test_balances_on_local_commitment_htlcs(keyed_anchors: bool, p2a_anchor: b
10151015
// Now confirm nodes[1]'s HTLC claim, giving nodes[0] the preimage. Note that the "maybe
10161016
// claimable" balance remains until we see ANTI_REORG_DELAY blocks.
10171017
mine_transaction(&nodes[0], &bs_htlc_claim_txn[0]);
1018-
expect_payment_sent(&nodes[0], payment_preimage_2, None, true, true);
1018+
expect_payment_sent!(&nodes[0], payment_preimage_2);
10191019
assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
10201020
amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value,
10211021
confirmation_height: node_a_commitment_claimable,
@@ -2097,7 +2097,7 @@ fn do_test_revoked_counterparty_aggregated_claims(keyed_anchors: bool, p2a_ancho
20972097
as_revoked_txn[1].clone()
20982098
};
20992099
mine_transaction(&nodes[1], &htlc_success_claim);
2100-
expect_payment_sent(&nodes[1], claimed_payment_preimage, None, true, true);
2100+
expect_payment_sent!(&nodes[1], claimed_payment_preimage);
21012101

21022102
let mut claim_txn_2 = nodes[1].tx_broadcaster.txn_broadcast();
21032103
// Once B sees the HTLC-Success transaction it splits its claim transaction into two, though in
@@ -3545,9 +3545,13 @@ fn do_test_lost_preimage_monitor_events(on_counterparty_tx: bool, p2a_anchor: bo
35453545
// After the background events are processed in `get_and_clear_pending_events`, above, node B
35463546
// will create the requisite `ChannelMontiorUpdate` for claiming the forwarded payment back.
35473547
// The HTLC, however, is added to the holding cell for replay after the peer connects, below.
3548-
// It will also apply a `ChannelMonitorUpdate` to let the `ChannelMonitor` know that the
3549-
// payment can now be forgotten as the `PaymentSent` event was handled.
3550-
check_added_monitors(&nodes[1], 2);
3548+
if nodes[1].node.test_persistent_monitor_events_enabled() {
3549+
check_added_monitors(&nodes[1], 1);
3550+
} else {
3551+
// It will also apply a `ChannelMonitorUpdate` to let the `ChannelMonitor` know that the
3552+
// payment can now be forgotten as the `PaymentSent` event was handled.
3553+
check_added_monitors(&nodes[1], 2);
3554+
}
35513555

35523556
nodes[0].node.peer_disconnected(nodes[1].node.get_our_node_id());
35533557

@@ -3941,8 +3945,7 @@ fn test_ladder_preimage_htlc_claims() {
39413945
connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
39423946
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
39433947

3944-
expect_payment_sent(&nodes[0], payment_preimage1, None, true, false);
3945-
check_added_monitors(&nodes[0], 1);
3948+
expect_payment_sent!(&nodes[0], payment_preimage1);
39463949

39473950
nodes[1].node.claim_funds(payment_preimage2);
39483951
expect_payment_claimed!(&nodes[1], payment_hash2, 1_000_000);
@@ -3964,6 +3967,5 @@ fn test_ladder_preimage_htlc_claims() {
39643967
connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
39653968
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
39663969

3967-
expect_payment_sent(&nodes[0], payment_preimage2, None, true, false);
3968-
check_added_monitors(&nodes[0], 1);
3970+
expect_payment_sent!(&nodes[0], payment_preimage2);
39693971
}

lightning/src/ln/payment_tests.rs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
950950
assert_eq!(txn[0].compute_txid(), as_commitment_tx.compute_txid());
951951
}
952952
mine_transaction(&nodes[0], &bs_htlc_claim_txn);
953-
expect_payment_sent(&nodes[0], payment_preimage_1, None, true, true);
953+
expect_payment_sent!(&nodes[0], payment_preimage_1);
954954
connect_blocks(&nodes[0], TEST_FINAL_CLTV * 4 + 20);
955955
let (first_htlc_timeout_tx, second_htlc_timeout_tx) = {
956956
let mut txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
@@ -1361,7 +1361,7 @@ fn do_test_dup_htlc_onchain_doesnt_fail_on_reload(
13611361
let conditions = PaymentFailedConditions::new().from_mon_update();
13621362
expect_payment_failed_conditions(&nodes[0], payment_hash, false, conditions);
13631363
} else {
1364-
expect_payment_sent(&nodes[0], payment_preimage, None, true, true);
1364+
expect_payment_sent!(&nodes[0], payment_preimage);
13651365
}
13661366
// Note that if we persist the monitor before processing the events, above, we'll always get
13671367
// them replayed on restart no matter what
@@ -1399,18 +1399,22 @@ fn do_test_dup_htlc_onchain_doesnt_fail_on_reload(
13991399
} else {
14001400
expect_payment_sent(&nodes[0], payment_preimage, None, true, false);
14011401
}
1402-
if persist_manager_post_event {
1403-
// After reload, the ChannelManager identified the failed payment and queued up the
1404-
// PaymentSent (or not, if `persist_manager_post_event` resulted in us detecting we
1405-
// already did that) and corresponding ChannelMonitorUpdate to mark the payment
1406-
// handled, but while processing the pending `MonitorEvent`s (which were not processed
1407-
// before the monitor was persisted) we will end up with a duplicate
1408-
// ChannelMonitorUpdate.
1409-
check_added_monitors(&nodes[0], 2);
1402+
if !nodes[0].node.test_persistent_monitor_events_enabled() {
1403+
if persist_manager_post_event {
1404+
// After reload, the ChannelManager identified the failed payment and queued up the
1405+
// PaymentSent (or not, if `persist_manager_post_event` resulted in us detecting we
1406+
// already did that) and corresponding ChannelMonitorUpdate to mark the payment
1407+
// handled, but while processing the pending `MonitorEvent`s (which were not processed
1408+
// before the monitor was persisted) we will end up with a duplicate
1409+
// ChannelMonitorUpdate.
1410+
check_added_monitors(&nodes[0], 2);
1411+
} else {
1412+
// ...unless we got the PaymentSent event, in which case we have de-duplication logic
1413+
// preventing a redundant monitor event.
1414+
check_added_monitors(&nodes[0], 1);
1415+
}
14101416
} else {
1411-
// ...unless we got the PaymentSent event, in which case we have de-duplication logic
1412-
// preventing a redundant monitor event.
1413-
check_added_monitors(&nodes[0], 1);
1417+
check_added_monitors(&nodes[0], 0);
14141418
}
14151419
}
14161420

@@ -4177,10 +4181,14 @@ fn do_no_missing_sent_on_reload(persist_manager_with_payment: bool, at_midpoint:
41774181
check_added_monitors(&nodes[0], 0);
41784182
nodes[0].node.test_process_background_events();
41794183
check_added_monitors(&nodes[0], 1);
4180-
// Then once we process the PaymentSent event we'll apply a monitor update to remove the
4181-
// pending payment from being re-hydrated on the next startup.
41824184
let events = nodes[0].node.get_and_clear_pending_events();
4183-
check_added_monitors(&nodes[0], 1);
4185+
if nodes[0].node.test_persistent_monitor_events_enabled() {
4186+
check_added_monitors(&nodes[0], 0);
4187+
} else {
4188+
// Once we process the PaymentSent event we'll apply a monitor update to remove the
4189+
// pending payment from being re-hydrated on the next startup.
4190+
check_added_monitors(&nodes[0], 1);
4191+
}
41844192
assert_eq!(events.len(), 3, "{events:?}");
41854193
if let Event::ChannelClosed { reason: ClosureReason::OutdatedChannelManager, .. } = events[0] {
41864194
} else {

lightning/src/ln/reorg_tests.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ fn test_counterparty_revoked_reorg() {
254254

255255
// Connect the HTLC claim transaction for HTLC 3
256256
mine_transaction(&nodes[1], &unrevoked_local_txn[2]);
257-
expect_payment_sent(&nodes[1], payment_preimage_3, None, true, true);
257+
expect_payment_sent!(&nodes[1], payment_preimage_3);
258258
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
259259

260260
// Connect blocks to confirm the unrevoked commitment transaction
@@ -1228,7 +1228,10 @@ fn do_test_split_htlc_expiry_tracking(use_third_htlc: bool, reorg_out: bool, p2a
12281228

12291229
check_added_monitors(&nodes[0], 0);
12301230
let sent_events = nodes[0].node.get_and_clear_pending_events();
1231-
check_added_monitors(&nodes[0], 2);
1231+
check_added_monitors(
1232+
&nodes[0],
1233+
if nodes[0].node.test_persistent_monitor_events_enabled() { 0 } else { 2 },
1234+
);
12321235
assert_eq!(sent_events.len(), 4, "{sent_events:?}");
12331236
let mut found_expected_events = [false, false, false, false];
12341237
for event in sent_events {

lightning/src/ln/splicing_tests.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1981,7 +1981,12 @@ fn do_test_splice_commitment_broadcast(splice_status: SpliceStatus, claim_htlcs:
19811981
2
19821982
);
19831983
}
1984-
check_added_monitors(&nodes[0], 2); // Two `ReleasePaymentComplete` monitor updates
1984+
let expected_mons = if nodes[0].node.test_persistent_monitor_events_enabled() && claim_htlcs {
1985+
0
1986+
} else {
1987+
2 // Two `ReleasePaymentComplete` monitor updates
1988+
};
1989+
check_added_monitors(&nodes[0], expected_mons);
19851990

19861991
// When the splice never confirms and we see a commitment transaction broadcast and confirm for
19871992
// the current funding instead, we should expect to see an `Event::DiscardFunding` for the

0 commit comments

Comments
 (0)