Skip to content

Commit 2a22b3e

Browse files
Support persistent monitor events
Monitor events will keep being provided on restart to the ChannelManager until they are explicitly ACK'd. This new code will run randomly in tests, to ensure we still support the old paths. XXX
1 parent 7828343 commit 2a22b3e

File tree

5 files changed

+73
-5
lines changed

5 files changed

+73
-5
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,7 +2191,24 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
21912191

21922192
/// Removes a [`MonitorEvent`] by its event ID, acknowledging that it has been processed.
21932193
pub(super) fn ack_monitor_event(&self, event_id: u64) {
2194-
self.inner.lock().unwrap().pending_monitor_events.retain(|(id, _)| *id != event_id);
2194+
let inner = &mut *self.inner.lock().unwrap();
2195+
inner.pending_monitor_events.retain(|(id, _)| *id != event_id);
2196+
inner.provided_monitor_event_ids.remove(&event_id);
2197+
}
2198+
2199+
/// Enables persistent monitor events mode. When enabled, monitor events are retained until
2200+
/// explicitly acked rather than cleared on read.
2201+
pub(crate) fn set_persistent_events_enabled(&self, enabled: bool) {
2202+
self.inner.lock().unwrap().persistent_events_enabled = enabled;
2203+
}
2204+
2205+
/// Copies the in-memory `provided_monitor_event_ids` from `other` into `self`.
2206+
/// Used in tests to align transient runtime state before equality comparison after a
2207+
/// serialization round-trip.
2208+
#[cfg(any(test, feature = "_test_utils"))]
2209+
pub fn copy_provided_monitor_event_ids(&self, other: &ChannelMonitor<Signer>) {
2210+
let ids = other.inner.lock().unwrap().provided_monitor_event_ids.clone();
2211+
self.inner.lock().unwrap().provided_monitor_event_ids = ids;
21952212
}
21962213

21972214
/// Processes [`SpendableOutputs`] events produced from each [`ChannelMonitor`] upon maturity.
@@ -4418,9 +4435,22 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
44184435
}
44194436

44204437
fn get_and_clear_pending_monitor_events(&mut self) -> Vec<(u64, MonitorEvent)> {
4421-
let mut ret = Vec::new();
4422-
mem::swap(&mut ret, &mut self.pending_monitor_events);
4423-
ret
4438+
if self.persistent_events_enabled {
4439+
let ret: Vec<_> = self
4440+
.pending_monitor_events
4441+
.iter()
4442+
.filter(|(id, _)| !self.provided_monitor_event_ids.contains(id))
4443+
.cloned()
4444+
.collect();
4445+
for (id, _) in &ret {
4446+
self.provided_monitor_event_ids.insert(*id);
4447+
}
4448+
ret
4449+
} else {
4450+
let mut ret = Vec::new();
4451+
mem::swap(&mut ret, &mut self.pending_monitor_events);
4452+
ret
4453+
}
44244454
}
44254455

44264456
/// Gets the set of events that are repeated regularly (e.g. those which RBF bump

lightning/src/ln/channelmanager.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3630,6 +3630,8 @@ impl<
36303630
our_network_pubkey, current_timestamp, expanded_inbound_key,
36313631
node_signer.get_receive_auth_key(), secp_ctx.clone(), message_router, logger.clone(),
36323632
);
3633+
#[cfg(test)]
3634+
let override_persistent_monitor_events = config.override_persistent_monitor_events;
36333635

36343636
ChannelManager {
36353637
config: RwLock::new(config),
@@ -3686,7 +3688,27 @@ impl<
36863688

36873689
logger,
36883690

3689-
persistent_monitor_events: false,
3691+
persistent_monitor_events: {
3692+
#[cfg(not(test))]
3693+
{ false }
3694+
#[cfg(test)]
3695+
{
3696+
override_persistent_monitor_events.unwrap_or_else(|| {
3697+
use core::hash::{BuildHasher, Hasher};
3698+
match std::env::var("LDK_TEST_PERSISTENT_MON_EVENTS") {
3699+
Ok(val) => match val.as_str() {
3700+
"1" => true,
3701+
"0" => false,
3702+
_ => panic!("LDK_TEST_PERSISTENT_MON_EVENTS must be 0 or 1, got: {}", val),
3703+
},
3704+
Err(_) => {
3705+
let rand_val = std::collections::hash_map::RandomState::new().build_hasher().finish();
3706+
rand_val % 2 == 0
3707+
},
3708+
}
3709+
})
3710+
}
3711+
},
36903712

36913713
#[cfg(feature = "_test_utils")]
36923714
testing_dnssec_proof_offer_resolution_override: Mutex::new(new_hash_map()),
@@ -11570,6 +11592,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1157011592
fail_chan!("Already had channel with the new channel_id");
1157111593
},
1157211594
hash_map::Entry::Vacant(e) => {
11595+
monitor.set_persistent_events_enabled(self.persistent_monitor_events);
1157311596
let monitor_res = self.chain_monitor.watch_channel(monitor.channel_id(), monitor);
1157411597
if let Ok(persist_state) = monitor_res {
1157511598
// There's no problem signing a counterparty's funding transaction if our monitor
@@ -11740,6 +11763,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1174011763
match chan
1174111764
.funding_signed(&msg, best_block, &self.signer_provider, &self.logger)
1174211765
.and_then(|(funded_chan, monitor)| {
11766+
monitor.set_persistent_events_enabled(self.persistent_monitor_events);
1174311767
self.chain_monitor
1174411768
.watch_channel(funded_chan.context.channel_id(), monitor)
1174511769
.map_err(|()| {
@@ -12655,6 +12679,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1265512679

1265612680
if let Some(chan) = chan.as_funded_mut() {
1265712681
if let Some(monitor) = monitor_opt {
12682+
monitor.set_persistent_events_enabled(self.persistent_monitor_events);
1265812683
let monitor_res =
1265912684
self.chain_monitor.watch_channel(monitor.channel_id(), monitor);
1266012685
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
@@ -3591,6 +3591,9 @@ fn do_test_lost_timeout_monitor_events(confirm_tx: CommitmentType, dust_htlcs: b
35913591
let mut cfg = test_default_channel_config();
35923592
cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
35933593
cfg.channel_handshake_config.negotiate_anchor_zero_fee_commitments = p2a_anchor;
3594+
// This test specifically tests lost monitor events, which requires the legacy
3595+
// (non-persistent) monitor event behavior.
3596+
cfg.override_persistent_monitor_events = Some(false);
35943597
let cfgs = [Some(cfg.clone()), Some(cfg.clone()), Some(cfg.clone())];
35953598

35963599
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
}

lightning/src/util/test_utils.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ impl<'a> chain::Watch<TestChannelSigner> for TestChainMonitor<'a> {
606606
)
607607
.unwrap()
608608
.1;
609+
new_monitor.copy_provided_monitor_event_ids(&monitor);
609610
assert!(new_monitor == monitor);
610611
self.latest_monitor_update_id
611612
.lock()
@@ -662,6 +663,9 @@ impl<'a> chain::Watch<TestChannelSigner> for TestChainMonitor<'a> {
662663
)
663664
.unwrap()
664665
.1;
666+
// The deserialized monitor won't have provided_monitor_event_ids (it's in-memory only),
667+
// so copy it from the live monitor before comparing.
668+
new_monitor.copy_provided_monitor_event_ids(&monitor);
665669
if let Some(chan_id) = self.expect_monitor_round_trip_fail.lock().unwrap().take() {
666670
assert_eq!(chan_id, channel_id);
667671
assert!(new_monitor != *monitor);

0 commit comments

Comments
 (0)