@@ -66,7 +66,7 @@ use crate::ln::channel_state::ChannelDetails;
6666use crate::ln::funding::SpliceContribution;
6767use crate::ln::inbound_payment;
6868use crate::ln::interactivetxs::InteractiveTxMessageSend;
69- use crate::ln::msgs;
69+ use crate::ln::msgs::{self, OnionPacket, UpdateAddHTLC} ;
7070use 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
0 commit comments