Move a handful of channel messages to notify-without-persist

Many channel related messages don't actually change the channel
state in a way that changes the persisted channel. For example,
an `update_add_htlc` or `update_fail_htlc` message simply adds the
change to a queue, changing the channel state when we receive a
`commitment_signed` message.

In these cases there's really no reason to wake the background
processor at all - there's no response message and there's no state
update. However, note that if we close the channel we should
persist the `ChannelManager`. If we send an error message without
closing the channel, we should wake the background processor
without persisting.

Here we move to the appropriate `NotifyOption` on some of the
simpler channel message handlers.
This commit is contained in:
Matt Corallo 2023-08-24 19:36:58 +00:00
parent 305df1d7da
commit 71bafecafc

View File

@ -494,6 +494,10 @@ impl MsgHandleErrInternal {
channel_capacity: None,
}
}
fn closes_channel(&self) -> bool {
self.chan_id.is_some()
}
}
/// We hold back HTLCs we intend to relay for a random interval greater than this (see
@ -1238,6 +1242,12 @@ struct PersistenceNotifierGuard<'a, F: Fn() -> NotifyOption> {
}
impl<'a> PersistenceNotifierGuard<'a, fn() -> NotifyOption> { // We don't care what the concrete F is here, it's unused
/// Notifies any waiters and indicates that we need to persist, in addition to possibly having
/// events to handle.
///
/// This must always be called if the changes included a `ChannelMonitorUpdate`, as well as in
/// other cases where losing the changes on restart may result in a force-close or otherwise
/// isn't ideal.
fn notify_on_drop<C: AChannelManager>(cm: &'a C) -> PersistenceNotifierGuard<'a, impl Fn() -> NotifyOption> {
Self::optionally_notify(cm, || -> NotifyOption { NotifyOption::DoPersist })
}
@ -2152,9 +2162,14 @@ macro_rules! process_events_body {
processed_all_events = false;
}
if result == NotifyOption::DoPersist {
$self.needs_persist_flag.store(true, Ordering::Release);
$self.event_persist_notifier.notify();
match result {
NotifyOption::DoPersist => {
$self.needs_persist_flag.store(true, Ordering::Release);
$self.event_persist_notifier.notify();
},
NotifyOption::SkipPersistHandleEvents =>
$self.event_persist_notifier.notify(),
NotifyOption::SkipPersistNoEvents => {},
}
}
}
@ -5560,6 +5575,8 @@ where
}
fn internal_open_channel(&self, counterparty_node_id: &PublicKey, msg: &msgs::OpenChannel) -> Result<(), MsgHandleErrInternal> {
// Note that the ChannelManager is NOT re-persisted on disk after this, so any changes are
// likely to be lost on restart!
if msg.chain_hash != self.genesis_hash {
return Err(MsgHandleErrInternal::send_err_msg_no_close("Unknown genesis block hash".to_owned(), msg.temporary_channel_id.clone()));
}
@ -5659,6 +5676,8 @@ where
}
fn internal_accept_channel(&self, counterparty_node_id: &PublicKey, msg: &msgs::AcceptChannel) -> Result<(), MsgHandleErrInternal> {
// Note that the ChannelManager is NOT re-persisted on disk after this, so any changes are
// likely to be lost on restart!
let (value, output_script, user_id) = {
let per_peer_state = self.per_peer_state.read().unwrap();
let peer_state_mutex = per_peer_state.get(counterparty_node_id)
@ -5819,6 +5838,8 @@ where
}
fn internal_channel_ready(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReady) -> Result<(), MsgHandleErrInternal> {
// Note that the ChannelManager is NOT re-persisted on disk after this (unless we error
// closing a channel), so any changes are likely to be lost on restart!
let per_peer_state = self.per_peer_state.read().unwrap();
let peer_state_mutex = per_peer_state.get(counterparty_node_id)
.ok_or_else(|| {
@ -5997,6 +6018,9 @@ where
//encrypted with the same key. It's not immediately obvious how to usefully exploit that,
//but we should prevent it anyway.
// Note that the ChannelManager is NOT re-persisted on disk after this (unless we error
// closing a channel), so any changes are likely to be lost on restart!
let decoded_hop_res = self.decode_update_add_htlc_onion(msg);
let per_peer_state = self.per_peer_state.read().unwrap();
let peer_state_mutex = per_peer_state.get(counterparty_node_id)
@ -6078,6 +6102,8 @@ where
}
fn internal_update_fail_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFailHTLC) -> Result<(), MsgHandleErrInternal> {
// Note that the ChannelManager is NOT re-persisted on disk after this (unless we error
// closing a channel), so any changes are likely to be lost on restart!
let per_peer_state = self.per_peer_state.read().unwrap();
let peer_state_mutex = per_peer_state.get(counterparty_node_id)
.ok_or_else(|| {
@ -6101,6 +6127,8 @@ where
}
fn internal_update_fail_malformed_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFailMalformedHTLC) -> Result<(), MsgHandleErrInternal> {
// Note that the ChannelManager is NOT re-persisted on disk after this (unless we error
// closing a channel), so any changes are likely to be lost on restart!
let per_peer_state = self.per_peer_state.read().unwrap();
let peer_state_mutex = per_peer_state.get(counterparty_node_id)
.ok_or_else(|| {
@ -7476,8 +7504,21 @@ where
L::Target: Logger,
{
fn handle_open_channel(&self, counterparty_node_id: &PublicKey, msg: &msgs::OpenChannel) {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
let _ = handle_error!(self, self.internal_open_channel(counterparty_node_id, msg), *counterparty_node_id);
// Note that we never need to persist the updated ChannelManager for an inbound
// open_channel message - pre-funded channels are never written so there should be no
// change to the contents.
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
let res = self.internal_open_channel(counterparty_node_id, msg);
let persist = match &res {
Err(e) if e.closes_channel() => {
debug_assert!(false, "We shouldn't close a new channel");
NotifyOption::DoPersist
},
_ => NotifyOption::SkipPersistHandleEvents,
};
let _ = handle_error!(self, res, *counterparty_node_id);
persist
});
}
fn handle_open_channel_v2(&self, counterparty_node_id: &PublicKey, msg: &msgs::OpenChannelV2) {
@ -7487,8 +7528,13 @@ where
}
fn handle_accept_channel(&self, counterparty_node_id: &PublicKey, msg: &msgs::AcceptChannel) {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
let _ = handle_error!(self, self.internal_accept_channel(counterparty_node_id, msg), *counterparty_node_id);
// Note that we never need to persist the updated ChannelManager for an inbound
// accept_channel message - pre-funded channels are never written so there should be no
// change to the contents.
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
let _ = handle_error!(self, self.internal_accept_channel(counterparty_node_id, msg), *counterparty_node_id);
NotifyOption::SkipPersistHandleEvents
});
}
fn handle_accept_channel_v2(&self, counterparty_node_id: &PublicKey, msg: &msgs::AcceptChannelV2) {
@ -7508,8 +7554,19 @@ where
}
fn handle_channel_ready(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReady) {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
let _ = handle_error!(self, self.internal_channel_ready(counterparty_node_id, msg), *counterparty_node_id);
// Note that we never need to persist the updated ChannelManager for an inbound
// channel_ready message - while the channel's state will change, any channel_ready message
// will ultimately be re-sent on startup and the `ChannelMonitor` won't be updated so we
// will not force-close the channel on startup.
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
let res = self.internal_channel_ready(counterparty_node_id, msg);
let persist = match &res {
Err(e) if e.closes_channel() => NotifyOption::DoPersist,
_ => NotifyOption::SkipPersistHandleEvents,
};
let _ = handle_error!(self, res, *counterparty_node_id);
persist
});
}
fn handle_shutdown(&self, counterparty_node_id: &PublicKey, msg: &msgs::Shutdown) {
@ -7523,8 +7580,19 @@ where
}
fn handle_update_add_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateAddHTLC) {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
let _ = handle_error!(self, self.internal_update_add_htlc(counterparty_node_id, msg), *counterparty_node_id);
// Note that we never need to persist the updated ChannelManager for an inbound
// update_add_htlc message - the message itself doesn't change our channel state only the
// `commitment_signed` message afterwards will.
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
let res = self.internal_update_add_htlc(counterparty_node_id, msg);
let persist = match &res {
Err(e) if e.closes_channel() => NotifyOption::DoPersist,
Err(_) => NotifyOption::SkipPersistHandleEvents,
Ok(()) => NotifyOption::SkipPersistNoEvents,
};
let _ = handle_error!(self, res, *counterparty_node_id);
persist
});
}
fn handle_update_fulfill_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFulfillHTLC) {
@ -7533,13 +7601,35 @@ where
}
fn handle_update_fail_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFailHTLC) {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
let _ = handle_error!(self, self.internal_update_fail_htlc(counterparty_node_id, msg), *counterparty_node_id);
// Note that we never need to persist the updated ChannelManager for an inbound
// update_fail_htlc message - the message itself doesn't change our channel state only the
// `commitment_signed` message afterwards will.
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
let res = self.internal_update_fail_htlc(counterparty_node_id, msg);
let persist = match &res {
Err(e) if e.closes_channel() => NotifyOption::DoPersist,
Err(_) => NotifyOption::SkipPersistHandleEvents,
Ok(()) => NotifyOption::SkipPersistNoEvents,
};
let _ = handle_error!(self, res, *counterparty_node_id);
persist
});
}
fn handle_update_fail_malformed_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFailMalformedHTLC) {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
let _ = handle_error!(self, self.internal_update_fail_malformed_htlc(counterparty_node_id, msg), *counterparty_node_id);
// Note that we never need to persist the updated ChannelManager for an inbound
// update_fail_malformed_htlc message - the message itself doesn't change our channel state
// only the `commitment_signed` message afterwards will.
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
let res = self.internal_update_fail_malformed_htlc(counterparty_node_id, msg);
let persist = match &res {
Err(e) if e.closes_channel() => NotifyOption::DoPersist,
Err(_) => NotifyOption::SkipPersistHandleEvents,
Ok(()) => NotifyOption::SkipPersistNoEvents,
};
let _ = handle_error!(self, res, *counterparty_node_id);
persist
});
}
fn handle_commitment_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::CommitmentSigned) {
@ -7553,8 +7643,19 @@ where
}
fn handle_update_fee(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFee) {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
let _ = handle_error!(self, self.internal_update_fee(counterparty_node_id, msg), *counterparty_node_id);
// Note that we never need to persist the updated ChannelManager for an inbound
// update_fee message - the message itself doesn't change our channel state only the
// `commitment_signed` message afterwards will.
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
let res = self.internal_update_fee(counterparty_node_id, msg);
let persist = match &res {
Err(e) if e.closes_channel() => NotifyOption::DoPersist,
Err(_) => NotifyOption::SkipPersistHandleEvents,
Ok(()) => NotifyOption::SkipPersistNoEvents,
};
let _ = handle_error!(self, res, *counterparty_node_id);
persist
});
}
fn handle_announcement_signatures(&self, counterparty_node_id: &PublicKey, msg: &msgs::AnnouncementSignatures) {