Skip to content

Commit bbf1786

Browse files
Support persistent monitor events
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. Here we complete work that was built on recent prior commits and actually start re-providing monitor events on startup if they went un-acked during runtime. This isn't actually supported in prod yet, so this new code will run randomly in tests, to ensure we still support the old paths.
1 parent 20ebcd3 commit bbf1786

File tree

4 files changed

+74
-9
lines changed

4 files changed

+74
-9
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,11 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
12881288
// block/transaction-connected events and *not* during block/transaction-disconnected events,
12891289
// we further MUST NOT generate events during block/transaction-disconnection.
12901290
pending_monitor_events: Vec<(u64, MonitorEvent)>,
1291+
// `MonitorEvent`s that have been provided to the `ChannelManager` via
1292+
// [`ChannelMonitor::get_and_clear_pending_monitor_events`] and are awaiting
1293+
// [`ChannelMonitor::ack_monitor_event`] for removal. If an event in this queue is not ack'd, it
1294+
// will be re-provided to the `ChannelManager` on startup.
1295+
provided_monitor_events: Vec<(u64, MonitorEvent)>,
12911296
/// When set, monitor events are retained until explicitly acked rather than cleared on read.
12921297
///
12931298
/// Allows the ChannelManager to reconstruct pending HTLC state by replaying monitor events on
@@ -1765,7 +1770,12 @@ pub(crate) fn write_chanmon_internal<Signer: EcdsaChannelSigner, W: Writer>(
17651770
// Only write `persistent_events_enabled` if it's set to true, as it's an even TLV.
17661771
let persistent_events_enabled = channel_monitor.persistent_events_enabled.then_some(true);
17671772
let pending_mon_evs_with_ids = if persistent_events_enabled.is_some() {
1768-
Some(Iterable(channel_monitor.pending_monitor_events.iter()))
1773+
Some(Iterable(
1774+
channel_monitor
1775+
.provided_monitor_events
1776+
.iter()
1777+
.chain(channel_monitor.pending_monitor_events.iter()),
1778+
))
17691779
} else {
17701780
None
17711781
};
@@ -1978,6 +1988,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
19781988

19791989
payment_preimages: new_hash_map(),
19801990
pending_monitor_events: Vec::new(),
1991+
provided_monitor_events: Vec::new(),
19811992
persistent_events_enabled: false,
19821993
next_monitor_event_id: 0,
19831994
pending_events: Vec::new(),
@@ -2202,20 +2213,32 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
22022213
}
22032214

22042215
/// Removes a [`MonitorEvent`] by its event ID, acknowledging that it has been processed.
2205-
pub(super) fn ack_monitor_event(&self, _event_id: u64) {
2206-
// TODO: once events have ids, remove the corresponding event here
2216+
pub(super) fn ack_monitor_event(&self, event_id: u64) {
2217+
let inner = &mut *self.inner.lock().unwrap();
2218+
inner.provided_monitor_events.retain(|(id, _)| *id != event_id);
2219+
}
2220+
2221+
/// Enables persistent monitor events mode. When enabled, monitor events are retained until
2222+
/// explicitly acked rather than cleared on read.
2223+
pub(crate) fn set_persistent_events_enabled(&self, enabled: bool) {
2224+
self.inner.lock().unwrap().persistent_events_enabled = enabled;
22072225
}
22082226

22092227
/// Copies [`MonitorEvent`] state from `other` into `self`.
22102228
/// Used in tests to align transient runtime state before equality comparison after a
22112229
/// serialization round-trip.
22122230
#[cfg(any(test, feature = "_test_utils"))]
22132231
pub fn copy_monitor_event_state(&self, other: &ChannelMonitor<Signer>) {
2214-
let (pending, next_id) = {
2232+
let (provided, pending, next_id) = {
22152233
let other_inner = other.inner.lock().unwrap();
2216-
(other_inner.pending_monitor_events.clone(), other_inner.next_monitor_event_id)
2234+
(
2235+
other_inner.provided_monitor_events.clone(),
2236+
other_inner.pending_monitor_events.clone(),
2237+
other_inner.next_monitor_event_id,
2238+
)
22172239
};
22182240
let mut self_inner = self.inner.lock().unwrap();
2241+
self_inner.provided_monitor_events = provided;
22192242
self_inner.pending_monitor_events = pending;
22202243
self_inner.next_monitor_event_id = next_id;
22212244
}
@@ -4619,9 +4642,16 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
46194642
}
46204643

46214644
fn get_and_clear_pending_monitor_events(&mut self) -> Vec<(u64, MonitorEvent)> {
4622-
let mut ret = Vec::new();
4623-
mem::swap(&mut ret, &mut self.pending_monitor_events);
4624-
ret
4645+
if self.persistent_events_enabled {
4646+
let mut ret = Vec::new();
4647+
mem::swap(&mut ret, &mut self.pending_monitor_events);
4648+
self.provided_monitor_events.extend(ret.iter().cloned());
4649+
ret
4650+
} else {
4651+
let mut ret = Vec::new();
4652+
mem::swap(&mut ret, &mut self.pending_monitor_events);
4653+
ret
4654+
}
46254655
}
46264656

46274657
/// Gets the set of events that are repeated regularly (e.g. those which RBF bump
@@ -6971,6 +7001,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
69717001

69727002
payment_preimages,
69737003
pending_monitor_events,
7004+
provided_monitor_events: Vec::new(),
69747005
persistent_events_enabled,
69757006
next_monitor_event_id,
69767007
pending_events,

lightning/src/ln/channelmanager.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3641,6 +3641,8 @@ impl<
36413641
our_network_pubkey, current_timestamp, expanded_inbound_key,
36423642
node_signer.get_receive_auth_key(), secp_ctx.clone(), message_router, logger.clone(),
36433643
);
3644+
#[cfg(test)]
3645+
let override_persistent_monitor_events = config.override_persistent_monitor_events;
36443646

