Skip to content

Commit f76f166

Browse files
Add persistent_monitor_events flag to monitors/manager
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. As a first step towards this, here we persist a flag in the ChannelManager and ChannelMonitors indicating whether this new feature is enabled. It will be used in upcoming commits to maintain compatibility and create an upgrade/downgrade path between LDK versions.
1 parent 8f12703 commit f76f166

2 files changed

Lines changed: 48 additions & 0 deletions

File tree

lightning/src/chain/channelmonitor.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,12 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
12811281
// block/transaction-connected events and *not* during block/transaction-disconnected events,
12821282
// we further MUST NOT generate events during block/transaction-disconnection.
12831283
pending_monitor_events: Vec<MonitorEvent>,
1284+
/// When set, monitor events are retained until explicitly acked rather than cleared on read.
1285+
///
1286+
/// Allows the ChannelManager to reconstruct pending HTLC state by replaying monitor events on
1287+
/// startup, and make the monitor responsible for both off- and on-chain payment resolution. Will
1288+
/// be always set once support for this feature is complete.
1289+
persistent_events_enabled: bool,
12841290

12851291
pub(super) pending_events: Vec<Event>,
12861292
pub(super) is_processing_pending_events: bool,
@@ -1732,8 +1738,12 @@ pub(crate) fn write_chanmon_internal<Signer: EcdsaChannelSigner, W: Writer>(
17321738
channel_monitor.pending_monitor_events.iter().chain(holder_force_closed_compat.as_ref()),
17331739
);
17341740

1741+
// Only write `persistent_events_enabled` if it's set to true, as it's an even TLV.
1742+
let persistent_events_enabled = channel_monitor.persistent_events_enabled.then_some(());
1743+
17351744
write_tlv_fields!(writer, {
17361745
(1, channel_monitor.funding_spend_confirmed, option),
1746+
(2, persistent_events_enabled, option),
17371747
(3, channel_monitor.htlcs_resolved_on_chain, required_vec),
17381748
(5, pending_monitor_events, required), // Equivalent to required_vec because Iterable also writes as WithoutLength
17391749
(7, channel_monitor.funding_spend_seen, required),
@@ -1938,6 +1948,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
19381948

19391949
payment_preimages: new_hash_map(),
19401950
pending_monitor_events: Vec::new(),
1951+
persistent_events_enabled: false,
19411952
pending_events: Vec::new(),
19421953
is_processing_pending_events: false,
19431954

@@ -6695,8 +6706,10 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
66956706
let mut is_manual_broadcast = RequiredWrapper(None);
66966707
let mut funding_seen_onchain = RequiredWrapper(None);
66976708
let mut best_block_previous_blocks = None;
6709+
let mut persistent_events_enabled: Option<()> = None;
66986710
read_tlv_fields!(reader, {
66996711
(1, funding_spend_confirmed, option),
6712+
(2, persistent_events_enabled, option),
67006713
(3, htlcs_resolved_on_chain, optional_vec),
67016714
(5, pending_monitor_events, optional_vec),
67026715
(7, funding_spend_seen, option),
@@ -6723,6 +6736,12 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
67236736
best_block.previous_blocks = previous_blocks;
67246737
}
67256738

6739+
#[cfg(not(any(feature = "_test_utils", test)))]
6740+
if persistent_events_enabled.is_some() {
6741+
// This feature isn't supported yet so error if the writer expected it to be.
6742+
return Err(DecodeError::InvalidValue)
6743+
}
6744+
67266745
// Note that `payment_preimages_with_info` was added (and is always written) in LDK 0.1, so
67276746
// we can use it to determine if this monitor was last written by LDK 0.1 or later.
67286747
let written_by_0_1_or_later = payment_preimages_with_info.is_some();
@@ -6871,6 +6890,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
68716890

68726891
payment_preimages,
68736892
pending_monitor_events: pending_monitor_events.unwrap(),
6893+
persistent_events_enabled: persistent_events_enabled.is_some(),
68746894
pending_events,
68756895
is_processing_pending_events: false,
68766896

lightning/src/ln/channelmanager.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2928,6 +2928,15 @@ pub struct ChannelManager<
29282928
/// [`ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee`] estimate.
29292929
last_days_feerates: Mutex<VecDeque<(u32, u32)>>,
29302930

2931+
/// When set, monitors will repeatedly provide an event back to the `ChannelManager` on restart
2932+
/// until the event is explicitly acknowledged as processed.
2933+
///
2934+
/// Allows us to reconstruct pending HTLC state by replaying monitor events on startup, rather
2935+
/// than from complexly polling and reconciling Channel{Monitor} APIs, as well as move the
2936+
/// responsibility of off-chain payment resolution from the Channel to the monitor. Will be
2937+
/// always set once support is complete.
2938+
persistent_monitor_events: bool,
2939+
29312940
#[cfg(test)]
29322941
pub(super) entropy_source: ES,
29332942
#[cfg(not(test))]
@@ -3658,6 +3667,8 @@ impl<
36583667
signer_provider,
36593668

36603669
logger,
3670+
3671+
persistent_monitor_events: false,
36613672
}
36623673
}
36633674

@@ -18102,6 +18113,9 @@ impl<
1810218113
}
1810318114
}
1810418115

