Skip to content

Commit 260341b

Browse files
committed
Support persisting ChannelMonitors after splicing
ChannelMonitors are persisted using the corresponding channel's funding outpoint for the key. This is fine for v1 channels since the funding output will never change. However, this is not the case for v2 channels since a splice will result in a new funding outpoint. Instead, use the channel id as the persistence key for v2 channels since this is fixed. For v1 channels, continue to use the funding outpoint for backwards compatibility. Any v1 channel upgraded to a v2 channel via splicing will continue to use the original funding outpoint as the persistence key.
1 parent dd00a0c commit 260341b

File tree

6 files changed

+86
-108
lines changed

6 files changed

+86
-108
lines changed

fuzz/src/utils/test_persister.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use lightning::chain;
2-
use lightning::chain::transaction::OutPoint;
32
use lightning::chain::{chainmonitor, channelmonitor};
3+
use lightning::util::persist::MonitorName;
44
use lightning::util::test_channel_signer::TestChannelSigner;
55

66
use std::sync::Mutex;
@@ -10,17 +10,17 @@ pub struct TestPersister {
1010
}
1111
impl chainmonitor::Persist<TestChannelSigner> for TestPersister {
1212
fn persist_new_channel(
13-
&self, _funding_txo: OutPoint, _data: &channelmonitor::ChannelMonitor<TestChannelSigner>,
13+
&self, _data: &channelmonitor::ChannelMonitor<TestChannelSigner>,
1414
) -> chain::ChannelMonitorUpdateStatus {
1515
self.update_ret.lock().unwrap().clone()
1616
}
1717

1818
fn update_persisted_channel(
19-
&self, _funding_txo: OutPoint, _update: Option<&channelmonitor::ChannelMonitorUpdate>,
19+
&self, _update: Option<&channelmonitor::ChannelMonitorUpdate>,
2020
_data: &channelmonitor::ChannelMonitor<TestChannelSigner>,
2121
) -> chain::ChannelMonitorUpdateStatus {
2222
self.update_ret.lock().unwrap().clone()
2323
}
2424

25-
fn archive_persisted_channel(&self, _: OutPoint) {}
25+
fn archive_persisted_channel(&self, _monitor_name: MonitorName) {}
2626
}

lightning-persister/src/fs_store.rs

+2-20
Original file line numberDiff line numberDiff line change
@@ -498,17 +498,13 @@ mod tests {
498498
do_read_write_remove_list_persist, do_test_data_migration, do_test_store,
499499
};
500500

501-
use bitcoin::Txid;
502-
503501
use lightning::chain::chainmonitor::Persist;
504-
use lightning::chain::transaction::OutPoint;
505502
use lightning::chain::ChannelMonitorUpdateStatus;
506503
use lightning::check_closed_event;
507504
use lightning::events::{ClosureReason, MessageSendEventsProvider};
508505
use lightning::ln::functional_test_utils::*;
509506
use lightning::util::persist::read_channel_monitors;
510507
use lightning::util::test_utils;
511-
use std::str::FromStr;
512508

