Skip to content

Commit ef09096

Browse files
committed
Stop cleaning monitor updates on new block connect
Previously, we used to cleanup monitor updates at both consolidation threshold and new block connects. With this change we will only cleanup when our consolidation criteria is met. Also, we remove monitor read from cleanup logic, in case of update consolidation. Note: In case of channel-closing monitor update, we still need to read the old monitor before persisting the new one in order to determine the cleanup range.
1 parent c2bbfff commit ef09096

File tree

1 file changed

+82
-89
lines changed

1 file changed

+82
-89
lines changed

lightning/src/util/persist.rs

Lines changed: 82 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,10 @@ where
346346
///
347347
/// # Pruning stale channel updates
348348
///
349-
/// Stale updates are pruned when a full monitor is written. The old monitor is first read, and if
350-
/// that succeeds, updates in the range between the old and new monitors are deleted. The `lazy`
351-
/// flag is used on the [`KVStore::remove`] method, so there are no guarantees that the deletions
349+
/// Stale updates are pruned when the consolidation threshold is reached according to `maximum_pending_updates`.
350+
/// Monitor updates in the range between the latest `update_id` and `update_id - maximum_pending_updates`
351+
/// are deleted.
352+
/// The `lazy` flag is used on the [`KVStore::remove`] method, so there are no guarantees that the deletions
352353
/// will complete. However, stale updates are not a problem for data integrity, since updates are
353354
/// only read that are higher than the stored [`ChannelMonitor`]'s `update_id`.
354355
///
@@ -610,24 +611,6 @@ where
610611
) -> chain::ChannelMonitorUpdateStatus {
611612
// Determine the proper key for this monitor
612613
let monitor_name = MonitorName::from(funding_txo);
613-
let maybe_old_monitor = self.read_monitor(&monitor_name);
614-
match maybe_old_monitor {
615-
Ok((_, ref old_monitor)) => {
616-
// Check that this key isn't already storing a monitor with a higher update_id
617-
// (collision)
618-
if old_monitor.get_latest_update_id() > monitor.get_latest_update_id() {
619-
log_error!(
620-
self.logger,
621-
"Tried to write a monitor at the same outpoint {} with a higher update_id!",
622-
monitor_name.as_str()
623-
);
624-
return chain::ChannelMonitorUpdateStatus::UnrecoverableError;
625-
}
626-
}
627-
// This means the channel monitor is new.
628-
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
629-
_ => return chain::ChannelMonitorUpdateStatus::UnrecoverableError,
630-
}
631614
// Serialize and write the new monitor
632615
let mut monitor_bytes = Vec::with_capacity(
633616
MONITOR_UPDATING_PERSISTER_PREPEND_SENTINEL.len() + monitor.serialized_length(),
@@ -641,65 +624,12 @@ where
641624
&monitor_bytes,
642625
) {
643626
Ok(_) => {
644-
// Assess cleanup. Typically, we'll clean up only between the last two known full
645-
// monitors.
646-
if let Ok((_, old_monitor)) = maybe_old_monitor {
647-
let start = old_monitor.get_latest_update_id();
648-
let end = if monitor.get_latest_update_id() == CLOSED_CHANNEL_UPDATE_ID {
649-
// We don't want to clean the rest of u64, so just do possible pending
650-
// updates. Note that we never write updates at
651-
// `CLOSED_CHANNEL_UPDATE_ID`.
652-
cmp::min(
653-
start.saturating_add(self.maximum_pending_updates),
654-
CLOSED_CHANNEL_UPDATE_ID - 1,
655-
)
656-
} else {
657-
monitor.get_latest_update_id().saturating_sub(1)
658-
};
659-
// We should bother cleaning up only if there's at least one update
660-
// expected.
661-
for update_id in start..=end {
662-
let update_name = UpdateName::from(update_id);
663-
#[cfg(debug_assertions)]
664-
{
665-
if let Ok(update) =
666-
self.read_monitor_update(&monitor_name, &update_name)
667-
{
668-
// Assert that we are reading what we think we are.
669-
debug_assert_eq!(update.update_id, update_name.0);
670-
} else if update_id != start && monitor.get_latest_update_id() != CLOSED_CHANNEL_UPDATE_ID
671-
{
672-
// We're deleting something we should know doesn't exist.
673-
panic!(
674-
"failed to read monitor update {}",
675-
update_name.as_str()
676-
);
677-
}
678-
// On closed channels, we will unavoidably try to read
679-
// non-existent updates since we have to guess at the range of
680-
// stale updates, so do nothing.
681-
}
682-
if let Err(e) = self.kv_store.remove(
683-
CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE,
684-
monitor_name.as_str(),
685-
update_name.as_str(),
686-
true,
687-
) {
688-
log_error!(
689-
self.logger,
690-
"error cleaning up channel monitor updates for monitor {}, reason: {}",
691-
monitor_name.as_str(),
692-
e
693-
);
694-
};
695-
}
696-
};
697627
chain::ChannelMonitorUpdateStatus::Completed
698628
}
699629
Err(e) => {
700630
log_error!(
701631
self.logger,
702-
"error writing channel monitor {}/{}/{} reason: {}",
632+
"Failed to write ChannelMonitor {}/{}/{} reason: {}",
703633
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
704634
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
705635
monitor_name.as_str(),
@@ -741,7 +671,7 @@ where
741671
Err(e) => {
742672
log_error!(
743673
self.logger,
744-
"error writing channel monitor update {}/{}/{} reason: {}",
674+
"Failed to write ChannelMonitorUpdate {}/{}/{} reason: {}",
745675
CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE,
746676
monitor_name.as_str(),
747677
update_name.as_str(),
@@ -751,8 +681,41 @@ where
751681
}
752682
}
753683
} else {
754-
// We could write this update, but it meets criteria of our design that call for a full monitor write.
755-
self.persist_new_channel(funding_txo, monitor, monitor_update_call_id)
684+
let monitor_name = MonitorName::from(funding_txo);
685+
// In case of channel-close monitor update, we need to read old monitor before persisting
686+
// the new one in order to determine the cleanup range.
687+
let maybe_old_monitor = match monitor.get_latest_update_id() {
688+
CLOSED_CHANNEL_UPDATE_ID => self.read_monitor(&monitor_name).ok(),
689+
_ => None
690+
};
691+
692+
// We could write this update, but it meets criteria of our design that calls for a full monitor write.
693+
let monitor_update_status = self.persist_new_channel(funding_txo, monitor, monitor_update_call_id);
694+
695+
if let chain::ChannelMonitorUpdateStatus::Completed = monitor_update_status {
696+
let cleanup_range = if monitor.get_latest_update_id() == CLOSED_CHANNEL_UPDATE_ID {
697+
// If there is an error while reading old monitor, we skip clean up.
698+
maybe_old_monitor.map(|(_, ref old_monitor)| {
699+
let start = old_monitor.get_latest_update_id();
700+
// We never persist an update with update_id = CLOSED_CHANNEL_UPDATE_ID
701+
let end = cmp::min(
702+
start.saturating_add(self.maximum_pending_updates),
703+
CLOSED_CHANNEL_UPDATE_ID - 1,
704+
);
705+
(start, end)
706+
})
707+
} else {
708+
let end = monitor.get_latest_update_id();
709+
let start = end.saturating_sub(self.maximum_pending_updates);
710+
Some((start, end))
711+
};
712+
713+
if let Some((start, end)) = cleanup_range {
714+
self.cleanup_in_range(monitor_name, start, end);
715+
}
716+
}
717+
718+
monitor_update_status
756719
}
757720
} else {
758721
// There is no update given, so we must persist a new monitor.
@@ -761,6 +724,34 @@ where
761724
}
762725
}
763726

727+
impl<K: Deref, L: Deref, ES: Deref, SP: Deref> MonitorUpdatingPersister<K, L, ES, SP>
728+
where
729+
ES::Target: EntropySource + Sized,
730+
K::Target: KVStore,
731+
L::Target: Logger,
732+
SP::Target: SignerProvider + Sized
733+
{
734+
// Cleans up monitor updates for given monitor in range `start..=end`.
735+
fn cleanup_in_range(&self, monitor_name: MonitorName, start: u64, end: u64) {
736+
for update_id in start..=end {
737+
let update_name = UpdateName::from(update_id);
738+
if let Err(e) = self.kv_store.remove(
739+
CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE,
740+
monitor_name.as_str(),
741+
update_name.as_str(),
742+
true,
743+
) {
744+
log_error!(
745+
self.logger,
746+
"Failed to clean up channel monitor updates for monitor {}, reason: {}",
747+
monitor_name.as_str(),
748+
e
749+
);
750+
};
751+
}
752+
}
753+
}
754+
764755
/// A struct representing a name for a monitor.
765756
#[derive(Debug)]
766757
struct MonitorName(String);
@@ -896,20 +887,21 @@ mod tests {
896887
#[test]
897888
fn persister_with_real_monitors() {
898889
// This value is used later to limit how many iterations we perform.
899-
let test_max_pending_updates = 7;
890+
let persister_0_max_pending_updates = 7;
891+
// Intentionally set this to a smaller value to test a different alignment.
892+
let persister_1_max_pending_updates = 3;
900893
let chanmon_cfgs = create_chanmon_cfgs(4);
901894
let persister_0 = MonitorUpdatingPersister {
902895
kv_store: &TestStore::new(false),
903896
logger: &TestLogger::new(),
904-
maximum_pending_updates: test_max_pending_updates,
897+
maximum_pending_updates: persister_0_max_pending_updates,
905898
entropy_source: &chanmon_cfgs[0].keys_manager,
906899
signer_provider: &chanmon_cfgs[0].keys_manager,
907900
};
908901
let persister_1 = MonitorUpdatingPersister {
909902
kv_store: &TestStore::new(false),
910903
logger: &TestLogger::new(),
911-
// Intentionally set this to a smaller value to test a different alignment.
912-
maximum_pending_updates: 3,
904+
maximum_pending_updates: persister_1_max_pending_updates,
913905
entropy_source: &chanmon_cfgs[1].keys_manager,
914906
signer_provider: &chanmon_cfgs[1].keys_manager,
915907
};
@@ -934,7 +926,6 @@ mod tests {
934926
node_cfgs[1].chain_monitor = chain_mon_1;
935927
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
936928
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
937-
938929
let broadcaster_0 = &chanmon_cfgs[2].tx_broadcaster;
939930
let broadcaster_1 = &chanmon_cfgs[3].tx_broadcaster;
940931

@@ -957,10 +948,11 @@ mod tests {
957948
for (_, mon) in persisted_chan_data_0.iter() {
958949
// check that when we read it, we got the right update id
959950
assert_eq!(mon.get_latest_update_id(), $expected_update_id);
960-
// if the CM is at the correct update id without updates, ensure no updates are stored
951+
952+
// if the CM is at consolidation threshold, ensure no updates are stored.
961953
let monitor_name = MonitorName::from(mon.get_funding_txo().0);
962-
let (_, cm_0) = persister_0.read_monitor(&monitor_name).unwrap();
963-
if cm_0.get_latest_update_id() == $expected_update_id {
954+
if mon.get_latest_update_id() % persister_0_max_pending_updates == 0
955+
|| mon.get_latest_update_id() == CLOSED_CHANNEL_UPDATE_ID {
964956
assert_eq!(
965957
persister_0.kv_store.list(CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE,
966958
monitor_name.as_str()).unwrap().len(),
@@ -975,8 +967,9 @@ mod tests {
975967
for (_, mon) in persisted_chan_data_1.iter() {
976968
assert_eq!(mon.get_latest_update_id(), $expected_update_id);
977969
let monitor_name = MonitorName::from(mon.get_funding_txo().0);
978-
let (_, cm_1) = persister_1.read_monitor(&monitor_name).unwrap();
979-
if cm_1.get_latest_update_id() == $expected_update_id {
970+
// if the CM is at consolidation threshold, ensure no updates are stored.
971+
if mon.get_latest_update_id() % persister_1_max_pending_updates == 0
972+
|| mon.get_latest_update_id() == CLOSED_CHANNEL_UPDATE_ID {
980973
assert_eq!(
981974
persister_1.kv_store.list(CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE,
982975
monitor_name.as_str()).unwrap().len(),
@@ -1001,7 +994,7 @@ mod tests {
1001994
// Send a few more payments to try all the alignments of max pending updates with
1002995
// updates for a payment sent and received.
1003996
let mut sender = 0;
1004-
for i in 3..=test_max_pending_updates * 2 {
997+
for i in 3..=persister_0_max_pending_updates * 2 {
1005998
let receiver;
1006999
if sender == 0 {
10071000
sender = 1;

0 commit comments

Comments
 (0)