Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
09fa534
Split up some tests that have many variants
valentinewallace Mar 17, 2026
7ff95bd
Remove unnecessary pending_monitor_events clone
valentinewallace Mar 19, 2026
df348e2
Add persistent_monitor_events flag to monitors/manager
valentinewallace Mar 17, 2026
65c5863
Add helper to push monitor events
valentinewallace Mar 18, 2026
f1570bd
Rename pending_monitor_events to _legacy
valentinewallace Mar 18, 2026
8c07223
Add chain::Watch ack_monitor_event API
valentinewallace Mar 16, 2026
6e0b5c5
Add monitor event ids
valentinewallace Mar 18, 2026
67121df
Ack monitor events immediately
valentinewallace Mar 16, 2026
d58e4e0
Support persistent monitor events
valentinewallace Mar 17, 2026
ac68071
Track recent monitor updates in TestChainMonitor
valentinewallace Mar 30, 2026
e6835d8
Persist user channel id in monitors
valentinewallace Mar 24, 2026
ed01b0d
Include user channel id in monitor event
valentinewallace Mar 24, 2026
f47b2c5
Pass best block height to outbound_payments::claim_htlc
valentinewallace Apr 3, 2026
ba25dc7
Pass monitor event id to claim_funds_internal
valentinewallace Apr 3, 2026
7881a0f
Stop hardcoding from_onchain in monitor ev claim_funds
valentinewallace Apr 3, 2026
f36036e
Add EventCompletionAction::AckMonitorEvent
valentinewallace Apr 3, 2026
65f5806
Persistent mon events for off-chain outbound claims
valentinewallace Apr 3, 2026
7f2abd9
Filter claims from get_onchain_failed_htlcs return value
valentinewallace Apr 3, 2026
eb5ee1a
Persistent monitor events for onchain outbound claims
valentinewallace Apr 3, 2026
357b307
Check for dangling monitor events in tests
valentinewallace May 8, 2026
29ac9a3
claim_funds api: Event -> ForwardEventContents
valentinewallace Apr 4, 2026
fbb07dd
Abstract params for claim monitor completion action
valentinewallace Apr 5, 2026
04eb49f
Include inbound htlc_id in PaymentForwarded
valentinewallace May 12, 2026
be7ac43
HTLCUpdate::htlc_value_satoshis -> msats
valentinewallace Apr 6, 2026
81017c8
Lay groundwork for forward monitor event tracking
valentinewallace May 19, 2026
7287132
Ack monitor events post-initial CommitmentSecret
valentinewallace Apr 4, 2026
db0f0a2
Ack monitor events if CommitmentSecret was blocked
valentinewallace Apr 5, 2026
160407d
Ack monitor events if HTLC was fully removed
valentinewallace May 12, 2026
531368e
Add MonitorUpdateCompletionAction::EmitForwardEvent
valentinewallace Apr 5, 2026
25c4922
Ack HTLC monitor events on mid-fulfill channel shutdown
valentinewallace May 12, 2026
4c11112
Persistent monitor events for HTLC forward claims
valentinewallace Apr 7, 2026
134857e
Add skimmed fee to monitor updates
valentinewallace Mar 24, 2026
5252aa5
MonitorEvents: HTLC failure reason and skimmed fee
valentinewallace Apr 7, 2026
70b7645
Store HTLC failure reasons in monitor
valentinewallace Mar 31, 2026
c323996
Persist outbound HTLC failures in monitor
valentinewallace Mar 31, 2026
c520866
Pass HTLC failures channel -> monitor
valentinewallace Mar 31, 2026
afc2b16
Push monitor events when HTLCs fail off-chain
valentinewallace Apr 8, 2026
9fa1f28
fail_htlc: PaymentCompleteUpdate -> EventComplAction
valentinewallace Apr 8, 2026
916c0e5
Persistent monitor events for off-chain outbound fails
valentinewallace Apr 8, 2026
745bff6
Helper for confirmed_funding_spend_past_anti_reorg
valentinewallace May 7, 2026
15c06fd
Persistent monitor events for onchain outbound fails
valentinewallace May 7, 2026
2e6a533
Persist upstream channel ID in HTLCForwardInfo fails
valentinewallace May 26, 2026
4a6bc66
Add htlc_not_found return value to queue_fail_htlc
valentinewallace May 26, 2026
43999b4
Thread htlc hold time to monitor on fail
valentinewallace May 26, 2026
0344807
Hold back HTLC mon events while updates in-progress
valentinewallace May 26, 2026
e1021bc
Persistent monitor events for HTLC forward fails
valentinewallace May 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lightning-liquidity/tests/lsps2_integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use common::{
};

