Skip to content

Commit d003a46

Browse files
committed
Introduce Payment Dummy Hop parsing mechanism
1 parent 3425345 commit d003a46

File tree

3 files changed

+114
-28
lines changed

3 files changed

+114
-28
lines changed

lightning/src/blinded_path/payment.rs

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ use crate::util::ser::{
3434
Writeable, Writer,
3535
};
3636

37-
use core::mem;
3837
use core::ops::Deref;
3938

4039
#[allow(unused_imports)]
@@ -219,28 +218,31 @@ impl BlindedPaymentPath {
219218
NL::Target: NodeIdLookUp,
220219
T: secp256k1::Signing + secp256k1::Verification,
221220
{
222-
match self.decrypt_intro_payload::<NS>(node_signer) {
223-
Ok((
224-
BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, .. }),
225-
control_tlvs_ss,
226-
)) => {
227-
let next_node_id = match node_id_lookup.next_node_id(short_channel_id) {
228-
Some(node_id) => node_id,
229-
None => return Err(()),
230-
};
231-
let mut new_blinding_point = onion_utils::next_hop_pubkey(
232-
secp_ctx,
233-
self.inner_path.blinding_point,
234-
control_tlvs_ss.as_ref(),
235-
)
236-
.map_err(|_| ())?;
237-
mem::swap(&mut self.inner_path.blinding_point, &mut new_blinding_point);
238-
self.inner_path.introduction_node = IntroductionNode::NodeId(next_node_id);
239-
self.inner_path.blinded_hops.remove(0);
240-
Ok(())
241-
},
242-
_ => Err(()),
243-
}
221+
let (next_node_id, control_tlvs_ss) =
222+
match self.decrypt_intro_payload::<NS>(node_signer).map_err(|_| ())? {
223+
(BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, .. }), ss) => {
224+
let node_id = node_id_lookup.next_node_id(short_channel_id).ok_or(())?;
225+
(node_id, ss)
226+
},
227+
(BlindedPaymentTlvs::Dummy, ss) => {
228+
let node_id = node_signer.get_node_id(Recipient::Node)?;
229+
(node_id, ss)
230+
},
231+
_ => return Err(()),
232+
};
233+
234+
let new_blinding_point = onion_utils::next_hop_pubkey(
235+
secp_ctx,
236+
self.inner_path.blinding_point,
237+
control_tlvs_ss.as_ref(),
238+
)
239+
.map_err(|_| ())?;
240+
241+
self.inner_path.blinding_point = new_blinding_point;
242+
self.inner_path.introduction_node = IntroductionNode::NodeId(next_node_id);
243+
self.inner_path.blinded_hops.remove(0);
244+
245+
Ok(())
244246
}
245247