18116+
// Only write `persistent_events_enabled` if it's set to true, as it's an even TLV.
18117+
let persistent_monitor_events = self.persistent_monitor_events.then_some(());
18118+
1810518119
write_tlv_fields!(writer, {
1810618120
(1, pending_outbound_payments_no_retry, required),
1810718121
(2, pending_intercepted_htlcs, option),
@@ -18114,6 +18128,7 @@ impl<
1811418128
(9, htlc_purposes, required_vec),
1811518129
(10, legacy_in_flight_monitor_updates, option),
1811618130
(11, self.probing_cookie_secret, required),
18131+
(12, persistent_monitor_events, option),
1811718132
(13, htlc_onion_fields, optional_vec),
1811818133
(14, decode_update_add_htlcs_opt, option),
1811918134
(15, self.inbound_payment_id_secret, required),
@@ -18213,6 +18228,7 @@ pub(super) struct ChannelManagerData<SP: SignerProvider> {
1821318228
forward_htlcs_legacy: HashMap<u64, Vec<HTLCForwardInfo>>,
1821418229
pending_intercepted_htlcs_legacy: HashMap<InterceptId, PendingAddHTLCInfo>,
1821518230
decode_update_add_htlcs_legacy: HashMap<u64, Vec<msgs::UpdateAddHTLC>>,
18231+
persistent_monitor_events: bool,
1821618232
// The `ChannelManager` version that was written.
1821718233
version: u8,
1821818234
}
@@ -18399,6 +18415,7 @@ impl<'a, ES: EntropySource, SP: SignerProvider, L: Logger>
1839918415
let mut peer_storage_dir: Option<Vec<(PublicKey, Vec<u8>)>> = None;
1840018416
let mut async_receive_offer_cache: AsyncReceiveOfferCache = AsyncReceiveOfferCache::new();
1840118417
let mut best_block_previous_blocks = None;
18418+
let mut persistent_monitor_events: Option<()> = None;
1840218419
read_tlv_fields!(reader, {
1840318420
(1, pending_outbound_payments_no_retry, option),
1840418421
(2, pending_intercepted_htlcs_legacy, option),
@@ -18411,6 +18428,7 @@ impl<'a, ES: EntropySource, SP: SignerProvider, L: Logger>
1841118428
(9, claimable_htlc_purposes, optional_vec),
1841218429
(10, legacy_in_flight_monitor_updates, option),
1841318430
(11, probing_cookie_secret, option),
18431+
(12, persistent_monitor_events, option),
1841418432
(13, amountless_claimable_htlc_onion_fields, optional_vec),
1841518433
(14, decode_update_add_htlcs_legacy, option),
1841618434
(15, inbound_payment_id_secret, option),
@@ -18420,6 +18438,12 @@ impl<'a, ES: EntropySource, SP: SignerProvider, L: Logger>
1842018438
(23, best_block_previous_blocks, option),
1842118439
});
1842218440

18441+
#[cfg(not(any(feature = "_test_utils", test)))]
18442+
if persistent_monitor_events.is_some() {
18443+
// This feature isn't supported yet so error if the writer expected it to be.
18444+
return Err(DecodeError::InvalidValue);
18445+
}
18446+
1842318447
// Merge legacy pending_outbound_payments fields into a single HashMap.
1842418448
// Priority: pending_outbound_payments (TLV 3) > pending_outbound_payments_no_retry (TLV 1)
1842518449
// > pending_outbound_payments_compat (non-TLV legacy)
@@ -18539,6 +18563,7 @@ impl<'a, ES: EntropySource, SP: SignerProvider, L: Logger>
1853918563
peer_storage_dir: peer_storage_dir.unwrap_or_default(),
1854018564
async_receive_offer_cache,
1854118565
version,
18566+
persistent_monitor_events: persistent_monitor_events.is_some(),
1854218567
})
1854318568
}
1854418569
}
@@ -18839,6 +18864,7 @@ impl<
1883918864
mut in_flight_monitor_updates,
1884018865
peer_storage_dir,
1884118866
async_receive_offer_cache,
18867+
persistent_monitor_events,
1884218868
version: _version,
1884318869
} = data;
1884418870

@@ -20100,6 +20126,8 @@ impl<
2010020126

2010120127
logger: args.logger,
2010220128
config: RwLock::new(args.config),
20129+
20130+
persistent_monitor_events,
2010320131
};
2010420132

2010520133
let mut processed_claims: HashSet<Vec<MPPClaimHTLCSource>> = new_hash_set();

0 commit comments

Comments
 (0)