-
Notifications
You must be signed in to change notification settings - Fork 417
Async send always-online counterparty side #4045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
valentinewallace
wants to merge
11
commits into
lightningdevkit:main
Choose a base branch
from
valentinewallace:2025-08-async-send-lsp
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
c41fe2f
Cache peers in OffersMessageFlow
valentinewallace bbe17ed
f remove limits on peer cache
valentinewallace b8258aa
Add UpdateAddHTLC::hold_htlc
valentinewallace f74ce65
Add feature bit for HtlcHold (52/53)
valentinewallace 1653cf2
Add enable_htlc_hold cfg flag + fail hold htlcs
valentinewallace 1878efd
Add RevokeAndACK::release_htlc_message_paths
valentinewallace 324312e
Extract helper for failing HTLC intercepts
valentinewallace 380ac96
Store held htlcs in pending_intercepted_htlcs
valentinewallace c575274
Support creating reply_path for HeldHtlcAvailable
valentinewallace 6c252df
Include release_held_htlc blinded paths in RAA
valentinewallace aeaa42d
Release held htlcs on release_held_htlc
valentinewallace File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -229,6 +229,9 @@ pub enum PendingHTLCRouting { | |
blinded: Option<BlindedForward>, | ||
/// The absolute CLTV of the inbound HTLC | ||
incoming_cltv_expiry: Option<u32>, | ||
/// Whether this HTLC should be held by our node until we receive a corresponding | ||
/// [`ReleaseHeldHtlc`] onion message. | ||
hold_htlc: Option<()>, | ||
}, | ||
/// An HTLC which should be forwarded on to another Trampoline node. | ||
TrampolineForward { | ||
|
@@ -371,6 +374,15 @@ impl PendingHTLCRouting { | |
Self::ReceiveKeysend { incoming_cltv_expiry, .. } => Some(*incoming_cltv_expiry), | ||
} | ||
} | ||
|
||
/// Whether this HTLC should be held by our node until we receive a corresponding | ||
/// [`ReleaseHeldHtlc`] onion message. | ||
fn should_hold_htlc(&self) -> bool { | ||
match self { | ||
Self::Forward { hold_htlc: Some(()), .. } => true, | ||
_ => false, | ||
} | ||
} | ||
} | ||
|
||
/// Information about an incoming HTLC, including the [`PendingHTLCRouting`] describing where it | ||
|
@@ -641,6 +653,34 @@ impl Readable for PaymentId { | |
#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] | ||
pub struct InterceptId(pub [u8; 32]); | ||
|
||
impl InterceptId { | ||
/// This intercept id corresponds to an HTLC that will be forwarded on | ||
/// [`ChannelManager::forward_intercepted_htlc`]. | ||
fn from_incoming_shared_secret(ss: &[u8; 32]) -> Self { | ||
Self(Sha256::hash(ss).to_byte_array()) | ||
} | ||
|
||
/// This intercept id corresponds to an HTLC that will be forwarded on receipt of a | ||
/// [`ReleaseHeldHtlc`] onion message. | ||
fn from_htlc_id_and_chan_id( | ||
htlc_id: u64, channel_id: &ChannelId, counterparty_node_id: &PublicKey, | ||
) -> Self { | ||
let htlc_id_size = core::mem::size_of::<u64>(); | ||
let chan_id_size = core::mem::size_of::<ChannelId>(); | ||
let cp_id_serialized = counterparty_node_id.serialize(); | ||
|
||
const RES_SIZE: usize = 8 + 32 + 33; | ||
debug_assert_eq!(RES_SIZE, htlc_id_size + chan_id_size + cp_id_serialized.len()); | ||
|
||
let mut res = [0u8; RES_SIZE]; | ||
res[..htlc_id_size].copy_from_slice(&htlc_id.to_be_bytes()); | ||
res[htlc_id_size..htlc_id_size + chan_id_size].copy_from_slice(&channel_id.0); | ||
res[htlc_id_size + chan_id_size..].copy_from_slice(&cp_id_serialized); | ||
|
||
Self(Sha256::hash(&res[..]).to_byte_array()) | ||
} | ||
} | ||
|
||
impl Writeable for InterceptId { | ||
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> { | ||
self.0.write(w) | ||
|
@@ -2588,8 +2628,14 @@ pub struct ChannelManager< | |
pub(super) forward_htlcs: Mutex<HashMap<u64, Vec<HTLCForwardInfo>>>, | ||
#[cfg(not(test))] | ||
forward_htlcs: Mutex<HashMap<u64, Vec<HTLCForwardInfo>>>, | ||
/// Storage for HTLCs that have been intercepted and bubbled up to the user. We hold them here | ||
/// until the user tells us what we should do with them. | ||
/// Storage for HTLCs that have been intercepted. | ||
/// | ||
/// These HTLCs fall into two categories: | ||
/// 1. HTLCs that are bubbled up to the user and held until the invocation of | ||
/// [`ChannelManager::forward_intercepted_htlc`] or [`ChannelManager::fail_intercepted_htlc`] | ||
/// (or timeout) | ||
/// 2. HTLCs that are being held on behalf of an often-offline sender until receipt of a | ||
/// [`ReleaseHeldHtlc`] onion message from an often-offline recipient | ||
/// | ||
/// See `ChannelManager` struct-level documentation for lock order requirements. | ||
pending_intercepted_htlcs: Mutex<HashMap<InterceptId, PendingAddHTLCInfo>>, | ||
|
@@ -6268,13 +6314,18 @@ where | |
})?; | ||
|
||
let routing = match payment.forward_info.routing { | ||
PendingHTLCRouting::Forward { onion_packet, blinded, incoming_cltv_expiry, .. } => { | ||
PendingHTLCRouting::Forward { | ||
onion_packet, | ||
blinded, | ||
incoming_cltv_expiry, | ||
short_channel_id: next_hop_scid, | ||
} | ||
PendingHTLCRouting::Forward { | ||
onion_packet, | ||
blinded, | ||
incoming_cltv_expiry, | ||
hold_htlc, | ||
.. | ||
} => PendingHTLCRouting::Forward { | ||
onion_packet, | ||
blinded, | ||
incoming_cltv_expiry, | ||
hold_htlc, | ||
short_channel_id: next_hop_scid, | ||
}, | ||
_ => unreachable!(), // Only `PendingHTLCRouting::Forward`s are intercepted | ||
}; | ||
|
@@ -10682,7 +10733,25 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ | |
}; | ||
match forward_htlcs.entry(scid) { | ||
hash_map::Entry::Occupied(mut entry) => { | ||
entry.get_mut().push(HTLCForwardInfo::AddHTLC(pending_add)); | ||
if pending_add.forward_info.routing.should_hold_htlc() { | ||
let intercept_id = InterceptId::from_htlc_id_and_chan_id( | ||
prev_htlc_id, | ||
&prev_channel_id, | ||
&prev_counterparty_node_id, | ||
); | ||
let mut held_htlcs = self.pending_intercepted_htlcs.lock().unwrap(); | ||
match held_htlcs.entry(intercept_id) { | ||
hash_map::Entry::Vacant(entry) => { | ||
entry.insert(pending_add); | ||
}, | ||
hash_map::Entry::Occupied(_) => { | ||
debug_assert!(false, "Should never have two HTLCs with the same channel id and htlc id"); | ||
fail_intercepted_htlc(); | ||
}, | ||
} | ||
} else { | ||
entry.get_mut().push(HTLCForwardInfo::AddHTLC(pending_add)); | ||
} | ||
}, | ||
hash_map::Entry::Vacant(entry) => { | ||
if !is_our_scid | ||
|
@@ -10692,9 +10761,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ | |
scid, | ||
&self.chain_hash, | ||
) { | ||
let intercept_id = InterceptId( | ||
Sha256::hash(&pending_add.forward_info.incoming_shared_secret) | ||
.to_byte_array(), | ||
let intercept_id = InterceptId::from_incoming_shared_secret( | ||
&pending_add.forward_info.incoming_shared_secret, | ||
); | ||
let mut pending_intercepts = | ||
self.pending_intercepted_htlcs.lock().unwrap(); | ||
|
@@ -10732,6 +10800,22 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ | |
fail_intercepted_htlc(); | ||
}, | ||
} | ||
} else if pending_add.forward_info.routing.should_hold_htlc() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicated code. I know that Rust isn't very inviting towards reusing code... |
||
let intercept_id = InterceptId::from_htlc_id_and_chan_id( | ||
prev_htlc_id, | ||
&prev_channel_id, | ||
&prev_counterparty_node_id, | ||
); | ||
let mut held_htlcs = self.pending_intercepted_htlcs.lock().unwrap(); | ||
match held_htlcs.entry(intercept_id) { | ||
hash_map::Entry::Vacant(entry) => { | ||
entry.insert(pending_add); | ||
}, | ||
hash_map::Entry::Occupied(_) => { | ||
debug_assert!(false, "Should never have two HTLCs with the same channel id and htlc id"); | ||
fail_intercepted_htlc(); | ||
}, | ||
} | ||
} else { | ||
entry.insert(vec![HTLCForwardInfo::AddHTLC(pending_add)]); | ||
} | ||
|
@@ -14850,6 +14934,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, | |
(1, blinded, option), | ||
(2, short_channel_id, required), | ||
(3, incoming_cltv_expiry, option), | ||
(5, hold_htlc, option), | ||
}, | ||
(1, Receive) => { | ||
(0, payment_data, required), | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.