Skip to content

Commit 35fe23a

Browse files
Send held_htlc_available with counterparty reply path
As part of supporting sending payments as an often-offline sender, the sender needs to send held_htlc_available onion messages such that the reply path to the message terminates at their always-online channel counterparty that is holding the HTLC. That way when the recipient responds with release_held_htlc, the sender's counterparty will receive that message. After laying groundwork over some past commits, here we as an async sender send held_htlc_available messages using reply paths created by our always-online channel counterparty.
1 parent 6e8efb6 commit 35fe23a

File tree

2 files changed

+50
-6
lines changed

2 files changed

+50
-6
lines changed

lightning/src/ln/channel.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ use crate::ln::script::{self, ShutdownScript};
7979
use crate::ln::types::ChannelId;
8080
#[cfg(splicing)]
8181
use crate::ln::LN_MAX_MSG_LEN;
82+
use crate::offers::static_invoice::StaticInvoice;
8283
use crate::routing::gossip::NodeId;
8384
use crate::sign::ecdsa::EcdsaChannelSigner;
8485
use crate::sign::tx_builder::{HTLCAmountDirection, NextCommitmentStats, SpecTxBuilder, TxBuilder};
@@ -7992,10 +7993,25 @@ where
79927993
/// waiting on this revoke_and_ack. The generation of this new commitment_signed may also fail,
79937994
/// generating an appropriate error *after* the channel state has been updated based on the
79947995
/// revoke_and_ack message.
7996+
///
7997+
/// The static invoices will be used by us as an async sender to enqueue [`HeldHtlcAvailable`]
7998+
/// onion messages for the often-offline recipient, and the blinded reply paths the invoices are
7999+
/// paired with were created by our channel counterparty and will be used as reply paths for
8000+
/// corresponding [`ReleaseHeldHtlc`] messages.
8001+
///
8002+
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
8003+
/// [`ReleaseHeldHtlc`]: crate::onion_message::async_payments::ReleaseHeldHtlc
79958004
pub fn revoke_and_ack<F: Deref, L: Deref>(
79968005
&mut self, msg: &msgs::RevokeAndACK, fee_estimator: &LowerBoundedFeeEstimator<F>,
79978006
logger: &L, hold_mon_update: bool,
7998-
) -> Result<(Vec<(HTLCSource, PaymentHash)>, Option<ChannelMonitorUpdate>), ChannelError>
8007+
) -> Result<
8008+
(
8009+
Vec<(HTLCSource, PaymentHash)>,
8010+
Vec<(StaticInvoice, BlindedMessagePath)>,
8011+
Option<ChannelMonitorUpdate>,
8012+
),
8013+
ChannelError,
8014+
>
79998015
where
80008016
F::Target: FeeEstimator,
80018017
L::Target: Logger,
@@ -8110,6 +8126,7 @@ where
81108126
let mut finalized_claimed_htlcs = Vec::new();
81118127
let mut update_fail_htlcs = Vec::new();
81128128
let mut update_fail_malformed_htlcs = Vec::new();
8129+
let mut static_invoices = Vec::new();
81138130
let mut require_commitment = false;
81148131
let mut value_to_self_msat_diff: i64 = 0;
81158132

@@ -8225,6 +8242,20 @@ where
82258242
}
82268243
}
82278244
for htlc in pending_outbound_htlcs.iter_mut() {
8245+
for (htlc_id, blinded_path) in &msg.release_htlc_message_paths {
8246+
if htlc.htlc_id != *htlc_id {
8247+
continue;
8248+
}
8249+
let static_invoice = match htlc.source.static_invoice() {
8250+
Some(inv) => inv,
8251+
None => {
8252+
// This is reachable but it means the counterparty is buggy and included a release
8253+
// path for an HTLC that we didn't originally flag as a hold_htlc.
8254+
continue;
8255+
},
8256+
};
8257+
static_invoices.push((static_invoice, blinded_path.clone()));
8258+
}
82288259
if let OutboundHTLCState::LocalAnnounced(_) = htlc.state {
82298260
log_trace!(
82308261
logger,
@@ -8292,9 +8323,9 @@ where
82928323
self.context
82938324
.blocked_monitor_updates
82948325
.push(PendingChannelMonitorUpdate { update: monitor_update });
8295-
return Ok(($htlcs_to_fail, None));
8326+
return Ok(($htlcs_to_fail, static_invoices, None));
82968327
} else {
8297-
return Ok(($htlcs_to_fail, Some(monitor_update)));
8328+
return Ok(($htlcs_to_fail, static_invoices, Some(monitor_update)));
82988329
}
82998330
};
83008331
}

lightning/src/ln/channelmanager.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,16 @@ impl HTLCSource {
839839
_ => false,
840840
}
841841
}
842+
843+
pub(crate) fn static_invoice(&self) -> Option<StaticInvoice> {
844+
match self {
845+
Self::OutboundRoute {
846+
bolt12_invoice: Some(PaidBolt12Invoice::StaticInvoice(inv)),
847+
..
848+
} => Some(inv.clone()),
849+
_ => None,
850+
}
851+
}
842852
}
843853

844854
/// This enum is used to specify which error data to send to peers when failing back an HTLC
@@ -10946,7 +10956,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1094610956

1094710957
#[rustfmt::skip]
1094810958
fn internal_revoke_and_ack(&self, counterparty_node_id: &PublicKey, msg: &msgs::RevokeAndACK) -> Result<(), MsgHandleErrInternal> {
10949-
let htlcs_to_fail = {
10959+
let (htlcs_to_fail, static_invoices) = {
1095010960
let per_peer_state = self.per_peer_state.read().unwrap();
1095110961
let mut peer_state_lock = per_peer_state.get(counterparty_node_id)
1095210962
.ok_or_else(|| {
@@ -10962,15 +10972,15 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1096210972
let mon_update_blocked = self.raa_monitor_updates_held(
1096310973
&peer_state.actions_blocking_raa_monitor_updates, msg.channel_id,
1096410974
*counterparty_node_id);
10965-
let (htlcs_to_fail, monitor_update_opt) = try_channel_entry!(self, peer_state,
10975+
let (htlcs_to_fail, static_invoices, monitor_update_opt) = try_channel_entry!(self, peer_state,
1096610976
chan.revoke_and_ack(&msg, &self.fee_estimator, &&logger, mon_update_blocked), chan_entry);
1096710977
if let Some(monitor_update) = monitor_update_opt {
1096810978
let funding_txo = funding_txo_opt
1096910979
.expect("Funding outpoint must have been set for RAA handling to succeed");
1097010980
handle_new_monitor_update!(self, funding_txo, monitor_update,
1097110981
peer_state_lock, peer_state, per_peer_state, chan);
1097210982
}
10973-
htlcs_to_fail
10983+
(htlcs_to_fail, static_invoices)
1097410984
} else {
1097510985
return try_channel_entry!(self, peer_state, Err(ChannelError::close(
1097610986
"Got a revoke_and_ack message for an unfunded channel!".into())), chan_entry);
@@ -10980,6 +10990,9 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1098010990
}
1098110991
};
1098210992
self.fail_holding_cell_htlcs(htlcs_to_fail, msg.channel_id, counterparty_node_id);
10993+
for (static_invoice, reply_path) in static_invoices {
10994+
self.flow.enqueue_held_htlc_available(&static_invoice, HeldHtlcReplyPath::ToCounterparty { path: reply_path });
10995+
}
1098310996
Ok(())
1098410997
}
1098510998

0 commit comments

Comments
 (0)