Skip to content

Commit 63e6b80

Browse files
committed
Make it harder to forget to call CM::process_background_events
Prior to any actions which may generate a `ChannelMonitorUpdate`, and in general after startup, `ChannelManager::process_background_events` must be called. This is mostly accomplished by doing so on taking the `total_consistency_lock` via the `PersistenceNotifierGuard`. In order to skip this call in block connection logic, the `PersistenceNotifierGuard::optionally_notify` constructor did not call the `process_background_events` method. However, this is very easy to misuse - `optionally_notify` does not convey to the reader that they need to call `process_background_events` at all. Here we fix this by adding a separate `optionally_notify_skipping_background_events` method, making the requirements much clearer to callers.
1 parent c2aee57 commit 63e6b80

File tree

1 file changed

+33
-19
lines changed

1 file changed

+33
-19
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,21 +1236,32 @@ struct PersistenceNotifierGuard<'a, F: Fn() -> NotifyOption> {
12361236

12371237
impl<'a> PersistenceNotifierGuard<'a, fn() -> NotifyOption> { // We don't care what the concrete F is here, it's unused
12381238
fn notify_on_drop<C: AChannelManager>(cm: &'a C) -> PersistenceNotifierGuard<'a, impl Fn() -> NotifyOption> {
1239+
Self::optionally_notify(cm, || -> NotifyOption { NotifyOption::DoPersist })
1240+
}
1241+
1242+
fn optionally_notify<F: Fn() -> NotifyOption, C: AChannelManager>(cm: &'a C, persist_check: F)
1243+
-> PersistenceNotifierGuard<'a, impl Fn() -> NotifyOption> {
12391244
let read_guard = cm.get_cm().total_consistency_lock.read().unwrap();
1240-
let _ = cm.get_cm().process_background_events(); // We always persist
1245+
let force_notify = cm.get_cm().process_background_events();
12411246

12421247
PersistenceNotifierGuard {
12431248
event_persist_notifier: &cm.get_cm().event_persist_notifier,
1244-
should_persist: || -> NotifyOption { NotifyOption::DoPersist },
1249+
should_persist: move || {
1250+
// Pick the "most" action between `persist_check` and the background events
1251+
// processing and return that.
1252+
let notify = persist_check();
1253+
if force_notify == NotifyOption::DoPersist { NotifyOption::DoPersist }
1254+
else { notify }
1255+
},
12451256
_read_guard: read_guard,
12461257
}
1247-
12481258
}
12491259

12501260
/// Note that if any [`ChannelMonitorUpdate`]s are possibly generated,
1251-
/// [`ChannelManager::process_background_events`] MUST be called first.
1252-
fn optionally_notify<F: Fn() -> NotifyOption, C: AChannelManager>(cm: &'a C, persist_check: F)
1253-
-> PersistenceNotifierGuard<'a, F> {
1261+
/// [`ChannelManager::process_background_events`] MUST be called first (or
1262+
/// [`Self::optionally_notify`] used).
1263+
fn optionally_notify_skipping_background_events<F: Fn() -> NotifyOption, C: AChannelManager>
1264+
(cm: &'a C, persist_check: F) -> PersistenceNotifierGuard<'a, F> {
12541265
let read_guard = cm.get_cm().total_consistency_lock.read().unwrap();
12551266

12561267
PersistenceNotifierGuard {
@@ -4424,7 +4435,7 @@ where
44244435
/// it wants to detect). Thus, we have a variant exposed here for its benefit.
44254436
pub fn maybe_update_chan_fees(&self) {
44264437
PersistenceNotifierGuard::optionally_notify(self, || {
4427-
let mut should_persist = self.process_background_events();
4438+
let mut should_persist = NotifyOption::SkipPersist;
44284439

44294440
let normal_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
44304441
let min_mempool_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::MempoolMinimum);
@@ -4469,7 +4480,7 @@ where
44694480
/// [`ChannelConfig`]: crate::util::config::ChannelConfig
44704481
pub fn timer_tick_occurred(&self) {
44714482
PersistenceNotifierGuard::optionally_notify(self, || {
4472-
let mut should_persist = self.process_background_events();
4483+
let mut should_persist = NotifyOption::SkipPersist;
44734484

44744485
let normal_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
44754486
let min_mempool_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::MempoolMinimum);
@@ -7002,7 +7013,7 @@ where
70027013
fn get_and_clear_pending_msg_events(&self) -> Vec<MessageSendEvent> {
70037014
let events = RefCell::new(Vec::new());
70047015
PersistenceNotifierGuard::optionally_notify(self, || {
7005-
let mut result = self.process_background_events();
7016+
let mut result = NotifyOption::SkipPersist;
70067017

70077018
// TODO: This behavior should be documented. It's unintuitive that we query
70087019
// ChannelMonitors when clearing other events.
@@ -7083,8 +7094,9 @@ where
70837094
}
70847095

70857096
fn block_disconnected(&self, header: &BlockHeader, height: u32) {
7086-
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self,
7087-
|| -> NotifyOption { NotifyOption::DoPersist });
7097+
let _persistence_guard =
7098+
PersistenceNotifierGuard::optionally_notify_skipping_background_events(
7099+
self, || -> NotifyOption { NotifyOption::DoPersist });
70887100
let new_height = height - 1;
70897101
{
70907102
let mut best_block = self.best_block.write().unwrap();
@@ -7118,8 +7130,9 @@ where
71187130
let block_hash = header.block_hash();
71197131
log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height);
71207132

7121-
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self,
7122-
|| -> NotifyOption { NotifyOption::DoPersist });
7133+
let _persistence_guard =
7134+
PersistenceNotifierGuard::optionally_notify_skipping_background_events(
7135+
self, || -> NotifyOption { NotifyOption::DoPersist });
71237136
self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, self.genesis_hash.clone(), &self.node_signer, &self.default_configuration, &self.logger)
71247137
.map(|(a, b)| (a, Vec::new(), b)));
71257138

@@ -7138,8 +7151,9 @@ where
71387151
let block_hash = header.block_hash();
71397152
log_trace!(self.logger, "New best block: {} at height {}", block_hash, height);
71407153

7141-
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self,
7142-
|| -> NotifyOption { NotifyOption::DoPersist });
7154+
let _persistence_guard =
7155+
PersistenceNotifierGuard::optionally_notify_skipping_background_events(
7156+
self, || -> NotifyOption { NotifyOption::DoPersist });
71437157
*self.best_block.write().unwrap() = BestBlock::new(block_hash, height);
71447158

71457159
self.do_chain_event(Some(height), |channel| channel.best_block_updated(height, header.time, self.genesis_hash.clone(), &self.node_signer, &self.default_configuration, &self.logger));
@@ -7182,8 +7196,9 @@ where
71827196
}
71837197

71847198
fn transaction_unconfirmed(&self, txid: &Txid) {
7185-
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self,
7186-
|| -> NotifyOption { NotifyOption::DoPersist });
7199+
let _persistence_guard =
7200+
PersistenceNotifierGuard::optionally_notify_skipping_background_events(
7201+
self, || -> NotifyOption { NotifyOption::DoPersist });
71877202
self.do_chain_event(None, |channel| {
71887203
if let Some(funding_txo) = channel.context.get_funding_txo() {
71897204
if funding_txo.txid == *txid {
@@ -7522,9 +7537,8 @@ where
75227537

75237538
fn handle_channel_update(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelUpdate) {
75247539
PersistenceNotifierGuard::optionally_notify(self, || {
7525-
let force_persist = self.process_background_events();
75267540
if let Ok(persist) = handle_error!(self, self.internal_channel_update(counterparty_node_id, msg), *counterparty_node_id) {
7527-
if force_persist == NotifyOption::DoPersist { NotifyOption::DoPersist } else { persist }
7541+
persist
75287542
} else {
75297543
NotifyOption::SkipPersist
75307544
}

0 commit comments

Comments
 (0)