Skip to content

Commit 2a15c45

Browse files
committed
Hold in-flight monitor updates until background event processing
We previously assumed background events would eventually be processed prior to another `ChannelManager` write, so we would immediately remove all in-flight monitor updates that completed since the last `ChannelManager` serialization. This isn't always the case, so we now keep them all around until we're ready to handle them, i.e., when `process_background_events` is called. This was discovered while fuzzing `chanmon_consistency_target` on the main branch with some changes that allow it to connect blocks. It was triggered by reloading the `ChannelManager` after a monitor update completion for an outgoing HTLC, calling `ChannelManager::best_block_updated`, and reloading the `ChannelManager` once again. A test is included that provides a minimal reproduction of this case.
1 parent 817ab5e commit 2a15c45

2 files changed

Lines changed: 157 additions & 20 deletions

File tree

lightning/src/ln/channelmanager.rs

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8151,9 +8151,50 @@ impl<
81518151
for event in background_events.drain(..) {
81528152
match event {
81538153
BackgroundEvent::MonitorUpdateRegeneratedOnStartup { counterparty_node_id, funding_txo, channel_id, update } => {
8154+
// We previously assumed background events would eventually be processed prior
8155+
// to another `ChannelManager` write, so we would immediately remove all
8156+
// in-flight monitor updates that completed since the last `ChannelManager`
8157+
// serialization. This isn't always the case, so we now keep them all around
8158+
// until we're ready to handle them, i.e., when `process_background_events` is
8159+
// called.
8160+
//
8161+
// Remove the matching in-flight monitor update for this channel, as it has
8162+
// already been persisted to the monitor and can be applied to our internal
8163+
// state such that the channel may make forward progress.
8164+
{
8165+
let per_peer_state = self.per_peer_state.read().unwrap();
8166+
let mut peer_state_lock;
8167+
let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
8168+
if peer_state_mutex_opt.is_none() { continue; }
8169+
peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
8170+
let peer_state = &mut *peer_state_lock;
8171+
if let Some((_, updates)) = peer_state.in_flight_monitor_updates.get_mut(&channel_id) {
8172+
updates.retain(|upd| upd.update_id != update.update_id);
8173+
}
8174+
}
81548175
self.apply_post_close_monitor_update(counterparty_node_id, channel_id, funding_txo, update);
81558176
},
81568177
BackgroundEvent::MonitorUpdatesComplete { counterparty_node_id, channel_id } => {
8178+
// We previously assumed background events would eventually be processed prior
8179+
// to another `ChannelManager` write, so we would immediately remove all
8180+
// in-flight monitor updates that completed since the last `ChannelManager`
8181+
// serialization. This isn't always the case, so we now keep them all around
8182+
// until we're ready to handle them, i.e., when `process_background_events` is
8183+
// called.
8184+
//
8185+
// Now that we can finally handle the background event, remove all in-flight
8186+
// monitor updates for this channel, as they have already been persisted to the
8187+
// monitor and can be applied to our internal state such that the channel
8188+
// resumes operation.
8189+
{
8190+
let per_peer_state = self.per_peer_state.read().unwrap();
8191+
let mut peer_state_lock;
8192+
let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
8193+
if peer_state_mutex_opt.is_none() { continue; }
8194+
peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
8195+
let peer_state = &mut *peer_state_lock;
8196+
peer_state.in_flight_monitor_updates.remove(&channel_id);
8197+
}
81578198
self.channel_monitor_updated(&channel_id, None, &counterparty_node_id);
81588199
},
81598200
}
@@ -18134,39 +18175,47 @@ impl<
1813418175
($counterparty_node_id: expr, $chan_in_flight_upds: expr, $monitor: expr,
1813518176
$peer_state: expr, $logger: expr, $channel_info_log: expr
1813618177
) => { {
18178+
// We previously assumed background events would eventually be processed prior to
18179+
// another `ChannelManager` write, so we would immediately remove all in-flight
18180+
// monitor updates that completed since the last `ChannelManager` serialization.
18181+
// This isn't always the case, so we now keep them all around until we're ready to
18182+
// handle them, i.e., when `process_background_events` is called.
1813718183
let mut max_in_flight_update_id = 0;
18138-
let starting_len = $chan_in_flight_upds.len();
18139-
$chan_in_flight_upds.retain(|upd| upd.update_id > $monitor.get_latest_update_id());
18140-
if $chan_in_flight_upds.len() < starting_len {
18184+
let num_updates_completed = $chan_in_flight_upds
18185+
.iter()
18186+
.filter(|upd| upd.update_id <= $monitor.get_latest_update_id())
18187+
.count();
18188+
if num_updates_completed > 0 {
1814118189
log_debug!(
1814218190
$logger,
1814318191
"{} ChannelMonitorUpdates completed after ChannelManager was last serialized",
18144-
starting_len - $chan_in_flight_upds.len()
18192+
num_updates_completed,
1814518193
);
1814618194
}
1814718195
let funding_txo = $monitor.get_funding_txo();
18148-
for update in $chan_in_flight_upds.iter() {
18149-
log_debug!($logger, "Replaying ChannelMonitorUpdate {} for {}channel {}",
18150-
update.update_id, $channel_info_log, &$monitor.channel_id());
18151-
max_in_flight_update_id = cmp::max(max_in_flight_update_id, update.update_id);
18152-
pending_background_events.push(
18153-
BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
18154-
counterparty_node_id: $counterparty_node_id,
18155-
funding_txo: funding_txo,
18156-
channel_id: $monitor.channel_id(),
18157-
update: update.clone(),
18158-
});
18159-
}
18160-
if $chan_in_flight_upds.is_empty() {
18196+
if num_updates_completed == $chan_in_flight_upds.len() {
1816118197
// We had some updates to apply, but it turns out they had completed before we
1816218198
// were serialized, we just weren't notified of that. Thus, we may have to run
1816318199
// the completion actions for any monitor updates, but otherwise are done.
18200+
log_debug!($logger, "All monitor updates completed since the ChannelManager was last serialized");
1816418201
pending_background_events.push(
1816518202
BackgroundEvent::MonitorUpdatesComplete {
1816618203
counterparty_node_id: $counterparty_node_id,
1816718204
channel_id: $monitor.channel_id(),
1816818205
});
1816918206
} else {
18207+
for update in $chan_in_flight_upds.iter() {
18208+
log_debug!($logger, "Replaying ChannelMonitorUpdate {} for {}channel {}",
18209+
update.update_id, $channel_info_log, &$monitor.channel_id());
18210+
max_in_flight_update_id = cmp::max(max_in_flight_update_id, update.update_id);
18211+
pending_background_events.push(
18212+
BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
18213+
counterparty_node_id: $counterparty_node_id,
18214+
funding_txo: funding_txo,
18215+
channel_id: $monitor.channel_id(),
18216+
update: update.clone(),
18217+
});
18218+
}
1817018219
$peer_state.closed_channel_monitor_update_ids.entry($monitor.channel_id())
1817118220
.and_modify(|v| *v = cmp::max(max_in_flight_update_id, *v))
1817218221
.or_insert(max_in_flight_update_id);
@@ -18194,7 +18243,7 @@ impl<
1819418243
.expect("We already checked for monitor presence when loading channels");
1819518244
let mut max_in_flight_update_id = monitor.get_latest_update_id();
1819618245
if let Some(in_flight_upds) = &mut in_flight_monitor_updates {
18197-
if let Some(mut chan_in_flight_upds) =
18246+
if let Some(chan_in_flight_upds) =
1819818247
in_flight_upds.remove(&(*counterparty_id, *chan_id))
1819918248
{
1820018249
max_in_flight_update_id = cmp::max(
@@ -18238,7 +18287,7 @@ impl<
1823818287
}
1823918288

1824018289
if let Some(in_flight_upds) = in_flight_monitor_updates {
18241-
for ((counterparty_id, channel_id), mut chan_in_flight_updates) in in_flight_upds {
18290+
for ((counterparty_id, channel_id), chan_in_flight_updates) in in_flight_upds {
1824218291
let logger =
1824318292
WithContext::from(&args.logger, Some(counterparty_id), Some(channel_id), None);
1824418293
if let Some(monitor) = args.channel_monitors.get(&channel_id) {

lightning/src/ln/reload_tests.rs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
//! Functional tests which test for correct behavior across node restarts.
1313
14-
use crate::chain::{ChannelMonitorUpdateStatus, Watch};
14+
use crate::chain::{ChannelMonitorUpdateStatus, Confirm, Watch};
1515
use crate::chain::chaininterface::LowerBoundedFeeEstimator;
1616
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateStep};
1717
use crate::routing::router::{PaymentParameters, RouteParameters};
@@ -37,6 +37,13 @@ use crate::prelude::*;
3737

3838
use crate::ln::functional_test_utils::*;
3939

40+
fn get_latest_mon_update_id<'a, 'b, 'c>(
41+
node: &Node<'a, 'b, 'c>, channel_id: ChannelId,
42+
) -> (u64, u64) {
43+
let monitor_id_state = node.chain_monitor.latest_monitor_update_id.lock().unwrap();
44+
monitor_id_state.get(&channel_id).unwrap().clone()
45+
}
46+
4047
#[test]
4148
fn test_funding_peer_disconnect() {
4249
// Test that we can lock in our funding tx while disconnected
@@ -1566,3 +1573,84 @@ fn test_peer_storage() {
15661573
assert!(res.is_err());
15671574
}
15681575

1576+
#[test]
1577+
fn test_hold_completed_inflight_monitor_updates_upon_manager_reload() {
1578+
// Test that if a `ChannelMonitorUpdate` completes after the `ChannelManager` is serialized,
1579+
// but before it is deserialized, we hold any completed in-flight updates until background event
1580+
// processing. Previously, we would remove completed monitor updates from
1581+
// `in_flight_monitor_updates` during deserialization, relying on
1582+
// [`ChannelManager::process_background_events`] to eventually be called before the
1583+
// `ChannelManager` is serialized again such that the channel is resumed and further updates can
1584+
// be made.
1585+
let chanmon_cfgs = create_chanmon_cfgs(2);
1586+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
1587+
let (persister_a, persister_b);
1588+
let (chain_monitor_a, chain_monitor_b);
1589+
1590+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
1591+
let nodes_0_deserialized_a;
1592+
let nodes_0_deserialized_b;
1593+
1594+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1595+
let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1).2;
1596+
1597+
send_payment(&nodes[0], &[&nodes[1]], 1_000_000);
1598+
1599+
chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
1600+
1601+
// Send a payment that will be pending due to an async monitor update.
1602+
let (route, payment_hash, _, payment_secret) =
1603+
get_route_and_payment_hash!(nodes[0], nodes[1], 1_000_000);
1604+
let payment_id = PaymentId(payment_hash.0);
1605+
let onion = RecipientOnionFields::secret_only(payment_secret);
1606+
nodes[0].node.send_payment_with_route(route, payment_hash, onion, payment_id).unwrap();
1607+
check_added_monitors(&nodes[0], 1);
1608+
1609+
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
1610+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
1611+
1612+
// Serialize the ChannelManager while the monitor update is still in-flight.
1613+
let node_0_serialized = nodes[0].node.encode();
1614+
1615+
// Now complete the monitor update by calling force_channel_monitor_updated.
1616+
// This updates the monitor's state, but the ChannelManager still thinks it's pending.
1617+
let (_, latest_update_id) = get_latest_mon_update_id(&nodes[0], chan_id);
1618+
nodes[0].chain_monitor.chain_monitor.force_channel_monitor_updated(chan_id, latest_update_id);
1619+
let monitor_serialized_updated = get_monitor!(nodes[0], chan_id).encode();
1620+
1621+
// Reload the node with the updated monitor. Upon deserialization, the ChannelManager will
1622+
// detect that the monitor update completed (monitor's update_id >= the in-flight update_id)
1623+
// and queue a `BackgroundEvent::MonitorUpdatesComplete`.
1624+
nodes[0].node.peer_disconnected(nodes[1].node.get_our_node_id());
1625+
nodes[1].node.peer_disconnected(nodes[0].node.get_our_node_id());
1626+
reload_node!(
1627+
nodes[0],
1628+
test_default_channel_config(),
1629+
&node_0_serialized,
1630+
&[&monitor_serialized_updated[..]],
1631+
persister_a,
1632+
chain_monitor_a,
1633+
nodes_0_deserialized_a
1634+
);
1635+
1636+
// If we serialize again, even though we haven't processed any background events yet, we should
1637+
// still see the `BackgroundEvent::MonitorUpdatesComplete` be regenerated on startup.
1638+
let node_0_serialized = nodes[0].node.encode();
1639+
reload_node!(
1640+
nodes[0],
1641+
test_default_channel_config(),
1642+
&node_0_serialized,
1643+
&[&monitor_serialized_updated[..]],
1644+
persister_b,
1645+
chain_monitor_b,
1646+
nodes_0_deserialized_b
1647+
);
1648+
1649+
// Reconnect the nodes. We should finally see the `update_add_htlc` go out, as the reconnection
1650+
// should first process `BackgroundEvent::MonitorUpdatesComplete, allowing the channel to be
1651+
// resumed.
1652+
let mut reconnect_args = ReconnectArgs::new(&nodes[0], &nodes[1]);
1653+
reconnect_args.pending_htlc_adds = (0, 1);
1654+
reconnect_nodes(reconnect_args);
1655+
}
1656+

0 commit comments

Comments
 (0)