Skip to content

Commit 67545a3

Browse files
committed
f Split prun_stale_monitors to archive_.. and remove_..
1 parent 3282321 commit 67545a3

File tree

3 files changed

+178
-70
lines changed

3 files changed

+178
-70
lines changed

lightning/src/chain/chainmonitor.rs

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,35 @@ pub trait Persist<ChannelSigner: WriteableEcdsaChannelSigner> {
194194
///
195195
/// [`Writeable::write`]: crate::util::ser::Writeable::write
196196
fn update_persisted_channel(&self, channel_funding_outpoint: OutPoint, update: Option<&ChannelMonitorUpdate>, data: &ChannelMonitor<ChannelSigner>, update_id: MonitorUpdateId) -> ChannelMonitorUpdateStatus;
197-
198-
/// Prune a channel's data.
197+
/// Archive a channel's data to a backup location.
198+
///
199+
/// Invoked by [`ChainMonitor::archive_stale_channel_monitors`].
200+
///
201+
/// This function can be used as a first step in pruning a channel's monitor data.
202+
/// The data should be moved to an archive location, and then removed
203+
/// using [`Persist::remove_persisted_channel`].
204+
///
205+
/// This is usually called when a channel monitor is in a stale state, ie no
206+
/// fund can be claimed with its data. This is a good time to
207+
/// archive the channel data to a backup location, before removing
208+
/// it from the primary storage.
199209
///
200-
/// This is called when a channel is stale, ie we dont have balance to claim and its
201-
/// closed.
202-
fn prune_persisted_channel(&self, channel_funding_outpoint: OutPoint) -> bool;
210+
/// Archiving the data is useful for hedging against data loss in
211+
/// case of an unexpected failure/bug.
212+
fn archive_persisted_channel(&self, channel_funding_outpoint: OutPoint) -> ChannelMonitorUpdateStatus;
213+
/// *Dangerous* - removes a channel's data.
214+
///
215+
/// Only call this when the data have been archived using [`Persist::archive_persisted_channel`].
216+
///
217+
/// This function will remove the persisted channel data for the
218+
/// given `channel_funding_outpoint` and should only be used when
219+
/// the data is stale and no longer needed.` A stale channel
220+
/// monitor is one where no funds can be claimed with its data.
221+
///
222+
/// Invoked by [`ChainMonitor::archive_stale_channel_monitors`]
223+
/// after verifying the channel's data is no longer needed and has been archived using
224+
/// [`Persist::archive_persisted_channel`].
225+
fn remove_persisted_channel(&self, channel_funding_outpoint: OutPoint) -> ChannelMonitorUpdateStatus;
203226
}
204227

205228
struct MonitorHolder<ChannelSigner: WriteableEcdsaChannelSigner> {
@@ -663,21 +686,23 @@ where C::Target: chain::Filter,
663686
}
664687
}
665688

666-
pub fn prune_stale_channel_monitors(&self, to_prune: Vec<OutPoint>) {
689+
/// Archives channel monitors which are stale, meaning they have
690+
/// no funds to claim and are eligible for removal.
691+
///
692+
/// This is useful for pruning stale channels from the monitor set.
693+
///
694+
/// The monitor data is archived to a backup location and then removed from the primary storage.
695+
pub fn archive_stale_channel_monitors(&self, to_archive: Vec<OutPoint>) {
667696
let mut monitors = self.monitors.write().unwrap();
668-
for funding_txo in to_prune {
697+
for funding_txo in to_archive {
669698
let channel_monitor = monitors.get(&funding_txo);
670699
if let Some(channel_monitor) = channel_monitor {
671-
if channel_monitor.monitor.is_stale() {
672-
log_info!(self.logger, "Pruning stale ChannelMonitor for
673-
channel {}", log_funding_info!(channel_monitor.monitor));
674-
//TODO: save the channel monitor to disk in an archived namespace before removing it
675-
676-
self.persister.prune_persisted_channel(funding_txo);
677-
monitors.remove(&funding_txo);
678-
}
679-
}
680-
700+
if channel_monitor.monitor.is_stale()
701+
&& self.persister.archive_persisted_channel(funding_txo) == ChannelMonitorUpdateStatus::Completed
702+
&& self.persister.remove_persisted_channel(funding_txo) == ChannelMonitorUpdateStatus::Completed {
703+
monitors.remove(&funding_txo);
704+
};
705+
};
681706
}
682707
}
683708
}
@@ -1133,26 +1158,8 @@ mod tests {
11331158
}).is_err());
11341159
}
11351160

