Skip to content

Commit b962285

Browse files
Add chain::Watch ack_monitor_event API
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 simplify things - on restart instead of examining the set of HTLCs in monitors we can simply replay all the pending MonitorEvents. Here we add an as-yet-unused API to chain::Watch to allow the ChannelManager to tell the a ChannelMonitor that a MonitorEvent has been irrevocably processed and can be deleted.
1 parent 1338cb8 commit b962285

4 files changed

Lines changed: 49 additions & 1 deletion

File tree

lightning/src/chain/chainmonitor.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,21 @@ use core::iter::Cycle;
6666
use core::ops::Deref;
6767
use core::sync::atomic::{AtomicUsize, Ordering};
6868

69+
/// Identifies the source of a [`MonitorEvent`] for acknowledgment via
70+
/// [`chain::Watch::ack_monitor_event`] once the event has been processed.
71+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72+
pub struct MonitorEventSource {
73+
/// The event ID assigned by the [`ChannelMonitor`].
74+
pub event_id: u64,
75+
/// The channel from which the [`MonitorEvent`] originated.
76+
pub channel_id: ChannelId,
77+
}
78+
79+
impl_writeable_tlv_based!(MonitorEventSource, {
80+
(1, event_id, required),
81+
(3, channel_id, required),
82+
});
83+
6984
/// A pending operation queued for later execution when `ChainMonitor` is in deferred mode.
7085
enum PendingMonitorOp<ChannelSigner: EcdsaChannelSigner> {
7186
/// A new monitor to insert and persist.
@@ -1646,6 +1661,15 @@ where
16461661
}
16471662
pending_monitor_events
16481663
}
1664+
1665+
fn ack_monitor_event(&self, source: MonitorEventSource) {
1666+
let monitors = self.monitors.read().unwrap();
1667+
if let Some(monitor_state) = monitors.get(&source.channel_id) {
1668+
monitor_state.monitor.ack_monitor_event(source.event_id);
1669+
} else {
1670+
debug_assert!(false, "Ack'd monitor events should always have a corresponding monitor");
1671+
}
1672+
}
16491673
}
16501674

16511675
impl<

lightning/src/chain/channelmonitor.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2190,6 +2190,12 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
21902190
self.inner.lock().unwrap().push_monitor_event(event);
21912191
}
21922192

2193+
/// Removes a [`MonitorEvent`] by its event ID, acknowledging that it has been processed.
2194+
/// Generally called by [`chain::Watch::ack_monitor_event`].
2195+
pub fn ack_monitor_event(&self, _event_id: u64) {
2196+
// TODO: once events have ids, remove the corresponding event here
2197+
}
2198+
21932199
/// Processes [`SpendableOutputs`] events produced from each [`ChannelMonitor`] upon maturity.
21942200
///
21952201
/// For channels featuring anchor outputs, this method will also process [`BumpTransaction`]

lightning/src/chain/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use bitcoin::network::Network;
1818
use bitcoin::script::{Script, ScriptBuf};
1919
use bitcoin::secp256k1::PublicKey;
2020

21+
use crate::chain::chainmonitor::MonitorEventSource;
2122
use crate::chain::channelmonitor::{
2223
ChannelMonitor, ChannelMonitorUpdate, MonitorEvent, ANTI_REORG_DELAY,
2324
};
@@ -427,6 +428,15 @@ pub trait Watch<ChannelSigner: EcdsaChannelSigner> {
427428
fn release_pending_monitor_events(
428429
&self,
429430
) -> Vec<(OutPoint, ChannelId, Vec<MonitorEvent>, PublicKey)>;
431+
432+
/// Acknowledges and removes a [`MonitorEvent`] previously returned by
433+
/// [`Watch::release_pending_monitor_events`] by its event ID.
434+
///
435+
/// Once acknowledged, the event will no longer be returned by future calls to
436+
/// [`Watch::release_pending_monitor_events`] and will not be replayed on restart.
437+
///
438+
/// Events may be acknowledged in any order.
439+
fn ack_monitor_event(&self, source: MonitorEventSource);
430440
}
431441

432442
impl<ChannelSigner: EcdsaChannelSigner, T: Watch<ChannelSigner> + ?Sized, W: Deref<Target = T>>
@@ -449,6 +459,10 @@ impl<ChannelSigner: EcdsaChannelSigner, T: Watch<ChannelSigner> + ?Sized, W: Der
449459
) -> Vec<(OutPoint, ChannelId, Vec<MonitorEvent>, PublicKey)> {
450460
self.deref().release_pending_monitor_events()
451461
}
462+
463+
fn ack_monitor_event(&self, source: MonitorEventSource) {
464+
self.deref().ack_monitor_event(source)
465+
}
452466
}
453467

454468
/// The `Filter` trait defines behavior for indicating chain activity of interest pertaining to

lightning/src/util/test_utils.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::chain::chaininterface;
1717
#[cfg(any(test, feature = "_externalize_tests"))]
1818
use crate::chain::chaininterface::FEERATE_FLOOR_SATS_PER_KW;
1919
use crate::chain::chaininterface::{ConfirmationTarget, TransactionType};
20-
use crate::chain::chainmonitor::{ChainMonitor, Persist};
20+
use crate::chain::chainmonitor::{ChainMonitor, MonitorEventSource, Persist};
2121
use crate::chain::channelmonitor::{
2222
ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, MonitorEvent,
2323
};
@@ -750,6 +750,10 @@ impl<'a> chain::Watch<TestChannelSigner> for TestChainMonitor<'a> {
750750
}
751751
return self.chain_monitor.release_pending_monitor_events();
752752
}
753+
754+
fn ack_monitor_event(&self, source: MonitorEventSource) {
755+
self.chain_monitor.ack_monitor_event(source);
756+
}
753757
}
754758

755759
#[cfg(any(test, feature = "_externalize_tests"))]

0 commit comments

Comments
 (0)