Fix PaymentPathFailed::payment_failed_permanently on blinded path fail
authorValentine Wallace <vwallace@protonmail.com>
Thu, 14 Sep 2023 15:46:02 +0000 (11:46 -0400)
committerValentine Wallace <vwallace@protonmail.com>
Fri, 22 Sep 2023 19:56:23 +0000 (15:56 -0400)
Previously this value would be incorrectly set to true because we wouldn't
account for blinded hops when determining if we were processing the last hop's
failure packet.

lightning/src/ln/onion_utils.rs

index 4b5ccfe92dd1ce2d768950eee2c1c6df5fa31b3d..f3f8608604d3230ee113996a21f64d36720cd49a 100644 (file)
@@ -481,6 +481,26 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing, L: Deref>(
                        },
                };
 
+               // The failing hop includes either the inbound channel to the recipient or the outbound channel
+               // from the current hop (i.e., the next hop's inbound channel).
+               let num_blinded_hops = path.blinded_tail.as_ref().map_or(0, |bt| bt.hops.len());
+               // For 1-hop blinded paths, the final `path.hops` entry is the recipient.
+               is_from_final_node = route_hop_idx + 1 == path.hops.len() && num_blinded_hops <= 1;
+               let failing_route_hop = if is_from_final_node { route_hop } else {
+                       match path.hops.get(route_hop_idx + 1) {
+                               Some(hop) => hop,
+                               None => {
+                                       // The failing hop is within a multi-hop blinded path.
+                                       error_code_ret = Some(BADONION | PERM | 24); // invalid_onion_blinding
+                                       error_packet_ret = Some(vec![0; 32]);
+                                       res = Some(FailureLearnings {
+                                               network_update: None, short_channel_id: None, payment_failed_permanently: false
+                                       });
+                                       return
+                               }
+                       }
+               };
+
                let amt_to_forward = htlc_msat - route_hop.fee_msat;
                htlc_msat = amt_to_forward;
 
@@ -492,11 +512,6 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing, L: Deref>(
                chacha.process(&packet_decrypted, &mut decryption_tmp[..]);
                packet_decrypted = decryption_tmp;
 
-               // The failing hop includes either the inbound channel to the recipient or the outbound channel
-               // from the current hop (i.e., the next hop's inbound channel).
-               is_from_final_node = route_hop_idx + 1 == path.hops.len();
-               let failing_route_hop = if is_from_final_node { route_hop } else { &path.hops[route_hop_idx + 1] };
-
                let err_packet = match msgs::DecodedOnionErrorPacket::read(&mut Cursor::new(&packet_decrypted)) {
                        Ok(p) => p,
                        Err(_) => return