1136-
#[test]
1137-
fn prune_stale_channel_monitor() {
1138-
// Test that we can prune a ChannelMonitor that has no active channel.
1139-
let chanmon_cfgs = create_chanmon_cfgs(2);
1140-
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
1141-
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
1142-
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1143-
create_announced_chan_between_nodes(&nodes, 0, 1);
1144-
// Get a route for later and rebalance the channel somewhat
1145-
send_payment(&nodes[0], &[&nodes[1]], 10_000_000);
1146-
// First route a payment that we will claim on chain and give the recipient the preimage.
1147-
let (payment_preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
1148-
nodes[1].node.claim_funds(payment_preimage);
1149-
expect_payment_claimed!(nodes[1], payment_hash, 1_000_000);
1150-
nodes[1].node.get_and_clear_pending_msg_events();
1151-
let binding = node_cfgs[1].chain_monitor.added_monitors.lock().unwrap();
1152-
let monitors_b = binding.first().unwrap();
1153-
let outpoint = monitors_b.0.clone();
1154-
dbg!(&outpoint);
1155-
// nodes[1].chain_monitor().unwrap().chain_monitor.prune_stale_channel_monitors(vec![outpoint]); // lock order problem
1156-
assert!(false);
1157-
}
1161+
// #[test]
1162+
// fn archive_stale_channel_monitors() {
1163+
// unimplemented!()
1164+
// }
11581165
}

lightning/src/util/persist.rs

Lines changed: 120 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ pub const CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE: &str = "";
5858
/// The primary namespace under which [`ChannelMonitorUpdate`]s will be persisted.
5959
pub const CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE: &str = "monitor_updates";
6060

61-
/// The primary namespace under which [`ChannelMonitor`]s will be persisted.
62-
pub const PRUNED_CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE: &str = "pruned_monitors";
63-
/// The secondary namespace under which [`ChannelMonitor`]s will be persisted.
64-
pub const PRUNED_CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE: &str = "";
61+
/// The primary namespace under which archived [`ChannelMonitor`]s will be persisted.
62+
pub const ARCHIVED_CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE: &str = "archived_monitors";
63+
/// The secondary namespace under which archived [`ChannelMonitor`]s will be persisted.
64+
pub const ARCHIVED_CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE: &str = "";
6565

6666
/// The primary namespace under which the [`NetworkGraph`] will be persisted.
6767
pub const NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE: &str = "";
@@ -247,15 +247,38 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner, K: KVStore> Persist<ChannelSign
247247
}
248248
}
249249

