Skip to content

Commit 3333677

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 9f10157 commit 3333677

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
@@ -5665,15 +5665,6 @@ impl<Signer: Sign> Channel<Signer> {
56655665
Ok(Some(res))
56665666
}
56675667

5668-
/// Only fails in case of signer rejection.
5669-
fn send_commitment_no_status_check<L: Deref>(&mut self, logger: &L) -> Result<(msgs::CommitmentSigned, ChannelMonitorUpdate), ChannelError> where L::Target: Logger {
5670-
let monitor_update = self.build_commitment_no_status_check(logger);
5671-
match self.send_commitment_no_state_update(logger) {
5672-
Ok((commitment_signed, _)) => Ok((commitment_signed, monitor_update)),
5673-
Err(e) => Err(e),
5674-
}
5675-
}
5676-
56775668
fn build_commitment_no_status_check<L: Deref>(&mut self, logger: &L) -> ChannelMonitorUpdate where L::Target: Logger {
56785669
log_trace!(logger, "Updating HTLC state for a newly-sent commitment_signed...");
56795670
// We can upgrade the status of some HTLCs that are waiting on a commitment, even if we
@@ -5800,16 +5791,20 @@ impl<Signer: Sign> Channel<Signer> {
58005791
}, (counterparty_commitment_txid, commitment_stats.htlcs_included)))
58015792
}
58025793

5803-
/// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction
5804-
/// to send to the remote peer in one go.
5794+
/// Adds a pending outbound HTLC to this channel, and builds a new remote commitment
5795+
/// transaction and generates the corresponding [`ChannelMonitorUpdate`] in one go.
58055796
///
58065797
/// Shorthand for calling [`Self::send_htlc`] followed by a commitment update, see docs on
5807-
/// [`Self::send_htlc`] and [`Self::send_commitment_no_state_update`] for more info.
5808-
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 {
5809-
match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, false, logger)? {
5810-
Some(update_add_htlc) => {
5811-
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?;
5812-
Ok(Some((update_add_htlc, commitment_signed, monitor_update)))
5798+
/// [`Self::send_htlc`] and [`Self::build_commitment_no_state_update`] for more info.
5799+
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 {
5800+
let send_res = self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, false, logger);
5801+
if let Err(e) = &send_res { if let ChannelError::Ignore(_) = e {} else { debug_assert!(false, "Sending cannot trigger channel failure"); } }
5802+
match send_res? {
5803+
Some(_) => {
5804+
let monitor_update = self.build_commitment_no_status_check(logger);
5805+
self.monitor_updating_paused(false, true, false, Vec::new(), Vec::new(), Vec::new());
5806+
self.pending_monitor_updates.push(monitor_update);
5807+
Ok(Some(self.pending_monitor_updates.last().unwrap()))
58135808
},
58145809
None => Ok(None)
58155810
}

lightning/src/ln/channelmanager.rs

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,6 +2410,7 @@ where
24102410
if !chan.get().is_live() {
24112411
return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!".to_owned()});
24122412
}
2413+
(chan.get().get_funding_txo().unwrap(),
24132414
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(
24142415
htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
24152416
path: path.clone(),
@@ -2420,42 +2421,25 @@ where
24202421
payment_params: payment_params.clone(),
24212422
}, onion_packet, &self.logger),
24222423
chan)
2424+
)
24232425
} {
2424-
Some((update_add, commitment_signed, monitor_update)) => {
2425-
let update_err = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), &monitor_update);
2426-
let chan_id = chan.get().channel_id();
2427-
match (update_err,
2428-
handle_monitor_update_res!(self, update_err, chan,
2429-
RAACommitmentOrder::CommitmentFirst, false, true))
2430-
{
2431-
(ChannelMonitorUpdateStatus::PermanentFailure, Err(e)) => break Err(e),
2432-
(ChannelMonitorUpdateStatus::Completed, Ok(())) => {},
2433-
(ChannelMonitorUpdateStatus::InProgress, Err(_)) => {
2434-
// Note that MonitorUpdateInProgress here indicates (per function
2435-
// docs) that we will resend the commitment update once monitor
2436-
// updating completes. Therefore, we must return an error
2437-
// indicating that it is unsafe to retry the payment wholesale,
2438-
// which we do in the send_payment check for
2439-
// MonitorUpdateInProgress, below.
2440-
return Err(APIError::MonitorUpdateInProgress);
2441-
},
2442-
_ => unreachable!(),
2426+
(funding_txo, Some(monitor_update)) => {
2427+
let update_id = monitor_update.update_id;
2428+
let update_res = self.chain_monitor.update_channel(funding_txo, monitor_update);
2429+
if let Err(e) = handle_new_monitor_update!(self, update_res, update_id, peer_state_lock, peer_state, chan) {
2430+
break Err(e);
2431+
}
2432+
if update_res == ChannelMonitorUpdateStatus::InProgress {
2433+
// Note that MonitorUpdateInProgress here indicates (per function
2434+
// docs) that we will resend the commitment update once monitor
2435+
// updating completes. Therefore, we must return an error
2436+
// indicating that it is unsafe to retry the payment wholesale,
2437+
// which we do in the send_payment check for
2438+
// MonitorUpdateInProgress, below.
2439+
return Err(APIError::MonitorUpdateInProgress);
24432440
}
2444-
2445-
log_debug!(self.logger, "Sending payment along path resulted in a commitment_signed for channel {}", log_bytes!(chan_id));
2446-
peer_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
2447-
node_id: path.first().unwrap().pubkey,
2448-
updates: msgs::CommitmentUpdate {
2449-
update_add_htlcs: vec![update_add],
2450-
update_fulfill_htlcs: Vec::new(),
2451-
update_fail_htlcs: Vec::new(),
2452-
update_fail_malformed_htlcs: Vec::new(),
2453-
update_fee: None,
2454-
commitment_signed,
2455-
},
2456-
});
24572441
},
2458-
None => { },
2442+
(_, None) => { },
24592443
}
24602444
} else {
24612445
// The channel was likely removed after we fetched the id from the

0 commit comments

Comments
 (0)