Skip to content

Commit fd353e5

Browse files
committed
Always process payment send ChannelMonitorUpdates asynchronously
We currently have two codepaths on most channel update functions - most methods return a set of messages to send a peer iff the `ChannelMonitorUpdate` succeeds, but if it does not we push the messages back into the `Channel` and then pull them back out when the `ChannelMonitorUpdate` completes and send them then. This adds a substantial amount of complexity in very critical codepaths. Instead, here we swap all our channel update codepaths to immediately set the channel-update-required flag and only return a `ChannelMonitorUpdate` to the `ChannelManager`. Internally in the `Channel` we store a queue of `ChannelMonitorUpdate`s, which will become critical in future work to surface pending `ChannelMonitorUpdate`s to users at startup so they can complete. This leaves some redundant work in `Channel` to be cleaned up later. Specifically, we still generate the messages which we will now ignore and regenerate later. This commit updates the `ChannelMonitorUpdate` pipeline for HTLC sends originating from an outbound payment.
1 parent aca17c4 commit fd353e5

File tree

2 files changed

+29
-50
lines changed

2 files changed

+29
-50
lines changed

lightning/src/ln/channel.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5635,15 +5635,6 @@ impl<Signer: Sign> Channel<Signer> {
56355635
Ok(Some(res))
56365636
}
56375637

5638-
/// Only fails in case of signer rejection.
5639-
fn send_commitment_no_status_check<L: Deref>(&mut self, logger: &L) -> Result<(msgs::CommitmentSigned, ChannelMonitorUpdate), ChannelError> where L::Target: Logger {
5640-
let monitor_update = self.build_commitment_no_status_check(logger);
5641-
match self.send_commitment_no_state_update(logger) {
5642-
Ok((commitment_signed, _)) => Ok((commitment_signed, monitor_update)),
5643-
Err(e) => Err(e),
5644-
}
5645-
}
5646-
56475638
fn build_commitment_no_status_check<L: Deref>(&mut self, logger: &L) -> ChannelMonitorUpdate where L::Target: Logger {
56485639
log_trace!(logger, "Updating HTLC state for a newly-sent commitment_signed...");
56495640
// We can upgrade the status of some HTLCs that are waiting on a commitment, even if we
@@ -5770,16 +5761,20 @@ impl<Signer: Sign> Channel<Signer> {
57705761
}, (counterparty_commitment_txid, commitment_stats.htlcs_included)))
57715762
}
57725763

5773-
/// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction
5774-
/// to send to the remote peer in one go.
5764+
/// Adds a pending outbound HTLC to this channel, and builds a new remote commitment
5765+
/// transaction and generates the corresponding [`ChannelMonitorUpdate`] in one go.
57755766
///
57765767
/// Shorthand for calling [`Self::send_htlc`] followed by a commitment update, see docs on
5777-
/// [`Self::send_htlc`] and [`Self::send_commitment_no_state_update`] for more info.
5778-
pub fn send_htlc_and_commit<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, logger: &L) -> Result<Option<(msgs::UpdateAddHTLC, msgs::CommitmentSigned, ChannelMonitorUpdate)>, ChannelError> where L::Target: Logger {
5779-
match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, false, logger)? {
5780-
Some(update_add_htlc) => {
5781-
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?;
5782-
Ok(Some((update_add_htlc, commitment_signed, monitor_update)))
5768+
/// [`Self::send_htlc`] and [`Self::build_commitment_no_state_update`] for more info.
5769+
pub fn send_htlc_and_commit<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, logger: &L) -> Result<Option<&ChannelMonitorUpdate>, ChannelError> where L::Target: Logger {
5770+
let send_res = self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, false, logger);
5771+
if let Err(e) = &send_res { if let ChannelError::Ignore(_) = e {} else { debug_assert!(false, "Sending cannot trigger channel failure"); } }
5772+
match send_res? {
5773+
Some(_) => {
5774+
let monitor_update = self.build_commitment_no_status_check(logger);
5775+
self.monitor_updating_paused(false, true, false, Vec::new(), Vec::new(), Vec::new());
5776+
self.pending_monitor_updates.push(monitor_update);
5777+
Ok(Some(self.pending_monitor_updates.last().unwrap()))
57835778
},
57845779
None => Ok(None)
57855780
}

lightning/src/ln/channelmanager.rs

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,6 +2550,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
25502550
if !chan.get().is_live() {
25512551
return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!".to_owned()});
25522552
}
2553+
(chan.get().get_funding_txo().unwrap(),
25532554
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(
25542555
htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
25552556
path: path.clone(),
@@ -2560,42 +2561,25 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
25602561
payment_params: payment_params.clone(),
25612562
}, onion_packet, &self.logger),
25622563
chan)
2564+
)
25632565
} {
2564-
Some((update_add, commitment_signed, monitor_update)) => {
2565-
let update_err = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), &monitor_update);
2566-
let chan_id = chan.get().channel_id();
2567-
match (update_err,
2568-
handle_monitor_update_res!(self, update_err, chan,
2569-
RAACommitmentOrder::CommitmentFirst, false, true))
2570-
{
2571-
(ChannelMonitorUpdateStatus::PermanentFailure, Err(e)) => break Err(e),
2572-
(ChannelMonitorUpdateStatus::Completed, Ok(())) => {},
2573-
(ChannelMonitorUpdateStatus::InProgress, Err(_)) => {
2574-
// Note that MonitorUpdateInProgress here indicates (per function
2575-
// docs) that we will resend the commitment update once monitor
2576-
// updating completes. Therefore, we must return an error
2577-
// indicating that it is unsafe to retry the payment wholesale,
2578-
// which we do in the send_payment check for
2579-
// MonitorUpdateInProgress, below.
2580-
return Err(APIError::MonitorUpdateInProgress);
2581-
},
2582-
_ => unreachable!(),
2566+
(funding_txo, Some(monitor_update)) => {
2567+
let update_id = monitor_update.update_id;
2568+
let update_res = self.chain_monitor.update_channel(funding_txo, monitor_update);
2569+
if let Err(e) = handle_new_monitor_update!(self, update_res, update_id, channel_lock, channel_state.pending_msg_events, chan) {
2570+
break Err(e);
2571+
}
2572+
if update_res == ChannelMonitorUpdateStatus::InProgress {
2573+
// Note that MonitorUpdateInProgress here indicates (per function
2574+
// docs) that we will resend the commitment update once monitor
2575+
// updating completes. Therefore, we must return an error
2576+
// indicating that it is unsafe to retry the payment wholesale,
2577+
// which we do in the send_payment check for
2578+
// MonitorUpdateInProgress, below.
2579+
return Err(APIError::MonitorUpdateInProgress);
25832580
}
2584-
2585-
log_debug!(self.logger, "Sending payment along path resulted in a commitment_signed for channel {}", log_bytes!(chan_id));
2586-
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
2587-
node_id: path.first().unwrap().pubkey,
2588-
updates: msgs::CommitmentUpdate {
2589-
update_add_htlcs: vec![update_add],
2590-
update_fulfill_htlcs: Vec::new(),
2591-
update_fail_htlcs: Vec::new(),
2592-
update_fail_malformed_htlcs: Vec::new(),
2593-
update_fee: None,
2594-
commitment_signed,
2595-
},
2596-
});
25972581
},
2598-
None => { },
2582+
(_, None) => { },
25992583
}
26002584
} else {
26012585
// The channel was likely removed after we fetched the id from the

0 commit comments

Comments
 (0)