Skip to content

Commit b05da8c

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 06e3e96 commit b05da8c

File tree

2 files changed

+27
-49
lines changed

2 files changed

+27
-49
lines changed

lightning/src/ln/channel.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5769,15 +5769,6 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
57695769
Ok(Some(res))
57705770
}
57715771

5772-
/// Only fails in case of signer rejection.
5773-
fn send_commitment_no_status_check<L: Deref>(&mut self, logger: &L) -> Result<(msgs::CommitmentSigned, ChannelMonitorUpdate), ChannelError> where L::Target: Logger {
5774-
let monitor_update = self.build_commitment_no_status_check(logger);
5775-
match self.send_commitment_no_state_update(logger) {
5776-
Ok((commitment_signed, _)) => Ok((commitment_signed, monitor_update)),
5777-
Err(e) => Err(e),
5778-
}
5779-
}
5780-
57815772
fn build_commitment_no_status_check<L: Deref>(&mut self, logger: &L) -> ChannelMonitorUpdate where L::Target: Logger {
57825773
log_trace!(logger, "Updating HTLC state for a newly-sent commitment_signed...");
57835774
// We can upgrade the status of some HTLCs that are waiting on a commitment, even if we
@@ -5903,16 +5894,20 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
59035894
}, (counterparty_commitment_txid, commitment_stats.htlcs_included)))
59045895
}
59055896

5906-
/// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction
5907-
/// to send to the remote peer in one go.
5897+
/// Adds a pending outbound HTLC to this channel, and builds a new remote commitment
5898+
/// transaction and generates the corresponding [`ChannelMonitorUpdate`] in one go.
59085899
///
59095900
/// Shorthand for calling [`Self::send_htlc`] followed by a commitment update, see docs on
5910-
/// [`Self::send_htlc`] and [`Self::send_commitment_no_state_update`] for more info.
5911-
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 {
5912-
match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, false, logger)? {
5913-
Some(update_add_htlc) => {
5914-
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?;
5915-
Ok(Some((update_add_htlc, commitment_signed, monitor_update)))
5901+
/// [`Self::send_htlc`] and [`Self::build_commitment_no_state_update`] for more info.
5902+
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 {
5903+
let send_res = self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, false, logger);
5904+
if let Err(e) = &send_res { if let ChannelError::Ignore(_) = e {} else { debug_assert!(false, "Sending cannot trigger channel failure"); } }
5905+
match send_res? {
5906+
Some(_) => {
5907+
let monitor_update = self.build_commitment_no_status_check(logger);
5908+
self.monitor_updating_paused(false, true, false, Vec::new(), Vec::new(), Vec::new());
5909+
self.pending_monitor_updates.push(monitor_update);
5910+
Ok(Some(self.pending_monitor_updates.last().unwrap()))
59165911
},
59175912
None => Ok(None)
59185913
}

lightning/src/ln/channelmanager.rs

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2482,6 +2482,7 @@ where
24822482
if !chan.get().is_live() {
24832483
return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected".to_owned()});
24842484
}
2485+
let funding_txo = chan.get().get_funding_txo().unwrap();
24852486
match {
24862487
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(
24872488
htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
@@ -2494,39 +2495,21 @@ where
24942495
}, onion_packet, &self.logger),
24952496
chan)
24962497
} {
2497-
Some((update_add, commitment_signed, monitor_update)) => {
2498-
let update_err = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), &monitor_update);
2499-
let chan_id = chan.get().channel_id();
2500-
match (update_err,
2501-
handle_monitor_update_res!(self, update_err, chan,
2502-
RAACommitmentOrder::CommitmentFirst, false, true))
2503-
{
2504-
(ChannelMonitorUpdateStatus::PermanentFailure, Err(e)) => break Err(e),
2505-
(ChannelMonitorUpdateStatus::Completed, Ok(())) => {},
2506-
(ChannelMonitorUpdateStatus::InProgress, Err(_)) => {
2507-
// Note that MonitorUpdateInProgress here indicates (per function
2508-
// docs) that we will resend the commitment update once monitor
2509-
// updating completes. Therefore, we must return an error
2510-
// indicating that it is unsafe to retry the payment wholesale,
2511-
// which we do in the send_payment check for
2512-
// MonitorUpdateInProgress, below.
2513-
return Err(APIError::MonitorUpdateInProgress);
2514-
},
2515-
_ => unreachable!(),
2498+
Some(monitor_update) => {
2499+
let update_id = monitor_update.update_id;
2500+
let update_res = self.chain_monitor.update_channel(funding_txo, monitor_update);
2501+
if let Err(e) = handle_new_monitor_update!(self, update_res, update_id, peer_state_lock, peer_state, chan) {
2502+
break Err(e);
2503+
}
2504+
if update_res == ChannelMonitorUpdateStatus::InProgress {
2505+
// Note that MonitorUpdateInProgress here indicates (per function
2506+
// docs) that we will resend the commitment update once monitor
2507+
// updating completes. Therefore, we must return an error
2508+
// indicating that it is unsafe to retry the payment wholesale,
2509+
// which we do in the send_payment check for
2510+
// MonitorUpdateInProgress, below.
2511+
return Err(APIError::MonitorUpdateInProgress);
25162512
}
2517-
2518-
log_debug!(self.logger, "Sending payment along path resulted in a commitment_signed for channel {}", log_bytes!(chan_id));
2519-
peer_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
2520-
node_id: path.first().unwrap().pubkey,
2521-
updates: msgs::CommitmentUpdate {
2522-
update_add_htlcs: vec![update_add],
2523-
update_fulfill_htlcs: Vec::new(),
2524-
update_fail_htlcs: Vec::new(),
2525-
update_fail_malformed_htlcs: Vec::new(),
2526-
update_fee: None,
2527-
commitment_signed,
2528-
},
2529-
});
25302513
},
25312514
None => { },
25322515
}

0 commit comments

Comments
 (0)