use lightning::events::{ClosureReason, Event};
use lightning::get_event_msg;
use lightning::ln::channelmanager::{
OptionalBolt11PaymentParams, PaymentId, TrustedChannelFeatures,
};
Expand All @@ -17,6 +16,7 @@ use lightning::ln::msgs::BaseMessageHandler;
use lightning::ln::msgs::ChannelMessageHandler;
use lightning::ln::msgs::MessageSendEvent;
use lightning::ln::types::ChannelId;
use lightning::{expect_payment_sent, get_event_msg};

use lightning_liquidity::events::LiquidityEvent;
use lightning_liquidity::lsps0::ser::LSPSDateTime;
Expand Down Expand Up @@ -1340,7 +1340,7 @@ fn client_trusts_lsp_end_to_end_test() {
let broadcasted = service_node.inner.tx_broadcaster.txn_broadcasted.lock().unwrap();
assert!(broadcasted.iter().any(|b| b.compute_txid() == funding_tx.compute_txid()));

expect_payment_sent(&payer_node, preimage.unwrap(), Some(total_fee_msat), true, true);
expect_payment_sent!(&payer_node, preimage.unwrap(), total_fee_msat);
}

fn execute_lsps2_dance(
Expand Down
99 changes: 57 additions & 42 deletions lightning/src/chain/chainmonitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ use core::iter::Cycle;
use core::ops::Deref;
use core::sync::atomic::{AtomicUsize, Ordering};

/// Identifies the source of a [`MonitorEvent`] for acknowledgment via
/// [`chain::Watch::ack_monitor_event`] once the event has been processed.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MonitorEventSource {
/// The event ID assigned by the [`ChannelMonitor`].
pub event_id: u64,
/// The channel from which the [`MonitorEvent`] originated.
pub channel_id: ChannelId,
}

impl_ser_tlv_based!(MonitorEventSource, {
(1, event_id, required),
(3, channel_id, required),
});

/// A pending operation queued for later execution when `ChainMonitor` is in deferred mode.
enum PendingMonitorOp<ChannelSigner: EcdsaChannelSigner> {
/// A new monitor to insert and persist.
Expand Down Expand Up @@ -366,9 +381,6 @@ pub struct ChainMonitor<
fee_estimator: F,
persister: P,
_entropy_source: ES,
/// "User-provided" (ie persistence-completion/-failed) [`MonitorEvent`]s. These came directly
/// from the user and not from a [`ChannelMonitor`].
pending_monitor_events: Mutex<Vec<(OutPoint, ChannelId, Vec<MonitorEvent>, PublicKey)>>,
/// The best block height seen, used as a proxy for the passage of time.
highest_chain_height: AtomicUsize,

Expand Down Expand Up @@ -436,7 +448,6 @@ where
logger,
fee_estimator: feeest,
_entropy_source,
pending_monitor_events: Mutex::new(Vec::new()),
highest_chain_height: AtomicUsize::new(0),
event_notifier: Arc::clone(&event_notifier),
persister: AsyncPersister { persister, event_notifier },
Expand Down Expand Up @@ -657,7 +668,6 @@ where
fee_estimator: feeest,
persister,
_entropy_source,
pending_monitor_events: Mutex::new(Vec::new()),
highest_chain_height: AtomicUsize::new(0),
event_notifier: Arc::new(Notifier::new()),
pending_send_only_events: Mutex::new(Vec::new()),
Expand Down Expand Up @@ -802,16 +812,11 @@ where
return Ok(());
}
let funding_txo = monitor_data.monitor.get_funding_txo();
self.pending_monitor_events.lock().unwrap().push((
monitor_data.monitor.push_monitor_event(MonitorEvent::Completed {
funding_txo,
channel_id,
vec![MonitorEvent::Completed {
funding_txo,
channel_id,
monitor_update_id: monitor_data.monitor.get_latest_update_id(),
}],
monitor_data.monitor.get_counterparty_node_id(),
));
monitor_update_id: monitor_data.monitor.get_latest_update_id(),
});

