Skip to content

Commit f968fa1

Browse files
committed
Add a method to avoid re-persisting monitors during startup
Prior to LDK 0.1, in rare cases we could replay payment claims to `ChannelMonitor`s on startup, which we then expected to be persisted prior to normal node operation. This required re-persisting `ChannelMonitor`s after deserializing the `ChannelManager`, delaying startup in some cases substantially. In 0.1 we fixed this, moving claim replays to the background to run after the `ChannelManager` starts operating (and only updating/persisting changes to the `ChannelMonitor`s which need it). However, we didn't actually enable this meaningfully in our API - nearly all users use our `ChainMonitor` and the only way to get a chanel into `ChainMonitor` is through the normal flow which expects to persist. Here we add a simple method to load `ChannelMonitor`s into the `ChainMonitor` without persisting them.
1 parent ed1f304 commit f968fa1

File tree

4 files changed

+70
-4
lines changed

4 files changed

+70
-4
lines changed

lightning/src/chain/chainmonitor.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,43 @@ where
825825

826826
self.pending_send_only_events.lock().unwrap().push(send_peer_storage_event)
827827
}
828+
829+
/// Loads a [`ChannelMonitor`] which already exists on disk after startup.
830+
///
831+
/// Using this over [`chain::Watch::watch_channel`] avoids re-persisting a [`ChannelMonitor`]
832+
/// that hasn't changed, slowing down startup.
833+
///
834+
/// Note that this method *can* be used if additional blocks were replayed against the
835+
/// [`ChannelMonitor`], and in general can only *not* be used if a [`ChannelMonitorUpdate`] was
836+
/// replayed against the [`ChannelMonitor`] which needs to be psersisted (i.e. the state has
837+
/// changed due to a [`ChannelMonitorUpdate`] such that it may be different after another
838+
/// restart).
839+
///
840+
/// This method is only safe for [`ChannelMonitor`]s which have been loaded (in conjunction
841+
/// with a `ChannelManager`) at least once by LDK 0.1 or later.
842+
pub fn load_post_0_1_existing_monitor(
843+
&self, channel_id: ChannelId, monitor: ChannelMonitor<ChannelSigner>,
844+
) -> Result<(), ()> {
845+
let logger = WithChannelMonitor::from(&self.logger, &monitor, None);
846+
let mut monitors = self.monitors.write().unwrap();
847+
let entry = match monitors.entry(channel_id) {
848+
hash_map::Entry::Occupied(_) => {
849+
log_error!(logger, "Failed to add new channel data: channel monitor for given channel ID is already present");
850+
return Err(());
851+
},
852+
hash_map::Entry::Vacant(e) => e,
853+
};
854+
log_trace!(
855+
logger,
856+
"Loaded existing ChannelMonitor for channel {}",
857+
log_funding_info!(monitor)
858+
);
859+
if let Some(ref chain_source) = self.chain_source {
860+
monitor.load_outputs_to_watch(chain_source, &self.logger);
861+
}
862+
entry.insert(MonitorHolder { monitor, pending_monitor_updates: Mutex::new(Vec::new()) });
863+
Ok(())
864+
}
828865
}
829866

830867
impl<

lightning/src/ln/channelmanager.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15396,9 +15396,13 @@ impl Readable for VecDeque<(Event, Option<EventCompletionAction>)> {
1539615396
/// This is important if you have replayed a nontrivial number of blocks in step (4), allowing
1539715397
/// you to avoid having to replay the same blocks if you shut down quickly after startup. It is
1539815398
/// otherwise not required.
15399+
///
1539915400
/// Note that if you're using a [`ChainMonitor`] for your [`chain::Watch`] implementation, you
1540015401
/// will likely accomplish this as a side-effect of calling [`chain::Watch::watch_channel`] in
1540115402
/// the next step.
15403+
///
15404+
/// If you wish to avoid this for performance reasons, use
15405+
/// [`ChainMonitor::load_post_0_1_existing_monitor`].
1540215406
/// 7) Move the [`ChannelMonitor`]s into your local [`chain::Watch`]. If you're using a
1540315407
/// [`ChainMonitor`], this is done by calling [`chain::Watch::watch_channel`].
1540415408
///
@@ -15413,6 +15417,7 @@ impl Readable for VecDeque<(Event, Option<EventCompletionAction>)> {
1541315417
/// which you've already broadcasted the transaction.
1541415418
///
1541515419
/// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor
15420+
/// [`ChainMonitor::load_post_0_1_existing_monitor`]: ChainMonitor::load_post_0_1_existing_monitor
1541615421
pub struct ChannelManagerReadArgs<
1541715422
'a,
1541815423
M: Deref,

lightning/src/ln/functional_test_utils.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,10 +1323,7 @@ pub fn _reload_node<'a, 'b, 'c>(
13231323

13241324
for monitor in monitors_read.drain(..) {
13251325
let channel_id = monitor.channel_id();
1326-
assert_eq!(
1327-
node.chain_monitor.watch_channel(channel_id, monitor),
1328-
Ok(ChannelMonitorUpdateStatus::Completed)
1329-
);
1326+
assert_eq!(node.chain_monitor.load_post_0_1_existing_monitor(channel_id, monitor), Ok(()));
13301327
check_added_monitors!(node, 1);
13311328
}
13321329

lightning/src/util/test_utils.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,33 @@ impl<'a> TestChainMonitor<'a> {
515515
self.latest_monitor_update_id.lock().unwrap().get(channel_id).unwrap().clone();
516516
self.chain_monitor.channel_monitor_updated(*channel_id, latest_update).unwrap();
517517
}
518+
519+
pub fn load_post_0_1_existing_monitor(
520+
&self, channel_id: ChannelId, monitor: ChannelMonitor<TestChannelSigner>,
521+
) -> Result<(), ()> {
522+
#[cfg(feature = "std")]
523+
if let Some(blocker) = &*self.write_blocker.lock().unwrap() {
524+
blocker.recv().unwrap();
525+
}
526+
527+
// At every point where we get a monitor update, we should be able to send a useful monitor
528+
// to a watchtower and disk...
529+
let mut w = TestVecWriter(Vec::new());
530+
monitor.write(&mut w).unwrap();
531+
let new_monitor = <(BlockHash, ChannelMonitor<TestChannelSigner>)>::read(
532+
&mut io::Cursor::new(&w.0),
533+
(self.keys_manager, self.keys_manager),
534+
)
535+
.unwrap()
536+
.1;
537+
assert!(new_monitor == monitor);
538+
self.latest_monitor_update_id
539+
.lock()
540+
.unwrap()
541+
.insert(channel_id, (monitor.get_latest_update_id(), monitor.get_latest_update_id()));
542+
self.added_monitors.lock().unwrap().push((channel_id, monitor));
543+
self.chain_monitor.load_post_0_1_existing_monitor(channel_id, new_monitor)
544+
}
518545
}
519546
impl<'a> chain::Watch<TestChannelSigner> for TestChainMonitor<'a> {
520547
fn watch_channel(

0 commit comments

Comments
 (0)