513509
impl Drop for FilesystemStore {
514510
fn drop(&mut self) {
@@ -622,14 +618,7 @@ mod tests {
622618
perms.set_readonly(true);
623619
fs::set_permissions(path, perms).unwrap();
624620

625-
let test_txo = OutPoint {
626-
txid: Txid::from_str(
627-
"8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be",
628-
)
629-
.unwrap(),
630-
index: 0,
631-
};
632-
match store.persist_new_channel(test_txo, &added_monitors[0].1) {
621+
match store.persist_new_channel(&added_monitors[0].1) {
633622
ChannelMonitorUpdateStatus::UnrecoverableError => {},
634623
_ => panic!("unexpected result from persisting new channel"),
635624
}
@@ -676,14 +665,7 @@ mod tests {
676665
// handle, hence why the test is Windows-only.
677666
let store = FilesystemStore::new(":<>/".into());
678667

679-
let test_txo = OutPoint {
680-
txid: Txid::from_str(
681-
"8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be",
682-
)
683-
.unwrap(),
684-
index: 0,
685-
};
686-
match store.persist_new_channel(test_txo, &added_monitors[0].1) {
668+
match store.persist_new_channel(&added_monitors[0].1) {
687669
ChannelMonitorUpdateStatus::UnrecoverableError => {},
688670
_ => panic!("unexpected result from persisting new channel"),
689671
}

lightning/src/chain/chainmonitor.rs

+13-14
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use crate::sign::ecdsa::EcdsaChannelSigner;
3636
use crate::events::{self, Event, EventHandler, ReplayEvent};
3737
use crate::util::logger::{Logger, WithContext};
3838
use crate::util::errors::APIError;
39+
use crate::util::persist::MonitorName;
3940
use crate::util::wakers::{Future, Notifier};
4041
use crate::ln::channel_state::ChannelDetails;
4142

@@ -104,9 +105,9 @@ pub trait Persist<ChannelSigner: EcdsaChannelSigner> {
104105
/// Persist a new channel's data in response to a [`chain::Watch::watch_channel`] call. This is
105106
/// called by [`ChannelManager`] for new channels, or may be called directly, e.g. on startup.
106107
///
107-
/// The data can be stored any way you want, but the identifier provided by LDK is the
108-
/// channel's outpoint (and it is up to you to maintain a correct mapping between the outpoint
109-
/// and the stored channel data). Note that you **must** persist every new monitor to disk.
108+
/// The data can be stored any way you want, so long as [`ChannelMonitor::persistence_key`] is
109+
/// used to maintain a correct mapping with the stored channel data. Note that you **must**
110+
/// persist every new monitor to disk.
110111
///
111112
/// The [`ChannelMonitor::get_latest_update_id`] uniquely links this call to [`ChainMonitor::channel_monitor_updated`].
112113
/// For [`Persist::persist_new_channel`], it is only necessary to call [`ChainMonitor::channel_monitor_updated`]
@@ -117,7 +118,7 @@ pub trait Persist<ChannelSigner: EcdsaChannelSigner> {
117118
///
118119
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
119120
/// [`Writeable::write`]: crate::util::ser::Writeable::write
120-
fn persist_new_channel(&self, channel_funding_outpoint: OutPoint, monitor: &ChannelMonitor<ChannelSigner>) -> ChannelMonitorUpdateStatus;
121+
fn persist_new_channel(&self, monitor: &ChannelMonitor<ChannelSigner>) -> ChannelMonitorUpdateStatus;
121122

122123
/// Update one channel's data. The provided [`ChannelMonitor`] has already applied the given
123124
/// update.
@@ -156,7 +157,7 @@ pub trait Persist<ChannelSigner: EcdsaChannelSigner> {
156157
/// [`ChannelMonitorUpdateStatus`] for requirements when returning errors.
157158
///
158159
/// [`Writeable::write`]: crate::util::ser::Writeable::write
159-
fn update_persisted_channel(&self, channel_funding_outpoint: OutPoint, monitor_update: Option<&ChannelMonitorUpdate>, monitor: &ChannelMonitor<ChannelSigner>) -> ChannelMonitorUpdateStatus;
160+
fn update_persisted_channel(&self, monitor_update: Option<&ChannelMonitorUpdate>, monitor: &ChannelMonitor<ChannelSigner>) -> ChannelMonitorUpdateStatus;
160161
/// Prevents the channel monitor from being loaded on startup.
161162
///
162163
/// Archiving the data in a backup location (rather than deleting it fully) is useful for
@@ -168,7 +169,7 @@ pub trait Persist<ChannelSigner: EcdsaChannelSigner> {
168169
/// the archive process. Additionally, because the archive operation could be retried on
169170
/// restart, this method must in that case be idempotent, ensuring it can handle scenarios where
170171
/// the monitor already exists in the archive.
171-
fn archive_persisted_channel(&self, channel_funding_outpoint: OutPoint);
172+
fn archive_persisted_channel(&self, monitor_name: MonitorName);
172173
}
173174

174175
struct MonitorHolder<ChannelSigner: EcdsaChannelSigner> {
@@ -342,8 +343,7 @@ where C::Target: chain::Filter,
342343
// `ChannelMonitorUpdate` after a channel persist for a channel with the same
343344
// `latest_update_id`.
344345
let _pending_monitor_updates = monitor_state.pending_monitor_updates.lock().unwrap();
345-
let funding_txo = monitor.get_funding_txo().0;
346-
match self.persister.update_persisted_channel(funding_txo, None, monitor) {
346+
match self.persister.update_persisted_channel(None, monitor) {
347347
ChannelMonitorUpdateStatus::Completed =>
348348
log_trace!(logger, "Finished syncing Channel Monitor for channel {} for block-data",
349349
log_funding_info!(monitor)
@@ -642,7 +642,7 @@ where C::Target: chain::Filter,
642642
have_monitors_to_prune = true;
643643
}
644644
if needs_persistence {
645-
self.persister.update_persisted_channel(monitor_holder.monitor.get_funding_txo().0, None, &monitor_holder.monitor);
645+
self.persister.update_persisted_channel(None, &monitor_holder.monitor);
646646
}
647647
}
648648
if have_monitors_to_prune {
@@ -655,7 +655,7 @@ where C::Target: chain::Filter,
655655
"Archiving fully resolved ChannelMonitor for channel ID {}",
656656
channel_id
657657
);
658-
self.persister.archive_persisted_channel(monitor_holder.monitor.get_funding_txo().0);
658+
self.persister.archive_persisted_channel(monitor_holder.monitor.persistence_key());
659659
false
660660
} else {
661661
true
@@ -769,7 +769,7 @@ where C::Target: chain::Filter,
769769
log_trace!(logger, "Got new ChannelMonitor for channel {}", log_funding_info!(monitor));
770770
let update_id = monitor.get_latest_update_id();
771771
let mut pending_monitor_updates = Vec::new();
772-
let persist_res = self.persister.persist_new_channel(monitor.get_funding_txo().0, &monitor);
772+
let persist_res = self.persister.persist_new_channel(&monitor);
773773
match persist_res {
774774
ChannelMonitorUpdateStatus::InProgress => {
775775
log_info!(logger, "Persistence of new ChannelMonitor for channel {} in progress", log_funding_info!(monitor));
@@ -825,17 +825,16 @@ where C::Target: chain::Filter,
825825
let update_res = monitor.update_monitor(update, &self.broadcaster, &self.fee_estimator, &self.logger);
826826

827827
let update_id = update.update_id;
828-
let funding_txo = monitor.get_funding_txo().0;
829828
let persist_res = if update_res.is_err() {
830829
// Even if updating the monitor returns an error, the monitor's state will
831830
// still be changed. Therefore, we should persist the updated monitor despite the error.
832831
// We don't want to persist a `monitor_update` which results in a failure to apply later
833832
// while reading `channel_monitor` with updates from storage. Instead, we should persist
834833
// the entire `channel_monitor` here.
835834
log_warn!(logger, "Failed to update ChannelMonitor for channel {}. Going ahead and persisting the entire ChannelMonitor", log_funding_info!(monitor));
836-
self.persister.update_persisted_channel(funding_txo, None, monitor)
835+
self.persister.update_persisted_channel(None, monitor)
837836
} else {
838-
self.persister.update_persisted_channel(funding_txo, Some(update), monitor)
837+
self.persister.update_persisted_channel(Some(update), monitor)
839838
};
840839
match persist_res {
841840
ChannelMonitorUpdateStatus::InProgress => {

lightning/src/chain/channelmonitor.rs

+21
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use crate::chain::onchaintx::{ClaimEvent, FeerateStrategy, OnchainTxHandler};
4848
use crate::chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput};
4949
use crate::chain::Filter;
5050
use crate::util::logger::{Logger, Record};
51+
use crate::util::persist::MonitorName;
5152
use crate::util::ser::{Readable, ReadableArgs, RequiredWrapper, MaybeReadable, UpgradableRequired, Writer, Writeable, U48};
5253
use crate::util::byte_utils;
5354
use crate::events::{ClosureReason, Event, EventHandler, ReplayEvent};
@@ -1465,6 +1466,26 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
14651466
})
14661467
}
14671468

1469+
/// Returns a unique id for persisting the [`ChannelMonitor`], which may be useful as a key in a
1470+
/// key-value store.
1471+
///
1472+
/// Note: Previously, the funding outpoint was used in the [`Persist`] trait. However, since the
1473+
/// outpoint may change during splicing, using this method to obtain a unique key is recommended
1474+
/// instead. For v1 channels, the funding outpoint is still used for backwards compatibility,
1475+
/// whereas v2 channels use the channel id since it is fixed.
1476+
///
1477+
/// [`Persist`]: crate::chain::chainmonitor::Persist
1478+
pub fn persistence_key(&self) -> MonitorName {
1479+
let inner = self.inner.lock().unwrap();
1480+
let funding_outpoint = inner.first_confirmed_funding_txo;
1481+
let channel_id = inner.channel_id;
1482+
if ChannelId::v1_from_funding_outpoint(funding_outpoint) == channel_id {
1483+
MonitorName::from(funding_outpoint)
1484+
} else {
1485+
MonitorName::from(channel_id)
1486+
}
1487+
}
1488+
14681489
#[cfg(test)]
14691490
fn provide_secret(&self, idx: u64, secret: [u8; 32]) -> Result<(), &'static str> {
14701491
self.inner.lock().unwrap().provide_secret(idx, secret)

0 commit comments

Comments
 (0)