36453647
ChannelManager {
36463648
config: RwLock::new(config),
@@ -3697,7 +3699,27 @@ impl<
36973699

36983700
logger,
36993701

3700-
persistent_monitor_events: false,
3702+
persistent_monitor_events: {
3703+
#[cfg(not(test))]
3704+
{ false }
3705+
#[cfg(test)]
3706+
{
3707+
override_persistent_monitor_events.unwrap_or_else(|| {
3708+
use core::hash::{BuildHasher, Hasher};
3709+
match std::env::var("LDK_TEST_PERSISTENT_MON_EVENTS") {
3710+
Ok(val) => match val.as_str() {
3711+
"1" => true,
3712+
"0" => false,
3713+
_ => panic!("LDK_TEST_PERSISTENT_MON_EVENTS must be 0 or 1, got: {}", val),
3714+
},
3715+
Err(_) => {
3716+
let rand_val = std::collections::hash_map::RandomState::new().build_hasher().finish();
3717+
rand_val % 2 == 0
3718+
},
3719+
}
3720+
})
3721+
}
3722+
},
37013723

37023724
#[cfg(feature = "_test_utils")]
37033725
testing_dnssec_proof_offer_resolution_override: Mutex::new(new_hash_map()),
@@ -11718,6 +11740,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1171811740
fail_chan!("Already had channel with the new channel_id");
1171911741
},
1172011742
hash_map::Entry::Vacant(e) => {
11743+
monitor.set_persistent_events_enabled(self.persistent_monitor_events);
1172111744
let monitor_res = self.chain_monitor.watch_channel(monitor.channel_id(), monitor);
1172211745
if let Ok(persist_state) = monitor_res {
1172311746
// There's no problem signing a counterparty's funding transaction if our monitor
@@ -11888,6 +11911,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1188811911
match chan
1188911912
.funding_signed(&msg, best_block, &self.signer_provider, &self.logger)
1189011913
.and_then(|(funded_chan, monitor)| {
11914+
monitor.set_persistent_events_enabled(self.persistent_monitor_events);
1189111915
self.chain_monitor
1189211916
.watch_channel(funded_chan.context.channel_id(), monitor)
1189311917
.map_err(|()| {
@@ -12803,6 +12827,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1280312827

1280412828
if let Some(chan) = chan.as_funded_mut() {
1280512829
if let Some(monitor) = monitor_opt {
12830+
monitor.set_persistent_events_enabled(self.persistent_monitor_events);
1280612831
let monitor_res =
1280712832
self.chain_monitor.watch_channel(monitor.channel_id(), monitor);
1280812833
if let Ok(persist_state) = monitor_res {

lightning/src/ln/monitor_tests.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3592,6 +3592,9 @@ fn do_test_lost_timeout_monitor_events(confirm_tx: CommitmentType, dust_htlcs: b
35923592
let mut cfg = test_default_channel_config();
35933593
cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
35943594
cfg.channel_handshake_config.negotiate_anchor_zero_fee_commitments = p2a_anchor;
3595+
// This test specifically tests lost monitor events, which requires the legacy
3596+
// (non-persistent) monitor event behavior.
3597+
cfg.override_persistent_monitor_events = Some(false);
35953598
let cfgs = [Some(cfg.clone()), Some(cfg.clone()), Some(cfg.clone())];
35963599

35973600
let chanmon_cfgs = create_chanmon_cfgs(3);

lightning/src/util/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,10 @@ pub struct UserConfig {
11031103
///
11041104
/// [`ChannelManager::splice_channel`]: crate::ln::channelmanager::ChannelManager::splice_channel
11051105
pub reject_inbound_splices: bool,
1106+
/// If set to `Some`, overrides the random selection of whether to use persistent monitor
1107+
/// events. Only available in tests.
1108+
#[cfg(test)]
1109+
pub override_persistent_monitor_events: Option<bool>,
11061110
}
11071111

11081112
impl Default for UserConfig {
@@ -1119,6 +1123,8 @@ impl Default for UserConfig {
11191123
enable_htlc_hold: false,
11201124
hold_outbound_htlcs_at_next_hop: false,
11211125
reject_inbound_splices: true,
1126+
#[cfg(test)]
1127+
override_persistent_monitor_events: None,
11221128
}
11231129
}
11241130
}

0 commit comments

Comments
 (0)