Skip to content

Commit b8a1f84

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 9905e60 commit b8a1f84

File tree

6 files changed

+93
-116
lines changed

6 files changed

+93
-116
lines changed

fuzz/src/utils/test_persister.rs

Lines changed: 5 additions & 4 deletions
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,18 @@ 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, _monitor_name: MonitorName,
14+
_data: &channelmonitor::ChannelMonitor<TestChannelSigner>,
1415
) -> chain::ChannelMonitorUpdateStatus {
1516
self.update_ret.lock().unwrap().clone()
1617
}
1718

1819
fn update_persisted_channel(
19-
&self, _funding_txo: OutPoint, _update: Option<&channelmonitor::ChannelMonitorUpdate>,
20+
&self, _monitor_name: MonitorName, _update: Option<&channelmonitor::ChannelMonitorUpdate>,
2021
_data: &channelmonitor::ChannelMonitor<TestChannelSigner>,
2122
) -> chain::ChannelMonitorUpdateStatus {
2223
self.update_ret.lock().unwrap().clone()
2324
}
2425

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

lightning-persister/src/fs_store.rs

Lines changed: 4 additions & 20 deletions
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,8 @@ 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+
let monitor_name = added_monitors[0].1.persistence_key();
622+
match store.persist_new_channel(monitor_name, &added_monitors[0].1) {
633623
ChannelMonitorUpdateStatus::UnrecoverableError => {},
634624
_ => panic!("unexpected result from persisting new channel"),
635625
}
@@ -676,14 +666,8 @@ mod tests {
676666
// handle, hence why the test is Windows-only.
677667
let store = FilesystemStore::new(":<>/".into());
678668

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) {
669+
let monitor_name = added_monitors[0].1.persistence_key();
670+
match store.persist_new_channel(monitor_name, &added_monitors[0].1) {
687671
ChannelMonitorUpdateStatus::UnrecoverableError => {},
688672
_ => panic!("unexpected result from persisting new channel"),
689673
}

lightning/src/chain/chainmonitor.rs

Lines changed: 16 additions & 15 deletions
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

@@ -102,11 +103,13 @@ use bitcoin::secp256k1::PublicKey;
102103
/// [`TrustedCommitmentTransaction::build_to_local_justice_tx`]: crate::ln::chan_utils::TrustedCommitmentTransaction::build_to_local_justice_tx
103104
pub trait Persist<ChannelSigner: EcdsaChannelSigner> {
104105
/// Persist a new channel's data in response to a [`chain::Watch::watch_channel`] call. This is
105-
/// called by [`ChannelManager`] for new channels, or may be called directly, e.g. on startup.
106+
/// called by [`ChannelManager`] for new channels, or may be called directly, e.g. on startup,
107+
/// with the `monitor_name` returned by [`ChannelMonitor::persistence_key`].
106108
///
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.
109+
/// The data can be stored any way you want, so long as `monitor_name` is used to maintain a
110+
/// correct mapping with the stored channel data (i.e., calls to `update_persisted_channel` with
111+
/// the same `monitor_name` must be applied to or overwrite this data). Note that you **must**
112+
/// persist every new monitor to disk.
110113
///
111114
/// The [`ChannelMonitor::get_latest_update_id`] uniquely links this call to [`ChainMonitor::channel_monitor_updated`].
112115
/// For [`Persist::persist_new_channel`], it is only necessary to call [`ChainMonitor::channel_monitor_updated`]
@@ -117,7 +120,7 @@ pub trait Persist<ChannelSigner: EcdsaChannelSigner> {
117120
///
118121
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
119122
/// [`Writeable::write`]: crate::util::ser::Writeable::write
120-
fn persist_new_channel(&self, channel_funding_outpoint: OutPoint, monitor: &ChannelMonitor<ChannelSigner>) -> ChannelMonitorUpdateStatus;
123+
fn persist_new_channel(&self, monitor_name: MonitorName, monitor: &ChannelMonitor<ChannelSigner>) -> ChannelMonitorUpdateStatus;
121124

122125
/// Update one channel's data. The provided [`ChannelMonitor`] has already applied the given
123126
/// update.
@@ -156,7 +159,7 @@ pub trait Persist<ChannelSigner: EcdsaChannelSigner> {
156159
/// [`ChannelMonitorUpdateStatus`] for requirements when returning errors.
157160
///
158161
/// [`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;
162+
fn update_persisted_channel(&self, monitor_name: MonitorName, monitor_update: Option<&ChannelMonitorUpdate>, monitor: &ChannelMonitor<ChannelSigner>) -> ChannelMonitorUpdateStatus;
160163
/// Prevents the channel monitor from being loaded on startup.
161164
///
162165
/// Archiving the data in a backup location (rather than deleting it fully) is useful for
@@ -168,7 +171,7 @@ pub trait Persist<ChannelSigner: EcdsaChannelSigner> {
168171
/// the archive process. Additionally, because the archive operation could be retried on
169172
/// restart, this method must in that case be idempotent, ensuring it can handle scenarios where
170173
/// the monitor already exists in the archive.
171-
fn archive_persisted_channel(&self, channel_funding_outpoint: OutPoint);
174+
fn archive_persisted_channel(&self, monitor_name: MonitorName);
172175
}
173176

174177
struct MonitorHolder<ChannelSigner: EcdsaChannelSigner> {
@@ -342,8 +345,7 @@ where C::Target: chain::Filter,
342345
// `ChannelMonitorUpdate` after a channel persist for a channel with the same
343346
// `latest_update_id`.
344347
let _pending_monitor_updates = monitor_state.pending_monitor_updates.lock().unwrap();
345-
let funding_txo = monitor.get_funding_txo();
346-
match self.persister.update_persisted_channel(funding_txo, None, monitor) {
348+
match self.persister.update_persisted_channel(monitor.persistence_key(), None, monitor) {
347349
ChannelMonitorUpdateStatus::Completed =>
348350
log_trace!(logger, "Finished syncing Channel Monitor for channel {} for block-data",
349351
log_funding_info!(monitor)
@@ -642,7 +644,7 @@ where C::Target: chain::Filter,
642644
have_monitors_to_prune = true;
643645
}
644646
if needs_persistence {
645-
self.persister.update_persisted_channel(monitor_holder.monitor.get_funding_txo(), None, &monitor_holder.monitor);
647+
self.persister.update_persisted_channel(monitor_holder.monitor.persistence_key(), None, &monitor_holder.monitor);
646648
}
647649
}
648650
if have_monitors_to_prune {
@@ -655,7 +657,7 @@ where C::Target: chain::Filter,
655657
"Archiving fully resolved ChannelMonitor for channel ID {}",
656658
channel_id
657659
);
658-
self.persister.archive_persisted_channel(monitor_holder.monitor.get_funding_txo());
660+
self.persister.archive_persisted_channel(monitor_holder.monitor.persistence_key());
659661
false
660662
} else {
661663
true
@@ -769,7 +771,7 @@ where C::Target: chain::Filter,
769771
log_trace!(logger, "Got new ChannelMonitor for channel {}", log_funding_info!(monitor));
770772
let update_id = monitor.get_latest_update_id();
771773
let mut pending_monitor_updates = Vec::new();
772-
let persist_res = self.persister.persist_new_channel(monitor.get_funding_txo(), &monitor);
774+
let persist_res = self.persister.persist_new_channel(monitor.persistence_key(), &monitor);
773775
match persist_res {
774776
ChannelMonitorUpdateStatus::InProgress => {
775777
log_info!(logger, "Persistence of new ChannelMonitor for channel {} in progress", log_funding_info!(monitor));
@@ -825,17 +827,16 @@ where C::Target: chain::Filter,
825827
let update_res = monitor.update_monitor(update, &self.broadcaster, &self.fee_estimator, &self.logger);
826828

827829
let update_id = update.update_id;
828-
let funding_txo = monitor.get_funding_txo();
829830
let persist_res = if update_res.is_err() {
830831
// Even if updating the monitor returns an error, the monitor's state will
831832
// still be changed. Therefore, we should persist the updated monitor despite the error.
832833
// We don't want to persist a `monitor_update` which results in a failure to apply later
833834
// while reading `channel_monitor` with updates from storage. Instead, we should persist
834835
// the entire `channel_monitor` here.
835836
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)
837+
self.persister.update_persisted_channel(monitor.persistence_key(), None, monitor)
837838
} else {
838-
self.persister.update_persisted_channel(funding_txo, Some(update), monitor)
839+
self.persister.update_persisted_channel(monitor.persistence_key(), Some(update), monitor)
839840
};
840841
match persist_res {
841842
ChannelMonitorUpdateStatus::InProgress => {

lightning/src/chain/channelmonitor.rs

Lines changed: 21 additions & 0 deletions
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 is used 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, this method is used to obtain a unique key instead. For
1474+
/// v1 channels, the funding outpoint is still used for backwards compatibility, whereas v2
1475+
/// 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)