246248
pub(crate) fn decrypt_intro_payload<NS: Deref>(
@@ -262,9 +264,9 @@ impl BlindedPaymentPath {
262264
.map_err(|_| ())?;
263265

264266
match (&readable, used_aad) {
265-
(BlindedPaymentTlvs::Forward(_), false) | (BlindedPaymentTlvs::Receive(_), true) => {
266-
Ok((readable, control_tlvs_ss))
267-
},
267+
(BlindedPaymentTlvs::Forward(_), false)
268+
| (BlindedPaymentTlvs::Dummy, true)
269+
| (BlindedPaymentTlvs::Receive(_), true) => Ok((readable, control_tlvs_ss)),
268270
_ => Err(()),
269271
}
270272
}

lightning/src/ln/channelmanager.rs

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ use crate::ln::channel_state::ChannelDetails;
6666
use crate::ln::funding::SpliceContribution;
6767
use crate::ln::inbound_payment;
6868
use crate::ln::interactivetxs::InteractiveTxMessageSend;
69-
use crate::ln::msgs;
69+
use crate::ln::msgs::{self, OnionPacket, UpdateAddHTLC};
7070
use crate::ln::msgs::{
7171
BaseMessageHandler, ChannelMessageHandler, CommitmentUpdate, DecodeError, LightningError,
7272
MessageSendEvent,
@@ -6884,6 +6884,7 @@ where
68846884
fn process_pending_update_add_htlcs(&self) -> bool {
68856885
let mut should_persist = false;
68866886
let mut decode_update_add_htlcs = new_hash_map();
6887+
let mut dummy_update_add_htlcs = new_hash_map();
68876888
mem::swap(&mut decode_update_add_htlcs, &mut self.decode_update_add_htlcs.lock().unwrap());
68886889

68896890
let get_htlc_failure_type = |outgoing_scid_opt: Option<u64>, payment_hash: PaymentHash| {
@@ -6947,7 +6948,67 @@ where
69476948
&*self.logger,
69486949
&self.secp_ctx,
69496950
) {
6950-
Ok(decoded_onion) => decoded_onion,
6951+
Ok(decoded_onion) => match decoded_onion {
6952+
(
6953+
onion_utils::Hop::Dummy {
6954+
intro_node_blinding_point,
6955+
next_hop_hmac,
6956+
new_packet_bytes,
6957+
..
6958+
},
6959+
Some(NextPacketDetails {
6960+
next_packet_pubkey,
6961+
next_hop_forward_info,
6962+
}),
6963+
) => {
6964+
debug_assert!(
6965+
next_hop_forward_info.is_none(),
6966+
"Dummy hops must not contain any forward info, since they are not actually forwarded."
6967+
);
6968+
6969+
// Dummy hops are not forwarded. Instead, we reconstruct a new UpdateAddHTLC
6970+
// with the next onion packet (ephemeral pubkey, hop data, and HMAC) and push
6971+
// it back into our own processing queue. This lets us step through the dummy
6972+
// layers locally until we reach the next real hop.
6973+
let next_blinding_point = intro_node_blinding_point
6974+
.or(update_add_htlc.blinding_point)
6975+
.and_then(|blinding_point| {
6976+
let ss = self
6977+
.node_signer
6978+
.ecdh(Recipient::Node, &blinding_point, None)
6979+
.ok()?
6980+
.secret_bytes();
6981+
6982+
onion_utils::next_hop_pubkey(
6983+
&self.secp_ctx,
6984+
blinding_point,
6985+
&ss,
6986+
)
6987+
.ok()
6988+
});
6989+
6990+
let new_onion_packet = OnionPacket {
6991+
version: 0,
6992+
public_key: next_packet_pubkey,
6993+
hop_data: new_packet_bytes,
6994+
hmac: next_hop_hmac,
6995+
};
6996+
6997+
let new_update_add_htlc = UpdateAddHTLC {
6998+
onion_routing_packet: new_onion_packet,
6999+
blinding_point: next_blinding_point,
7000+
..update_add_htlc.clone()
7001+
};
7002+
7003+
dummy_update_add_htlcs
7004+
.entry(incoming_scid_alias)
7005+
.or_insert_with(Vec::new)
7006+
.push(new_update_add_htlc);
7007+
7008+
continue;
7009+
},
7010+
_ => decoded_onion,
7011+
},
69517012

69527013
Err((htlc_fail, reason)) => {
69537014
let failure_type = HTLCHandlingFailureType::InvalidOnion;
@@ -7104,6 +7165,23 @@ where
71047165
));
71057166
}
71067167
}
7168+
7169+
// Merge peeled dummy HTLCs into the existing decode queue so they can be
7170+
// processed in the next iteration. We avoid replacing the whole queue
7171+
// (e.g. via mem::swap) because other threads may have enqueued new HTLCs
7172+
// meanwhile; merging preserves everything safely.
7173+
if !dummy_update_add_htlcs.is_empty() {
7174+
let mut decode_update_add_htlc_source =
7175+
self.decode_update_add_htlcs.lock().unwrap();
7176+
7177+
for (incoming_scid_alias, htlcs) in dummy_update_add_htlcs.into_iter() {
7178+
decode_update_add_htlc_source
7179+
.entry(incoming_scid_alias)
7180+
.or_default()
7181+
.extend(htlcs);
7182+
}
7183+
}
7184+
71077185
should_persist
71087186
}
71097187

lightning/src/ln/onion_utils.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,6 +2356,12 @@ where
23562356
new_packet_bytes,
23572357
})
23582358
},
2359+
msgs::InboundOnionPayload::Dummy { intro_node_blinding_point } => Ok(Hop::Dummy {
2360+
intro_node_blinding_point,
2361+
shared_secret,
2362+
next_hop_hmac,
2363+
new_packet_bytes,
2364+
}),
23592365
_ => {
23602366
if blinding_point.is_some() {
23612367
return Err(OnionDecodeErr::Malformed {

0 commit comments

Comments
 (0)