250-
fn prune_persisted_channel(&self, funding_txo: OutPoint) -> bool {
250+
fn archive_persisted_channel(&self, funding_txo: OutPoint) -> chain::ChannelMonitorUpdateStatus {
251+
let monitor_name = MonitorName::from(funding_txo);
252+
let monitor = match self.read(
253+
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
254+
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
255+
monitor_name.as_str(),
256+
) {
257+
Ok(monitor) => monitor,
258+
Err(_) => return chain::ChannelMonitorUpdateStatus::UnrecoverableError
259+
260+
};
261+
match self.write(
262+
ARCHIVED_CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
263+
ARCHIVED_CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
264+
monitor_name.as_str(),
265+
&monitor
266+
) {
267+
Ok(()) => chain::ChannelMonitorUpdateStatus::Completed,
268+
Err(_e) => chain::ChannelMonitorUpdateStatus::UnrecoverableError // TODO: Should we return UnrecoverableError here?
269+
}
270+
}
271+
272+
fn remove_persisted_channel(&self, funding_txo: OutPoint) -> chain::ChannelMonitorUpdateStatus {
251273
let key = format!("{}_{}", funding_txo.txid.to_string(), funding_txo.index);
252274
match self.remove(
253275
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
254276
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
255-
&key, false)
256-
{
257-
Ok(()) => true,
258-
Err(_) => false
277+
&key,
278+
false,
279+
) {
280+
Ok(()) => chain::ChannelMonitorUpdateStatus::Completed,
281+
Err(_) => chain::ChannelMonitorUpdateStatus::UnrecoverableError
259282
}
260283
}
261284
}
@@ -290,15 +313,38 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> Persist<ChannelSigner> for dyn
290313
}
291314
}
292315

293-
fn prune_persisted_channel(&self, funding_txo: OutPoint) -> bool {
316+
fn archive_persisted_channel(&self, funding_txo: OutPoint) -> chain::ChannelMonitorUpdateStatus {
317+
let monitor_name = MonitorName::from(funding_txo);
318+
let monitor = match self.read(
319+
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
320+
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
321+
monitor_name.as_str(),
322+
) {
323+
Ok(monitor) => monitor,
324+
Err(_) => return chain::ChannelMonitorUpdateStatus::UnrecoverableError
325+
326+
};
327+
match self.write(
328+
ARCHIVED_CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
329+
ARCHIVED_CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
330+
monitor_name.as_str(),
331+
&monitor
332+
) {
333+
Ok(()) => chain::ChannelMonitorUpdateStatus::Completed,
334+
Err(_e) => chain::ChannelMonitorUpdateStatus::UnrecoverableError // TODO: Should we return UnrecoverableError here?
335+
}
336+
}
337+
338+
fn remove_persisted_channel(&self, funding_txo: OutPoint) -> chain::ChannelMonitorUpdateStatus {
294339
let key = format!("{}_{}", funding_txo.txid.to_string(), funding_txo.index);
295340
match self.remove(
296341
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
297342
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
298-
&key, false)
299-
{
300-
Ok(()) => true,
301-
Err(_) => false
343+
&key,
344+
false,
345+
) {
346+
Ok(()) => chain::ChannelMonitorUpdateStatus::Completed,
347+
Err(_) => chain::ChannelMonitorUpdateStatus::UnrecoverableError
302348
}
303349
}
304350
}
@@ -623,6 +669,46 @@ where
623669
}
624670
}
625671
}
672+
/// Read an archived channel monitor.
673+
fn read_archived_channel_monitor(&self, archived_monitor_name: &MonitorName) -> Result<(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), io::Error> {
674+
let outpoint: OutPoint = archived_monitor_name.try_into()?;
675+
let mut monitor_cursor = io::Cursor::new(self.kv_store.read(
676+
ARCHIVED_CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
677+
ARCHIVED_CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
678+
archived_monitor_name.as_str(),
679+
)?);
680+
match <(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>)>::read(
681+
&mut monitor_cursor,
682+
(&*self.entropy_source, &*self.signer_provider),
683+
) {
684+
Ok((blockhash, channel_monitor)) => {
685+
if channel_monitor.get_funding_txo().0.txid != outpoint.txid
686+
|| channel_monitor.get_funding_txo().0.index != outpoint.index
687+
{
688+
log_error!(
689+
self.logger,
690+
"Archived ChannelMonitor {} was stored under the wrong key!",
691+
archived_monitor_name.as_str()
692+
);
693+
Err(io::Error::new(
694+
io::ErrorKind::InvalidData,
695+
"Archived ChannelMonitor was stored under the wrong key",
696+
))
697+
} else {
698+
Ok((blockhash, channel_monitor))
699+
}
700+
}
701+
Err(e) => {
702+
log_error!(
703+
self.logger,
704+
"Failed to read archived ChannelMonitor {}, reason: {}",
705+
archived_monitor_name.as_str(),
706+
e,
707+
);
708+
Err(io::Error::new(io::ErrorKind::InvalidData, "Failed to read archived ChannelMonitor"))
709+
}
710+
}
711+
}
626712