self.event_notifier.notify();
Ok(())
Expand All @@ -823,15 +828,15 @@ where
#[cfg(any(test, fuzzing))]
pub fn force_channel_monitor_updated(&self, channel_id: ChannelId, monitor_update_id: u64) {
let monitors = self.monitors.read().unwrap();
let monitor = &monitors.get(&channel_id).unwrap().monitor;
let counterparty_node_id = monitor.get_counterparty_node_id();
let funding_txo = monitor.get_funding_txo();
self.pending_monitor_events.lock().unwrap().push((
funding_txo,
let monitor_state = monitors.get(&channel_id).unwrap();
let monitor = &monitor_state.monitor;
let mut pending_monitor_updates = monitor_state.pending_monitor_updates.lock().unwrap();
pending_monitor_updates.retain(|update_id| *update_id > monitor_update_id);
monitor.push_monitor_event(MonitorEvent::Completed {
funding_txo: monitor.get_funding_txo(),
channel_id,
vec![MonitorEvent::Completed { funding_txo, channel_id, monitor_update_id }],
counterparty_node_id,
));
monitor_update_id,
});
self.event_notifier.notify();
}

Expand Down Expand Up @@ -1266,21 +1271,13 @@ where
// The channel is post-close (funding spend seen, lockdown, or
// holder tx signed). Return InProgress so ChannelManager freezes
// the channel until the force-close MonitorEvents are processed.
// Push a Completed event into pending_monitor_events so it gets
// picked up after the per-monitor events in the next
// release_pending_monitor_events call.
let funding_txo = monitor.get_funding_txo();
let channel_id = monitor.channel_id();
self.pending_monitor_events.lock().unwrap().push((
funding_txo,
channel_id,
vec![MonitorEvent::Completed {
funding_txo,
channel_id,
monitor_update_id: monitor.get_latest_update_id(),
}],
monitor.get_counterparty_node_id(),
));
// Push a Completed event into the monitor so it gets picked up
// in the next release_pending_monitor_events call.
monitor.push_monitor_event(MonitorEvent::Completed {
funding_txo: monitor.get_funding_txo(),
channel_id: monitor.channel_id(),
monitor_update_id: monitor.get_latest_update_id(),
});
log_debug!(
logger,
"Deferring completion of ChannelMonitorUpdate id {:?} (channel is post-close)",
Expand Down Expand Up @@ -1645,14 +1642,27 @@ where

fn release_pending_monitor_events(
&self,
) -> Vec<(OutPoint, ChannelId, Vec<MonitorEvent>, PublicKey)> {
) -> Vec<(OutPoint, ChannelId, Vec<(u64, MonitorEvent)>, PublicKey)> {
for (channel_id, update_id) in self.persister.get_and_clear_completed_updates() {
let _ = self.channel_monitor_updated(channel_id, update_id);
}
let monitors = self.monitors.read().unwrap();
let mut pending_monitor_events = Vec::new();
for monitor_state in monitors.values() {
let monitor_events = monitor_state.monitor.get_and_clear_pending_monitor_events();
// Hold back HTLC monitor events for channels with in-flight updates. The monitor may have
// queued an event based on in-memory state from an as-yet-unpersisted update; surfacing it
// before persistence would let us act on (e.g. fail upstream) state that could be lost on a
// crash + reconnect. Other monitor events (e.g., channel close) aren't subject to those
// restrictions and can be released immediately.
let has_pending_updates = {
let pending_updates = monitor_state.pending_monitor_updates.lock().unwrap();
monitor_state.has_pending_updates(&pending_updates)
};
let monitor_events = if has_pending_updates {
monitor_state.monitor.get_and_clear_pending_non_htlc_monitor_events()
} else {
monitor_state.monitor.get_and_clear_pending_monitor_events()
};
if monitor_events.len() > 0 {
let monitor_funding_txo = monitor_state.monitor.get_funding_txo();
let monitor_channel_id = monitor_state.monitor.channel_id();
Expand All @@ -1665,12 +1675,17 @@ where
));
}
}
// Drain pending_monitor_events (which includes deferred post-close
// completions) after per-monitor events so that force-close
// MonitorEvents are processed by ChannelManager first.
pending_monitor_events.extend(self.pending_monitor_events.lock().unwrap().split_off(0));
pending_monitor_events
}

fn ack_monitor_event(&self, source: MonitorEventSource) {
let monitors = self.monitors.read().unwrap();
if let Some(monitor_state) = monitors.get(&source.channel_id) {
monitor_state.monitor.ack_monitor_event(source.event_id);
} else {
debug_assert!(false, "Ack'd monitor events should always have a corresponding monitor");
}
}
}

impl<
Expand Down
Loading
Loading