627713
/// Read a channel monitor update.
628714
fn read_monitor_update(
@@ -808,26 +894,33 @@ where
808894
}
809895
}
810896

811-
fn prune_persisted_channel(&self, funding_txo: OutPoint) -> bool {
897+
fn archive_persisted_channel(&self, funding_txo: OutPoint) -> chain::ChannelMonitorUpdateStatus {
898+
let monitor_name = MonitorName::from(funding_txo);
899+
let monitor = match self.read_monitor(&monitor_name) {
900+
Ok((_block_hash, monitor)) => monitor,
901+
Err(_) => return chain::ChannelMonitorUpdateStatus::UnrecoverableError
902+
};
903+
match self.kv_store.write(
904+
ARCHIVED_CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
905+
ARCHIVED_CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
906+
monitor_name.as_str(),
907+
&monitor.encode()
908+
) {
909+
Ok(()) => chain::ChannelMonitorUpdateStatus::Completed,
910+
Err(_e) => chain::ChannelMonitorUpdateStatus::UnrecoverableError // TODO: Should we return UnrecoverableError here?
911+
}
912+
}
913+
914+
fn remove_persisted_channel(&self, funding_txo: OutPoint) -> chain::ChannelMonitorUpdateStatus {
812915
let monitor_name = MonitorName::from(funding_txo);
813916
match self.kv_store.remove(
814917
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
815918
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
816919
monitor_name.as_str(),
817920
false,
818921
) {
819-
Ok(()) => true,
820-
Err(e) => {
821-
log_error!(
822-
self.logger,
823-
"Failed to remove ChannelMonitor {}/{}/{} reason: {}",
824-
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
825-
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
826-
monitor_name.as_str(),
827-
e
828-
);
829-
false
830-
}
922+
Ok(()) => chain::ChannelMonitorUpdateStatus::Completed,
923+
Err(_) => chain::ChannelMonitorUpdateStatus::UnrecoverableError
831924
}
832925
}
833926
}

lightning/src/util/test_utils.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,12 @@ impl<Signer: sign::ecdsa::WriteableEcdsaChannelSigner> chainmonitor::Persist<Sig
502502
res
503503
}
504504

505-
fn prune_persisted_channel(&self, _funding_txo: OutPoint) -> bool {
506-
false
505+
fn archive_persisted_channel(&self, _funding_txo: OutPoint) -> chain::ChannelMonitorUpdateStatus {
506+
unimplemented!()
507+
}
508+
509+
fn remove_persisted_channel(&self, _funding_txo: OutPoint) -> chain::ChannelMonitorUpdateStatus {
510+
unimplemented!()
507511
}
508512
}
509513

@@ -554,8 +558,12 @@ impl<Signer: sign::ecdsa::WriteableEcdsaChannelSigner> chainmonitor::Persist<Sig
554558
ret
555559
}
556560

557-
fn prune_persisted_channel(&self, _funding_txo: OutPoint) -> bool {
558-
false
561+
fn archive_persisted_channel(&self, _funding_txo: OutPoint) -> chain::ChannelMonitorUpdateStatus {
562+
unimplemented!()
563+
}
564+
565+
fn remove_persisted_channel(&self, _funding_txo: OutPoint) -> chain::ChannelMonitorUpdateStatus {
566+
unimplemented!()
559567
}
560568
}
561569

0 commit comments

Comments
 (0)